1 /*
2 * Copyright (C) 2022 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 #define MLOG_TAG "MediaLibraryNapiUtils"
16
17 #include "medialibrary_napi_utils.h"
18
19 #include "datashare_predicates_proxy.h"
20 #include "media_library_napi.h"
21 #include "medialibrary_data_manager_utils.h"
22 #include "smart_album_napi.h"
23
24 using namespace std;
25 using namespace OHOS::DataShare;
26
27 namespace OHOS {
28 namespace Media {
GetNetworkIdAndFileIdFromUri(const string & uri,string & networkId,string & fileId)29 void MediaLibraryNapiUtils::GetNetworkIdAndFileIdFromUri(const string &uri, string &networkId, string &fileId)
30 {
31 networkId = "";
32 fileId = "-1";
33 if (uri.empty()) {
34 NAPI_ERR_LOG("input uri is empty");
35 return;
36 }
37 size_t pos = uri.find(MEDIALIBRARY_DATA_ABILITY_PREFIX);
38 if (pos == string::npos) {
39 NAPI_ERR_LOG("invalid input uri: %{private}s", uri.c_str());
40 return;
41 }
42 string tempUri = uri.substr(MEDIALIBRARY_DATA_ABILITY_PREFIX.length());
43 if (tempUri.empty()) {
44 NAPI_ERR_LOG("invalid input uri: %{private}s", uri.c_str());
45 return;
46 }
47 pos = tempUri.find_first_of('/');
48 if (pos != 0 && pos != string::npos) {
49 networkId = tempUri.substr(0, pos);
50 }
51
52 pos = uri.rfind('/');
53 if (pos != std::string::npos) {
54 fileId = uri.substr(pos + 1);
55 } else {
56 NAPI_ERR_LOG("get file_id failed, uri: %{private}s", uri.c_str());
57 }
58 }
59
NapiDefineClass(napi_env env,napi_value exports,const NapiClassInfo & info)60 napi_value MediaLibraryNapiUtils::NapiDefineClass(napi_env env, napi_value exports, const NapiClassInfo &info)
61 {
62 napi_value ctorObj;
63 NAPI_CALL(env, napi_define_class(env, info.name.c_str(), NAPI_AUTO_LENGTH, info.constructor, nullptr,
64 info.props.size(), info.props.data(), &ctorObj));
65 NAPI_CALL(env, napi_create_reference(env, ctorObj, NAPI_INIT_REF_COUNT, info.ref));
66 NAPI_CALL(env, napi_set_named_property(env, exports, info.name.c_str(), ctorObj));
67 return exports;
68 }
69
NapiAddStaticProps(napi_env env,napi_value exports,const std::vector<napi_property_descriptor> & staticProps)70 napi_value MediaLibraryNapiUtils::NapiAddStaticProps(napi_env env, napi_value exports,
71 const std::vector<napi_property_descriptor> &staticProps)
72 {
73 NAPI_CALL(env, napi_define_properties(env, exports, staticProps.size(), staticProps.data()));
74 return exports;
75 }
76
GetUInt32(napi_env env,napi_value arg,uint32_t & value)77 napi_status MediaLibraryNapiUtils::GetUInt32(napi_env env, napi_value arg, uint32_t &value)
78 {
79 napi_valuetype valueType = napi_undefined;
80 CHECK_STATUS_RET(napi_typeof(env, arg, &valueType), "Failed to get type");
81 CHECK_COND_RET(valueType == napi_number, napi_number_expected, "Type is not as expected number");
82 CHECK_STATUS_RET(napi_get_value_uint32(env, arg, &value), "Failed to get uint32 value");
83 return napi_ok;
84 }
85
GetInt32(napi_env env,napi_value arg,int32_t & value)86 napi_status MediaLibraryNapiUtils::GetInt32(napi_env env, napi_value arg, int32_t &value)
87 {
88 napi_valuetype valueType = napi_undefined;
89 CHECK_STATUS_RET(napi_typeof(env, arg, &valueType), "Failed to get type");
90 CHECK_COND_RET(valueType == napi_number, napi_number_expected, "Type is not as expected number");
91 CHECK_STATUS_RET(napi_get_value_int32(env, arg, &value), "Failed to get int32 value");
92 return napi_ok;
93 }
94
GetParamBool(napi_env env,napi_value arg,bool & value)95 napi_status MediaLibraryNapiUtils::GetParamBool(napi_env env, napi_value arg, bool &value)
96 {
97 napi_valuetype valueType = napi_undefined;
98 CHECK_STATUS_RET(napi_typeof(env, arg, &valueType), "Failed to get type");
99 CHECK_COND_RET(valueType == napi_boolean, napi_boolean_expected, "Type is not as expected boolean");
100 CHECK_STATUS_RET(napi_get_value_bool(env, arg, &value), "Failed to get param");
101 return napi_ok;
102 }
103
GetUInt32Array(napi_env env,napi_value arg,std::vector<uint32_t> & result)104 napi_status MediaLibraryNapiUtils::GetUInt32Array(napi_env env, napi_value arg, std::vector<uint32_t> &result)
105 {
106 uint32_t arraySize = 0;
107 CHECK_COND_RET(IsArrayForNapiValue(env, arg, arraySize), napi_array_expected, "Failed to check array type");
108 for (uint32_t i = 0; i < arraySize; i++) {
109 napi_value val = nullptr;
110 CHECK_STATUS_RET(napi_get_element(env, arg, i, &val), "Failed to get element");
111 uint32_t value = 0;
112 CHECK_STATUS_RET(GetUInt32(env, val, value), "Failed to get element value");
113 result.push_back(value);
114 }
115 return napi_ok;
116 }
117
GetParamFunction(napi_env env,napi_value arg,napi_ref & callbackRef)118 napi_status MediaLibraryNapiUtils::GetParamFunction(napi_env env, napi_value arg, napi_ref &callbackRef)
119 {
120 napi_valuetype valueType = napi_undefined;
121 CHECK_STATUS_RET(napi_typeof(env, arg, &valueType), "Failed to get type");
122 CHECK_COND_RET(valueType == napi_function, napi_function_expected, "Type is not as expected function");
123 CHECK_STATUS_RET(napi_create_reference(env, arg, NAPI_INIT_REF_COUNT, &callbackRef), "Failed to make callbackref");
124 return napi_ok;
125 }
126
GetParamStr(napi_env env,napi_value arg,const size_t size,std::string & result)127 static napi_status GetParamStr(napi_env env, napi_value arg, const size_t size, std::string &result)
128 {
129 size_t res = 0;
130 std::unique_ptr<char[]> buffer = std::make_unique<char[]>(size);
131 CHECK_COND_RET(buffer != nullptr, napi_invalid_arg, "Failed to alloc buffer for parameter");
132 napi_valuetype valueType = napi_undefined;
133 CHECK_STATUS_RET(napi_typeof(env, arg, &valueType), "Failed to get type");
134 CHECK_COND_RET(valueType == napi_string, napi_string_expected, "Type is not as expected string");
135 CHECK_STATUS_RET(napi_get_value_string_utf8(env, arg, buffer.get(), size, &res), "Failed to get string value");
136 result = std::string(buffer.get());
137 return napi_ok;
138 }
139
GetParamString(napi_env env,napi_value arg,std::string & result)140 napi_status MediaLibraryNapiUtils::GetParamString(napi_env env, napi_value arg, std::string &result)
141 {
142 CHECK_STATUS_RET(GetParamStr(env, arg, ARG_BUF_SIZE, result), "Failed to get string parameter");
143 return napi_ok;
144 }
145
GetParamStringPathMax(napi_env env,napi_value arg,std::string & result)146 napi_status MediaLibraryNapiUtils::GetParamStringPathMax(napi_env env, napi_value arg, std::string &result)
147 {
148 CHECK_STATUS_RET(GetParamStr(env, arg, PATH_MAX, result), "Failed to get string parameter");
149 return napi_ok;
150 }
151
GetProperty(napi_env env,const napi_value arg,const std::string & propName,std::string & propValue)152 napi_status MediaLibraryNapiUtils::GetProperty(napi_env env, const napi_value arg, const std::string &propName,
153 std::string &propValue)
154 {
155 bool present = false;
156 napi_value property = nullptr;
157 CHECK_STATUS_RET(napi_has_named_property(env, arg, propName.c_str(), &present),
158 "Failed to check property name");
159 if (present) {
160 CHECK_STATUS_RET(napi_get_named_property(env, arg, propName.c_str(), &property), "Failed to get property");
161 CHECK_STATUS_RET(GetParamStringPathMax(env, property, propValue), "Failed to get string buffer");
162 }
163 return napi_ok;
164 }
165
GetArrayProperty(napi_env env,napi_value arg,const std::string & propName,std::vector<std::string> & array)166 napi_status MediaLibraryNapiUtils::GetArrayProperty(napi_env env, napi_value arg, const std::string &propName,
167 std::vector<std::string> &array)
168 {
169 bool present = false;
170 CHECK_STATUS_RET(napi_has_named_property(env, arg, propName.c_str(), &present), "Failed to check property name");
171 if (present) {
172 uint32_t len = 0;
173 napi_value property = nullptr;
174 bool isArray = false;
175 CHECK_STATUS_RET(napi_get_named_property(env, arg, propName.c_str(), &property),
176 "Failed to get selectionArgs property");
177 CHECK_STATUS_RET(napi_is_array(env, property, &isArray), "Failed to check array type");
178 CHECK_COND_RET(isArray, napi_array_expected, "Expected array type");
179 CHECK_STATUS_RET(napi_get_array_length(env, property, &len), "Failed to get array length");
180 for (uint32_t i = 0; i < len; i++) {
181 napi_value item = nullptr;
182 std::string val = "";
183 CHECK_STATUS_RET(napi_get_element(env, property, i, &item), "Failed to get array item");
184 CHECK_STATUS_RET(GetParamStringPathMax(env, item, val), "Failed to get string buffer");
185 array.push_back(val);
186 }
187 }
188 return napi_ok;
189 }
190
GenTypeMaskFromArray(const std::vector<uint32_t> types,std::string & typeMask)191 void MediaLibraryNapiUtils::GenTypeMaskFromArray(const std::vector<uint32_t> types, std::string &typeMask)
192 {
193 typeMask.resize(TYPE_MASK_STRING_SIZE, TYPE_MASK_BIT_DEFAULT);
194 for (auto &type : types) {
195 if ((type >= MEDIA_TYPE_FILE) && (type <= MEDIA_TYPE_AUDIO)) {
196 typeMask[std::get<POS_TYPE_MASK_STRING_INDEX>(MEDIA_TYPE_TUPLE_VEC[type])] = TYPE_MASK_BIT_SET;
197 }
198 }
199 }
200
hasCallback(napi_env env,const size_t argc,const napi_value argv[],bool & isCallback)201 napi_status MediaLibraryNapiUtils::hasCallback(napi_env env, const size_t argc, const napi_value argv[],
202 bool &isCallback)
203 {
204 isCallback = false;
205 if (argc < ARGS_ONE) {
206 return napi_ok;
207 }
208 napi_valuetype valueType = napi_undefined;
209 CHECK_STATUS_RET(napi_typeof(env, argv[argc - 1], &valueType), "Failed to get type");
210 isCallback = (valueType == napi_function);
211 return napi_ok;
212 }
213
hasFetchOpt(napi_env env,const napi_value arg,bool & hasFetchOpt)214 napi_status MediaLibraryNapiUtils::hasFetchOpt(napi_env env, const napi_value arg, bool &hasFetchOpt)
215 {
216 hasFetchOpt = false;
217 napi_valuetype valueType = napi_undefined;
218 CHECK_STATUS_RET(napi_typeof(env, arg, &valueType), "Failed to get type");
219 if (valueType != napi_object) {
220 hasFetchOpt = false;
221 return napi_ok;
222 }
223 CHECK_STATUS_RET(napi_has_named_property(env, arg, "selections", &hasFetchOpt),
224 "Failed to get property selections");
225 return napi_ok;
226 }
227
UriAddFragmentTypeMask(std::string & uri,const std::string & typeMask)228 void MediaLibraryNapiUtils::UriAddFragmentTypeMask(std::string &uri, const std::string &typeMask)
229 {
230 if (!typeMask.empty()) {
231 uri += "#" + URI_PARAM_KEY_TYPE + ":" + typeMask;
232 }
233 }
234
UriRemoveAllFragment(std::string & uri)235 void MediaLibraryNapiUtils::UriRemoveAllFragment(std::string &uri)
236 {
237 size_t fragIndex = uri.find_first_of('#');
238 if (fragIndex != std::string::npos) {
239 uri = uri.substr(0, fragIndex);
240 }
241 }
242
GetFileIdFromUri(const string & uri)243 std::string MediaLibraryNapiUtils::GetFileIdFromUri(const string &uri)
244 {
245 string id = "-1";
246
247 string temp = uri;
248 UriRemoveAllFragment(temp);
249 size_t pos = temp.rfind('/');
250 if (pos != std::string::npos) {
251 id = temp.substr(pos + 1);
252 }
253
254 return id;
255 }
256
GetMediaTypeFromUri(const string & uri)257 MediaType MediaLibraryNapiUtils::GetMediaTypeFromUri(const string &uri)
258 {
259 if (uri.find(MEDIALIBRARY_IMAGE_URI) != string::npos) {
260 return MediaType::MEDIA_TYPE_IMAGE;
261 } else if (uri.find(MEDIALIBRARY_VIDEO_URI) != string::npos) {
262 return MediaType::MEDIA_TYPE_VIDEO;
263 } else if (uri.find(MEDIALIBRARY_AUDIO_URI) != string::npos) {
264 return MediaType::MEDIA_TYPE_AUDIO;
265 } else if (uri.find(MEDIALIBRARY_FILE_URI) != string::npos) {
266 return MediaType::MEDIA_TYPE_FILE;
267 }
268 return MediaType::MEDIA_TYPE_ALL;
269 }
270
271 template <class AsyncContext>
HandleSpecialPredicate(AsyncContext & context,shared_ptr<DataShareAbsPredicates> & predicate,bool isAlbum)272 bool MediaLibraryNapiUtils::HandleSpecialPredicate(AsyncContext &context,
273 shared_ptr<DataShareAbsPredicates> &predicate, bool isAlbum)
274 {
275 constexpr int32_t FIELD_IDX = 0;
276 constexpr int32_t VALUE_IDX = 1;
277 list<OperationItem> operList;
278 for (auto item : predicate->GetOperationList()) {
279 // change uri ->file id
280 // get networkid
281 // replace networkid with file id
282 if (item.singleParams[FIELD_IDX].operator string() == MEDIA_DATA_DB_URI) {
283 if (item.operation != DataShare::EQUAL_TO) {
284 NAPI_ERR_LOG("MEDIA_DATA_DB_URI predicates not support %{public}d", item.operation);
285 return false;
286 }
287 string uri = item.singleParams[VALUE_IDX].operator string();
288 UriRemoveAllFragment(uri);
289 string fileId;
290 MediaLibraryNapiUtils::GetNetworkIdAndFileIdFromUri(uri, context->networkId, fileId);
291 item.singleParams[FIELD_IDX] = isAlbum ? DataShare::DataSharePredicatesObject(MEDIA_DATA_DB_BUCKET_ID) :
292 DataShare::DataSharePredicatesObject(MEDIA_DATA_DB_ID);
293 item.singleParams[VALUE_IDX] = DataShare::DataSharePredicatesObject(fileId);
294 }
295
296 if (item.singleParams[FIELD_IDX].operator string() == DEVICE_DB_NETWORK_ID) {
297 if (item.operation != DataShare::EQUAL_TO ||
298 item.singleParams[VALUE_IDX].GetType() != DataShare::DataSharePredicatesObjectType::TYPE_STRING) {
299 NAPI_ERR_LOG("DEVICE_DB_NETWORK_ID predicates not support %{public}d", item.operation);
300 return false;
301 }
302 context->networkId = item.singleParams[VALUE_IDX].operator string();
303 continue;
304 }
305 operList.push_back(item);
306 }
307 if (operList.size()) {
308 context->predicates = DataSharePredicates(operList);
309 }
310 return true;
311 }
312
313 template <class AsyncContext>
GetAssetFetchOption(napi_env env,napi_value arg,AsyncContext & context)314 napi_status MediaLibraryNapiUtils::GetAssetFetchOption(napi_env env, napi_value arg, AsyncContext &context)
315 {
316 // Parse the argument into fetchOption if any
317 CHECK_STATUS_RET(GetPredicate(env, arg, "predicates", context, false), "invalid predicate");
318 CHECK_STATUS_RET(GetArrayProperty(env, arg, "fetchColumns", context->fetchColumn),
319 "Failed to parse fetchColumn");
320 return napi_ok;
321 }
322
323 template <class AsyncContext>
GetPredicate(napi_env env,const napi_value arg,const std::string & propName,AsyncContext & context,bool isAlbum)324 napi_status MediaLibraryNapiUtils::GetPredicate(napi_env env, const napi_value arg, const std::string &propName,
325 AsyncContext &context, bool isAlbum)
326 {
327 bool present = false;
328 napi_value property = nullptr;
329 CHECK_STATUS_RET(napi_has_named_property(env, arg, propName.c_str(), &present),
330 "Failed to check property name");
331 if (present) {
332 CHECK_STATUS_RET(napi_get_named_property(env, arg, propName.c_str(), &property), "Failed to get property");
333 shared_ptr<DataShareAbsPredicates> predicate = DataSharePredicatesProxy::GetNativePredicates(env, property);
334 CHECK_COND_RET(HandleSpecialPredicate(context, predicate, isAlbum) == TRUE, napi_invalid_arg,
335 "invalid predicate");
336 }
337 return napi_ok;
338 }
339
340 template <class AsyncContext>
ParseAssetFetchOptCallback(napi_env env,napi_callback_info info,AsyncContext & context)341 napi_status MediaLibraryNapiUtils::ParseAssetFetchOptCallback(napi_env env, napi_callback_info info,
342 AsyncContext &context)
343 {
344 constexpr size_t minArgs = ARGS_ONE;
345 constexpr size_t maxArgs = ARGS_TWO;
346 CHECK_STATUS_RET(AsyncContextSetObjectInfo(env, info, context, minArgs, maxArgs),
347 "Failed to get object info");
348 CHECK_STATUS_RET(GetAssetFetchOption(env, context->argv[PARAM0], context), "Failed to get fetch option");
349 CHECK_STATUS_RET(GetParamCallback(env, context), "Failed to get callback");
350 return napi_ok;
351 }
352
353 template <class AsyncContext>
ParseAlbumFetchOptCallback(napi_env env,napi_callback_info info,AsyncContext & context)354 napi_status MediaLibraryNapiUtils::ParseAlbumFetchOptCallback(napi_env env, napi_callback_info info,
355 AsyncContext &context)
356 {
357 constexpr size_t minArgs = ARGS_ONE;
358 constexpr size_t maxArgs = ARGS_TWO;
359 CHECK_STATUS_RET(AsyncContextSetObjectInfo(env, info, context, minArgs, maxArgs),
360 "Failed to get object info");
361 // Parse the argument into fetchOption if any
362 CHECK_STATUS_RET(GetPredicate(env, context->argv[PARAM0], "predicates", context, true), "invalid predicate");
363 CHECK_STATUS_RET(GetParamCallback(env, context), "Failed to get callback");
364 return napi_ok;
365 }
366
367 template <class AsyncContext>
UpdateMediaTypeSelections(AsyncContext * context)368 void MediaLibraryNapiUtils::UpdateMediaTypeSelections(AsyncContext *context)
369 {
370 constexpr int FIRST_MEDIA_TYPE = 0;
371 constexpr int SECOND_MEDIA_TYPE = 1;
372 if ((context->mediaTypes.size() != ARGS_ONE) && (context->mediaTypes.size() != ARGS_TWO)) {
373 return;
374 }
375 DataShare::DataSharePredicates &predicates = context->predicates;
376 predicates.BeginWrap();
377 predicates.EqualTo(MEDIA_DATA_DB_MEDIA_TYPE, (int)context->mediaTypes[FIRST_MEDIA_TYPE]);
378 if (context->mediaTypes.size() == ARGS_TWO) {
379 predicates.Or()->EqualTo(MEDIA_DATA_DB_MEDIA_TYPE, (int)context->mediaTypes[SECOND_MEDIA_TYPE]);
380 }
381 predicates.EndWrap();
382 }
383
384 template bool MediaLibraryNapiUtils::HandleSpecialPredicate<unique_ptr<MediaLibraryAsyncContext>>(
385 unique_ptr<MediaLibraryAsyncContext> &context, shared_ptr<DataShareAbsPredicates> &predicate, bool isAlbum);
386
387 template bool MediaLibraryNapiUtils::HandleSpecialPredicate<unique_ptr<AlbumNapiAsyncContext>>(
388 unique_ptr<AlbumNapiAsyncContext> &context, shared_ptr<DataShareAbsPredicates> &predicate, bool isAlbum);
389
390 template bool MediaLibraryNapiUtils::HandleSpecialPredicate<unique_ptr<SmartAlbumNapiAsyncContext>>(
391 unique_ptr<SmartAlbumNapiAsyncContext> &context, shared_ptr<DataShareAbsPredicates> &predicate, bool isAlbum);
392
393 template napi_status MediaLibraryNapiUtils::GetAssetFetchOption<unique_ptr<MediaLibraryAsyncContext>>(napi_env env,
394 napi_value arg, unique_ptr<MediaLibraryAsyncContext> &context);
395
396 template napi_status MediaLibraryNapiUtils::GetPredicate<unique_ptr<MediaLibraryAsyncContext>>(napi_env env,
397 const napi_value arg, const std::string &propName, unique_ptr<MediaLibraryAsyncContext> &context, bool isAlbum);
398
399 template napi_status MediaLibraryNapiUtils::GetPredicate<unique_ptr<AlbumNapiAsyncContext>>(napi_env env,
400 const napi_value arg, const std::string &propName, unique_ptr<AlbumNapiAsyncContext> &context, bool isAlbum);
401
402 template napi_status MediaLibraryNapiUtils::GetPredicate<unique_ptr<SmartAlbumNapiAsyncContext>>(napi_env env,
403 const napi_value arg, const std::string &propName, unique_ptr<SmartAlbumNapiAsyncContext> &context, bool isAlbum);
404
405 template napi_status MediaLibraryNapiUtils::ParseAssetFetchOptCallback<unique_ptr<MediaLibraryAsyncContext>>(
406 napi_env env, napi_callback_info info, unique_ptr<MediaLibraryAsyncContext> &context);
407
408 template napi_status MediaLibraryNapiUtils::ParseAssetFetchOptCallback<unique_ptr<AlbumNapiAsyncContext>>(
409 napi_env env, napi_callback_info info, unique_ptr<AlbumNapiAsyncContext> &context);
410
411 template napi_status MediaLibraryNapiUtils::ParseAssetFetchOptCallback<unique_ptr<SmartAlbumNapiAsyncContext>>(
412 napi_env env, napi_callback_info info, unique_ptr<SmartAlbumNapiAsyncContext> &context);
413
414 template napi_status MediaLibraryNapiUtils::ParseAlbumFetchOptCallback<unique_ptr<MediaLibraryAsyncContext>>(
415 napi_env env, napi_callback_info info, unique_ptr<MediaLibraryAsyncContext> &context);
416
417 template void MediaLibraryNapiUtils::UpdateMediaTypeSelections<SmartAlbumNapiAsyncContext>(
418 SmartAlbumNapiAsyncContext *context);
419
420 template void MediaLibraryNapiUtils::UpdateMediaTypeSelections<AlbumNapiAsyncContext>(
421 AlbumNapiAsyncContext *context);
422
423 template void MediaLibraryNapiUtils::UpdateMediaTypeSelections<MediaLibraryAsyncContext>(
424 MediaLibraryAsyncContext *context);
425 } // namespace Media
426 } // namespace OHOS
427