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