1 /*
2 * Copyright (C) 2024 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "moving_photo_napi.h"
17
18 #include <fcntl.h>
19 #include <unistd.h>
20
21 #include "directory_ex.h"
22 #include "file_uri.h"
23 #include "media_file_utils.h"
24 #include "media_library_napi.h"
25 #include "medialibrary_client_errno.h"
26 #include "medialibrary_errno.h"
27 #include "medialibrary_napi_utils.h"
28 #include "userfile_client.h"
29 #include "userfile_manager_types.h"
30
31 using namespace std;
32
33 namespace OHOS {
34 namespace Media {
35
36 static const string MOVING_PHOTO_NAPI_CLASS = "MovingPhoto";
37 thread_local napi_ref MovingPhotoNapi::constructor_ = nullptr;
Init(napi_env env,napi_value exports)38 napi_value MovingPhotoNapi::Init(napi_env env, napi_value exports)
39 {
40 NapiClassInfo info = {
41 .name = MOVING_PHOTO_NAPI_CLASS,
42 .ref = &constructor_,
43 .constructor = Constructor,
44 .props = {
45 DECLARE_NAPI_FUNCTION("requestContent", JSRequestContent),
46 DECLARE_NAPI_FUNCTION("getUri", JSGetUri),
47 }
48 };
49 MediaLibraryNapiUtils::NapiDefineClass(env, exports, info);
50 return exports;
51 }
52
Constructor(napi_env env,napi_callback_info info)53 napi_value MovingPhotoNapi::Constructor(napi_env env, napi_callback_info info)
54 {
55 napi_value newTarget = nullptr;
56 CHECK_ARGS(env, napi_get_new_target(env, info, &newTarget), JS_INNER_FAIL);
57 CHECK_COND_RET(newTarget != nullptr, nullptr, "Invalid call to constructor");
58
59 size_t argc = ARGS_ONE;
60 napi_value argv[ARGS_ONE] = { 0 };
61 napi_value thisVar = nullptr;
62 napi_valuetype valueType;
63 CHECK_ARGS(env, napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr), JS_INNER_FAIL);
64 CHECK_COND_WITH_MESSAGE(env, argc == ARGS_ONE, "Number of args is invalid");
65 CHECK_ARGS(env, napi_typeof(env, argv[PARAM0], &valueType), JS_INNER_FAIL);
66 CHECK_COND_WITH_MESSAGE(env, valueType == napi_string, "Invalid argument type");
67 size_t result;
68 char photoUri[PATH_MAX];
69 CHECK_ARGS(env, napi_get_value_string_utf8(env, argv[PARAM0], photoUri, PATH_MAX, &result), JS_INNER_FAIL);
70
71 unique_ptr<MovingPhotoNapi> obj = make_unique<MovingPhotoNapi>(string(photoUri));
72 CHECK_ARGS(env,
73 napi_wrap(env, thisVar, reinterpret_cast<void*>(obj.get()), MovingPhotoNapi::Destructor, nullptr,
74 nullptr),
75 JS_INNER_FAIL);
76 obj.release();
77 return thisVar;
78 }
79
Destructor(napi_env env,void * nativeObject,void * finalizeHint)80 void MovingPhotoNapi::Destructor(napi_env env, void* nativeObject, void* finalizeHint)
81 {
82 auto* movingPhotoNapi = reinterpret_cast<MovingPhotoNapi*>(nativeObject);
83 if (movingPhotoNapi == nullptr) {
84 return;
85 }
86
87 delete movingPhotoNapi;
88 movingPhotoNapi = nullptr;
89 }
90
GetUri()91 string MovingPhotoNapi::GetUri()
92 {
93 return photoUri_;
94 }
95
GetSourceMode()96 SourceMode MovingPhotoNapi::GetSourceMode()
97 {
98 return sourceMode_;
99 }
100
SetSourceMode(SourceMode sourceMode)101 void MovingPhotoNapi::SetSourceMode(SourceMode sourceMode)
102 {
103 sourceMode_ = sourceMode;
104 }
105
OpenReadOnlyVideo(const std::string & videoUri,bool isMediaLibUri)106 static int32_t OpenReadOnlyVideo(const std::string& videoUri, bool isMediaLibUri)
107 {
108 if (isMediaLibUri) {
109 std::string openVideoUri = videoUri;
110 MediaFileUtils::UriAppendKeyValue(openVideoUri, MEDIA_MOVING_PHOTO_OPRN_KEYWORD,
111 OPEN_MOVING_PHOTO_VIDEO);
112 Uri uri(openVideoUri);
113 return UserFileClient::OpenFile(uri, MEDIA_FILEMODE_READONLY);
114 }
115 AppFileService::ModuleFileUri::FileUri fileUri(videoUri);
116 std::string realPath = fileUri.GetRealPath();
117 int32_t fd = open(realPath.c_str(), O_RDONLY);
118 if (fd < 0) {
119 NAPI_ERR_LOG("Failed to open read only video file, errno:%{public}d", errno);
120 return -1;
121 }
122 return fd;
123 }
124
OpenReadOnlyImage(const std::string & imageUri,bool isMediaLibUri)125 static int32_t OpenReadOnlyImage(const std::string& imageUri, bool isMediaLibUri)
126 {
127 if (isMediaLibUri) {
128 Uri uri(imageUri);
129 return UserFileClient::OpenFile(uri, MEDIA_FILEMODE_READONLY);
130 }
131 AppFileService::ModuleFileUri::FileUri fileUri(imageUri);
132 std::string realPath = fileUri.GetRealPath();
133 int32_t fd = open(realPath.c_str(), O_RDONLY);
134 if (fd < 0) {
135 NAPI_ERR_LOG("Failed to open read only image file, errno: %{public}d", errno);
136 return -1;
137 }
138 return fd;
139 }
140
OpenReadOnlyFile(const std::string & uri,bool isReadImage)141 int32_t MovingPhotoNapi::OpenReadOnlyFile(const std::string& uri, bool isReadImage)
142 {
143 if (uri.empty()) {
144 NAPI_ERR_LOG("Failed to open read only file, uri is empty");
145 return -1;
146 }
147 std::string curUri = uri;
148 bool isMediaLibUri = MediaFileUtils::IsMediaLibraryUri(uri);
149 if (!isMediaLibUri) {
150 std::vector<std::string> uris;
151 if (!MediaFileUtils::SplitMovingPhotoUri(uri, uris)) {
152 NAPI_ERR_LOG("Failed to open read only file, split moving photo failed");
153 return -1;
154 }
155 curUri = uris[isReadImage ? MOVING_PHOTO_IMAGE_POS : MOVING_PHOTO_VIDEO_POS];
156 }
157 return isReadImage ? OpenReadOnlyImage(curUri, isMediaLibUri) : OpenReadOnlyVideo(curUri, isMediaLibUri);
158 }
159
OpenReadOnlyLivePhoto(const string & destLivePhotoUri)160 int32_t MovingPhotoNapi::OpenReadOnlyLivePhoto(const string& destLivePhotoUri)
161 {
162 if (destLivePhotoUri.empty()) {
163 NAPI_ERR_LOG("Failed to open read only file, uri is empty");
164 return E_ERR;
165 }
166 if (MediaFileUtils::IsMediaLibraryUri(destLivePhotoUri)) {
167 std::string str = destLivePhotoUri;
168 std::string MULTI_USER_URI_FLAG = "user=";
169 size_t pos = str.find(MULTI_USER_URI_FLAG);
170 std::string userId = "";
171 if (pos != std::string::npos) {
172 pos += MULTI_USER_URI_FLAG.length();
173 size_t end = str.find_first_of("&?", pos);
174 if (end == std::string::npos) {
175 end = str.length();
176 }
177 userId = str.substr(pos, end - pos);
178 NAPI_ERR_LOG("ReadMovingPhotoVideo for other user is %{public}s", userId.c_str());
179 }
180 string livePhotoUri = destLivePhotoUri;
181 MediaFileUtils::UriAppendKeyValue(livePhotoUri, MEDIA_MOVING_PHOTO_OPRN_KEYWORD,
182 OPEN_PRIVATE_LIVE_PHOTO);
183 Uri uri(livePhotoUri);
184 return UserFileClient::OpenFile(uri, MEDIA_FILEMODE_READONLY, userId !="" ? stoi(userId) : -1);
185 }
186 return E_ERR;
187 }
188
OpenReadOnlyMetadata(const string & movingPhotoUri)189 int32_t MovingPhotoNapi::OpenReadOnlyMetadata(const string& movingPhotoUri)
190 {
191 if (movingPhotoUri.empty()) {
192 NAPI_ERR_LOG("Failed to open metadata of moving photo, uri is empty");
193 return E_ERR;
194 }
195
196 if (!MediaFileUtils::IsMediaLibraryUri(movingPhotoUri)) {
197 NAPI_ERR_LOG("Failed to check uri of moving photo: %{private}s", movingPhotoUri.c_str());
198 return E_ERR;
199 }
200
201 string movingPhotoMetadataUri = movingPhotoUri;
202 MediaFileUtils::UriAppendKeyValue(
203 movingPhotoMetadataUri, MEDIA_MOVING_PHOTO_OPRN_KEYWORD, OPEN_PRIVATE_MOVING_PHOTO_METADATA);
204 Uri uri(movingPhotoMetadataUri);
205 return UserFileClient::OpenFile(uri, MEDIA_FILEMODE_READONLY);
206 }
207
CopyFileFromMediaLibrary(int32_t srcFd,int32_t destFd)208 static int32_t CopyFileFromMediaLibrary(int32_t srcFd, int32_t destFd)
209 {
210 constexpr size_t bufferSize = 4096;
211 char buffer[bufferSize];
212 ssize_t bytesRead;
213 ssize_t bytesWritten;
214 while ((bytesRead = read(srcFd, buffer, bufferSize)) > 0) {
215 bytesWritten = write(destFd, buffer, bytesRead);
216 if (bytesWritten != bytesRead) {
217 NAPI_ERR_LOG("Failed to copy file from srcFd=%{public}d to destFd=%{public}d, errno=%{public}d",
218 srcFd, destFd, errno);
219 return E_HAS_FS_ERROR;
220 }
221 }
222
223 if (bytesRead < 0) {
224 NAPI_ERR_LOG("Failed to read from srcFd=%{public}d, errno=%{public}d", srcFd, errno);
225 return E_HAS_FS_ERROR;
226 }
227 return E_OK;
228 }
229
WriteToSandboxUri(int32_t srcFd,const string & sandboxUri)230 static int32_t WriteToSandboxUri(int32_t srcFd, const string& sandboxUri)
231 {
232 UniqueFd srcUniqueFd(srcFd);
233
234 AppFileService::ModuleFileUri::FileUri fileUri(sandboxUri);
235 string destPath = fileUri.GetRealPath();
236 if (!MediaFileUtils::IsFileExists(destPath) && !MediaFileUtils::CreateFile(destPath)) {
237 NAPI_ERR_LOG("Create empty dest file in sandbox failed, path:%{private}s", destPath.c_str());
238 return E_HAS_FS_ERROR;
239 }
240 int32_t destFd = MediaFileUtils::OpenFile(destPath, MEDIA_FILEMODE_READWRITE);
241 if (destFd < 0) {
242 NAPI_ERR_LOG("Open dest file failed, error: %{public}d", errno);
243 return E_HAS_FS_ERROR;
244 }
245 UniqueFd destUniqueFd(destFd);
246
247 if (ftruncate(destUniqueFd.Get(), 0) == -1) {
248 NAPI_ERR_LOG("Truncate old file in sandbox failed, error:%{public}d", errno);
249 return E_HAS_FS_ERROR;
250 }
251 return CopyFileFromMediaLibrary(srcUniqueFd.Get(), destUniqueFd.Get());
252 }
253
HandleFd(int32_t & fd)254 static bool HandleFd(int32_t& fd)
255 {
256 if (fd == E_ERR) {
257 fd = E_HAS_FS_ERROR;
258 return false;
259 } else if (fd < 0) {
260 NAPI_ERR_LOG("Open failed due to OpenFile failure, error: %{public}d", fd);
261 return false;
262 }
263 return true;
264 }
265
RequestContentToSandbox(MovingPhotoAsyncContext * context)266 static int32_t RequestContentToSandbox(MovingPhotoAsyncContext* context)
267 {
268 string movingPhotoUri = context->movingPhotoUri;
269 if (context->sourceMode == SourceMode::ORIGINAL_MODE) {
270 MediaFileUtils::UriAppendKeyValue(movingPhotoUri, MEDIA_OPERN_KEYWORD, SOURCE_REQUEST);
271 }
272 if (!context->destImageUri.empty()) {
273 int32_t imageFd = MovingPhotoNapi::OpenReadOnlyFile(movingPhotoUri, true);
274 CHECK_COND_RET(HandleFd(imageFd), imageFd, "Open source image file failed");
275 int32_t ret = WriteToSandboxUri(imageFd, context->destImageUri);
276 CHECK_COND_RET(ret == E_OK, ret, "Write image to sandbox failed");
277 }
278 if (!context->destVideoUri.empty()) {
279 int32_t videoFd = MovingPhotoNapi::OpenReadOnlyFile(movingPhotoUri, false);
280 CHECK_COND_RET(HandleFd(videoFd), videoFd, "Open source video file failed");
281 int32_t ret = WriteToSandboxUri(videoFd, context->destVideoUri);
282 CHECK_COND_RET(ret == E_OK, ret, "Write video to sandbox failed");
283 }
284 if (!context->destLivePhotoUri.empty()) {
285 int32_t livePhotoFd = MovingPhotoNapi::OpenReadOnlyLivePhoto(movingPhotoUri);
286 CHECK_COND_RET(HandleFd(livePhotoFd), livePhotoFd, "Open source video file failed");
287 int32_t ret = WriteToSandboxUri(livePhotoFd, context->destLivePhotoUri);
288 CHECK_COND_RET(ret == E_OK, ret, "Write video to sandbox failed");
289 }
290
291 return E_OK;
292 }
293
AcquireFdForArrayBuffer(MovingPhotoAsyncContext * context)294 static int32_t AcquireFdForArrayBuffer(MovingPhotoAsyncContext* context)
295 {
296 int32_t fd = 0;
297 string movingPhotoUri = context->movingPhotoUri;
298 if (context->sourceMode == SourceMode::ORIGINAL_MODE) {
299 MediaFileUtils::UriAppendKeyValue(movingPhotoUri, MEDIA_OPERN_KEYWORD, SOURCE_REQUEST);
300 }
301 switch (context->resourceType) {
302 case ResourceType::IMAGE_RESOURCE: {
303 fd = MovingPhotoNapi::OpenReadOnlyFile(movingPhotoUri, true);
304 CHECK_COND_RET(HandleFd(fd), fd, "Open source image file failed");
305 return fd;
306 }
307 case ResourceType::VIDEO_RESOURCE:
308 fd = MovingPhotoNapi::OpenReadOnlyFile(movingPhotoUri, false);
309 CHECK_COND_RET(HandleFd(fd), fd, "Open source video file failed");
310 return fd;
311 case ResourceType::PRIVATE_MOVING_PHOTO_RESOURCE:
312 fd = MovingPhotoNapi::OpenReadOnlyLivePhoto(movingPhotoUri);
313 CHECK_COND_RET(HandleFd(fd), fd, "Open live photo failed");
314 return fd;
315 case ResourceType::PRIVATE_MOVING_PHOTO_METADATA:
316 fd = MovingPhotoNapi::OpenReadOnlyMetadata(movingPhotoUri);
317 CHECK_COND_RET(HandleFd(fd), fd, "Open moving photo metadata failed");
318 return fd;
319 default:
320 NAPI_ERR_LOG("Invalid resource type: %{public}d", static_cast<int32_t>(context->resourceType));
321 return -EINVAL;
322 }
323 }
324
RequestContentToArrayBuffer(napi_env env,MovingPhotoAsyncContext * context)325 static int32_t RequestContentToArrayBuffer(napi_env env, MovingPhotoAsyncContext* context)
326 {
327 int32_t fd = AcquireFdForArrayBuffer(context);
328 if (fd < 0) {
329 return fd;
330 }
331 UniqueFd uniqueFd(fd);
332
333 off_t fileLen = lseek(uniqueFd.Get(), 0, SEEK_END);
334 if (fileLen < 0) {
335 NAPI_ERR_LOG("Failed to get file length, error: %{public}d", errno);
336 return E_HAS_FS_ERROR;
337 }
338
339 off_t ret = lseek(uniqueFd.Get(), 0, SEEK_SET);
340 if (ret < 0) {
341 NAPI_ERR_LOG("Failed to reset file offset, error: %{public}d", errno);
342 return E_HAS_FS_ERROR;
343 }
344
345 size_t fileSize = static_cast<size_t>(fileLen);
346
347 context->arrayBufferData = malloc(fileSize);
348 if (!context->arrayBufferData) {
349 NAPI_ERR_LOG("Failed to malloc array buffer data, moving photo uri is %{public}s, resource type is %{public}d",
350 context->movingPhotoUri.c_str(), static_cast<int32_t>(context->resourceType));
351 return E_HAS_FS_ERROR;
352 }
353
354 size_t readBytes = static_cast<size_t>(read(uniqueFd.Get(), context->arrayBufferData, fileSize));
355 if (readBytes != fileSize) {
356 NAPI_ERR_LOG("read file failed, read bytes is %{public}zu, actual length is %{public}zu, "
357 "error: %{public}d", readBytes, fileSize, errno);
358 free(context->arrayBufferData);
359 context->arrayBufferData = nullptr;
360 return E_HAS_FS_ERROR;
361 }
362
363 context->arrayBufferLength = fileSize;
364 return E_OK;
365 }
366
IsValidResourceType(int32_t resourceType)367 static bool IsValidResourceType(int32_t resourceType)
368 {
369 return resourceType == static_cast<int32_t>(ResourceType::IMAGE_RESOURCE) ||
370 resourceType == static_cast<int32_t>(ResourceType::VIDEO_RESOURCE) ||
371 (resourceType == static_cast<int32_t>(ResourceType::PRIVATE_MOVING_PHOTO_RESOURCE) &&
372 MediaLibraryNapiUtils::IsSystemApp()) ||
373 (resourceType == static_cast<int32_t>(ResourceType::PRIVATE_MOVING_PHOTO_METADATA) &&
374 MediaLibraryNapiUtils::IsSystemApp());
375 }
376
ParseArgsForRequestContent(napi_env env,size_t argc,const napi_value argv[],MovingPhotoNapi * thisArg,unique_ptr<MovingPhotoAsyncContext> & context)377 static napi_value ParseArgsForRequestContent(napi_env env, size_t argc, const napi_value argv[],
378 MovingPhotoNapi* thisArg, unique_ptr<MovingPhotoAsyncContext>& context)
379 {
380 CHECK_COND_WITH_MESSAGE(env, (argc == ARGS_ONE || argc == ARGS_TWO), "Invalid number of arguments");
381 CHECK_COND(env, thisArg != nullptr, JS_INNER_FAIL);
382 context->movingPhotoUri = thisArg->GetUri();
383 context->sourceMode = thisArg->GetSourceMode();
384
385 int32_t resourceType = 0;
386 if (argc == ARGS_ONE) {
387 // return by array buffer
388 CHECK_ARGS(env, napi_get_value_int32(env, argv[ARGS_ZERO], &resourceType), JS_INNER_FAIL);
389 CHECK_COND_WITH_MESSAGE(env, IsValidResourceType(resourceType), "Invalid resource type");
390 context->requestContentMode = MovingPhotoAsyncContext::WRITE_TO_ARRAY_BUFFER;
391 context->resourceType = static_cast<ResourceType>(resourceType);
392 } else if (argc == ARGS_TWO) {
393 context->requestContentMode = MovingPhotoAsyncContext::WRITE_TO_SANDBOX;
394 napi_valuetype valueTypeFront;
395 napi_valuetype valueTypeBack;
396 CHECK_ARGS(env, napi_typeof(env, argv[ARGS_ZERO], &valueTypeFront), JS_INNER_FAIL);
397 CHECK_ARGS(env, napi_typeof(env, argv[ARGS_ONE], &valueTypeBack), JS_INNER_FAIL);
398 if (valueTypeFront == napi_string && valueTypeBack == napi_string) {
399 // write both image and video to sandbox
400 CHECK_ARGS(env, MediaLibraryNapiUtils::GetParamStringPathMax(env, argv[ARGS_ZERO], context->destImageUri),
401 JS_INNER_FAIL);
402 CHECK_ARGS(env, MediaLibraryNapiUtils::GetParamStringPathMax(env, argv[ARGS_ONE], context->destVideoUri),
403 JS_INNER_FAIL);
404 } else if (valueTypeFront == napi_number && valueTypeBack == napi_string) {
405 // write specific resource to sandbox
406 CHECK_ARGS(env, napi_get_value_int32(env, argv[ARGS_ZERO], &resourceType), JS_INNER_FAIL);
407 CHECK_COND_WITH_MESSAGE(env, IsValidResourceType(resourceType), "Invalid resource type");
408 if (resourceType == static_cast<int32_t>(ResourceType::IMAGE_RESOURCE)) {
409 CHECK_ARGS(env, MediaLibraryNapiUtils::GetParamStringPathMax(env, argv[ARGS_ONE],
410 context->destImageUri), JS_INNER_FAIL);
411 } else if (resourceType == static_cast<int32_t>(ResourceType::VIDEO_RESOURCE)) {
412 CHECK_ARGS(env, MediaLibraryNapiUtils::GetParamStringPathMax(env, argv[ARGS_ONE],
413 context->destVideoUri), JS_INNER_FAIL);
414 } else {
415 CHECK_ARGS(env, MediaLibraryNapiUtils::GetParamStringPathMax(env, argv[ARGS_ONE],
416 context->destLivePhotoUri), JS_INNER_FAIL);
417 }
418 context->resourceType = static_cast<ResourceType>(resourceType);
419 } else {
420 NapiError::ThrowError(env, OHOS_INVALID_PARAM_CODE, __FUNCTION__, __LINE__, "Invalid type of arguments");
421 return nullptr;
422 }
423 }
424 RETURN_NAPI_TRUE(env);
425 }
426
RequestContentExecute(napi_env env,void * data)427 static void RequestContentExecute(napi_env env, void *data)
428 {
429 auto* context = static_cast<MovingPhotoAsyncContext*>(data);
430 int32_t ret;
431 switch (context->requestContentMode) {
432 case MovingPhotoAsyncContext::WRITE_TO_SANDBOX:
433 ret = RequestContentToSandbox(context);
434 break;
435 case MovingPhotoAsyncContext::WRITE_TO_ARRAY_BUFFER:
436 ret = RequestContentToArrayBuffer(env, context);
437 break;
438 default:
439 NAPI_ERR_LOG("Invalid request content mode: %{public}d", static_cast<int32_t>(context->requestContentMode));
440 context->error = OHOS_INVALID_PARAM_CODE;
441 return;
442 }
443 if (ret != E_OK) {
444 context->SaveError(ret);
445 return;
446 }
447 }
448
RequestContentComplete(napi_env env,napi_status status,void * data)449 static void RequestContentComplete(napi_env env, napi_status status, void *data)
450 {
451 MovingPhotoAsyncContext *context = static_cast<MovingPhotoAsyncContext*>(data);
452 CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
453
454 napi_value outBuffer = nullptr;
455 if (context->error == E_OK && context->requestContentMode == MovingPhotoAsyncContext::WRITE_TO_ARRAY_BUFFER) {
456 napi_status status = napi_create_external_arraybuffer(
457 env, context->arrayBufferData, context->arrayBufferLength,
458 [](napi_env env, void* data, void* hint) { free(data); }, nullptr, &outBuffer);
459 if (status != napi_ok) {
460 NAPI_ERR_LOG("Failed to create array buffer object, uri is %{public}s, resource type is %{public}d",
461 context->movingPhotoUri.c_str(), context->resourceType);
462 free(context->arrayBufferData);
463 context->arrayBufferData = nullptr;
464 context->error = JS_INNER_FAIL;
465 }
466 } else if (context->arrayBufferData != nullptr) {
467 free(context->arrayBufferData);
468 context->arrayBufferData = nullptr;
469 }
470
471 unique_ptr<JSAsyncContextOutput> outContext = make_unique<JSAsyncContextOutput>();
472 outContext->status = false;
473 napi_get_undefined(env, &outContext->data);
474
475 if (context->error != E_OK) {
476 context->HandleError(env, outContext->error);
477 } else {
478 outContext->status = true;
479 if (context->requestContentMode == MovingPhotoAsyncContext::WRITE_TO_ARRAY_BUFFER) {
480 outContext->data = outBuffer;
481 }
482 }
483 if (context->work != nullptr) {
484 MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, nullptr,
485 context->work, *outContext);
486 } else {
487 NAPI_ERR_LOG("Async work is nullptr");
488 }
489 delete context;
490 }
491
JSRequestContent(napi_env env,napi_callback_info info)492 napi_value MovingPhotoNapi::JSRequestContent(napi_env env, napi_callback_info info)
493 {
494 size_t argc = ARGS_TWO;
495 napi_value argv[ARGS_TWO] = {0};
496 napi_value thisVar = nullptr;
497 CHECK_ARGS(env, napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr), JS_INNER_FAIL);
498
499 unique_ptr<MovingPhotoAsyncContext> asyncContext = make_unique<MovingPhotoAsyncContext>();
500 MovingPhotoNapi* nativeObject;
501 CHECK_ARGS(env, napi_unwrap(env, thisVar, reinterpret_cast<void **>(&nativeObject)), JS_INNER_FAIL);
502 CHECK_NULLPTR_RET(ParseArgsForRequestContent(env, argc, argv, nativeObject, asyncContext));
503
504 return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "JSRequestContent",
505 RequestContentExecute, RequestContentComplete);
506 }
507
NewMovingPhotoNapi(napi_env env,const string & photoUri,SourceMode sourceMode)508 napi_value MovingPhotoNapi::NewMovingPhotoNapi(napi_env env, const string& photoUri,
509 SourceMode sourceMode)
510 {
511 napi_value constructor = nullptr;
512 napi_value instance = nullptr;
513 napi_value napiStringUri = nullptr;
514 napi_status status = napi_create_string_utf8(env, photoUri.c_str(), NAPI_AUTO_LENGTH, &napiStringUri);
515 CHECK_COND_RET(status == napi_ok, nullptr, "Failed to create napi string, napi status: %{public}d",
516 static_cast<int>(status));
517 status = napi_get_reference_value(env, constructor_, &constructor);
518 CHECK_COND_RET(status == napi_ok, nullptr, "Failed to get reference of constructor, napi status: %{public}d",
519 static_cast<int>(status));
520 status = napi_new_instance(env, constructor, 1, &napiStringUri, &instance);
521 CHECK_COND_RET(status == napi_ok, nullptr, "Failed to get new instance of moving photo, napi status: %{public}d",
522 static_cast<int>(status));
523 CHECK_COND_RET(instance != nullptr, nullptr, "Instance is nullptr");
524
525 MovingPhotoNapi* movingPhotoNapi = nullptr;
526 status = napi_unwrap(env, instance, reinterpret_cast<void**>(&movingPhotoNapi));
527 CHECK_COND_RET(status == napi_ok, nullptr, "Failed to unwarp instance of MovingPhotoNapi");
528 CHECK_COND_RET(movingPhotoNapi != nullptr, nullptr, "movingPhotoNapi is nullptr");
529 movingPhotoNapi->SetSourceMode(sourceMode);
530 return instance;
531 }
532
JSGetUri(napi_env env,napi_callback_info info)533 napi_value MovingPhotoNapi::JSGetUri(napi_env env, napi_callback_info info)
534 {
535 MovingPhotoNapi *obj = nullptr;
536 napi_value thisVar = nullptr;
537 CHECK_ARGS(env, napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, nullptr), JS_INNER_FAIL);
538 if (thisVar == nullptr) {
539 NapiError::ThrowError(env, JS_INNER_FAIL);
540 return nullptr;
541 }
542
543 CHECK_ARGS(env, napi_unwrap(env, thisVar, reinterpret_cast<void **>(&obj)), JS_INNER_FAIL);
544 if (obj == nullptr) {
545 NapiError::ThrowError(env, JS_INNER_FAIL);
546 return nullptr;
547 }
548
549 napi_value jsResult = nullptr;
550 CHECK_ARGS(env, napi_create_string_utf8(env, obj->GetUri().c_str(), NAPI_AUTO_LENGTH, &jsResult), JS_INNER_FAIL);
551 return jsResult;
552 }
553 } // namespace Media
554 } // namespace OHOS