1 /*
2 * Copyright (c) 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 "raw_file_manager.h"
17
18 #include <climits>
19 #include <cstdio>
20 #include <cstdlib>
21 #include <dirent.h>
22 #include <fcntl.h>
23 #include <securec.h>
24 #include <unistd.h>
25
26 #include "raw_dir.h"
27 #include "raw_file.h"
28 #include "resource_manager.h"
29 #include "resource_manager_addon.h"
30 #include "resource_manager_impl.h"
31 #include "hilog/log_c.h"
32 #include "hilog/log_cpp.h"
33
34 #ifdef __WINNT__
35 #include <shlwapi.h>
36 #include <windows.h>
37 #endif
38
39 using namespace OHOS::Global::Resource;
40 using namespace OHOS::HiviewDFX;
41
42 namespace {
43 constexpr HiLogLabel LABEL = {LOG_CORE, 0xD001E00, "RawFile"};
44 }
45
46 struct NativeResourceManager {
47 std::shared_ptr<ResourceManager> resManager = nullptr;
48 };
49
50 struct FileNameCache {
51 std::vector<std::string> names;
52 };
53
54 struct RawDir {
55 std::shared_ptr<ResourceManager> resManager = nullptr;
56 struct FileNameCache fileNameCache;
57 };
58
59 struct RawFile {
60 const std::string filePath;
61 long offset;
62 long length;
63 FILE* pf;
64 uint8_t* buffer;
65
RawFileRawFile66 explicit RawFile(const std::string &path) : filePath(path), offset(0L), length(0L),
67 pf(nullptr), buffer(nullptr) {}
68
~RawFileRawFile69 ~RawFile()
70 {
71 if (buffer != nullptr) {
72 free(buffer);
73 buffer = nullptr;
74 }
75 if (pf != nullptr) {
76 fclose(pf);
77 pf = nullptr;
78 }
79 }
80
openRawFile81 bool open()
82 {
83 pf = std::fopen(filePath.c_str(), "rb");
84 return pf != nullptr;
85 }
86 };
87
OH_ResourceManager_InitNativeResourceManager(napi_env env,napi_value jsResMgr)88 NativeResourceManager *OH_ResourceManager_InitNativeResourceManager(napi_env env, napi_value jsResMgr)
89 {
90 napi_valuetype valueType;
91 napi_typeof(env, jsResMgr, &valueType);
92 if (valueType != napi_object) {
93 HiLog::Error(LABEL, "jsResMgr is not an object");
94 return nullptr;
95 }
96 std::shared_ptr<ResourceManagerAddon> *addonPtr = nullptr;
97 napi_status status = napi_unwrap(env, jsResMgr, reinterpret_cast<void **>(&addonPtr));
98 if (status != napi_ok) {
99 HiLog::Error(LABEL, "Failed to get native resourcemanager");
100 return nullptr;
101 }
102 std::unique_ptr<NativeResourceManager> result = std::make_unique<NativeResourceManager>();
103 result->resManager = (*addonPtr)->GetResMgr();
104 return result.release();
105 }
106
OH_ResourceManager_ReleaseNativeResourceManager(NativeResourceManager * resMgr)107 void OH_ResourceManager_ReleaseNativeResourceManager(NativeResourceManager *resMgr)
108 {
109 if (resMgr != nullptr) {
110 delete resMgr;
111 }
112 }
113
OH_ResourceManager_OpenRawDir(const NativeResourceManager * mgr,const char * dirName)114 RawDir *OH_ResourceManager_OpenRawDir(const NativeResourceManager *mgr, const char *dirName)
115 {
116 if (mgr == nullptr || dirName == nullptr) {
117 return nullptr;
118 }
119 ResourceManagerImpl* impl = static_cast<ResourceManagerImpl *>(mgr->resManager.get());
120 std::string tempName = dirName;
121 const std::string rawFileDirName = "rawfile/";
122 if (tempName.length() < rawFileDirName.length()
123 || (tempName.compare(0, rawFileDirName.length(), rawFileDirName) != 0)) {
124 tempName = rawFileDirName + tempName;
125 }
126 std::unique_ptr<RawDir> result = std::make_unique<RawDir>();
127 std::vector<std::string> resourcesPaths = impl->GetResourcePaths();
128 for (auto iter = resourcesPaths.begin(); iter != resourcesPaths.end(); iter++) {
129 std::string currentPath = *iter + tempName;
130 DIR* dir = opendir(currentPath.c_str());
131 if (dir == nullptr) {
132 continue;
133 }
134 struct dirent *dirp = readdir(dir);
135 while (dirp != nullptr) {
136 if (std::strcmp(dirp->d_name, ".") == 0 ||
137 std::strcmp(dirp->d_name, "..") == 0) {
138 dirp = readdir(dir);
139 continue;
140 }
141 if (dirp->d_type == DT_REG) {
142 result->fileNameCache.names.push_back(tempName + "/" + dirp->d_name);
143 }
144
145 dirp = readdir(dir);
146 }
147 closedir(dir);
148 }
149 return result.release();
150 }
151
IsLoadHap(const NativeResourceManager * mgr)152 static bool IsLoadHap(const NativeResourceManager *mgr)
153 {
154 RState state = mgr->resManager->IsLoadHap();
155 if (state != RState::SUCCESS) {
156 return false;
157 }
158 return true;
159 }
160
LoadRawFileFromHap(const NativeResourceManager * mgr,const char * fileName)161 RawFile *LoadRawFileFromHap(const NativeResourceManager *mgr, const char *fileName)
162 {
163 auto rawFile = std::make_unique<ResourceManager::RawFile>();
164 RState state = mgr->resManager->GetRawFileFromHap(fileName, rawFile);
165 if (state != SUCCESS) {
166 HiLog::Error(LABEL, "failed to get %{public}s rawfile", fileName);
167 return nullptr;
168 }
169 auto result = std::make_unique<RawFile>(fileName);
170 result->buffer = reinterpret_cast<uint8_t*>(malloc(rawFile->length));
171 if (result->buffer == nullptr) {
172 HiLog::Error(LABEL, "failed to malloc");
173 return nullptr;
174 }
175 int ret = memcpy_s(result->buffer, rawFile->length, rawFile->buffer.get(), rawFile->length);
176 if (ret != 0) {
177 HiLog::Error(LABEL, "failed to memcpy_s");
178 return nullptr;
179 }
180
181 result->length = rawFile->length;
182 return result.release();
183 }
184
OH_ResourceManager_OpenRawFile(const NativeResourceManager * mgr,const char * fileName)185 RawFile *OH_ResourceManager_OpenRawFile(const NativeResourceManager *mgr, const char *fileName)
186 {
187 if (mgr == nullptr || fileName == nullptr) {
188 return nullptr;
189 }
190 if (IsLoadHap(mgr)) {
191 return LoadRawFileFromHap(mgr, fileName);
192 }
193
194 std::string filePath;
195 RState state = mgr->resManager->GetRawFilePathByName(fileName, filePath);
196 if (state != SUCCESS) {
197 return nullptr;
198 }
199 std::unique_ptr<RawFile> result = std::make_unique<RawFile>(filePath);
200 if (!result->open()) {
201 return nullptr;
202 }
203
204 std::fseek(result->pf, 0, SEEK_END);
205 result->length = ftell(result->pf);
206 std::fseek(result->pf, 0, SEEK_SET);
207 return result.release();
208 }
209
OH_ResourceManager_GetRawFileCount(RawDir * rawDir)210 int OH_ResourceManager_GetRawFileCount(RawDir *rawDir)
211 {
212 if (rawDir == nullptr) {
213 return 0;
214 }
215 return rawDir->fileNameCache.names.size();
216 }
217
OH_ResourceManager_GetRawFileName(RawDir * rawDir,int index)218 const char *OH_ResourceManager_GetRawFileName(RawDir *rawDir, int index)
219 {
220 if (rawDir == nullptr || index < 0) {
221 return nullptr;
222 }
223 uint32_t rawFileCount = rawDir->fileNameCache.names.size();
224 if (rawFileCount == 0 || index >= static_cast<int>(rawFileCount)) {
225 return nullptr;
226 }
227 return rawDir->fileNameCache.names[index].c_str();
228 }
229
OH_ResourceManager_CloseRawDir(RawDir * rawDir)230 void OH_ResourceManager_CloseRawDir(RawDir *rawDir)
231 {
232 if (rawDir != nullptr) {
233 delete rawDir;
234 }
235 }
236
OH_ResourceManager_ReadRawFile(const RawFile * rawFile,void * buf,size_t length)237 int OH_ResourceManager_ReadRawFile(const RawFile *rawFile, void *buf, size_t length)
238 {
239 if (rawFile == nullptr || buf == nullptr || length == 0) {
240 return 0;
241 }
242 if (rawFile->buffer != nullptr) {
243 int ret = memcpy_s(buf, length, rawFile->buffer, rawFile->length);
244 if (ret != 0) {
245 HiLog::Error(LABEL, "failed to copy to buf");
246 return 0;
247 }
248 return rawFile->length;
249 } else {
250 return std::fread(buf, 1, length, rawFile->pf);
251 }
252 }
253
OH_ResourceManager_SeekRawFile(const RawFile * rawFile,long offset,int whence)254 int OH_ResourceManager_SeekRawFile(const RawFile *rawFile, long offset, int whence)
255 {
256 if (rawFile == nullptr) {
257 return 0;
258 }
259
260 int origin = 0;
261 int start = 0;
262 switch (whence) {
263 case SEEK_SET:
264 origin = SEEK_SET;
265 start = rawFile->offset + offset;
266 break;
267 case SEEK_CUR:
268 origin = SEEK_CUR;
269 start = offset;
270 break;
271 case SEEK_END:
272 start = rawFile->offset + rawFile->length + offset;
273 origin = SEEK_SET;
274 break;
275 default:
276 return -1;
277 }
278
279 return std::fseek(rawFile->pf, start, origin);
280 }
281
OH_ResourceManager_GetRawFileSize(RawFile * rawFile)282 long OH_ResourceManager_GetRawFileSize(RawFile *rawFile)
283 {
284 if (rawFile == nullptr) {
285 return 0;
286 }
287
288 return rawFile->length;
289 }
290
OH_ResourceManager_CloseRawFile(RawFile * rawFile)291 void OH_ResourceManager_CloseRawFile(RawFile *rawFile)
292 {
293 if (rawFile != nullptr) {
294 delete rawFile;
295 }
296 }
297
OH_ResourceManager_GetRawFileOffset(const RawFile * rawFile)298 long OH_ResourceManager_GetRawFileOffset(const RawFile *rawFile)
299 {
300 if (rawFile == nullptr) {
301 return 0;
302 }
303 return ftell(rawFile->pf) - rawFile->offset;
304 }
305
OH_ResourceManager_GetRawFileDescriptor(const RawFile * rawFile,RawFileDescriptor & descriptor)306 bool OH_ResourceManager_GetRawFileDescriptor(const RawFile *rawFile, RawFileDescriptor &descriptor)
307 {
308 if (rawFile == nullptr) {
309 return false;
310 }
311 char paths[PATH_MAX] = {0};
312 #ifdef __WINNT__
313 if (!PathCanonicalizeA(paths, rawFile->filePath.c_str())) {
314 HiLog::Error(LABEL, "failed to PathCanonicalizeA the rawFile path");
315 }
316 #else
317 if (realpath(rawFile->filePath.c_str(), paths) == nullptr) {
318 HiLog::Error(LABEL, "failed to realpath the rawFile path");
319 }
320 #endif
321 int fd = open(paths, O_RDONLY);
322 if (fd > 0) {
323 descriptor.fd = fd;
324 descriptor.length = rawFile->length;
325 descriptor.start = rawFile->offset;
326 } else {
327 return false;
328 }
329 return true;
330 }
331
OH_ResourceManager_ReleaseRawFileDescriptor(const RawFileDescriptor & descriptor)332 bool OH_ResourceManager_ReleaseRawFileDescriptor(const RawFileDescriptor &descriptor)
333 {
334 if (descriptor.fd > 0) {
335 return close(descriptor.fd) == 0;
336 }
337 return true;
338 }
339