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 <map>
17 #include "metadata_napi.h"
18 #include "media_errors.h"
19 #include "image_log.h"
20 #include "image_napi_utils.h"
21 #include "image_common.h"
22 #include "napi_message_sequence.h"
23 #include "exif_metadata_formatter.h"
24
25 #undef LOG_DOMAIN
26 #define LOG_DOMAIN LOG_TAG_DOMAIN_ID_IMAGE
27
28 #undef LOG_TAG
29 #define LOG_TAG "MetadataNapi"
30
31 namespace {
32 constexpr uint32_t NUM_0 = 0;
33 constexpr uint32_t NUM_1 = 1;
34 constexpr uint32_t NUM_2 = 2;
35 }
36
37 namespace OHOS {
38 namespace Media {
39 static const std::string CLASS_NAME = "ImageMetadata";
40 thread_local napi_ref MetadataNapi::sConstructor_ = nullptr;
41 thread_local std::shared_ptr<ImageMetadata> MetadataNapi::sMetadata_ = nullptr;
42
43 #if !defined(IOS_PLATFORM) && !defined(ANDROID_PLATFORM)
44 #endif
45
46 struct MetadataNapiAsyncContext {
47 napi_env env;
48 napi_async_work work;
49 napi_deferred deferred;
50 napi_ref callbackRef;
51 napi_ref error = nullptr;
52 uint32_t status;
53 MetadataNapi *nConstructor;
54 std::shared_ptr<ImageMetadata> rMetadata;
55 std::vector<std::string> keyStrArray;
56 std::multimap<int32_t, std::string> errMsgArray;
57 std::vector<std::pair<std::string, std::string>> KVSArray;
58 };
59 using MetadataNapiAsyncContextPtr = std::unique_ptr<MetadataNapiAsyncContext>;
60
MetadataNapi()61 MetadataNapi::MetadataNapi():env_(nullptr)
62 {
63 static std::atomic<uint32_t> currentId = 0;
64 uniqueId_ = currentId.fetch_add(1, std::memory_order_relaxed);
65 }
66
~MetadataNapi()67 MetadataNapi::~MetadataNapi()
68 {
69 release();
70 }
71
SetValueStr(napi_env env, std::string keyStr, std::string valueStr, napi_value &object)72 napi_status SetValueStr(napi_env env, std::string keyStr, std::string valueStr, napi_value &object)
73 {
74 napi_value value = nullptr;
75 napi_status status;
76 if (valueStr != "") {
77 status = napi_create_string_utf8(env, valueStr.c_str(), valueStr.length(), &value);
78 if (status != napi_ok) {
79 IMAGE_LOGE("Set Value failed %{public}d", status);
80 return napi_invalid_arg;
81 }
82 } else {
83 status = napi_get_null(env, &value);
84 if (status != napi_ok) {
85 IMAGE_LOGE("Set null failed %{public}d", status);
86 return napi_invalid_arg;
87 }
88 }
89 status = napi_set_named_property(env, object, keyStr.c_str(), value);
90 if (status != napi_ok) {
91 IMAGE_LOGE("Set Key failed %{public}d", status);
92 return napi_invalid_arg;
93 }
94 IMAGE_LOGD("Set string value success.");
95 return napi_ok;
96 }
97
SetArrayInfo(napi_env env, std::vector<std::pair<std::string, std::string>> recordParameters)98 napi_value SetArrayInfo(napi_env env, std::vector<std::pair<std::string, std::string>> recordParameters)
99 {
100 napi_value result = nullptr;
101 napi_get_undefined(env, &result);
102 napi_status status = napi_create_object(env, &result);
103 if (status != napi_ok) {
104 IMAGE_LOGE("Create record failed %{public}d", status);
105 return result;
106 }
107
108 for (size_t index = 0; index < recordParameters.size(); ++index) {
109 status = SetValueStr(env, recordParameters[index].first, recordParameters[index].second, result);
110 if (status != napi_ok) {
111 IMAGE_LOGE("Set current record parameter failed %{public}d", status);
112 continue;
113 }
114 }
115
116 IMAGE_LOGD("Set record parameters info success.");
117 return result;
118 }
119
CommonCallbackRoutine(napi_env env, MetadataNapiAsyncContext* &asyncContext, const napi_value &valueParam)120 static void CommonCallbackRoutine(napi_env env, MetadataNapiAsyncContext* &asyncContext, const napi_value &valueParam)
121 {
122 napi_value result[NUM_2] = {0};
123
124 napi_get_undefined(env, &result[NUM_0]);
125 napi_get_undefined(env, &result[NUM_1]);
126
127 napi_handle_scope scope = nullptr;
128 napi_open_handle_scope(env, &scope);
129 if (scope == nullptr) {
130 return;
131 }
132
133 if (asyncContext == nullptr) {
134 napi_close_handle_scope(env, scope);
135 return;
136 }
137 if (asyncContext->status == SUCCESS) {
138 result[NUM_1] = valueParam;
139 } else if (asyncContext->error != nullptr) {
140 napi_get_reference_value(env, asyncContext->error, &result[NUM_0]);
141 napi_delete_reference(env, asyncContext->error);
142 } else {
143 napi_create_uint32(env, asyncContext->status, &result[NUM_0]);
144 }
145
146 if (asyncContext->deferred) {
147 if (asyncContext->status == SUCCESS) {
148 napi_resolve_deferred(env, asyncContext->deferred, result[NUM_1]);
149 } else {
150 napi_reject_deferred(env, asyncContext->deferred, result[NUM_0]);
151 }
152 }
153
154 napi_delete_async_work(env, asyncContext->work);
155 napi_close_handle_scope(env, scope);
156
157 delete asyncContext;
158 asyncContext = nullptr;
159 }
160
Init(napi_env env, napi_value exports)161 napi_value MetadataNapi::Init(napi_env env, napi_value exports)
162 {
163 napi_property_descriptor props[] = {
164 DECLARE_NAPI_FUNCTION("getProperties", GetProperties),
165 DECLARE_NAPI_FUNCTION("setProperties", SetProperties),
166 DECLARE_NAPI_FUNCTION("getAllProperties", GetAllProperties),
167 DECLARE_NAPI_FUNCTION("clone", Clone),
168 };
169 napi_property_descriptor static_prop[] = {};
170
171 napi_value constructor = nullptr;
172
173 IMG_NAPI_CHECK_RET_D(IMG_IS_OK(
174 napi_define_class(env, CLASS_NAME.c_str(), NAPI_AUTO_LENGTH,
175 Constructor, nullptr, IMG_ARRAY_SIZE(props),
176 props, &constructor)),
177 nullptr, IMAGE_LOGE("Define class fail")
178 );
179
180 IMG_NAPI_CHECK_RET_D(IMG_IS_OK(
181 napi_create_reference(env, constructor, 1, &sConstructor_)),
182 nullptr, IMAGE_LOGE("Create reference fail")
183 );
184
185 napi_value global = nullptr;
186 IMG_NAPI_CHECK_RET_D(IMG_IS_OK(
187 napi_get_global(env, &global)),
188 nullptr, IMAGE_LOGE("Init:get global fail")
189 );
190
191 IMG_NAPI_CHECK_RET_D(IMG_IS_OK(
192 napi_set_named_property(env, global, CLASS_NAME.c_str(), constructor)),
193 nullptr, IMAGE_LOGE("Init:set global named property fail")
194 );
195
196 IMG_NAPI_CHECK_RET_D(IMG_IS_OK(
197 napi_set_named_property(env, exports, CLASS_NAME.c_str(), constructor)),
198 nullptr, IMAGE_LOGE("Set named property fail")
199 );
200
201 IMG_NAPI_CHECK_RET_D(IMG_IS_OK(
202 napi_define_properties(env, exports, IMG_ARRAY_SIZE(static_prop), static_prop)),
203 nullptr, IMAGE_LOGE("Define properties fail")
204 );
205
206 IMAGE_LOGD("Init success");
207 return exports;
208 }
209
CreateMetadata(napi_env env, std::shared_ptr<ImageMetadata> metadata)210 napi_value MetadataNapi::CreateMetadata(napi_env env, std::shared_ptr<ImageMetadata> metadata)
211 {
212 if (sConstructor_ == nullptr) {
213 napi_value exports = nullptr;
214 napi_create_object(env, &exports);
215 MetadataNapi::Init(env, exports);
216 }
217
218 napi_value constructor = nullptr;
219 napi_value result = nullptr;
220 IMAGE_LOGD("CreateMetadata IN");
221 napi_status status = napi_get_reference_value(env, sConstructor_, &constructor);
222 if (IMG_IS_OK(status)) {
223 sMetadata_ = metadata;
224 status = napi_new_instance(env, constructor, NUM_0, nullptr, &result);
225 }
226 if (!IMG_IS_OK(status)) {
227 IMAGE_LOGE("CreateMetadata | New instance could not be obtained");
228 napi_get_undefined(env, &result);
229 }
230 return result;
231 }
232
Constructor(napi_env env, napi_callback_info info)233 napi_value MetadataNapi::Constructor(napi_env env, napi_callback_info info)
234 {
235 napi_value undefineVar = nullptr;
236 napi_get_undefined(env, &undefineVar);
237
238 napi_status status;
239 napi_value thisVar = nullptr;
240 napi_get_undefined(env, &thisVar);
241 IMAGE_LOGD("Constructor IN");
242 status = napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, nullptr);
243 IMG_NAPI_CHECK_RET(IMG_IS_READY(status, thisVar), undefineVar);
244 std::unique_ptr<MetadataNapi> pMetadataNapi = std::make_unique<MetadataNapi>();
245 if (pMetadataNapi != nullptr) {
246 pMetadataNapi->env_ = env;
247 pMetadataNapi->nativeMetadata_ = sMetadata_;
248 if (pMetadataNapi->nativeMetadata_ == nullptr) {
249 IMAGE_LOGE("Failed to set nativeMetadata_ with null. Maybe a reentrancy error");
250 }
251 status = napi_wrap(env, thisVar, reinterpret_cast<void *>(pMetadataNapi.release()),
252 MetadataNapi::Destructor, nullptr, nullptr);
253 if (status != napi_ok) {
254 IMAGE_LOGE("Failure wrapping js to native napi");
255 return undefineVar;
256 }
257 }
258 return thisVar;
259 }
260
Destructor(napi_env env, void *nativeObject, void *finalize)261 void MetadataNapi::Destructor(napi_env env, void *nativeObject, void *finalize)
262 {
263 if (nativeObject != nullptr) {
264 IMAGE_LOGD("Destructor PictureNapi");
265 delete reinterpret_cast<MetadataNapi*>(nativeObject);
266 nativeObject = nullptr;
267 }
268 }
269
GetStringArgument(napi_env env, napi_value value)270 static std::string GetStringArgument(napi_env env, napi_value value)
271 {
272 std::string strValue = "";
273 size_t bufLength = 0;
274 napi_status status = napi_get_value_string_utf8(env, value, nullptr, NUM_0, &bufLength);
275 if (status == napi_ok && bufLength > NUM_0 && bufLength < PATH_MAX) {
276 char *buffer = reinterpret_cast<char *>(malloc((bufLength + NUM_1) * sizeof(char)));
277 if (buffer == nullptr) {
278 IMAGE_LOGE("No memory");
279 return strValue;
280 }
281
282 status = napi_get_value_string_utf8(env, value, buffer, bufLength + NUM_1, &bufLength);
283 if (status == napi_ok) {
284 IMAGE_LOGD("Get Success");
285 strValue.assign(buffer, 0, bufLength + NUM_1);
286 }
287 if (buffer != nullptr) {
288 free(buffer);
289 buffer = nullptr;
290 }
291 }
292 return strValue;
293 }
294
GetStrArrayArgument(napi_env env, napi_value object)295 std::vector<std::string> GetStrArrayArgument(napi_env env, napi_value object)
296 {
297 std::vector<std::string> keyStrArray;
298 uint32_t arrayLen = 0;
299 napi_status status = napi_get_array_length(env, object, &arrayLen);
300 if (status != napi_ok) {
301 IMAGE_LOGE("Get array length failed: %{public}d", status);
302 return keyStrArray;
303 }
304
305 for (uint32_t i = 0; i < arrayLen; i++) {
306 napi_value element;
307 if (napi_get_element(env, object, i, &element) == napi_ok) {
308 keyStrArray.emplace_back(GetStringArgument(env, element));
309 }
310 }
311 IMAGE_LOGD("Get string argument success.");
312 return keyStrArray;
313 }
314
GetArrayArgument(napi_env env, napi_value object)315 std::vector<std::pair<std::string, std::string>> GetArrayArgument(napi_env env, napi_value object)
316 {
317 std::vector<std::pair<std::string, std::string>> kVStrArray;
318 napi_value recordNameList = nullptr;
319 uint32_t recordCount = 0;
320 napi_status status = napi_get_property_names(env, object, &recordNameList);
321 if (status != napi_ok) {
322 IMAGE_LOGE("Get recordNameList property names failed %{public}d", status);
323 return kVStrArray;
324 }
325 status = napi_get_array_length(env, recordNameList, &recordCount);
326 if (status != napi_ok) {
327 IMAGE_LOGE("Get recordNameList array length failed %{public}d", status);
328 return kVStrArray;
329 }
330
331 napi_value recordName = nullptr;
332 napi_value recordValue = nullptr;
333 for (uint32_t i = 0; i < recordCount; ++i) {
334 status = napi_get_element(env, recordNameList, i, &recordName);
335 if (status != napi_ok) {
336 IMAGE_LOGE("Get recordName element failed %{public}d", status);
337 continue;
338 }
339 std::string keyStr = GetStringArgument(env, recordName);
340 status = napi_get_named_property(env, object, keyStr.c_str(), &recordValue);
341 if (status != napi_ok) {
342 IMAGE_LOGE("Get recordValue name property failed %{public}d", status);
343 continue;
344 }
345 std::string valueStr = GetStringArgument(env, recordValue);
346 kVStrArray.push_back(std::make_pair(keyStr, valueStr));
347 }
348
349 IMAGE_LOGD("Get record argument success.");
350 return kVStrArray;
351 }
352
CreateErrorArray(napi_env env, std::multimap<std::int32_t, std::string> errMsgArray)353 napi_value CreateErrorArray(napi_env env, std::multimap<std::int32_t, std::string> errMsgArray)
354 {
355 napi_value result = nullptr;
356 std::string errkey = "";
357 for (const auto &entry : errMsgArray) {
358 errkey += entry.second + " ";
359 }
360
361 if (errMsgArray.size() != 0) {
362 ImageNapiUtils::CreateErrorObj(env, result, IMAGE_BAD_PARAMETER,
363 "The input data is incorrect! error key: " + errkey);
364 }
365 return result;
366 }
367
GetPropertiesComplete(napi_env env, napi_status status, MetadataNapiAsyncContext *context)368 static void GetPropertiesComplete(napi_env env, napi_status status, MetadataNapiAsyncContext *context)
369 {
370 if (context == nullptr) {
371 IMAGE_LOGE("Context is nullptr");
372 return;
373 }
374
375 napi_value result[NUM_2] = {0};
376
377 napi_get_undefined(env, &result[NUM_0]);
378 napi_get_undefined(env, &result[NUM_1]);
379
380 if (context->status == SUCCESS) {
381 result[NUM_1] = SetArrayInfo(env, context->KVSArray);
382 } else {
383 result[NUM_0] = CreateErrorArray(env, context->errMsgArray);
384 }
385
386 if (context->status == SUCCESS) {
387 napi_resolve_deferred(env, context->deferred, result[NUM_1]);
388 } else {
389 napi_reject_deferred(env, context->deferred, result[NUM_0]);
390 }
391
392 napi_delete_async_work(env, context->work);
393 delete context;
394 context = nullptr;
395 }
396
SetPropertiesComplete(napi_env env, napi_status status, MetadataNapiAsyncContext *context)397 static void SetPropertiesComplete(napi_env env, napi_status status, MetadataNapiAsyncContext *context)
398 {
399 if (context == nullptr) {
400 IMAGE_LOGE("Context is nullptr");
401 return;
402 }
403
404 napi_value result[NUM_2] = {0};
405 napi_get_undefined(env, &result[NUM_0]);
406 napi_get_undefined(env, &result[NUM_1]);
407
408 result[NUM_0] = CreateErrorArray(env, context->errMsgArray);
409 if (context->status == SUCCESS) {
410 napi_resolve_deferred(env, context->deferred, result[NUM_1]);
411 } else {
412 napi_reject_deferred(env, context->deferred, result[NUM_0]);
413 }
414
415 napi_delete_async_work(env, context->work);
416
417 delete context;
418 context = nullptr;
419 }
420
UnwrapContext(napi_env env, napi_callback_info info)421 static std::unique_ptr<MetadataNapiAsyncContext> UnwrapContext(napi_env env, napi_callback_info info)
422 {
423 napi_status status;
424 napi_value thisVar = nullptr;
425 napi_value argValue[NUM_1] = {0};
426 size_t argCount = NUM_1;
427 IMG_JS_ARGS(env, info, status, argCount, argValue, thisVar);
428 IMAGE_LOGD("GetProperties argCount is [%{public}zu]", argCount);
429
430 IMG_NAPI_CHECK_RET_D(IMG_IS_OK(status), nullptr, IMAGE_LOGE("Fail to napi_get_cb_info"));
431
432 std::unique_ptr<MetadataNapiAsyncContext> context = std::make_unique<MetadataNapiAsyncContext>();
433 status = napi_unwrap(env, thisVar, reinterpret_cast<void**>(&context->nConstructor));
434
435 IMG_NAPI_CHECK_RET_D(IMG_IS_READY(status, context->nConstructor),
436 nullptr, IMAGE_LOGE("Fail to unwrap context"));
437
438 context->rMetadata = context->nConstructor->GetNativeMetadata();
439
440 IMG_NAPI_CHECK_RET_D(IMG_IS_READY(status, context->rMetadata),
441 nullptr, IMAGE_LOGE("Empty native rMetadata"));
442
443 if (argCount != NUM_1) {
444 IMAGE_LOGE("ArgCount mismatch");
445 return nullptr;
446 }
447 if (ImageNapiUtils::getType(env, argValue[NUM_0]) == napi_object) {
448 context->keyStrArray = GetStrArrayArgument(env, argValue[NUM_0]);
449 } else {
450 IMAGE_LOGE("Arg 0 type mismatch");
451 return nullptr;
452 }
453 return context;
454 }
455
UnwrapContextForModify(napi_env env, napi_callback_info info)456 static std::unique_ptr<MetadataNapiAsyncContext> UnwrapContextForModify(napi_env env, napi_callback_info info)
457 {
458 napi_status status;
459 napi_value thisVar = nullptr;
460 napi_value argValue[NUM_1] = {0};
461 size_t argCount = NUM_1;
462 IMG_JS_ARGS(env, info, status, argCount, argValue, thisVar);
463 IMG_NAPI_CHECK_RET_D(IMG_IS_OK(status), nullptr, IMAGE_LOGE("Fail to napi_get_cb_info"));
464
465 std::unique_ptr<MetadataNapiAsyncContext> context = std::make_unique<MetadataNapiAsyncContext>();
466 status = napi_unwrap(env, thisVar, reinterpret_cast<void**>(&context->nConstructor));
467 IMG_NAPI_CHECK_RET_D(IMG_IS_READY(status, context->nConstructor), nullptr, IMAGE_LOGE("Fail to unwrap context"));
468
469 context->rMetadata = context->nConstructor->GetNativeMetadata();
470
471 IMG_NAPI_CHECK_RET_D(IMG_IS_READY(status, context->rMetadata), nullptr, IMAGE_LOGE("Empty native rMetadata"));
472 if (argCount != NUM_1) {
473 IMAGE_LOGE("ArgCount mismatch");
474 return nullptr;
475 }
476 if (ImageNapiUtils::getType(env, argValue[NUM_0]) == napi_object) {
477 context->KVSArray = GetArrayArgument(env, argValue[NUM_0]);
478 } else {
479 IMAGE_LOGE("Arg 0 type mismatch");
480 return nullptr;
481 }
482 return context;
483 }
484
GetPropertiesExecute(napi_env env, void *data)485 static void GetPropertiesExecute(napi_env env, void *data)
486 {
487 auto context = static_cast<MetadataNapiAsyncContext*>(data);
488 if (context == nullptr) {
489 IMAGE_LOGE("Empty context");
490 return;
491 }
492 uint32_t status = SUCCESS;
493 for (auto keyStrIt = context->keyStrArray.begin(); keyStrIt != context->keyStrArray.end(); ++keyStrIt) {
494 std::string valueStr = "";
495 status = static_cast<uint32_t>(context->rMetadata->GetValue(*keyStrIt, valueStr));
496 if (status == SUCCESS) {
497 context->KVSArray.emplace_back(std::make_pair(*keyStrIt, valueStr));
498 } else {
499 context->KVSArray.emplace_back(std::make_pair(*keyStrIt, ""));
500 context->errMsgArray.insert(std::make_pair(status, *keyStrIt));
501 IMAGE_LOGE("ErrCode: %{public}u , exif key: %{public}s", status, keyStrIt->c_str());
502 }
503 }
504 context->status = context->KVSArray.size() == context->errMsgArray.size() ? ERROR : SUCCESS;
505 }
506
SetPropertiesExecute(napi_env env, void *data)507 static void SetPropertiesExecute(napi_env env, void *data)
508 {
509 auto context = static_cast<MetadataNapiAsyncContext*>(data);
510 if (context == nullptr) {
511 IMAGE_LOGE("Empty context");
512 return;
513 }
514 uint32_t status = SUCCESS;
515 for (auto recordIterator = context->KVSArray.begin(); recordIterator != context->KVSArray.end();
516 ++recordIterator) {
517 IMAGE_LOGD("CheckExifDataValue");
518 status = context->rMetadata->SetValue(recordIterator->first, recordIterator->second);
519 IMAGE_LOGD("Check ret status: %{public}d", status);
520 if (!status) {
521 IMAGE_LOGE("There is invalid exif data parameter");
522 context->errMsgArray.insert(std::make_pair(status, recordIterator->first));
523 continue;
524 }
525 }
526 context->status = context->errMsgArray.size() > 0 ? ERROR : SUCCESS;
527 }
528
CloneMetadataComplete(napi_env env, napi_status status, void *data)529 static void CloneMetadataComplete(napi_env env, napi_status status, void *data)
530 {
531 napi_value result = nullptr;
532 napi_get_undefined(env, &result);
533 auto context = static_cast<MetadataNapiAsyncContext*>(data);
534
535 if (context->rMetadata != nullptr) {
536 result = MetadataNapi::CreateMetadata(env, context->rMetadata);
537 context->status = SUCCESS;
538 } else {
539 context->status = ERROR;
540 }
541 CommonCallbackRoutine(env, context, result);
542 }
543
GetProperties(napi_env env, napi_callback_info info)544 napi_value MetadataNapi::GetProperties(napi_env env, napi_callback_info info)
545 {
546 napi_value result = nullptr;
547 napi_get_undefined(env, &result);
548
549 napi_status status;
550 std::unique_ptr<MetadataNapiAsyncContext> asyncContext = UnwrapContext(env, info);
551 if (asyncContext == nullptr) {
552 return ImageNapiUtils::ThrowExceptionError(env, IMAGE_BAD_PARAMETER, "Async context unwrap failed");
553 }
554
555 napi_create_promise(env, &(asyncContext->deferred), &result);
556 IMG_CREATE_CREATE_ASYNC_WORK(env, status, "GetProperties",
557 GetPropertiesExecute,
558 reinterpret_cast<napi_async_complete_callback>(GetPropertiesComplete),
559 asyncContext,
560 asyncContext->work);
561 IMG_NAPI_CHECK_RET_D(IMG_IS_OK(status),
562 nullptr, IMAGE_LOGE("Fail to create async work"));
563 return result;
564 }
565
SetProperties(napi_env env, napi_callback_info info)566 napi_value MetadataNapi::SetProperties(napi_env env, napi_callback_info info)
567 {
568 napi_value result = nullptr;
569 napi_get_undefined(env, &result);
570
571 napi_status status;
572 std::unique_ptr<MetadataNapiAsyncContext> asyncContext = UnwrapContextForModify(env, info);
573 if (asyncContext == nullptr) {
574 return ImageNapiUtils::ThrowExceptionError(env, IMAGE_BAD_PARAMETER, "Async context unwrap failed");
575 }
576
577 napi_create_promise(env, &(asyncContext->deferred), &result);
578
579 IMG_CREATE_CREATE_ASYNC_WORK(env, status, "SetProperties",
580 SetPropertiesExecute,
581 reinterpret_cast<napi_async_complete_callback>(SetPropertiesComplete),
582 asyncContext,
583 asyncContext->work);
584
585 IMG_NAPI_CHECK_RET_D(IMG_IS_OK(status),
586 nullptr, IMAGE_LOGE("Fail to create async work"));
587 return result;
588 }
589
GetAllProperties(napi_env env, napi_callback_info info)590 napi_value MetadataNapi::GetAllProperties(napi_env env, napi_callback_info info)
591 {
592 napi_value result = nullptr;
593 napi_get_undefined(env, &result);
594 napi_status status;
595 napi_value thisVar = nullptr;
596 size_t argCount = NUM_0;
597 IMG_JS_ARGS(env, info, status, argCount, nullptr, thisVar);
598 IMG_NAPI_CHECK_RET_D(IMG_IS_OK(status), nullptr, IMAGE_LOGE("Fail to napi_get_cb_info"));
599
600 std::unique_ptr<MetadataNapiAsyncContext> asyncContext = std::make_unique<MetadataNapiAsyncContext>();
601 status = napi_unwrap(env, thisVar, reinterpret_cast<void**>(&asyncContext->nConstructor));
602 IMG_NAPI_CHECK_RET_D(IMG_IS_READY(status, asyncContext->nConstructor), nullptr,
603 IMAGE_LOGE("Fail to unwrap context"));
604
605 asyncContext->rMetadata = asyncContext->nConstructor->nativeMetadata_;
606
607 IMG_NAPI_CHECK_RET_D(IMG_IS_READY(status, asyncContext->rMetadata), nullptr, IMAGE_LOGE("Empty native rMetadata"));
608 if (argCount != NUM_0) {
609 IMAGE_LOGE("ArgCount mismatch");
610 return nullptr;
611 }
612
613 napi_create_promise(env, &(asyncContext->deferred), &result);
614 IMG_CREATE_CREATE_ASYNC_WORK(env, status, "GetAllProperties",
615 [](napi_env env, void *data) {
616 auto context = static_cast<MetadataNapiAsyncContext*>(data);
617 if (context == nullptr) {
618 IMAGE_LOGE("Empty context");
619 return;
620 }
621 ImageMetadata::PropertyMapPtr allKey = context->rMetadata->GetAllProperties();
622 for (const auto &entry : *allKey) {
623 context->KVSArray.emplace_back(std::make_pair(entry.first, entry.second));
624 }
625 context->status = SUCCESS;
626 }, reinterpret_cast<napi_async_complete_callback>(GetPropertiesComplete),
627 asyncContext,
628 asyncContext->work);
629 IMG_NAPI_CHECK_RET_D(IMG_IS_OK(status),
630 nullptr, IMAGE_LOGE("Fail to create async work"));
631 return result;
632 }
633
Clone(napi_env env, napi_callback_info info)634 napi_value MetadataNapi::Clone(napi_env env, napi_callback_info info)
635 {
636 napi_value result = nullptr;
637 napi_get_undefined(env, &result);
638 napi_status status;
639 napi_value thisVar = nullptr;
640 size_t argCount = NUM_0;
641 IMG_JS_ARGS(env, info, status, argCount, nullptr, thisVar);
642 IMG_NAPI_CHECK_RET_D(IMG_IS_OK(status), nullptr, IMAGE_LOGE("Fail to napi_get_cb_info"));
643
644 std::unique_ptr<MetadataNapiAsyncContext> asyncContext = std::make_unique<MetadataNapiAsyncContext>();
645 status = napi_unwrap(env, thisVar, reinterpret_cast<void**>(&asyncContext->nConstructor));
646 IMG_NAPI_CHECK_RET_D(IMG_IS_READY(status, asyncContext->nConstructor), nullptr,
647 IMAGE_LOGE("Fail to unwrap context"));
648
649 asyncContext->rMetadata = asyncContext->nConstructor->nativeMetadata_;
650
651 IMG_NAPI_CHECK_RET_D(IMG_IS_READY(status, asyncContext->rMetadata), nullptr, IMAGE_LOGE("Empty native rMetadata"));
652 if (argCount != NUM_0) {
653 IMAGE_LOGE("ArgCount mismatch");
654 return nullptr;
655 }
656
657 napi_create_promise(env, &(asyncContext->deferred), &result);
658
659 IMG_CREATE_CREATE_ASYNC_WORK(env, status, "Clone",
660 [](napi_env env, void *data) {
661 auto context = static_cast<MetadataNapiAsyncContext*>(data);
662 auto tmpixel = context->rMetadata->CloneMetadata();
663 context->rMetadata = std::move(tmpixel);
664 context->status = SUCCESS;
665 }, CloneMetadataComplete, asyncContext, asyncContext->work);
666 IMG_NAPI_CHECK_RET_D(IMG_IS_OK(status),
667 nullptr, IMAGE_LOGE("Fail to create async work"));
668 return result;
669 }
670
release()671 void MetadataNapi::release()
672 {
673 if (!isRelease) {
674 if (nativeMetadata_ != nullptr) {
675 nativeMetadata_ = nullptr;
676 }
677 isRelease = true;
678 }
679 }
680 } // namespace Media
681 } // namespace OHOS