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