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
GetFormIdsByUris(const vector<string> & notifyUris,vector<int64_t> & formIds)142 void MediaLibraryFormMapOperations::GetFormIdsByUris(const vector<string> ¬ifyUris, vector<int64_t> &formIds)
143 {
144 lock_guard<mutex> lock(mutex_);
145 MediaLibraryCommand queryFormMapCmd(OperationObject::PAH_FORM_MAP, OperationType::QUERY);
146 queryFormMapCmd.GetAbsRdbPredicates()->And()->In(FormMap::FORMMAP_URI, notifyUris);
147
148 auto uniStore = MediaLibraryUnistoreManager::GetInstance().GetRdbStore();
149 if (uniStore == nullptr) {
150 MEDIA_ERR_LOG("UniStore is nullptr");
151 return;
152 }
153 vector<string> columns = {FormMap::FORMMAP_FORM_ID, FormMap::FORMMAP_URI};
154 auto queryResult = uniStore->Query(queryFormMapCmd, columns);
155 if (queryResult == nullptr) {
156 MEDIA_ERR_LOG("Failed to query form id!");
157 return;
158 }
159 while (queryResult->GoToNextRow() == NativeRdb::E_OK) {
160 string formId = GetStringVal(FormMap::FORMMAP_FORM_ID, queryResult);
161 if (formId.empty()) {
162 MEDIA_WARN_LOG("Failed to get form id from result!");
163 continue;
164 }
165 string uri = GetStringVal(FormMap::FORMMAP_URI, queryResult);
166 if (std::count(notifyUris.begin(), notifyUris.end(), uri) > 0) {
167 formIds.push_back(std::stoll(formId));
168 }
169 }
170 queryResult->Close();
171 }
172
GetFilePathById(const string & fileId)173 string MediaLibraryFormMapOperations::GetFilePathById(const string &fileId)
174 {
175 MediaLibraryCommand queryCmd(OperationObject::UFM_PHOTO, OperationType::QUERY);
176 queryCmd.GetAbsRdbPredicates()->EqualTo(MEDIA_DATA_DB_ID, fileId);
177 auto uniStore = MediaLibraryUnistoreManager::GetInstance().GetRdbStore();
178 if (uniStore == nullptr) {
179 MEDIA_ERR_LOG("UniStore is nullptr");
180 return "";
181 }
182 vector<string> columns = {
183 MEDIA_DATA_DB_ID, MEDIA_DATA_DB_FILE_PATH
184 };
185 auto queryResult = uniStore->Query(queryCmd, columns);
186 if (queryResult == nullptr || queryResult->GoToFirstRow() != NativeRdb::E_OK) {
187 MEDIA_ERR_LOG("Get path by Id failed , id is %{private}s", fileId.c_str());
188 return "";
189 }
190 return GetStringVal(MEDIA_DATA_DB_FILE_PATH, queryResult);
191 }
192
ModifyFormMapMessage(const string & uri,const int64_t & formId,const bool & isSave)193 void MediaLibraryFormMapOperations::ModifyFormMapMessage(const string &uri, const int64_t &formId, const bool &isSave)
194 {
195 if (isSave) {
196 MEDIA_INFO_LOG("Modify FormMap message return!, the case is saveFormInfo");
197 return;
198 }
199 lock_guard<mutex> lock(mutex_);
200 ValuesBucket value;
201 value.PutString(FormMap::FORMMAP_URI, uri);
202 RdbPredicates predicates(FormMap::FORM_MAP_TABLE);
203 predicates.And()->EqualTo(FormMap::FORMMAP_FORM_ID, std::to_string(formId));
204 int32_t updateRow = MediaLibraryRdbStore::UpdateWithDateTime(value, predicates);
205 if (updateRow < 0) {
206 MEDIA_ERR_LOG("Modify FormMap message err!, uri is %{private}s, formId is %{private}s",
207 uri.c_str(), to_string(formId).c_str());
208 }
209 return;
210 }
211
PublishedChange(const string newUri,const vector<int64_t> & formIds,const bool & isSave)212 void MediaLibraryFormMapOperations::PublishedChange(const string newUri, const vector<int64_t> &formIds,
213 const bool &isSave)
214 {
215 CreateOptions options;
216 options.enabled_ = true;
217 shared_ptr<DataShare::DataShareHelper> dataShareHelper =
218 DataShare::DataShareHelper::Creator(MEDIA_LIBRARY_PROXY_URI, options);
219 if (dataShareHelper == nullptr) {
220 MEDIA_ERR_LOG("dataShareHelper is nullptr");
221 return;
222 }
223 Data data;
224 PublishedDataItem::DataType tempData;
225 if (newUri.empty()) {
226 nlohmann::json noPicData = NO_PICTURES;
227 tempData = noPicData.dump();
228 for (auto &formId : formIds) {
229 MEDIA_INFO_LOG("Published formId is %{private}s, size of value is %{private}zu!",
230 to_string(formId).c_str(), NO_PICTURES.size());
231 data.datas_.emplace_back(PublishedDataItem(MEDIA_LIBRARY_PROXY_DATA_URI, formId, tempData));
232 data.datas_.emplace_back(PublishedDataItem(MEDIA_LIBRARY_PROXY_IMAGE_URI, formId, tempData));
233 dataShareHelper->Publish(data, BUNDLE_NAME);
234 MediaLibraryFormMapOperations::ModifyFormMapMessage(NO_PICTURES, formId, isSave);
235 }
236 } else {
237 MediaFileUri fileUri = MediaFileUri(newUri);
238 ThumbnailWait thumbnailWait(false);
239 thumbnailWait.CheckAndWait(fileUri.GetFileId(), true);
240 string filePath = MediaLibraryFormMapOperations::GetFilePathById(fileUri.GetFileId());
241 if (MediaType(MediaFileUtils::GetMediaType(filePath)) == MEDIA_TYPE_IMAGE) {
242 vector<uint8_t> buffer;
243 ReadThumbnailFile(filePath, buffer);
244 tempData = buffer;
245 nlohmann::json uriJson = newUri;
246 PublishedDataItem::DataType uriData = uriJson.dump();
247 for (auto &formId : formIds) {
248 MEDIA_INFO_LOG("Published formId: %{private}s!, value size: %{private}zu, image uri: %{private}s",
249 to_string(formId).c_str(), buffer.size(), newUri.c_str());
250 data.datas_.emplace_back(PublishedDataItem(MEDIA_LIBRARY_PROXY_DATA_URI, formId, tempData));
251 data.datas_.emplace_back(PublishedDataItem(MEDIA_LIBRARY_PROXY_IMAGE_URI, formId, uriData));
252 dataShareHelper->Publish(data, BUNDLE_NAME);
253 MediaLibraryFormMapOperations::ModifyFormMapMessage(newUri, formId, isSave);
254 }
255 }
256 }
257 }
258
RemoveFormIdOperations(RdbPredicates & predicates)259 int32_t MediaLibraryFormMapOperations::RemoveFormIdOperations(RdbPredicates &predicates)
260 {
261 lock_guard<mutex> lock(mutex_);
262 return MediaLibraryRdbStore::Delete(predicates);
263 }
264
GetStringObject(MediaLibraryCommand & cmd,const string & columnName)265 static string GetStringObject(MediaLibraryCommand &cmd, const string &columnName)
266 {
267 ValueObject valueObject;
268 ValuesBucket values = cmd.GetValueBucket();
269 string value;
270 if (values.GetObject(columnName, valueObject)) {
271 valueObject.GetString(value);
272 return value;
273 }
274 return "";
275 }
276
CheckQueryIsInDb(const OperationObject & operationObject,const string & queryId)277 bool MediaLibraryFormMapOperations::CheckQueryIsInDb(const OperationObject &operationObject, const string &queryId)
278 {
279 lock_guard<mutex> lock(mutex_);
280 MediaLibraryCommand queryFormMapCmd(operationObject, OperationType::QUERY);
281 vector<string> columns;
282 if (operationObject == OperationObject::PAH_FORM_MAP) {
283 queryFormMapCmd.GetAbsRdbPredicates()->EqualTo(FormMap::FORMMAP_FORM_ID, queryId);
284 columns = { FormMap::FORMMAP_FORM_ID };
285 } else if (operationObject == OperationObject::UFM_PHOTO) {
286 queryFormMapCmd.GetAbsRdbPredicates()->EqualTo(MEDIA_DATA_DB_ID, queryId);
287 columns = { MEDIA_DATA_DB_ID };
288 }
289 auto uniStore = MediaLibraryUnistoreManager::GetInstance().GetRdbStore();
290 if (uniStore == nullptr) {
291 MEDIA_ERR_LOG("UniStore is nullptr");
292 return false;
293 }
294 auto queryResultSet = uniStore->Query(queryFormMapCmd, columns);
295 if (queryResultSet != nullptr) {
296 if (queryResultSet->GoToFirstRow() == NativeRdb::E_OK) {
297 MEDIA_INFO_LOG("The id queried already exists!");
298 return true;
299 }
300 }
301 return false;
302 }
303
HandleStoreFormIdOperation(MediaLibraryCommand & cmd)304 int32_t MediaLibraryFormMapOperations::HandleStoreFormIdOperation(MediaLibraryCommand &cmd)
305 {
306 string formId = GetStringObject(cmd, FormMap::FORMMAP_FORM_ID);
307 if (formId.empty()) {
308 MEDIA_ERR_LOG("GetObject failed");
309 return E_GET_PRAMS_FAIL;
310 }
311 string uri = GetStringObject(cmd, FormMap::FORMMAP_URI);
312 ValuesBucket value;
313 value.PutString(FormMap::FORMMAP_URI, uri);
314
315 if (!uri.empty()) {
316 MediaFileUri mediaUri(uri);
317 CHECK_AND_RETURN_RET_LOG(MediaLibraryFormMapOperations::CheckQueryIsInDb(OperationObject::UFM_PHOTO,
318 mediaUri.GetFileId()), E_GET_PRAMS_FAIL, "the fileId is not exist");
319 vector<int64_t> formIds = { std::stoll(formId) };
320 MediaLibraryFormMapOperations::PublishedChange(uri, formIds, true);
321 }
322 if (MediaLibraryFormMapOperations::CheckQueryIsInDb(OperationObject::PAH_FORM_MAP, formId)) {
323 lock_guard<mutex> lock(mutex_);
324 RdbPredicates predicates(FormMap::FORM_MAP_TABLE);
325 predicates.EqualTo(FormMap::FORMMAP_FORM_ID, formId);
326 return MediaLibraryRdbStore::UpdateWithDateTime(value, predicates);
327 }
328
329 auto rdbStore = MediaLibraryUnistoreManager::GetInstance().GetRdbStore();
330 if (rdbStore == nullptr) {
331 return E_HAS_DB_ERROR;
332 }
333 int64_t outRowId = -1;
334 lock_guard<mutex> lock(mutex_);
335 int32_t errCode = rdbStore->Insert(cmd, outRowId);
336 if (errCode != NativeRdb::E_OK || outRowId < 0) {
337 MEDIA_ERR_LOG("Insert into db failed, errCode = %{public}d", errCode);
338 return E_HAS_DB_ERROR;
339 }
340 return static_cast<int32_t>(outRowId);
341 }
342 } // namespace Media
343 } // namespace OHOS
344