1 /*
2  * Copyright (C) 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 #define MLOG_TAG "DisplayNameInfo"
16 
17 #include "display_name_info.h"
18 
19 #include <vector>
20 #include <regex>
21 #include <iomanip>
22 
23 #include "userfile_manager_types.h"
24 #include "media_column.h"
25 #include "media_log.h"
26 
27 namespace OHOS::Media {
DisplayNameInfo(const PhotoAssetInfo & photoAssetInfo)28 DisplayNameInfo::DisplayNameInfo(const PhotoAssetInfo &photoAssetInfo)
29 {
30     ParseDisplayName(photoAssetInfo);
31 }
32 
33 // 处理重复displayName场景时,避免扩展的后缀长度超过255,截取超出的部分,保留最终总长为255
GetPrefixStrLength(std::string yearMonthDayStr,std::string hourMinuteSecondStr)34 int32_t DisplayNameInfo::GetPrefixStrLength(std::string yearMonthDayStr, std::string hourMinuteSecondStr)
35 {
36     int32_t extendLength = static_cast<int32_t>(yearMonthDayStr.size() + hourMinuteSecondStr.size()
37         + this->suffix.size());
38     return std::min<int32_t>(this->prefix.size(), static_cast<int32_t>(MAX_DISPLAY_NAME_LENGTH) - extendLength);
39 }
40 
ToString()41 std::string DisplayNameInfo::ToString()
42 {
43     std::string yearMonthDayStr;
44     std::string hourMinuteSecondStr;
45     if (this->yearMonthDay != 0) {
46         std::ostringstream yearMonthDayStream;
47         yearMonthDayStream << std::setw(YEAR_MONTH_DAY_LENGTH) << std::setfill('0') << this->yearMonthDay;
48         std::ostringstream hourMinuteSecondStream;
49         hourMinuteSecondStream << std::setw(HOUR_MINUTE_SECOND_LENGTH) << std::setfill('0') << this->hourMinuteSecond;
50         yearMonthDayStr = "_" + yearMonthDayStream.str();
51         hourMinuteSecondStr = "_" + hourMinuteSecondStream.str();
52     } else {
53         yearMonthDayStr = this->yearMonthDay == 0 ? "" : "_" + std::to_string(this->yearMonthDay);
54         hourMinuteSecondStr = this->hourMinuteSecond == 0 ? "" : "_" + std::to_string(this->hourMinuteSecond);
55     }
56     return this->prefix.substr(0, GetPrefixStrLength(yearMonthDayStr, hourMinuteSecondStr))
57         + yearMonthDayStr + hourMinuteSecondStr + this->suffix;
58 }
59 
Next()60 std::string DisplayNameInfo::Next()
61 {
62     this->hourMinuteSecond++;
63     return this->ToString();
64 }
65 
ParseDisplayName(const PhotoAssetInfo & photoAssetInfo)66 void DisplayNameInfo::ParseDisplayName(const PhotoAssetInfo &photoAssetInfo)
67 {
68     if (photoAssetInfo.subtype == static_cast<int32_t>(PhotoSubType::BURST)) {
69         ParseBurstDisplayName(photoAssetInfo);
70         return;
71     }
72     ParseNormalDisplayName(photoAssetInfo);
73     return;
74 }
75 
ParseBurstDisplayName(const PhotoAssetInfo & photoAssetInfo)76 void DisplayNameInfo::ParseBurstDisplayName(const PhotoAssetInfo &photoAssetInfo)
77 {
78     bool isValid = photoAssetInfo.subtype == static_cast<int32_t>(PhotoSubType::BURST);
79     isValid = isValid && photoAssetInfo.displayName.size() > BURST_DISPLAY_NAME_MIN_LENGTH;
80     if (!isValid) {
81         return ParseNormalDisplayName(photoAssetInfo);
82     }
83     std::string displayName = photoAssetInfo.displayName;
84     std::regex pattern(R"(IMG_\d{8}_\d{6}_)", std::regex_constants::icase);
85     std::smatch match;
86     if (!std::regex_search(displayName, match, pattern)) {
87         return ParseNormalDisplayName(photoAssetInfo);
88     }
89     std::vector<std::string> parts;
90     std::istringstream iss(displayName);
91     std::string part;
92     while (std::getline(iss, part, '_')) {
93         parts.push_back(part);
94     }
95     if (parts.size() >= BURST_DISPLAY_NAME_MIN_SUBLINE_COUNT) {
96         this->prefix = parts[0];
97         this->yearMonthDay = this->ToNumber(parts[BURST_DISPLAY_NAME_YEAR_INDEX]);
98         this->hourMinuteSecond = this->ToNumber(parts[BURST_DISPLAY_NAME_HOUR_INDEX]);
99         this->suffix = displayName.substr(BURST_DISPLAY_NAME_MIN_LENGTH - 1);
100     }
101     MEDIA_INFO_LOG("ParseBurstDisplayName Original display name: %{public}s, BurstDisplayNameInfo: %{public}s",
102         displayName.c_str(),
103         this->ToString().c_str());
104 }
105 
ToNumber(const std::string & str)106 int32_t DisplayNameInfo::ToNumber(const std::string &str)
107 {
108     char *end;
109     long number = std::strtol(str.c_str(), &end, 10);
110 
111     if (*end != '\0') {
112         MEDIA_ERR_LOG("ToNumber failed, has invalid char. str: %{public}s", str.c_str());
113         return 0;
114     } else if (number < INT_MIN || number > INT_MAX) {
115         MEDIA_ERR_LOG("ToNumber failed, number overflow. str: %{public}s", str.c_str());
116         return 0;
117     }
118     return static_cast<int32_t>(number);
119 }
120 
ParseNormalDisplayName(const PhotoAssetInfo & photoAssetInfo)121 void DisplayNameInfo::ParseNormalDisplayName(const PhotoAssetInfo &photoAssetInfo)
122 {
123     std::string displayName = photoAssetInfo.displayName;
124     size_t dotPos = displayName.rfind('.');
125     if (dotPos != std::string::npos) {
126         this->prefix = displayName.substr(0, dotPos);
127         this->suffix = displayName.substr(dotPos);  // include dot, e.g. ".jpg"
128     }
129     MEDIA_INFO_LOG("ParseNormalDisplayName Original display name: %{public}s, BurstDisplayNameInfo: %{public}s",
130         displayName.c_str(),
131         this->ToString().c_str());
132 }
133 }  // namespace OHOS::Media