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