• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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