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