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