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