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 context->arrayBufferLength = fileSize;
319
320 size_t readBytes = static_cast<size_t>(read(uniqueFd.Get(), context->arrayBufferData, fileSize));
321 if (readBytes != fileSize) {
322 NAPI_ERR_LOG("read file failed, read bytes is %{public}zu, actual length is %{public}zu, "
323 "error: %{public}d", readBytes, fileSize, errno);
324 return E_HAS_FS_ERROR;
325 }
326 return E_OK;
327 }
328
IsValidResourceType(int32_t resourceType)329 static bool IsValidResourceType(int32_t resourceType)
330 {
331 return (resourceType == static_cast<int>(ResourceType::IMAGE_RESOURCE) ||
332 resourceType == static_cast<int>(ResourceType::VIDEO_RESOURCE) ||
333 resourceType == static_cast<int>(ResourceType::PRIVATE_MOVING_PHOTO_RESOURCE));
334 }
335
ParseArgsForRequestContent(napi_env env,size_t argc,const napi_value argv[],MovingPhotoNapi * thisArg,unique_ptr<MovingPhotoAsyncContext> & context)336 static napi_value ParseArgsForRequestContent(napi_env env, size_t argc, const napi_value argv[],
337 MovingPhotoNapi* thisArg, unique_ptr<MovingPhotoAsyncContext>& context)
338 {
339 CHECK_COND_WITH_MESSAGE(env, (argc == ARGS_ONE || argc == ARGS_TWO), "Invalid number of arguments");
340 CHECK_COND(env, thisArg != nullptr, JS_INNER_FAIL);
341 context->movingPhotoUri = thisArg->GetUri();
342 context->sourceMode = thisArg->GetSourceMode();
343
344 int32_t resourceType = 0;
345 if (argc == ARGS_ONE) {
346 // return by array buffer
347 CHECK_ARGS(env, napi_get_value_int32(env, argv[ARGS_ZERO], &resourceType), JS_INNER_FAIL);
348 CHECK_COND_WITH_MESSAGE(env, IsValidResourceType(resourceType), "Invalid resource type");
349 context->requestContentMode = MovingPhotoAsyncContext::WRITE_TO_ARRAY_BUFFER;
350 context->resourceType = static_cast<ResourceType>(resourceType);
351 } else if (argc == ARGS_TWO) {
352 context->requestContentMode = MovingPhotoAsyncContext::WRITE_TO_SANDBOX;
353 napi_valuetype valueTypeFront;
354 napi_valuetype valueTypeBack;
355 CHECK_ARGS(env, napi_typeof(env, argv[ARGS_ZERO], &valueTypeFront), JS_INNER_FAIL);
356 CHECK_ARGS(env, napi_typeof(env, argv[ARGS_ONE], &valueTypeBack), JS_INNER_FAIL);
357 if (valueTypeFront == napi_string && valueTypeBack == napi_string) {
358 // write both image and video to sandbox
359 CHECK_ARGS(env, MediaLibraryNapiUtils::GetParamStringPathMax(env, argv[ARGS_ZERO], context->destImageUri),
360 JS_INNER_FAIL);
361 CHECK_ARGS(env, MediaLibraryNapiUtils::GetParamStringPathMax(env, argv[ARGS_ONE], context->destVideoUri),
362 JS_INNER_FAIL);
363 } else if (valueTypeFront == napi_number && valueTypeBack == napi_string) {
364 // write image or video to sandbox
365 CHECK_ARGS(env, napi_get_value_int32(env, argv[ARGS_ZERO], &resourceType), JS_INNER_FAIL);
366 CHECK_COND_WITH_MESSAGE(env, IsValidResourceType(resourceType), "Invalid resource type");
367 if (resourceType == static_cast<int>(ResourceType::IMAGE_RESOURCE)) {
368 CHECK_ARGS(env, MediaLibraryNapiUtils::GetParamStringPathMax(env, argv[ARGS_ONE],
369 context->destImageUri), JS_INNER_FAIL);
370 } else if (resourceType == static_cast<int>(ResourceType::VIDEO_RESOURCE)) {
371 CHECK_ARGS(env, MediaLibraryNapiUtils::GetParamStringPathMax(env, argv[ARGS_ONE],
372 context->destVideoUri), JS_INNER_FAIL);
373 } else {
374 CHECK_ARGS(env, MediaLibraryNapiUtils::GetParamStringPathMax(env, argv[ARGS_ONE],
375 context->destLivePhotoUri), JS_INNER_FAIL);
376 }
377 context->resourceType = static_cast<ResourceType>(resourceType);
378 } else {
379 NapiError::ThrowError(env, OHOS_INVALID_PARAM_CODE, __FUNCTION__, __LINE__, "Invalid type of arguments");
380 return nullptr;
381 }
382 }
383 RETURN_NAPI_TRUE(env);
384 }
385
RequestContentExecute(napi_env env,void * data)386 static void RequestContentExecute(napi_env env, void *data)
387 {
388 auto* context = static_cast<MovingPhotoAsyncContext*>(data);
389 int32_t ret;
390 switch (context->requestContentMode) {
391 case MovingPhotoAsyncContext::WRITE_TO_SANDBOX:
392 ret = RequestContentToSandbox(context);
393 break;
394 case MovingPhotoAsyncContext::WRITE_TO_ARRAY_BUFFER:
395 ret = RequestContentToArrayBuffer(env, context);
396 break;
397 default:
398 NAPI_ERR_LOG("Invalid request content mode: %{public}d", static_cast<int32_t>(context->requestContentMode));
399 context->error = OHOS_INVALID_PARAM_CODE;
400 return;
401 }
402 if (ret != E_OK) {
403 context->SaveError(ret);
404 return;
405 }
406 }
407
RequestContentComplete(napi_env env,napi_status status,void * data)408 static void RequestContentComplete(napi_env env, napi_status status, void *data)
409 {
410 MovingPhotoAsyncContext *context = static_cast<MovingPhotoAsyncContext*>(data);
411 CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
412
413 napi_value outBuffer = nullptr;
414 if (context->error == E_OK && context->requestContentMode == MovingPhotoAsyncContext::WRITE_TO_ARRAY_BUFFER) {
415 napi_status status = napi_create_external_arraybuffer(
416 env, context->arrayBufferData, context->arrayBufferLength,
417 [](napi_env env, void* data, void* hint) { free(data); }, nullptr, &outBuffer);
418 if (status != napi_ok) {
419 NAPI_ERR_LOG("Failed to create array buffer object, uri is %{public}s, resource type is %{public}d",
420 context->movingPhotoUri.c_str(), context->resourceType);
421 free(context->arrayBufferData);
422 context->arrayBufferData = nullptr;
423 context->error = JS_INNER_FAIL;
424 }
425 } else if (context->arrayBufferData != nullptr) {
426 free(context->arrayBufferData);
427 context->arrayBufferData = nullptr;
428 }
429
430 unique_ptr<JSAsyncContextOutput> outContext = make_unique<JSAsyncContextOutput>();
431 outContext->status = false;
432 napi_get_undefined(env, &outContext->data);
433
434 if (context->error != E_OK) {
435 context->HandleError(env, outContext->error);
436 } else {
437 outContext->status = true;
438 if (context->requestContentMode == MovingPhotoAsyncContext::WRITE_TO_ARRAY_BUFFER) {
439 outContext->data = outBuffer;
440 }
441 }
442 if (context->work != nullptr) {
443 MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, nullptr,
444 context->work, *outContext);
445 } else {
446 NAPI_ERR_LOG("Async work is nullptr");
447 }
448 delete context;
449 }
450
JSRequestContent(napi_env env,napi_callback_info info)451 napi_value MovingPhotoNapi::JSRequestContent(napi_env env, napi_callback_info info)
452 {
453 size_t argc = ARGS_TWO;
454 napi_value argv[ARGS_TWO] = {0};
455 napi_value thisVar = nullptr;
456 CHECK_ARGS(env, napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr), JS_INNER_FAIL);
457
458 unique_ptr<MovingPhotoAsyncContext> asyncContext = make_unique<MovingPhotoAsyncContext>();
459 MovingPhotoNapi* nativeObject;
460 CHECK_ARGS(env, napi_unwrap(env, thisVar, reinterpret_cast<void **>(&nativeObject)), JS_INNER_FAIL);
461 CHECK_NULLPTR_RET(ParseArgsForRequestContent(env, argc, argv, nativeObject, asyncContext));
462
463 return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "JSRequestContent",
464 RequestContentExecute, RequestContentComplete);
465 }
466
NewMovingPhotoNapi(napi_env env,const string & photoUri,SourceMode sourceMode)467 napi_value MovingPhotoNapi::NewMovingPhotoNapi(napi_env env, const string& photoUri,
468 SourceMode sourceMode)
469 {
470 napi_value constructor = nullptr;
471 napi_value instance = nullptr;
472 napi_value napiStringUri = nullptr;
473 napi_status status = napi_create_string_utf8(env, photoUri.c_str(), NAPI_AUTO_LENGTH, &napiStringUri);
474 CHECK_COND_RET(status == napi_ok, nullptr, "Failed to create napi string, napi status: %{public}d",
475 static_cast<int>(status));
476 status = napi_get_reference_value(env, constructor_, &constructor);
477 CHECK_COND_RET(status == napi_ok, nullptr, "Failed to get reference of constructor, napi status: %{public}d",
478 static_cast<int>(status));
479 status = napi_new_instance(env, constructor, 1, &napiStringUri, &instance);
480 CHECK_COND_RET(status == napi_ok, nullptr, "Failed to get new instance of moving photo, napi status: %{public}d",
481 static_cast<int>(status));
482 CHECK_COND_RET(instance != nullptr, nullptr, "Instance is nullptr");
483
484 MovingPhotoNapi* movingPhotoNapi = nullptr;
485 status = napi_unwrap(env, instance, reinterpret_cast<void**>(&movingPhotoNapi));
486 CHECK_COND_RET(status == napi_ok, nullptr, "Failed to unwarp instance of MovingPhotoNapi");
487 CHECK_COND_RET(movingPhotoNapi != nullptr, nullptr, "movingPhotoNapi is nullptr");
488 movingPhotoNapi->SetSourceMode(sourceMode);
489 return instance;
490 }
491
JSGetUri(napi_env env,napi_callback_info info)492 napi_value MovingPhotoNapi::JSGetUri(napi_env env, napi_callback_info info)
493 {
494 MovingPhotoNapi *obj = nullptr;
495 napi_value thisVar = nullptr;
496 CHECK_ARGS(env, napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, nullptr), JS_INNER_FAIL);
497 if (thisVar == nullptr) {
498 NapiError::ThrowError(env, JS_INNER_FAIL);
499 return nullptr;
500 }
501
502 CHECK_ARGS(env, napi_unwrap(env, thisVar, reinterpret_cast<void **>(&obj)), JS_INNER_FAIL);
503 if (obj == nullptr) {
504 NapiError::ThrowError(env, JS_INNER_FAIL);
505 return nullptr;
506 }
507
508 napi_value jsResult = nullptr;
509 CHECK_ARGS(env, napi_create_string_utf8(env, obj->GetUri().c_str(), NAPI_AUTO_LENGTH, &jsResult), JS_INNER_FAIL);
510 return jsResult;
511 }
512 } // namespace Media
513 } // namespace OHOS
514