• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2024-2024 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 #ifndef OHOS_MEDIA_PHOTO_DISPLAYNAME_OPERATIOIN_H
17 #define OHOS_MEDIA_PHOTO_DISPLAYNAME_OPERATIOIN_H
18 
19 #include <string>
20 #include <vector>
21 #include <regex>
22 #include <sstream>
23 
24 #include "rdb_store.h"
25 #include "result_set_utils.h"
26 #include "userfile_manager_types.h"
27 #include "media_column.h"
28 #include "media_log.h"
29 
30 namespace OHOS::Media {
31 class PhotoDisplayNameOperation {
32 private:
33     struct PhotoAssetInfo {
34         std::string displayName;
35         int32_t subtype;
36         int32_t ownerAlbumId;
37     };
38     class DisplayNameInfo {
39     public:
DisplayNameInfo(const PhotoAssetInfo & photoAssetInfo)40         explicit DisplayNameInfo(const PhotoAssetInfo &photoAssetInfo)
41         {
42             ParseDisplayName(photoAssetInfo);
43         }
44 
ToString()45         std::string ToString()
46         {
47             std::string yearMonthDayStr;
48             std::string hourMinuteSecondStr;
49             if (this->yearMonthDay != 0 && this->hourMinuteSecond != 0) {
50                 std::ostringstream yearMonthDayStream;
51                 yearMonthDayStream << std::setw(YEAR_MONTH_DAY_LENGTH) << std::setfill('0') << this->yearMonthDay;
52                 std::ostringstream hourMinuteSecondStream;
53                 hourMinuteSecondStream << std::setw(HOUR_MINUTE_SECOND_LENGTH) << std::setfill('0')
54                                        << this->hourMinuteSecond;
55                 yearMonthDayStr = "_" + yearMonthDayStream.str();
56                 hourMinuteSecondStr = "_" + hourMinuteSecondStream.str();
57             } else {
58                 yearMonthDayStr = this->yearMonthDay == 0 ? "" : "_" + std::to_string(this->yearMonthDay);
59                 hourMinuteSecondStr = this->hourMinuteSecond == 0 ? "" : "_" + std::to_string(this->hourMinuteSecond);
60             }
61             return this->prefix + yearMonthDayStr + hourMinuteSecondStr + this->suffix;
62         }
63 
Next()64         std::string Next()
65         {
66             this->hourMinuteSecond++;
67             return this->ToString();
68         }
69 
70     private:
ParseDisplayName(const PhotoAssetInfo & photoAssetInfo)71         void ParseDisplayName(const PhotoAssetInfo &photoAssetInfo)
72         {
73             if (photoAssetInfo.subtype == static_cast<int32_t>(PhotoSubType::BURST)) {
74                 ParseBurstDisplayName(photoAssetInfo);
75                 return;
76             }
77             ParseNormalDisplayName(photoAssetInfo);
78             return;
79         }
80 
ParseBurstDisplayName(const PhotoAssetInfo & photoAssetInfo)81         void ParseBurstDisplayName(const PhotoAssetInfo &photoAssetInfo)
82         {
83             bool isValid = photoAssetInfo.subtype == static_cast<int32_t>(PhotoSubType::BURST);
84             isValid = isValid && photoAssetInfo.displayName.size() > BURST_DISPLAY_NAME_MIN_LENGTH;
85             if (!isValid) {
86                 return ParseNormalDisplayName(photoAssetInfo);
87             }
88             std::string displayName = photoAssetInfo.displayName;
89             std::regex pattern(R"(IMG_\d{8}_\d{6}_)", std::regex_constants::icase);
90             std::smatch match;
91             if (!std::regex_search(displayName, match, pattern)) {
92                 return ParseNormalDisplayName(photoAssetInfo);
93             }
94             std::vector<std::string> parts;
95             std::istringstream iss(displayName);
96             std::string part;
97             while (std::getline(iss, part, '_')) {
98                 parts.push_back(part);
99             }
100             if (parts.size() >= BURST_DISPLAY_NAME_MIN_SUBLINE_COUNT) {
101                 this->prefix = parts[0];
102                 this->yearMonthDay = this->ToNumber(parts[BURST_DISPLAY_NAME_YEAR_INDEX]);
103                 this->hourMinuteSecond = this->ToNumber(parts[BURST_DISPLAY_NAME_HOUR_INDEX]);
104                 this->suffix = displayName.substr(BURST_DISPLAY_NAME_MIN_LENGTH - 1);
105             }
106             MEDIA_INFO_LOG("ParseBurstDisplayName Original display name: %{public}s, BurstDisplayNameInfo: %{public}s",
107                 displayName.c_str(),
108                 this->ToString().c_str());
109         }
110 
ToNumber(const std::string & str)111         int32_t ToNumber(const std::string &str)
112         {
113             char *end;
114             long number = std::strtol(str.c_str(), &end, 10);
115 
116             if (*end != '\0') {
117                 MEDIA_ERR_LOG("ToNumber failed, has invalid char. str: %{public}s", str.c_str());
118                 return 0;
119             } else if (number < INT_MIN || number > INT_MAX) {
120                 MEDIA_ERR_LOG("ToNumber failed, number overflow. str: %{public}s", str.c_str());
121                 return 0;
122             }
123             return static_cast<int32_t>(number);
124         }
125 
ParseNormalDisplayName(const PhotoAssetInfo & photoAssetInfo)126         void ParseNormalDisplayName(const PhotoAssetInfo &photoAssetInfo)
127         {
128             std::string displayName = photoAssetInfo.displayName;
129             size_t dotPos = displayName.rfind('.');
130             if (dotPos != std::string::npos) {
131                 this->prefix = displayName.substr(0, dotPos);
132                 this->suffix = displayName.substr(dotPos);  // include dot, e.g. ".jpg"
133             }
134             MEDIA_INFO_LOG("ParseNormalDisplayName Original display name: %{public}s, BurstDisplayNameInfo: %{public}s",
135                 displayName.c_str(),
136                 this->ToString().c_str());
137         }
138 
139     private:
140         enum {
141             YEAR_MONTH_DAY_LENGTH = 8,
142             HOUR_MINUTE_SECOND_LENGTH = 6,
143             BURST_DISPLAY_NAME_MIN_LENGTH = 20,
144             BURST_DISPLAY_NAME_YEAR_INDEX = 1,
145             BURST_DISPLAY_NAME_HOUR_INDEX = 2,
146             BURST_DISPLAY_NAME_MIN_SUBLINE_COUNT = 3
147         };
148         std::string prefix;
149         int32_t yearMonthDay;
150         int32_t hourMinuteSecond;
151         std::string suffix;
152     };
153 
154 public:
FindDisplayName(const std::shared_ptr<MediaLibraryRdbStore> rdbStore,const std::shared_ptr<NativeRdb::ResultSet> & resultSet,const int32_t targetAlbumId)155     std::string FindDisplayName(const std::shared_ptr<MediaLibraryRdbStore> rdbStore,
156         const std::shared_ptr<NativeRdb::ResultSet> &resultSet, const int32_t targetAlbumId)
157     {
158         if (resultSet == nullptr || targetAlbumId <= 0) {
159             MEDIA_ERR_LOG("Media_Operation: FindBurstKey: resultSet is null or targetAlbumId is invalid");
160             return "";
161         }
162         // Build the photo asset info.
163         PhotoDisplayNameOperation::PhotoAssetInfo photoAssetInfo;
164         photoAssetInfo.displayName = GetStringVal(MediaColumn::MEDIA_NAME, resultSet);
165         photoAssetInfo.subtype = GetInt32Val(PhotoColumn::PHOTO_SUBTYPE, resultSet);
166         photoAssetInfo.ownerAlbumId = targetAlbumId;
167         return this->FindDislayName(rdbStore, photoAssetInfo);
168     }
169 
170 private:
FindDislayName(const std::shared_ptr<MediaLibraryRdbStore> rdbStore,const PhotoAssetInfo & photoAssetInfo)171     std::string FindDislayName(const std::shared_ptr<MediaLibraryRdbStore> rdbStore,
172         const PhotoAssetInfo &photoAssetInfo)
173     {
174         DisplayNameInfo displayNameInfo(photoAssetInfo);
175         std::string displayName = displayNameInfo.ToString();
176         int32_t retryCount = 0;
177         const int32_t MAX_RETRY_COUNT = 100;
178         while (IsDisplayNameExists(rdbStore, photoAssetInfo.ownerAlbumId, displayName)) {
179             displayName = displayNameInfo.Next();
180             if (retryCount++ > MAX_RETRY_COUNT) {
181                 MEDIA_ERR_LOG("Media_Operation: can not find unique display after retry %{public}d", MAX_RETRY_COUNT);
182                 break;
183             }
184         }
185         if (photoAssetInfo.displayName != displayName) {
186             MEDIA_INFO_LOG("Media_Operation: displayName changed from %{public}s to %{public}s",
187                 photoAssetInfo.displayName.c_str(),
188                 displayName.c_str());
189         }
190         return displayName;
191     }
192 
IsDisplayNameExists(const std::shared_ptr<MediaLibraryRdbStore> rdbStore,const int32_t ownerAlbumId,const std::string & displayName)193     bool IsDisplayNameExists(const std::shared_ptr<MediaLibraryRdbStore> rdbStore, const int32_t ownerAlbumId,
194         const std::string &displayName)
195     {
196         if (ownerAlbumId <= 0 || displayName.empty()) {
197             return false;
198         }
199         std::string querySql = this->SQL_PHOTOS_TABLE_QUERY_DISPLAY_NAME;
200         const std::vector<NativeRdb::ValueObject> bindArgs = {ownerAlbumId, displayName};
201         auto resultSet = rdbStore->QuerySql(querySql, bindArgs);
202         if (resultSet == nullptr || resultSet->GoToFirstRow() != NativeRdb::E_OK) {
203             return false;
204         }
205         std::string displayNameInDb = GetStringVal(MediaColumn::MEDIA_NAME, resultSet);
206         return displayNameInDb.size() > 0;
207     }
208 
209 private:
210     const std::string SQL_PHOTOS_TABLE_QUERY_DISPLAY_NAME = "\
211         SELECT \
212             display_name \
213         FROM Photos \
214         WHERE owner_album_id = ? \
215             AND LOWER(display_name) = LOWER(?) \
216         LIMIT 1;";
217 };
218 }  // namespace OHOS::Media
219 #endif  // OHOS_MEDIA_PHOTO_DISPLAYNAME_OPERATIOIN_H