1 /*
2  * Copyright (C) 2023 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 "medialibrary_formmap_operations.h"
17 
18 #include <memory>
19 #include <mutex>
20 #include <string>
21 #include <sys/stat.h>
22 #include <fcntl.h>
23 
24 #include "abs_shared_result_set.h"
25 #include "file_ex.h"
26 #include "media_column.h"
27 #include "media_file_uri.h"
28 #include "media_file_utils.h"
29 #include "media_log.h"
30 #include "medialibrary_errno.h"
31 #include "medialibrary_object_utils.h"
32 #include "medialibrary_rdbstore.h"
33 #include "rdb_predicates.h"
34 #include "result_set_utils.h"
35 #include "string_ex.h"
36 #include "thumbnail_const.h"
37 #include "uri.h"
38 #include "userfile_manager_types.h"
39 #include "value_object.h"
40 #include "values_bucket.h"
41 #include "image_type.h"
42 #include "datashare_helper.h"
43 #include "unique_fd.h"
44 #include "medialibrary_data_manager.h"
45 #include "thumbnail_utils.h"
46 #include "ithumbnail_helper.h"
47 #include "form_map.h"
48 #include "nlohmann/json.hpp"
49 
50 using namespace OHOS::DataShare;
51 using namespace std;
52 using namespace OHOS::NativeRdb;
53 using namespace OHOS::RdbDataShareAdapter;
54 
55 namespace OHOS {
56 namespace Media {
57 std::mutex MediaLibraryFormMapOperations::mutex_;
58 const string MEDIA_LIBRARY_PROXY_URI = "datashareproxy://com.ohos.medialibrary.medialibrarydata";
59 const string MEDIA_LIBRARY_PROXY_DATA_URI = "datashareproxy://com.ohos.medialibrary.medialibrarydata/image_data";
60 const string MEDIA_LIBRARY_PROXY_IMAGE_URI = "datashareproxy://com.ohos.medialibrary.medialibrarydata/image_uri";
61 const string NO_PICTURES = "";
62 
ReadThumbnailFile(const string & path,vector<uint8_t> & buffer)63 static void ReadThumbnailFile(const string &path, vector<uint8_t> &buffer)
64 {
65     string thumbnailFileName = GetThumbnailPath(path, THUMBNAIL_LCD_SUFFIX);
66     auto fd = open(thumbnailFileName.c_str(), O_RDONLY);
67     UniqueFd uniqueFd(fd);
68     struct stat statInfo;
69     if (fstat(uniqueFd.Get(), &statInfo) == E_ERR) {
70         return ;
71     }
72     buffer.reserve(statInfo.st_size);
73     uint8_t *tempBuffer = (uint8_t *)malloc(statInfo.st_size);
74     if (tempBuffer == nullptr) {
75         MEDIA_ERR_LOG("The point tempBuffer is null!");
76         return ;
77     }
78     ssize_t bytes = read(uniqueFd.Get(), tempBuffer, statInfo.st_size);
79     if (bytes < 0) {
80         MEDIA_ERR_LOG("read file failed!");
81         free(tempBuffer);
82         return ;
83     }
84     buffer.assign(tempBuffer, tempBuffer + statInfo.st_size);
85     free(tempBuffer);
86 }
87 
GetUriByFileId(const int32_t & fileId,const string & path)88 string MediaLibraryFormMapOperations::GetUriByFileId(const int32_t &fileId, const string &path)
89 {
90     MediaLibraryCommand queryCmd(OperationObject::UFM_PHOTO, OperationType::QUERY);
91     queryCmd.GetAbsRdbPredicates()->EqualTo(MEDIA_DATA_DB_ID, to_string(fileId));
92     auto uniStore = MediaLibraryUnistoreManager::GetInstance().GetRdbStore();
93     if (uniStore == nullptr) {
94         MEDIA_ERR_LOG("UniStore is nullptr");
95         return "";
96     }
97     vector<string> columns = {
98         MEDIA_DATA_DB_ID, MEDIA_DATA_DB_MEDIA_TYPE, MEDIA_DATA_DB_NAME
99     };
100     auto queryResult = uniStore->Query(queryCmd, columns);
101     if (queryResult == nullptr || queryResult->GoToFirstRow() != NativeRdb::E_OK) {
102         return "";
103     }
104     string displayName = GetStringVal(MEDIA_DATA_DB_NAME, queryResult);
105     int32_t mediaType = GetInt32Val(MEDIA_DATA_DB_MEDIA_TYPE, queryResult);
106     if (mediaType != MEDIA_TYPE_IMAGE) {
107         return "";
108     }
109     string extraUri = MediaFileUtils::GetExtraUri(displayName, path, false);
110     return MediaFileUri(MediaType(mediaType), ToString(fileId), "", MEDIA_API_VERSION_V10,  extraUri).ToString();
111 }
112 
GetFormMapFormId(const string & uri,vector<int64_t> & formIds)113 void MediaLibraryFormMapOperations::GetFormMapFormId(const string &uri, vector<int64_t> &formIds)
114 {
115     lock_guard<mutex> lock(mutex_);
116     MediaLibraryCommand queryFormMapCmd(OperationObject::PAH_FORM_MAP, OperationType::QUERY);
117     queryFormMapCmd.GetAbsRdbPredicates()->EqualTo(FormMap::FORMMAP_URI, uri);
118 
119     auto uniStore = MediaLibraryUnistoreManager::GetInstance().GetRdbStore();
120     if (uniStore == nullptr) {
121         MEDIA_ERR_LOG("UniStore is nullptr");
122         return;
123     }
124     vector<string> columns = {FormMap::FORMMAP_FORM_ID, FormMap::FORMMAP_URI};
125     auto queryResult = uniStore->Query(queryFormMapCmd, columns);
126     if (queryResult == nullptr) {
127         MEDIA_ERR_LOG("Failed to query form id!");
128         return;
129     }
130     while (queryResult->GoToNextRow() == NativeRdb::E_OK) {
131         string formId = GetStringVal(FormMap::FORMMAP_FORM_ID, queryResult);
132         if (formId.empty()) {
133             MEDIA_WARN_LOG("Failed to get form id from result!");
134             continue;
135         }
136         if (GetStringVal(FormMap::FORMMAP_URI, queryResult) == uri) {
137             formIds.push_back(std::stoll(formId));
138         }
139     }
140 }
141 
GetFilePathById(const string & fileId)142 string MediaLibraryFormMapOperations::GetFilePathById(const string &fileId)
143 {
144     MediaLibraryCommand queryCmd(OperationObject::UFM_PHOTO, OperationType::QUERY);
145     queryCmd.GetAbsRdbPredicates()->EqualTo(MEDIA_DATA_DB_ID, fileId);
146     auto uniStore = MediaLibraryUnistoreManager::GetInstance().GetRdbStore();
147     if (uniStore == nullptr) {
148         MEDIA_ERR_LOG("UniStore is nullptr");
149         return "";
150     }
151     vector<string> columns = {
152         MEDIA_DATA_DB_ID, MEDIA_DATA_DB_FILE_PATH
153     };
154     auto queryResult = uniStore->Query(queryCmd, columns);
155     if (queryResult == nullptr || queryResult->GoToFirstRow() != NativeRdb::E_OK) {
156         MEDIA_ERR_LOG("Get path by Id failed , id is %{private}s", fileId.c_str());
157         return "";
158     }
159     return GetStringVal(MEDIA_DATA_DB_FILE_PATH, queryResult);
160 }
161 
ModifyFormMapMessage(const string & uri,const int64_t & formId,const bool & isSave)162 void MediaLibraryFormMapOperations::ModifyFormMapMessage(const string &uri, const int64_t &formId, const bool &isSave)
163 {
164     if (isSave) {
165         MEDIA_INFO_LOG("Modify FormMap message return!, the case is saveFormInfo");
166         return;
167     }
168     lock_guard<mutex> lock(mutex_);
169     ValuesBucket value;
170     value.PutString(FormMap::FORMMAP_URI, uri);
171     RdbPredicates predicates(FormMap::FORM_MAP_TABLE);
172     predicates.And()->EqualTo(FormMap::FORMMAP_FORM_ID, std::to_string(formId));
173     int32_t updateRow = MediaLibraryRdbStore::UpdateWithDateTime(value, predicates);
174     if (updateRow < 0) {
175         MEDIA_ERR_LOG("Modify FormMap message err!, uri is %{private}s, formId is %{private}s",
176             uri.c_str(), to_string(formId).c_str());
177     }
178     return;
179 }
180 
PublishedChange(const string newUri,const vector<int64_t> & formIds,const bool & isSave)181 void MediaLibraryFormMapOperations::PublishedChange(const string newUri, const vector<int64_t> &formIds,
182     const bool &isSave)
183 {
184     CreateOptions options;
185     options.enabled_ = true;
186     shared_ptr<DataShare::DataShareHelper> dataShareHelper =
187         DataShare::DataShareHelper::Creator(MEDIA_LIBRARY_PROXY_URI, options);
188     if (dataShareHelper == nullptr) {
189         MEDIA_ERR_LOG("dataShareHelper is nullptr");
190         return;
191     }
192     Data data;
193     PublishedDataItem::DataType tempData;
194     if (newUri.empty()) {
195         nlohmann::json noPicData = NO_PICTURES;
196         tempData = noPicData.dump();
197         for (auto &formId : formIds) {
198             MEDIA_INFO_LOG("Published formId is %{private}s, size of value is %{private}zu!",
199                 to_string(formId).c_str(), NO_PICTURES.size());
200             data.datas_.emplace_back(PublishedDataItem(MEDIA_LIBRARY_PROXY_DATA_URI, formId, tempData));
201             data.datas_.emplace_back(PublishedDataItem(MEDIA_LIBRARY_PROXY_IMAGE_URI, formId, tempData));
202             dataShareHelper->Publish(data, BUNDLE_NAME);
203             MediaLibraryFormMapOperations::ModifyFormMapMessage(NO_PICTURES, formId, isSave);
204         }
205     } else {
206         MediaFileUri fileUri = MediaFileUri(newUri);
207         ThumbnailWait thumbnailWait(false);
208         thumbnailWait.CheckAndWait(fileUri.GetFileId(), true);
209         string filePath = MediaLibraryFormMapOperations::GetFilePathById(fileUri.GetFileId());
210         if (MediaType(MediaFileUtils::GetMediaType(filePath)) == MEDIA_TYPE_IMAGE) {
211             vector<uint8_t> buffer;
212             ReadThumbnailFile(filePath, buffer);
213             tempData = buffer;
214             nlohmann::json uriJson = newUri;
215             PublishedDataItem::DataType uriData = uriJson.dump();
216             for (auto &formId : formIds) {
217                 MEDIA_INFO_LOG("Published formId: %{private}s!, value size: %{private}zu, image uri: %{private}s",
218                     to_string(formId).c_str(), buffer.size(), newUri.c_str());
219                 data.datas_.emplace_back(PublishedDataItem(MEDIA_LIBRARY_PROXY_DATA_URI, formId, tempData));
220                 data.datas_.emplace_back(PublishedDataItem(MEDIA_LIBRARY_PROXY_IMAGE_URI, formId, uriData));
221                 dataShareHelper->Publish(data, BUNDLE_NAME);
222                 MediaLibraryFormMapOperations::ModifyFormMapMessage(newUri, formId, isSave);
223             }
224         }
225     }
226 }
227 
RemoveFormIdOperations(RdbPredicates & predicates)228 int32_t MediaLibraryFormMapOperations::RemoveFormIdOperations(RdbPredicates &predicates)
229 {
230     lock_guard<mutex> lock(mutex_);
231     return MediaLibraryRdbStore::Delete(predicates);
232 }
233 
GetStringObject(MediaLibraryCommand & cmd,const string & columnName)234 static string GetStringObject(MediaLibraryCommand &cmd, const string &columnName)
235 {
236     ValueObject valueObject;
237     ValuesBucket values = cmd.GetValueBucket();
238     string value;
239     if (values.GetObject(columnName, valueObject)) {
240         valueObject.GetString(value);
241         return value;
242     }
243     return "";
244 }
245 
CheckQueryIsInDb(const OperationObject & operationObject,const string & queryId)246 bool MediaLibraryFormMapOperations::CheckQueryIsInDb(const OperationObject &operationObject, const string &queryId)
247 {
248     lock_guard<mutex> lock(mutex_);
249     MediaLibraryCommand queryFormMapCmd(operationObject, OperationType::QUERY);
250     vector<string> columns;
251     if (operationObject == OperationObject::PAH_FORM_MAP) {
252         queryFormMapCmd.GetAbsRdbPredicates()->EqualTo(FormMap::FORMMAP_FORM_ID, queryId);
253         columns = { FormMap::FORMMAP_FORM_ID };
254     } else if (operationObject == OperationObject::UFM_PHOTO) {
255         queryFormMapCmd.GetAbsRdbPredicates()->EqualTo(MEDIA_DATA_DB_ID, queryId);
256         columns = { MEDIA_DATA_DB_ID };
257     }
258     auto uniStore = MediaLibraryUnistoreManager::GetInstance().GetRdbStore();
259     if (uniStore == nullptr) {
260         MEDIA_ERR_LOG("UniStore is nullptr");
261         return false;
262     }
263     auto queryResultSet = uniStore->Query(queryFormMapCmd, columns);
264     if (queryResultSet != nullptr) {
265         if (queryResultSet->GoToFirstRow() == NativeRdb::E_OK) {
266             MEDIA_INFO_LOG("The id queried already exists!");
267             return true;
268         }
269     }
270     return false;
271 }
272 
HandleStoreFormIdOperation(MediaLibraryCommand & cmd)273 int32_t MediaLibraryFormMapOperations::HandleStoreFormIdOperation(MediaLibraryCommand &cmd)
274 {
275     string formId = GetStringObject(cmd, FormMap::FORMMAP_FORM_ID);
276     if (formId.empty()) {
277         MEDIA_ERR_LOG("GetObject failed");
278         return E_GET_PRAMS_FAIL;
279     }
280     string uri = GetStringObject(cmd, FormMap::FORMMAP_URI);
281     ValuesBucket value;
282     value.PutString(FormMap::FORMMAP_URI, uri);
283 
284     if (!uri.empty()) {
285         MediaFileUri mediaUri(uri);
286         CHECK_AND_RETURN_RET_LOG(MediaLibraryFormMapOperations::CheckQueryIsInDb(OperationObject::UFM_PHOTO,
287             mediaUri.GetFileId()), E_GET_PRAMS_FAIL, "the fileId is not exist");
288         vector<int64_t> formIds = { std::stoll(formId) };
289         MediaLibraryFormMapOperations::PublishedChange(uri, formIds, true);
290     }
291     if (MediaLibraryFormMapOperations::CheckQueryIsInDb(OperationObject::PAH_FORM_MAP, formId)) {
292         lock_guard<mutex> lock(mutex_);
293         RdbPredicates predicates(FormMap::FORM_MAP_TABLE);
294         predicates.EqualTo(FormMap::FORMMAP_FORM_ID, formId);
295         return MediaLibraryRdbStore::UpdateWithDateTime(value, predicates);
296     }
297 
298     auto rdbStore = MediaLibraryUnistoreManager::GetInstance().GetRdbStore();
299     if (rdbStore == nullptr) {
300         return E_HAS_DB_ERROR;
301     }
302     int64_t outRowId = -1;
303     lock_guard<mutex> lock(mutex_);
304     int32_t errCode = rdbStore->Insert(cmd, outRowId);
305     if (errCode != NativeRdb::E_OK || outRowId < 0) {
306         MEDIA_ERR_LOG("Insert into db failed, errCode = %{public}d", errCode);
307         return E_HAS_DB_ERROR;
308     }
309     return static_cast<int32_t>(outRowId);
310 }
311 } // namespace Media
312 } // namespace OHOS
313