• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #include "theme_pack_resource.h"
16 
17 #include "hilog_wrapper.h"
18 #include "utils/utils.h"
19 #include <dirent.h>
20 #include <tuple>
21 namespace OHOS {
22 namespace Global {
23 namespace Resource {
24 constexpr int FIRST_ELEMENT = 0;
25 constexpr int SECOND_ELEMENT = 1;
26 constexpr int THIRED_ELEMENT = 2;
27 ThemeResource *ThemeResource::themeRes = nullptr;
ThemeResource(std::string path)28 ThemeResource::ThemeResource(std::string path) : themePath_(path)
29 {
30     themeRes = this;
31 }
32 
~ThemeResource()33 ThemeResource::~ThemeResource()
34 {
35     themeValueVec_.clear();
36     iconValues_.clear();
37 }
38 
~ThemeQualifierValue()39 ThemeResource::ThemeQualifierValue::~ThemeQualifierValue()
40 {}
41 
~ThemeValue()42 ThemeResource::ThemeValue::~ThemeValue()
43 {
44     limitPaths_.clear();
45 }
46 
ThemeQualifierValue(const ThemeKey themeKey,std::shared_ptr<ThemeConfig> themeConfig,const std::string & value)47 ThemeResource::ThemeQualifierValue::ThemeQualifierValue(const ThemeKey themeKey,
48     std::shared_ptr<ThemeConfig> themeConfig, const std::string &value) : themeKey_(themeKey),
49     themeConfig_(themeConfig), resValue_(value)
50 {}
51 
52 std::unordered_map<std::string, ResType> themeResTypeMap {
53     {"color", COLOR},
54     {"float", FLOAT},
55     {"media", MEDIA},
56 };
57 
GetResKey(const std::string & jsonPath)58 std::string GetResKey(const std::string &jsonPath)
59 {
60     auto lastIndex = jsonPath.rfind('/');
61     auto secondLastIndex = jsonPath.rfind('/', lastIndex - 1);
62     auto thirdLastIndex = jsonPath.rfind('/', secondLastIndex - 1);
63     if (lastIndex == std::string::npos || secondLastIndex == std::string::npos
64         || thirdLastIndex == std::string::npos) {
65         return std::string("");
66     }
67     std::string res = jsonPath.substr(thirdLastIndex + 1, secondLastIndex - thirdLastIndex - 1);
68     return res;
69 }
70 
GetThemeConfig(const std::string & iconPath)71 std::shared_ptr<ThemeConfig> GetThemeConfig(const std::string &iconPath)
72 {
73     auto themeConfig = std::make_shared<ThemeConfig>();
74     std::string resKey = GetResKey(iconPath);
75     if (resKey == "dark") {
76         themeConfig->SetThemeColorMode(ColorMode::DARK);
77     } else if (resKey == "horizontal") {
78         themeConfig->SetThemeDirection(Direction::DIRECTION_HORIZONTAL);
79     } else if (resKey == "horizontal-dark") {
80         themeConfig->SetThemeDirection(Direction::DIRECTION_HORIZONTAL);
81         themeConfig->SetThemeColorMode(ColorMode::DARK);
82     } else {
83         // default
84     }
85     return themeConfig;
86 }
87 
GetResType(const std::string & resTypeStr)88 ResType GetResType(const std::string &resTypeStr)
89 {
90     ResType resType = ResType::VALUES;
91     if (themeResTypeMap.find(resTypeStr) != themeResTypeMap.end()) {
92         resType = themeResTypeMap[resTypeStr];
93         return resType;
94     }
95     return ResType::VALUES;
96 }
97 
InitThemeRes(std::pair<std::string,std::string> bundleInfo,cJSON * root,std::shared_ptr<ThemeConfig> themeConfig,const std::string & resTypeStr)98 void ThemeResource::InitThemeRes(std::pair<std::string, std::string> bundleInfo, cJSON *root,
99     std::shared_ptr<ThemeConfig> themeConfig, const std::string &resTypeStr)
100 {
101     if (root == nullptr) {
102         HILOG_WARN("The json file has not resType = %{public}s", resTypeStr.c_str());
103         return;
104     }
105 
106     ResType resType = GetResType(resTypeStr);
107     if (root->type == cJSON_Array) {
108         cJSON *childValue = root->child;
109         while (childValue != nullptr) {
110             cJSON *name = cJSON_GetObjectItem(childValue, "name");
111             if (name == nullptr) {
112                 HILOG_WARN("The resource name is not exist in childValue");
113                 return;
114             }
115             cJSON *value = cJSON_GetObjectItem(childValue, "value");
116             if (value == nullptr) {
117                 HILOG_WARN("The resource value is not exist in childValue");
118                 return;
119             }
120             auto themeValue = std::make_shared<ThemeValue>();
121             ThemeKey themeKey = ThemeKey(bundleInfo.first, bundleInfo.second, resType, name->valuestring);
122             auto themeQualifierValue = std::make_shared<ThemeQualifierValue>(themeKey, themeConfig,
123                 value->valuestring);
124             themeValue->AddThemeLimitPath(themeQualifierValue);
125             themeValueVec_.emplace_back(std::make_tuple(resType, name->valuestring, themeValue));
126             childValue = childValue->next;
127         }
128     }
129     return;
130 }
131 
ParseJson(const std::string & bundleName,const std::string & moduleName,const std::string & jsonPath)132 void ThemeResource::ParseJson(const std::string &bundleName, const std::string &moduleName,
133     const std::string &jsonPath)
134 {
135     size_t len = 0;
136     FILE* pf = std::fopen(jsonPath.c_str(), "r");
137     if (pf == nullptr) {
138         HILOG_ERROR("fopen failed in ParseJson");
139         return;
140     }
141     std::fseek(pf, 0, SEEK_END);
142     len = ftell(pf);
143     std::fseek(pf, 0, SEEK_SET);
144     char *jsonData = (char *)malloc(len + 1);
145     std::fread(jsonData, len, 1, pf);
146     jsonData[len] = '\0';
147     auto themeConfig = GetThemeConfig(jsonPath);
148     cJSON *jsonValue = cJSON_Parse(jsonData);
149     std::pair<std::string, std::string> bundleInfo(bundleName, moduleName);
150     cJSON *floatRoot = cJSON_GetObjectItem(jsonValue, "float");
151     InitThemeRes(bundleInfo, floatRoot, themeConfig, "float");
152 
153     cJSON *colorRoot = cJSON_GetObjectItem(jsonValue, "color");
154     InitThemeRes(bundleInfo, colorRoot, themeConfig, "color");
155     free(jsonData);
156     jsonData = nullptr;
157     if (pf != nullptr) {
158         fclose(pf);
159         pf = nullptr;
160     }
161     cJSON_Delete(jsonValue);
162     return;
163 }
164 
ParseIcon(const std::string & bundleName,const std::string & moduleName,const std::string & iconPath)165 void ThemeResource::ParseIcon(const std::string &bundleName, const std::string &moduleName,
166     const std::string &iconPath)
167 {
168     auto themeConfig = GetThemeConfig(iconPath);
169     auto pos1 = iconPath.rfind('.');
170     auto pos2 = iconPath.rfind('/');
171     if (pos1 == std::string::npos || pos2 == std::string::npos) {
172         HILOG_ERROR("invalid iconPath = %{public}s in ParseIcon", iconPath.c_str());
173         return;
174     }
175     std::string iconName = iconPath.substr(pos2 + 1, pos1 - pos2 - 1);
176     auto themeValue = std::make_shared<ThemeValue>();
177     ThemeKey themeKey = ThemeKey(bundleName, moduleName, ResType::MEDIA, iconName);
178     auto themeQualifierValue = std::make_shared<ThemeQualifierValue>(themeKey, themeConfig, iconPath);
179     themeValue->AddThemeLimitPath(themeQualifierValue);
180     themeValueVec_.emplace_back(std::make_tuple(ResType::MEDIA, iconName, themeValue));
181     return;
182 }
183 
GetThemeValues(const std::pair<std::string,std::string> & bundInfo,const ResType & resType,const std::string & name)184 std::vector<std::shared_ptr<ThemeResource::ThemeValue> > ThemeResource::GetThemeValues(
185     const std::pair<std::string, std::string> &bundInfo, const ResType &resType, const std::string &name)
186 {
187     std::vector<std::shared_ptr<ThemeResource::ThemeValue> > result;
188     if (themeValueVec_.empty()) {
189         return result;
190     }
191 
192     for (const auto &themeValue : themeValueVec_) {
193         ResType type = std::get<FIRST_ELEMENT>(themeValue);
194         std::string resName = std::get<SECOND_ELEMENT>(themeValue);
195         if (type == resType && resName == name) {
196             result.emplace_back(std::get<THIRED_ELEMENT>(themeValue));
197         }
198     }
199     return result;
200 }
201 
GetFiles(const std::string & strCurrentDir)202 std::vector<std::string> GetFiles(const std::string &strCurrentDir)
203 {
204     std::vector<std::string> vFiles;
205 #if !defined(__WINNT__) && !defined(__IDE_PREVIEW__) && !defined(__ARKUI_CROSS__)
206     DIR *dir;
207     struct dirent *pDir;
208     if ((dir = opendir(strCurrentDir.c_str())) == nullptr) {
209         HILOG_ERROR("opendir failed strCurrentDir = %{public}s", strCurrentDir.c_str());
210         return vFiles;
211     }
212     while ((pDir = readdir(dir)) != nullptr) {
213         if (strcmp(pDir->d_name, ".") == 0 || strcmp(pDir->d_name, "..") == 0) {
214             continue;
215         } else if (pDir->d_type == 8) { // 8 means the file
216             vFiles.emplace_back(strCurrentDir + "/" + pDir->d_name);
217         } else if (pDir->d_type == 4) { // 4 means the dir
218             std::string strNextDir = strCurrentDir + "/" + pDir->d_name;
219             std::vector<std::string> temp = GetFiles(strNextDir);
220             vFiles.insert(vFiles.end(), temp.begin(), temp.end());
221         } else {
222             continue;
223         }
224     }
225     closedir(dir);
226 #endif
227     return vFiles;
228 }
229 
GetBundleInfo(const std::string & rootDir,const std::string & path)230 std::tuple<std::string, std::string> GetBundleInfo(const std::string& rootDir, const std::string& path)
231 {
232     if (rootDir.empty() || path.empty()) {
233         return std::tuple<std::string, std::string>("", "");
234     }
235     size_t len = rootDir.size();
236     auto pos = rootDir.rfind('/');
237     if (pos == std::string::npos) {
238         HILOG_ERROR("invalid rootDir = %{public}s in GetBundleInfo", rootDir.c_str());
239         return std::tuple<std::string, std::string>("", "");
240     }
241     std::string bundleName = rootDir.substr(pos + 1);
242     auto pos2 = path.find('/', len + 1);
243     if (pos2 == std::string::npos) {
244         HILOG_ERROR("invalid path = %{public}s in GetBundleInfo", path.c_str());
245         return std::tuple<std::string, std::string>("", "");
246     }
247     std::string moduleName = path.substr(len + 1, pos2 - len -1);
248     std::tuple<std::string, std::string> bundleInfoTuple(bundleName, moduleName);
249     return bundleInfoTuple;
250 }
251 
LoadThemeResource(const std::string & rootDir)252 const std::shared_ptr<ThemeResource> ThemeResource::LoadThemeResource(const std::string& rootDir)
253 {
254     if (rootDir.empty()) {
255         HILOG_ERROR("Invalid rootDir in LoadThemeResource = %{public}s", rootDir.c_str());
256         return nullptr;
257     }
258     auto themeResource = std::make_shared<ThemeResource>(rootDir);
259     std::vector<std::string> resPaths = GetFiles(rootDir);
260     for (const auto &path : resPaths) {
261         auto bundleInfo = GetBundleInfo(rootDir, path);
262         auto pos = path.rfind('.');
263         if (pos == std::string::npos) {
264             HILOG_ERROR("invalid resPath = %{public}s", path.c_str());
265             continue;
266         }
267         std::string tail = path.substr(pos + 1);
268         if (tail == "json") {
269             themeRes->ParseJson(std::get<FIRST_ELEMENT>(bundleInfo), std::get<SECOND_ELEMENT>(bundleInfo), path);
270         } else {
271             themeRes->ParseIcon(std::get<FIRST_ELEMENT>(bundleInfo), std::get<SECOND_ELEMENT>(bundleInfo), path);
272         }
273     }
274     return themeResource;
275 }
276 
GetThemeResBundleName(const std::string & themePath)277 std::string ThemeResource::GetThemeResBundleName(const std::string &themePath)
278 {
279     auto pos = themePath.rfind('/');
280     if (pos == std::string::npos) {
281         HILOG_ERROR("invalid themePath = %{public}s", themePath.c_str());
282         return std::string("");
283     }
284     std::string bundleName = themePath.substr(pos + 1);
285     return bundleName;
286 }
287 
GetIconsBundleName(const std::string & iconPath)288 std::string GetIconsBundleName(const std::string& iconPath)
289 {
290     if (iconPath.empty()) {
291         return std::string("");
292     }
293     auto pos = iconPath.rfind('/');
294     if (pos == std::string::npos) {
295         HILOG_ERROR("invalid iconPath = %{public}s in GetIconsBundleName", iconPath.c_str());
296         return std::string("");
297     }
298     return iconPath.substr(pos + 1);
299 }
300 
LoadThemeIconResource(const std::string & iconPath)301 const std::shared_ptr<ThemeResource> ThemeResource::LoadThemeIconResource(const std::string& iconPath)
302 {
303     if (iconPath.empty()) {
304         return nullptr;
305     }
306     auto themeResource = std::make_shared<ThemeResource>(iconPath);
307     std::string bundleName = GetIconsBundleName(iconPath);
308     std::vector<std::string> resPaths = GetFiles(iconPath);
309     for (const auto &path : resPaths) {
310         auto pos1 = path.rfind('.');
311         auto pos2 = path.rfind('/');
312         if (pos1 == std::string::npos || pos2 == std::string::npos) {
313             HILOG_ERROR("invalid path = %{public}s in LoadThemeIconResource", path.c_str());
314             continue;
315         }
316         std::string iconName = path.substr(pos2 + 1, pos1 - pos2 - 1);
317         ThemeKey themeKey = ThemeKey(bundleName, "", ResType::MEDIA, iconName);
318         themeRes->iconValues_.emplace_back(std::make_pair(themeKey, path));
319     }
320     return themeResource;
321 }
322 
GetThemeAppIcon(const std::pair<std::string,std::string> & bundleInfo,const std::string & iconName)323 const std::string ThemeResource::GetThemeAppIcon(const std::pair<std::string, std::string> &bundleInfo,
324     const std::string &iconName)
325 {
326     for (size_t i = 0; i < iconValues_.size(); i++) {
327         if (iconValues_[i].first.bundleName != bundleInfo.first) {
328             continue;
329         }
330         if (iconName == iconValues_[i].first.resName) {
331             return iconValues_[i].second;
332         }
333     }
334     return std::string("");
335 }
336 } // namespace Resource
337 } // namespace Global
338 } // namespace OHOS
339