1 /*
2 * Copyright (c) 2021-2022 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 #include "holiday_manager.h"
16 #include "i18n_hilog.h"
17 #include <algorithm>
18 #include <climits>
19 #include <ctime>
20 #include <filesystem>
21 #include <format>
22 #include <fstream>
23 #include <iostream>
24 #include <regex>
25 #include "map"
26 #include "utils.h"
27
28 namespace OHOS {
29 namespace Global {
30 namespace I18n {
31 const char* HolidayManager::ITEM_BEGIN_TAG = "BEGIN:VEVENT";
32 const char* HolidayManager::ITEM_END_TAG = "END:VEVENT";
33 const char* HolidayManager::ITEM_DTSTART_TAG = "DTSTART";
34 const char* HolidayManager::ITEM_DTEND_TAG = "DTEND";
35 const char* HolidayManager::ITEM_SUMMARY_TAG = "SUMMARY";
36 const char* HolidayManager::ITEM_RESOURCES_TAG = "RESOURCES";
37
HolidayManager(const char * path)38 HolidayManager::HolidayManager(const char* path)
39 {
40 if (path == nullptr) {
41 HILOG_ERROR_I18N("Failed: parameter path is NULL.");
42 return;
43 }
44 std::string msg = ValidateHolidayFilePath(path);
45 if (msg.length() != 0) {
46 HILOG_ERROR_I18N("Failed: %{public}s .", msg.c_str());
47 return;
48 }
49 std::vector<HolidayInfoItem> items = ReadHolidayFile(path);
50 for (size_t i = 0; i < items.size(); i++) {
51 struct tm tmObj = {.tm_mday = items[i].day, .tm_mon = items[i].month, .tm_year = items[i].year};
52 char strDate[10];
53 size_t resCode = strftime(strDate, sizeof(strDate), "%Y%m%d", &tmObj);
54 if (resCode == 0) {
55 HILOG_ERROR_I18N("Failed: strftime error:%{public}zu.", resCode);
56 return;
57 }
58 std::string startDate(strDate);
59 items[i].year += YEAR_START;
60 items[i].month += MONTH_GREATER_ONE;
61 if (holidayItemMap.find(startDate) != holidayItemMap.end()) {
62 std::vector<HolidayInfoItem> *vetor = &(holidayItemMap.find(startDate)->second);
63 vetor->push_back(items[i]);
64 } else {
65 std::vector<HolidayInfoItem> vetor;
66 vetor.push_back(items[i]);
67 holidayItemMap.insert(std::pair<std::string, std::vector<HolidayInfoItem>>(startDate, vetor));
68 }
69 }
70 }
71
~HolidayManager()72 HolidayManager::~HolidayManager()
73 {
74 }
75
SetHolidayData(std::map<std::string,std::vector<HolidayInfoItem>> holidayDataMap)76 void HolidayManager::SetHolidayData(std::map<std::string, std::vector<HolidayInfoItem>> holidayDataMap)
77 {
78 holidayItemMap = holidayDataMap;
79 }
80
IsHoliday()81 bool HolidayManager::IsHoliday()
82 {
83 time_t timeStamp = time(NULL);
84 struct tm* timObj = localtime(&timeStamp);
85 if (timObj == nullptr) {
86 return false;
87 }
88 int32_t year = timObj->tm_year + YEAR_START;
89 int32_t month = timObj->tm_mon + MONTH_GREATER_ONE;
90 return IsHoliday(year, month, timObj->tm_mday);
91 }
92
IsHoliday(int32_t year,int32_t month,int32_t day)93 bool HolidayManager::IsHoliday(int32_t year, int32_t month, int32_t day)
94 {
95 std::string startDate = Format(year, month, day);
96 if (holidayItemMap.find(startDate) != holidayItemMap.end()) {
97 std::vector<HolidayInfoItem> list = holidayItemMap.find(startDate)->second;
98 return list.size() > 0;
99 }
100 return false;
101 }
102
Format(int32_t year,int32_t month,int32_t day)103 std::string HolidayManager::Format(int32_t year, int32_t month, int32_t day)
104 {
105 std::string formated;
106 formated += std::to_string(year);
107 // Numbers less than 10 are one digit
108 formated += month < 10 ? ("0" + std::to_string(month)) : std::to_string(month);
109 // Numbers less than 10 are one digit
110 formated += day < 10 ? ("0" + std::to_string(day)) : std::to_string(day);
111 return formated;
112 }
113
GetHolidayInfoItemArray()114 std::vector<HolidayInfoItem> HolidayManager::GetHolidayInfoItemArray()
115 {
116 time_t timeStamp = time(NULL);
117 struct tm* timObj = localtime(&timeStamp);
118 if (timObj == nullptr) {
119 std::vector<HolidayInfoItem> emptyList;
120 return emptyList;
121 }
122 int32_t realYear = timObj->tm_year + YEAR_START;
123 return GetHolidayInfoItemArray(realYear);
124 }
125
GetHolidayInfoItemArray(int32_t year)126 std::vector<HolidayInfoItem> HolidayManager::GetHolidayInfoItemArray(int32_t year)
127 {
128 std::vector<HolidayInfoItem> vetor;
129 std::string formatedYear = std::to_string(year);
130 std::map<std::string, std::vector<HolidayInfoItem>>::iterator iter;
131 for (iter = holidayItemMap.begin(); iter != holidayItemMap.end(); ++iter) {
132 std::string key = iter->first;
133 if (formatedYear == key.substr(0, 4)) { // 4 is the length of full year
134 std::vector<HolidayInfoItem> temp = iter->second;
135 for (size_t i = 0; i < temp.size(); i++) {
136 vetor.push_back(temp[i]);
137 }
138 }
139 }
140 return vetor;
141 }
142
ValidateHolidayFilePath(const char * path)143 std::string HolidayManager::ValidateHolidayFilePath(const char* path)
144 {
145 char *realpathRes = realpath(path, nullptr);
146 if (realpathRes == NULL) {
147 free(realpathRes);
148 return "the holiday resource file not exists.";
149 }
150 std::ifstream file(path);
151 if (!file.good()) {
152 free(realpathRes);
153 file.close();
154 return "the holiday resource file can't read.";
155 }
156 file.close();
157 free(realpathRes);
158 realpathRes = NULL;
159 return "";
160 }
161
ReadHolidayFile(const char * path)162 std::vector<HolidayInfoItem> HolidayManager::ReadHolidayFile(const char* path)
163 {
164 std::vector<HolidayInfoItem> items;
165 if (path == nullptr) {
166 return items;
167 }
168 std::ifstream fin;
169 fin.open(path, std::ios::in);
170 std::string line;
171 while (getline(fin, line)) {
172 line = Trim(line);
173 if (line.compare(ITEM_BEGIN_TAG) != 0) {
174 continue;
175 }
176 struct HolidayInfoItem holidayItem;
177 while (getline(fin, line)) {
178 line = Trim(line);
179 ParseFileLine(line, &(holidayItem));
180 if (line.compare(ITEM_END_TAG) == 0) {
181 items.push_back(holidayItem);
182 break;
183 }
184 }
185 }
186 fin.close();
187 return items;
188 }
189
ParseFileLine(const std::string & line,HolidayInfoItem * holidayItem)190 void HolidayManager::ParseFileLine(const std::string &line, HolidayInfoItem *holidayItem)
191 {
192 if (holidayItem == nullptr) {
193 return;
194 }
195 std::regex reg("([A-Z]+)[:;](.+)");
196 std::smatch match;
197 bool found = std::regex_search(line, match, reg);
198 if (found) {
199 std::string tag = match[1].str();
200 std::string value = line.substr(line.find_last_of(":") + 1, line.length());
201 if (tag.compare(ITEM_DTSTART_TAG) == 0) {
202 std::string startDate = value.size() >= 8 ? value.substr(0, 8) : ""; // 8 is date formarted string length
203 if (startDate.size() == 8) {
204 struct tm timeObj;
205 strptime(startDate.c_str(), "%Y%m%d", &timeObj);
206 holidayItem->year = timeObj.tm_year;
207 holidayItem->month = timeObj.tm_mon;
208 holidayItem->day = timeObj.tm_mday;
209 }
210 } else if (tag.compare(ITEM_SUMMARY_TAG) == 0) {
211 holidayItem->baseName = value;
212 } else if (tag.compare(ITEM_RESOURCES_TAG) == 0) {
213 std::string displayName = line.substr(line.find_last_of("=") + 1, line.length());
214 std::string language = displayName.substr(0, displayName.find_first_of(":"));
215 std::string localName = displayName.substr(displayName.find_first_of(":") + 1, displayName.length());
216 transform(language.begin(), language.end(), language.begin(), ::tolower);
217 HolidayLocalName localeName = {language, PseudoLocalizationProcessor(localName)};
218 holidayItem->localNames.push_back(localeName);
219 }
220 }
221 }
222
Trim(std::string & str)223 std::string& HolidayManager::Trim(std::string &str)
224 {
225 if (str.empty()) {
226 return str;
227 }
228 str.erase(0, str.find_first_not_of(" \t"));
229 str.erase(str.find_last_not_of("\r\n\t") + 1);
230 return str;
231 }
232 } // namespace I18n
233 } // namespace Global
234 } // namespace OHOS
235