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 
FragmentValueIsError(const std::multimap<std::int32_t,std::string> & errMsgArray)353 static bool FragmentValueIsError(const std::multimap<std::int32_t, std::string> &errMsgArray)
354 {
355     static std::set<std::string> fragmentKeys = {
356         "XInOriginal", "YInOriginal", "FragmentImageWidth", "FragmentImageHeight"
357     };
358     for (const auto &errMsg : errMsgArray) {
359         // As long as a key is found, return true
360         if (fragmentKeys.find(errMsg.second) != fragmentKeys.end()) {
361             return true;
362         }
363     }
364     return false;
365 }
366 
CreateErrorArray(napi_env env,const MetadataNapiAsyncContext * context)367 napi_value CreateErrorArray(napi_env env, const MetadataNapiAsyncContext *context)
368 {
369     napi_value result = nullptr;
370     std::string errkey = "";
371     if (context->errMsgArray.empty()) {
372         return result;
373     }
374     for (const auto &errMsg : context->errMsgArray) {
375         errkey += errMsg.second + " ";
376     }
377     if (context->rMetadata->GetType() == MetadataType::FRAGMENT && FragmentValueIsError(context->errMsgArray)) {
378         ImageNapiUtils::CreateErrorObj(env, result, IMAGE_BAD_PARAMETER, "The input value is incorrect!");
379     } else {
380         ImageNapiUtils::CreateErrorObj(env, result, IMAGE_UNSUPPORTED_METADATA,
381             "The input data is incorrect! error key: " + errkey);
382     }
383     return result;
384 }
385 
GetPropertiesComplete(napi_env env,napi_status status,MetadataNapiAsyncContext * context)386 static void GetPropertiesComplete(napi_env env, napi_status status, MetadataNapiAsyncContext *context)
387 {
388     if (context == nullptr) {
389         IMAGE_LOGE("Context is nullptr");
390         return;
391     }
392 
393     napi_value result[NUM_2] = {0};
394 
395     napi_get_undefined(env, &result[NUM_0]);
396     napi_get_undefined(env, &result[NUM_1]);
397 
398     if (context->status == SUCCESS) {
399         result[NUM_1] = SetArrayInfo(env, context->KVSArray);
400     } else {
401         result[NUM_0] = CreateErrorArray(env, context);
402     }
403 
404     if (context->status == SUCCESS) {
405         napi_resolve_deferred(env, context->deferred, result[NUM_1]);
406     } else {
407         napi_reject_deferred(env, context->deferred, result[NUM_0]);
408     }
409 
410     napi_delete_async_work(env, context->work);
411     delete context;
412     context = nullptr;
413 }
414 
SetPropertiesComplete(napi_env env,napi_status status,MetadataNapiAsyncContext * context)415 static void SetPropertiesComplete(napi_env env, napi_status status, MetadataNapiAsyncContext *context)
416 {
417     if (context == nullptr) {
418         IMAGE_LOGE("Context is nullptr");
419         return;
420     }
421 
422     napi_value result[NUM_2] = {0};
423     napi_get_undefined(env, &result[NUM_0]);
424     napi_get_undefined(env, &result[NUM_1]);
425 
426     result[NUM_0] = CreateErrorArray(env, context);
427     if (context->status == SUCCESS) {
428         napi_resolve_deferred(env, context->deferred, result[NUM_1]);
429     } else {
430         napi_reject_deferred(env, context->deferred, result[NUM_0]);
431     }
432 
433     napi_delete_async_work(env, context->work);
434 
435     delete context;
436     context = nullptr;
437 }
438 
UnwrapContext(napi_env env,napi_callback_info info)439 static std::unique_ptr<MetadataNapiAsyncContext> UnwrapContext(napi_env env, napi_callback_info info)
440 {
441     napi_status status;
442     napi_value thisVar = nullptr;
443     napi_value argValue[NUM_1] = {0};
444     size_t argCount = NUM_1;
445     IMG_JS_ARGS(env, info, status, argCount, argValue, thisVar);
446     IMAGE_LOGD("GetProperties argCount is [%{public}zu]", argCount);
447 
448     IMG_NAPI_CHECK_RET_D(IMG_IS_OK(status), nullptr, IMAGE_LOGE("Fail to napi_get_cb_info"));
449 
450     std::unique_ptr<MetadataNapiAsyncContext> context = std::make_unique<MetadataNapiAsyncContext>();
451     status = napi_unwrap(env, thisVar, reinterpret_cast<void**>(&context->nConstructor));
452 
453     IMG_NAPI_CHECK_RET_D(IMG_IS_READY(status, context->nConstructor),
454         nullptr, IMAGE_LOGE("Fail to unwrap context"));
455 
456     context->rMetadata = context->nConstructor->GetNativeMetadata();
457 
458     IMG_NAPI_CHECK_RET_D(IMG_IS_READY(status, context->rMetadata),
459         nullptr, IMAGE_LOGE("Empty native rMetadata"));
460 
461     if (argCount != NUM_1) {
462         IMAGE_LOGE("ArgCount mismatch");
463         return nullptr;
464     }
465     if (ImageNapiUtils::getType(env, argValue[NUM_0]) == napi_object) {
466         context->keyStrArray = GetStrArrayArgument(env, argValue[NUM_0]);
467     } else {
468         IMAGE_LOGE("Arg 0 type mismatch");
469         return nullptr;
470     }
471     return context;
472 }
473 
UnwrapContextForModify(napi_env env,napi_callback_info info)474 static std::unique_ptr<MetadataNapiAsyncContext> UnwrapContextForModify(napi_env env, napi_callback_info info)
475 {
476     napi_status status;
477     napi_value thisVar = nullptr;
478     napi_value argValue[NUM_1] = {0};
479     size_t argCount = NUM_1;
480     IMG_JS_ARGS(env, info, status, argCount, argValue, thisVar);
481     IMG_NAPI_CHECK_RET_D(IMG_IS_OK(status), nullptr, IMAGE_LOGE("Fail to napi_get_cb_info"));
482 
483     std::unique_ptr<MetadataNapiAsyncContext> context = std::make_unique<MetadataNapiAsyncContext>();
484     status = napi_unwrap(env, thisVar, reinterpret_cast<void**>(&context->nConstructor));
485     IMG_NAPI_CHECK_RET_D(IMG_IS_READY(status, context->nConstructor), nullptr, IMAGE_LOGE("Fail to unwrap context"));
486 
487     context->rMetadata = context->nConstructor->GetNativeMetadata();
488 
489     IMG_NAPI_CHECK_RET_D(IMG_IS_READY(status, context->rMetadata), nullptr, IMAGE_LOGE("Empty native rMetadata"));
490     if (argCount != NUM_1) {
491         IMAGE_LOGE("ArgCount mismatch");
492         return nullptr;
493     }
494     if (ImageNapiUtils::getType(env, argValue[NUM_0]) == napi_object) {
495         context->KVSArray = GetArrayArgument(env, argValue[NUM_0]);
496     } else {
497         IMAGE_LOGE("Arg 0 type mismatch");
498         return nullptr;
499     }
500     return context;
501 }
502 
GetPropertiesExecute(napi_env env,void * data)503 static void GetPropertiesExecute(napi_env env, void *data)
504 {
505     auto context = static_cast<MetadataNapiAsyncContext*>(data);
506     if (context == nullptr) {
507         IMAGE_LOGE("Empty context");
508         return;
509     }
510     uint32_t status = SUCCESS;
511     for (auto keyStrIt = context->keyStrArray.begin(); keyStrIt != context->keyStrArray.end(); ++keyStrIt) {
512         std::string valueStr = "";
513         status = static_cast<uint32_t>(context->rMetadata->GetValue(*keyStrIt, valueStr));
514         if (status == SUCCESS) {
515             context->KVSArray.emplace_back(std::make_pair(*keyStrIt, valueStr));
516         } else {
517             context->KVSArray.emplace_back(std::make_pair(*keyStrIt, ""));
518             context->errMsgArray.insert(std::make_pair(status, *keyStrIt));
519             IMAGE_LOGE("ErrCode: %{public}u , exif key: %{public}s", status, keyStrIt->c_str());
520         }
521     }
522     context->status = context->KVSArray.size() == context->errMsgArray.size() ? ERROR : SUCCESS;
523 }
524 
SetPropertiesExecute(napi_env env,void * data)525 static void SetPropertiesExecute(napi_env env, void *data)
526 {
527     auto context = static_cast<MetadataNapiAsyncContext*>(data);
528     if (context == nullptr) {
529         IMAGE_LOGE("Empty context");
530         return;
531     }
532     uint32_t status = SUCCESS;
533     for (auto recordIterator = context->KVSArray.begin(); recordIterator != context->KVSArray.end();
534         ++recordIterator) {
535         IMAGE_LOGD("CheckExifDataValue");
536         status = context->rMetadata->SetValue(recordIterator->first, recordIterator->second);
537         IMAGE_LOGD("Check ret status: %{public}d", status);
538         if (!status) {
539             IMAGE_LOGE("There is invalid exif data parameter");
540             context->errMsgArray.insert(std::make_pair(status, recordIterator->first));
541             continue;
542         }
543     }
544     context->status = context->errMsgArray.size() > 0 ? ERROR : SUCCESS;
545 }
546 
CloneMetadataComplete(napi_env env,napi_status status,void * data)547 static void CloneMetadataComplete(napi_env env, napi_status status, void *data)
548 {
549     napi_value result = nullptr;
550     napi_get_undefined(env, &result);
551     auto context = static_cast<MetadataNapiAsyncContext*>(data);
552 
553     if (context->rMetadata != nullptr) {
554         result = MetadataNapi::CreateMetadata(env, context->rMetadata);
555         context->status = SUCCESS;
556     } else {
557         context->status = ERROR;
558     }
559     CommonCallbackRoutine(env, context, result);
560 }
561 
GetProperties(napi_env env,napi_callback_info info)562 napi_value MetadataNapi::GetProperties(napi_env env, napi_callback_info info)
563 {
564     napi_value result = nullptr;
565     napi_get_undefined(env, &result);
566 
567     napi_status status;
568     std::unique_ptr<MetadataNapiAsyncContext> asyncContext = UnwrapContext(env, info);
569     if (asyncContext == nullptr) {
570         return ImageNapiUtils::ThrowExceptionError(env, IMAGE_BAD_PARAMETER, "Async context unwrap failed");
571     }
572 
573     napi_create_promise(env, &(asyncContext->deferred), &result);
574     IMG_CREATE_CREATE_ASYNC_WORK(env, status, "GetProperties",
575         GetPropertiesExecute,
576         reinterpret_cast<napi_async_complete_callback>(GetPropertiesComplete),
577         asyncContext,
578         asyncContext->work);
579     IMG_NAPI_CHECK_RET_D(IMG_IS_OK(status),
580         nullptr, IMAGE_LOGE("Fail to create async work"));
581     return result;
582 }
583 
SetProperties(napi_env env,napi_callback_info info)584 napi_value MetadataNapi::SetProperties(napi_env env, napi_callback_info info)
585 {
586     napi_value result = nullptr;
587     napi_get_undefined(env, &result);
588 
589     napi_status status;
590     std::unique_ptr<MetadataNapiAsyncContext> asyncContext = UnwrapContextForModify(env, info);
591     if (asyncContext == nullptr) {
592         return ImageNapiUtils::ThrowExceptionError(env, IMAGE_BAD_PARAMETER, "Async context unwrap failed");
593     }
594 
595     napi_create_promise(env, &(asyncContext->deferred), &result);
596 
597     IMG_CREATE_CREATE_ASYNC_WORK(env, status, "SetProperties",
598         SetPropertiesExecute,
599         reinterpret_cast<napi_async_complete_callback>(SetPropertiesComplete),
600         asyncContext,
601         asyncContext->work);
602 
603     IMG_NAPI_CHECK_RET_D(IMG_IS_OK(status),
604         nullptr, IMAGE_LOGE("Fail to create async work"));
605     return result;
606 }
607 
GetAllProperties(napi_env env,napi_callback_info info)608 napi_value MetadataNapi::GetAllProperties(napi_env env, napi_callback_info info)
609 {
610     napi_value result = nullptr;
611     napi_get_undefined(env, &result);
612     napi_status status;
613     napi_value thisVar = nullptr;
614     size_t argCount = NUM_0;
615     IMG_JS_ARGS(env, info, status, argCount, nullptr, thisVar);
616     IMG_NAPI_CHECK_RET_D(IMG_IS_OK(status), nullptr, IMAGE_LOGE("Fail to napi_get_cb_info"));
617 
618     std::unique_ptr<MetadataNapiAsyncContext> asyncContext = std::make_unique<MetadataNapiAsyncContext>();
619     status = napi_unwrap(env, thisVar, reinterpret_cast<void**>(&asyncContext->nConstructor));
620     IMG_NAPI_CHECK_RET_D(IMG_IS_READY(status, asyncContext->nConstructor), nullptr,
621                          IMAGE_LOGE("Fail to unwrap context"));
622 
623     asyncContext->rMetadata = asyncContext->nConstructor->nativeMetadata_;
624 
625     IMG_NAPI_CHECK_RET_D(IMG_IS_READY(status, asyncContext->rMetadata), nullptr, IMAGE_LOGE("Empty native rMetadata"));
626     if (argCount != NUM_0) {
627         IMAGE_LOGE("ArgCount mismatch");
628         return nullptr;
629     }
630 
631     napi_create_promise(env, &(asyncContext->deferred), &result);
632     IMG_CREATE_CREATE_ASYNC_WORK(env, status, "GetAllProperties",
633         [](napi_env env, void *data) {
634             auto context = static_cast<MetadataNapiAsyncContext*>(data);
635             if (context == nullptr) {
636                 IMAGE_LOGE("Empty context");
637                 return;
638             }
639             ImageMetadata::PropertyMapPtr allKey = context->rMetadata->GetAllProperties();
640             for (const auto &entry : *allKey) {
641                 context->KVSArray.emplace_back(std::make_pair(entry.first, entry.second));
642             }
643             context->status = SUCCESS;
644         }, reinterpret_cast<napi_async_complete_callback>(GetPropertiesComplete),
645         asyncContext,
646         asyncContext->work);
647     IMG_NAPI_CHECK_RET_D(IMG_IS_OK(status),
648         nullptr, IMAGE_LOGE("Fail to create async work"));
649     return result;
650 }
651 
Clone(napi_env env,napi_callback_info info)652 napi_value MetadataNapi::Clone(napi_env env, napi_callback_info info)
653 {
654     napi_value result = nullptr;
655     napi_get_undefined(env, &result);
656     napi_status status;
657     napi_value thisVar = nullptr;
658     size_t argCount = NUM_0;
659     IMG_JS_ARGS(env, info, status, argCount, nullptr, thisVar);
660     IMG_NAPI_CHECK_RET_D(IMG_IS_OK(status), nullptr, IMAGE_LOGE("Fail to napi_get_cb_info"));
661 
662     std::unique_ptr<MetadataNapiAsyncContext> asyncContext = std::make_unique<MetadataNapiAsyncContext>();
663     status = napi_unwrap(env, thisVar, reinterpret_cast<void**>(&asyncContext->nConstructor));
664     IMG_NAPI_CHECK_RET_D(IMG_IS_READY(status, asyncContext->nConstructor), nullptr,
665                          IMAGE_LOGE("Fail to unwrap context"));
666 
667     asyncContext->rMetadata = asyncContext->nConstructor->nativeMetadata_;
668 
669     IMG_NAPI_CHECK_RET_D(IMG_IS_READY(status, asyncContext->rMetadata), nullptr, IMAGE_LOGE("Empty native rMetadata"));
670     if (argCount != NUM_0) {
671         IMAGE_LOGE("ArgCount mismatch");
672         return nullptr;
673     }
674 
675     napi_create_promise(env, &(asyncContext->deferred), &result);
676 
677     IMG_CREATE_CREATE_ASYNC_WORK(env, status, "Clone",
678         [](napi_env env, void *data) {
679             auto context = static_cast<MetadataNapiAsyncContext*>(data);
680             auto tmpixel = context->rMetadata->CloneMetadata();
681             context->rMetadata = std::move(tmpixel);
682             context->status = SUCCESS;
683         }, CloneMetadataComplete, asyncContext, asyncContext->work);
684     IMG_NAPI_CHECK_RET_D(IMG_IS_OK(status),
685         nullptr, IMAGE_LOGE("Fail to create async work"));
686     return result;
687 }
688 
release()689 void MetadataNapi::release()
690 {
691     if (!isRelease) {
692         if (nativeMetadata_ != nullptr) {
693             nativeMetadata_ = nullptr;
694         }
695         isRelease = true;
696     }
697 }
698 } // namespace Media
699 } // namespace OHOS