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
16 #include "hap_resource.h"
17
18 #include <algorithm>
19 #include <climits>
20 #include <cstdlib>
21 #include <fstream>
22 #include "utils/utils.h"
23
24 #ifdef __WINNT__
25 #include <shlwapi.h>
26 #include <windows.h>
27 #endif
28
29 #ifdef __LINUX__
30 #include <cstring>
31 #endif
32
33 #if !defined(__WINNT__) && !defined(__IDE_PREVIEW__) && !defined(__ARKUI_CROSS__)
34 #include "hitrace_meter.h"
35 #endif
36 #include "hap_parser.h"
37 #include "hilog_wrapper.h"
38 #include "utils/errors.h"
39
40 namespace OHOS {
41 namespace Global {
42 namespace Resource {
ValueUnderQualifierDir(const std::vector<KeyParam * > & keyParams,IdItem * idItem,HapResource * hapResource,bool isOverlay,bool systemResource)43 HapResource::ValueUnderQualifierDir::ValueUnderQualifierDir(const std::vector<KeyParam *> &keyParams, IdItem *idItem,
44 HapResource *hapResource, bool isOverlay, bool systemResource) : hapResource_(hapResource)
45 {
46 keyParams_ = keyParams;
47 folder_ = HapParser::ToFolderPath(keyParams_);
48 idItem_ = idItem;
49 isOverlay_ = isOverlay;
50 isSystemResource_ = systemResource;
51 InitResConfig();
52 }
53
~ValueUnderQualifierDir()54 HapResource::ValueUnderQualifierDir::~ValueUnderQualifierDir()
55 {
56 // keyParams_ idItem_ was passed into this, we don't delete them because someone will do
57 if (resConfig_ != nullptr) {
58 delete (resConfig_);
59 resConfig_ = nullptr;
60 }
61 }
62
InitResConfig()63 void HapResource::ValueUnderQualifierDir::InitResConfig()
64 {
65 resConfig_ = HapParser::CreateResConfigFromKeyParams(keyParams_);
66 }
67
68 // IdValues
~IdValues()69 HapResource::IdValues::~IdValues()
70 {
71 for (size_t i = 0; i < limitPaths_.size(); ++i) {
72 if (limitPaths_[i] != nullptr) {
73 delete limitPaths_[i];
74 limitPaths_[i] = nullptr;
75 }
76 }
77 }
78
79 // HapResource
HapResource(const std::string path,time_t lastModTime,const ResConfig * defaultConfig,ResDesc * resDes)80 HapResource::HapResource(const std::string path, time_t lastModTime, const ResConfig *defaultConfig, ResDesc *resDes)
81 : indexPath_(path), lastModTime_(lastModTime), resDesc_(resDes), defaultConfig_(defaultConfig)
82 {
83 }
84
~HapResource()85 HapResource::~HapResource()
86 {
87 if (resDesc_ != nullptr) {
88 delete (resDesc_);
89 resDesc_ = nullptr;
90 }
91 std::map<uint32_t, IdValues *>::iterator iter;
92 for (iter = idValuesMap_.begin(); iter != idValuesMap_.end(); ++iter) {
93 if (iter->second != nullptr) {
94 IdValues *ptr = iter->second;
95 delete (ptr);
96 iter->second = nullptr;
97 }
98 }
99
100 for (size_t i = 0; i < idValuesNameMap_.size(); ++i) {
101 if (idValuesNameMap_[i] != nullptr) {
102 delete (idValuesNameMap_[i]);
103 idValuesNameMap_[i] = nullptr;
104 }
105 }
106 lastModTime_ = 0;
107 // defaultConfig_ was passed by constructor, we do not delete it here
108 defaultConfig_ = nullptr;
109 }
110
CanonicalizePath(const char * path,char * outPath,size_t len)111 void CanonicalizePath(const char *path, char *outPath, size_t len)
112 {
113 #if !defined(__WINNT__) && !defined(__IDE_PREVIEW__) && !defined(__ARKUI_CROSS__)
114 HITRACE_METER_NAME(HITRACE_TAG_APP, __PRETTY_FUNCTION__);
115 #endif
116 if (path == nullptr) {
117 HILOG_ERROR("path is null");
118 return;
119 }
120 if (strlen(path) >= len) {
121 HILOG_ERROR("the length of path longer than len");
122 return;
123 }
124 #ifdef __WINNT__
125 if (!PathCanonicalizeA(outPath, path)) {
126 HILOG_ERROR("failed to canonicalize the path");
127 return;
128 }
129 #else
130 if (realpath(path, outPath) == nullptr) {
131 HILOG_ERROR("failed to realpath the path errno:%{public}d", errno);
132 return;
133 }
134 #endif
135 }
136
Load(const char * path,const ResConfigImpl * defaultConfig,bool system)137 const HapResource* HapResource::Load(const char *path, const ResConfigImpl* defaultConfig, bool system)
138 {
139 if (Utils::ContainsTail(path, Utils::tailSet)) {
140 return LoadFromHap(path, defaultConfig, system);
141 } else {
142 return LoadFromIndex(path, defaultConfig, system);
143 }
144 }
145
LoadFromIndex(const char * path,const ResConfigImpl * defaultConfig,bool system)146 const HapResource* HapResource::LoadFromIndex(const char *path, const ResConfigImpl *defaultConfig, bool system)
147 {
148 char outPath[PATH_MAX + 1] = {0};
149 CanonicalizePath(path, outPath, PATH_MAX);
150 std::ifstream inFile(outPath, std::ios::binary | std::ios::in);
151 if (!inFile.good()) {
152 return nullptr;
153 }
154 inFile.seekg(0, std::ios::end);
155 int bufLen = inFile.tellg();
156 if (bufLen <= 0) {
157 HILOG_ERROR("file size is zero");
158 inFile.close();
159 return nullptr;
160 }
161 void *buf = malloc(bufLen);
162 if (buf == nullptr) {
163 HILOG_ERROR("Error allocating memory");
164 inFile.close();
165 return nullptr;
166 }
167 inFile.seekg(0, std::ios::beg);
168 inFile.read(static_cast<char *>(buf), bufLen);
169 inFile.close();
170
171 HILOG_DEBUG("extract success, bufLen:%d", bufLen);
172
173 ResDesc *resDesc = new (std::nothrow) ResDesc();
174 if (resDesc == nullptr) {
175 HILOG_ERROR("new ResDesc failed when LoadFromIndex");
176 free(buf);
177 return nullptr;
178 }
179 int32_t out = HapParser::ParseResHex(static_cast<char *>(buf), bufLen, *resDesc, defaultConfig);
180 if (out != OK) {
181 delete (resDesc);
182 free(buf);
183 HILOG_ERROR("ParseResHex failed! retcode:%d", out);
184 return nullptr;
185 }
186 free(buf);
187
188 HapResource *pResource = new (std::nothrow) HapResource(std::string(path), 0, defaultConfig, resDesc);
189 if (pResource == nullptr) {
190 HILOG_ERROR("new HapResource failed when LoadFromIndex");
191 delete (resDesc);
192 return nullptr;
193 }
194 if (!pResource->Init(system)) {
195 delete (pResource);
196 return nullptr;
197 }
198 return pResource;
199 }
200
LoadFromHap(const char * path,const ResConfigImpl * defaultConfig,bool system)201 const HapResource* HapResource::LoadFromHap(const char *path, const ResConfigImpl *defaultConfig, bool system)
202 {
203 std::unique_ptr<uint8_t[]> tmpBuf;
204 size_t tmpLen;
205 int32_t ret = HapParser::ReadIndexFromFile(path, tmpBuf, tmpLen);
206 if (ret != OK) {
207 HILOG_ERROR("read Index from file failed");
208 return nullptr;
209 }
210 ResDesc *resDesc = new (std::nothrow) ResDesc();
211 if (resDesc == nullptr) {
212 HILOG_ERROR("new ResDesc failed when LoadFromHap");
213 return nullptr;
214 }
215 int32_t out = HapParser::ParseResHex(reinterpret_cast<char *>(tmpBuf.get()), tmpLen, *resDesc, defaultConfig);
216 if (out != OK) {
217 HILOG_ERROR("ParseResHex failed! retcode:%d", out);
218 delete (resDesc);
219 return nullptr;
220 }
221
222 HapResource *pResource = new (std::nothrow) HapResource(path, 0, defaultConfig, resDesc);
223 if (pResource == nullptr) {
224 delete (resDesc);
225 return nullptr;
226 }
227
228 if (!pResource->Init(system)) {
229 delete (pResource);
230 return nullptr;
231 }
232 return pResource;
233 }
234
LoadOverlays(const std::string & path,const std::vector<std::string> & overlayPaths,const ResConfigImpl * defaultConfig)235 const std::unordered_map<std::string, HapResource *> HapResource::LoadOverlays(const std::string &path,
236 const std::vector<std::string> &overlayPaths, const ResConfigImpl *defaultConfig)
237 {
238 std::unordered_map<std::string, HapResource *> result;
239 do {
240 const HapResource *targetResource = Load(path.c_str(), defaultConfig, true);
241 if (targetResource == nullptr) {
242 HILOG_ERROR("load target failed");
243 break;
244 }
245 result[path] = const_cast<HapResource*>(targetResource);
246 bool success = true;
247 std::unordered_map<std::string, std::unordered_map<ResType, uint32_t>> mapping =
248 targetResource->BuildNameTypeIdMapping();
249 for (auto iter = overlayPaths.begin(); iter != overlayPaths.end(); iter++) {
250 const HapResource *overlayResource = Load(iter->c_str(), defaultConfig);
251 if (overlayResource == nullptr) {
252 HILOG_ERROR("load overlay failed");
253 success = false;
254 break;
255 }
256 result[*iter] = const_cast<HapResource*>(overlayResource);
257 }
258
259 if (!success) {
260 HILOG_ERROR("load overlay failed");
261 break;
262 }
263
264 for (auto iter = result.begin(); iter != result.end(); iter++) {
265 auto index = iter->first.find(path);
266 if (index == std::string::npos) {
267 iter->second->UpdateOverlayInfo(mapping);
268 }
269 }
270 return result;
271 } while (false);
272
273 for_each (result.begin(), result.end(), [](auto &iter) {
274 delete iter.second;
275 });
276 return std::unordered_map<std::string, HapResource *>();
277 }
278
BuildNameTypeIdMapping() const279 std::unordered_map<std::string, std::unordered_map<ResType, uint32_t>> HapResource::BuildNameTypeIdMapping() const
280 {
281 std::unordered_map<std::string, std::unordered_map<ResType, uint32_t>> result;
282 for (auto iter = idValuesMap_.begin(); iter != idValuesMap_.end(); iter++) {
283 const std::vector<ValueUnderQualifierDir *> &limitPaths = iter->second->GetLimitPathsConst();
284 if (limitPaths.size() > 0) {
285 ValueUnderQualifierDir* value = limitPaths[0];
286 result[value->idItem_->name_][value->idItem_->resType_] = value->idItem_->id_;
287 }
288 }
289 return result;
290 }
291
UpdateOverlayInfo(std::unordered_map<std::string,std::unordered_map<ResType,uint32_t>> & nameTypeId)292 void HapResource::UpdateOverlayInfo(std::unordered_map<std::string, std::unordered_map<ResType, uint32_t>> &nameTypeId)
293 {
294 std::map<uint32_t, IdValues *> newIdValuesMap;
295 for (auto iter = idValuesMap_.begin(); iter != idValuesMap_.end(); iter++) {
296 const std::vector<ValueUnderQualifierDir *> &limitPaths = iter->second->GetLimitPathsConst();
297 if (limitPaths.size() > 0) {
298 ValueUnderQualifierDir *value = limitPaths[0];
299 std::string name = value->idItem_->name_;
300 ResType type = value->idItem_->resType_;
301 if (nameTypeId.find(name) == nameTypeId.end()) {
302 continue;
303 }
304 auto &typeId = nameTypeId[name];
305 if (typeId.find(type) == typeId.end()) {
306 continue;
307 }
308 uint32_t newId = typeId[type];
309 for_each(limitPaths.begin(), limitPaths.end(), [&](auto &item) {
310 item->idItem_->id_ = newId;
311 item->isOverlay_ = true;
312 });
313 newIdValuesMap[newId] = iter->second;
314 }
315 }
316 idValuesMap_.swap(newIdValuesMap);
317 }
318
Init(bool system)319 bool HapResource::Init(bool system)
320 {
321 #if !defined(__WINNT__) && !defined(__IDE_PREVIEW__) && !defined(__ARKUI_CROSS__)
322 HITRACE_METER_NAME(HITRACE_TAG_APP, __PRETTY_FUNCTION__);
323 #endif
324 #ifdef __WINNT__
325 char separator = '\\';
326 #else
327 char separator = '/';
328 #endif
329 auto index = indexPath_.rfind(separator);
330 if (index == std::string::npos) {
331 HILOG_ERROR("index path format error, %s", indexPath_.c_str());
332 return false;
333 }
334 #if defined(__IDE_PREVIEW__) || defined(__ARKUI_CROSS__)
335 resourcePath_ = indexPath_.substr(0, index + 1);
336 #else
337 index = indexPath_.rfind(separator, index - 1);
338 if (index == std::string::npos) {
339 HILOG_ERROR("index path format error, %s", indexPath_.c_str());
340 return false;
341 }
342 resourcePath_ = indexPath_.substr(0, index + 1);
343 #endif
344 for (int i = 0; i < ResType::MAX_RES_TYPE; ++i) {
345 auto mptr = new (std::nothrow) std::map<std::string, IdValues *>();
346 if (mptr == nullptr) {
347 HILOG_ERROR("new std::map failed in HapResource::Init");
348 return false;
349 }
350 idValuesNameMap_.push_back(mptr);
351 }
352 return InitIdList(system);
353 }
354
InitIdList(bool system)355 bool HapResource::InitIdList(bool system)
356 {
357 if (resDesc_ == nullptr) {
358 HILOG_ERROR("resDesc_ is null ! InitIdList failed");
359 return false;
360 }
361 for (size_t i = 0; i < resDesc_->keys_.size(); i++) {
362 ResKey *resKey = resDesc_->keys_[i];
363
364 for (size_t j = 0; j < resKey->resId_->idParams_.size(); ++j) {
365 IdParam *idParam = resKey->resId_->idParams_[j];
366 uint32_t id = idParam->id_;
367 std::map<uint32_t, IdValues *>::iterator iter = idValuesMap_.find(id);
368 if (iter == idValuesMap_.end()) {
369 auto idValues = new (std::nothrow) HapResource::IdValues();
370 if (idValues == nullptr) {
371 HILOG_ERROR("new IdValues failed in HapResource::InitIdList");
372 return false;
373 }
374 auto limitPath = new (std::nothrow) HapResource::ValueUnderQualifierDir(resKey->keyParams_,
375 idParam->idItem_, this, false, system);
376 if (limitPath == nullptr) {
377 HILOG_ERROR("new ValueUnderQualifierDir failed in HapResource::InitIdList");
378 delete (idValues);
379 return false;
380 }
381 idValues->AddLimitPath(limitPath);
382 idValuesMap_.insert(std::make_pair(id, idValues));
383 std::string name = std::string(idParam->idItem_->name_);
384 idValuesNameMap_[idParam->idItem_->resType_]->insert(std::make_pair(name, idValues));
385 } else {
386 HapResource::IdValues *idValues = iter->second;
387 auto limitPath = new (std::nothrow) HapResource::ValueUnderQualifierDir(resKey->keyParams_,
388 idParam->idItem_, this, false, system);
389 if (limitPath == nullptr) {
390 HILOG_ERROR("new ValueUnderQualifierDir failed in HapResource::InitIdList");
391 return false;
392 }
393 idValues->AddLimitPath(limitPath);
394 }
395 }
396 }
397 return true;
398 };
399
GetIdValues(const uint32_t id) const400 const HapResource::IdValues *HapResource::GetIdValues(const uint32_t id) const
401 {
402 if (idValuesMap_.empty()) {
403 HILOG_ERROR("idValuesMap_ is empty");
404 return nullptr;
405 }
406 uint32_t uid = id;
407 std::map<uint32_t, IdValues *>::const_iterator iter = idValuesMap_.find(uid);
408 if (iter == idValuesMap_.end()) {
409 return nullptr;
410 }
411
412 return iter->second;
413 }
414
GetIdValuesByName(const std::string name,const ResType resType) const415 const HapResource::IdValues *HapResource::GetIdValuesByName(
416 const std::string name, const ResType resType) const
417 {
418 const std::map<std::string, IdValues *> *map = idValuesNameMap_[resType];
419 std::map<std::string, IdValues *>::const_iterator iter = map->find(name);
420 if (iter == map->end()) {
421 return nullptr;
422 }
423
424 return iter->second;
425 }
426
GetIdByName(const char * name,const ResType resType) const427 int HapResource::GetIdByName(const char *name, const ResType resType) const
428 {
429 if (name == nullptr) {
430 return -1;
431 }
432 const std::map<std::string, IdValues *> *map = idValuesNameMap_[resType];
433 std::map<std::string, IdValues *>::const_iterator iter = map->find(name);
434 if (iter == map->end()) {
435 return OBJ_NOT_FOUND;
436 }
437 const IdValues *ids = iter->second;
438
439 if (ids->GetLimitPathsConst().size() == 0) {
440 HILOG_ERROR("limitPaths empty");
441 return UNKNOWN_ERROR;
442 }
443
444 if (ids->GetLimitPathsConst()[0]->GetIdItem()->resType_ != resType) {
445 HILOG_ERROR("ResType mismatch");
446 return UNKNOWN_ERROR;
447 }
448 return ids->GetLimitPathsConst()[0]->GetIdItem()->id_;
449 }
450
GetQualifiers() const451 const std::vector<std::string> HapResource::GetQualifiers() const
452 {
453 std::vector<std::string> result;
454 for (size_t i = 0; i < resDesc_->keys_.size(); i++) {
455 result.push_back(resDesc_->keys_[i]->ToString());
456 }
457 return result;
458 }
459 } // namespace Resource
460 } // namespace Global
461 } // namespace OHOS
462