1 /*
2  * Copyright (c) 2024 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  *
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12 
13  * * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
15  * either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations
18  * under the License.
19  */
20 
21 #include "ohos_file.h"
22 
23 #include <cstdint>
24 
25 #ifdef __has_include
26 #if __has_include(<filesystem>)
27 #include <filesystem>
28 #define HAS_FILESYSTEM
29 #endif
30 #endif
31 
32 #ifndef HAS_FILESYSTEM
33 #include <cerrno>
34 #include <dirent.h>
35 
36 #ifndef _DIRENT_HAVE_D_TYPE
37 #include <sys/stat.h>
38 #include <sys/types.h>
39 
40 #endif
41 #include <climits>
42 #define CORE_MAX_PATH PATH_MAX
43 #endif
44 
45 #include <base/containers/string.h>
46 #include <base/containers/string_view.h>
47 #include <core/io/intf_file.h>
48 #include <core/log.h>
49 #include <core/namespace.h>
50 
51 #include "io/std_directory.h"
52 
53 CORE_BEGIN_NAMESPACE()
54 using BASE_NS::CloneData;
55 using BASE_NS::string;
56 using BASE_NS::string_view;
57 
58 const std::regex MEDIA_RES_ID_REGEX(R"(^\w+/([0-9]+)\.\w+$)", std::regex::icase);
59 const std::regex MEDIA_HAP_RES_PATH_REGEX(R"(^(.*)$)");
60 const std::regex MEDIA_HAP_RES_ID_REGEX(R"(^.*/([0-9]+)\.\w+$)", std::regex::icase);
61 const std::regex MEDIA_RES_NAME_REGEX(R"(^.*/(\w+)\.\w+$)", std::regex::icase);
62 
63 constexpr uint32_t OHOS_RESOURCE_MATCH_SIZE = 2;
64 
UpdateResManager(const PlatformHapInfo & hapInfo)65 void OhosResMgr::UpdateResManager(const PlatformHapInfo& hapInfo)
66 {
67     auto key = hapInfo.bundleName + "+" + hapInfo.moduleName;
68     auto resourceMgrIter = resourceManagers_.find(key);
69     if (resourceMgrIter != resourceManagers_.end()) {
70         resourceManager_ = resourceMgrIter->second;
71         return;
72     }
73     std::shared_ptr<OHOS::Global::Resource::ResourceManager>
74         newResMgr(OHOS::Global::Resource::CreateResourceManager());
75     auto resRet = newResMgr->AddResource(hapInfo.hapPath.c_str());
76     resourceManagers_[key] = newResMgr;
77     resourceManager_ = newResMgr;
78 }
79 
GetResMgr() const80 std::shared_ptr<OHOS::Global::Resource::ResourceManager> OhosResMgr::GetResMgr() const
81 {
82     return resourceManager_;
83 }
84 
OhosFileDirectory(BASE_NS::refcnt_ptr<OhosResMgr> resMgr)85 OhosFileDirectory::OhosFileDirectory(BASE_NS::refcnt_ptr<OhosResMgr> resMgr) : dirResMgr_(resMgr) {}
86 
~OhosFileDirectory()87 OhosFileDirectory::~OhosFileDirectory()
88 {
89     Close();
90 }
91 
Close()92 void OhosFileDirectory::Close()
93 {
94     if (dir_) {
95         dir_.reset();
96     }
97 }
98 
IsDir(BASE_NS::string_view path,std::vector<std::string> & fileList) const99 bool OhosFileDirectory::IsDir(BASE_NS::string_view path, std::vector<std::string>& fileList) const
100 {
101     auto state = dirResMgr_->GetResMgr()->GetRawFileList(path.data(), fileList);
102     if (state != OHOS::Global::Resource::SUCCESS || fileList.empty()) {
103         CORE_LOG_E("GetRawfilepath error, filename:%s, error:%u", path.data(), state);
104         return false;
105     }
106     return true;
107 }
108 
IsFile(BASE_NS::string_view path) const109 bool OhosFileDirectory::IsFile(BASE_NS::string_view path) const
110 {
111     std::unique_ptr<uint8_t[]> data;
112     size_t dataLen = 0;
113     auto state = dirResMgr_->GetResMgr()->GetRawFileFromHap(path.data(), dataLen, data);
114     if (state != OHOS::Global::Resource::SUCCESS) {
115         return false;
116     }
117     return true;
118 }
119 
Open(const BASE_NS::string_view pathIn)120 bool OhosFileDirectory::Open(const BASE_NS::string_view pathIn)
121 {
122     auto path = pathIn;
123     if (path.back() == '/') {
124         path.remove_suffix(1);
125     }
126     if (path.front() == '/') {
127         path.remove_prefix(1);
128     }
129     std::vector<std::string> fileList;
130     if (IsDir(path, fileList)) {
131         dir_ = BASE_NS::make_unique<OhosDirImpl>(path, fileList);
132         return true;
133     }
134     return false;
135 }
136 
GetEntries() const137 BASE_NS::vector<IDirectory::Entry> OhosFileDirectory::GetEntries() const
138 {
139     CORE_ASSERT_MSG(dir_, "Dir not open");
140     BASE_NS::vector<IDirectory::Entry> result;
141     if (dir_) {
142         for (int i = 0; i < static_cast<int>(dir_->fileList_.size()); i++) {
143             auto path = dir_->path_ + "/" + BASE_NS::string(dir_->fileList_[i].c_str());
144             auto entry = GetEntry(path);
145             entry.timestamp = static_cast<uint32_t>(i);
146             entry.name = dir_->fileList_[i].c_str();
147             result.emplace_back(entry);
148         }
149     }
150     return result;
151 }
152 
GetEntry(BASE_NS::string_view uriIn) const153 IDirectory::Entry OhosFileDirectory::GetEntry(BASE_NS::string_view uriIn) const
154 {
155     if (!uriIn.empty()) {
156         IDirectory::Entry::Type type;
157         std::vector<std::string> fileList;
158         if (IsFile(uriIn)) {
159             type = IDirectory::Entry::FILE;
160         } else if (IsDir(uriIn, fileList)) {
161             type = IDirectory::Entry::DIRECTORY;
162         } else {
163             type = IDirectory::Entry::UNKNOWN;
164         }
165         // timestamp set 0
166         uint64_t timestamp = 0;
167         BASE_NS::string entryName { uriIn };
168         return IDirectory::Entry { type, entryName, timestamp };
169     }
170     return {};
171 }
172 
OhosFile(BASE_NS::refcnt_ptr<OhosResMgr> resMgr)173 OhosFile::OhosFile(BASE_NS::refcnt_ptr<OhosResMgr> resMgr) : fileResMgr_(resMgr)
174 {
175     buffer_ = std::make_shared<OhosFileStorage>(nullptr);
176 }
177 
UpdateStorage(std::shared_ptr<OhosFileStorage> buffer)178 void OhosFile::UpdateStorage(std::shared_ptr<OhosFileStorage> buffer)
179 {
180     buffer_ = BASE_NS::move(buffer);
181 }
182 
GetMode() const183 IFile::Mode OhosFile::GetMode() const
184 {
185     return IFile::Mode::READ_ONLY;
186 }
187 
Close()188 void OhosFile::Close() {}
189 
Read(void * buffer,uint64_t count)190 uint64_t OhosFile::Read(void* buffer, uint64_t count)
191 {
192     uint64_t toRead = count;
193     uint64_t sum = index_ + toRead;
194     if (sum < index_) {
195         return 0;
196     }
197     if (sum > buffer_->Size()) {
198         toRead = buffer_->Size() - index_;
199     }
200     if (toRead <= 0) {
201         return toRead;
202     }
203     if (toRead > SIZE_MAX) {
204         CORE_ASSERT_MSG(false, "Unable to read chunks bigger than (SIZE_MAX) bytes.");
205         return 0;
206     }
207     if (CloneData(buffer, static_cast<size_t>(count), &(buffer_->GetStorage()[index_]),
208                 static_cast<size_t>(toRead))) {
209         index_ += toRead;
210     }
211     return toRead;
212 }
213 
Write(const void * buffer,uint64_t count)214 uint64_t OhosFile::Write(const void* buffer, uint64_t count)
215 {
216     return 0;
217 }
218 
GetLength() const219 uint64_t OhosFile::GetLength() const
220 {
221     return buffer_->Size();
222 }
223 
Seek(uint64_t aOffset)224 bool OhosFile::Seek(uint64_t aOffset)
225 {
226     if (aOffset < buffer_->Size()) {
227         index_ = aOffset;
228         return true;
229     }
230     return false;
231 }
232 
GetPosition() const233 uint64_t OhosFile::GetPosition() const
234 {
235     return index_;
236 }
237 
Open(BASE_NS::string_view rawFile)238 std::shared_ptr<OhosFileStorage> OhosFile::Open(BASE_NS::string_view rawFile)
239 {
240     std::unique_ptr<uint8_t[]> data;
241     size_t dataLen = 0;
242     if (OpenRawFile(rawFile, dataLen, data)) {
243         buffer_->SetBuffer(std::move(data), static_cast<uint64_t>(dataLen));
244         return buffer_;
245     }
246     return nullptr;
247 }
248 
249 // Parsing URI
GetResourceId(const std::string & uri,uint32_t & resId) const250 bool OhosFile::GetResourceId(const std::string& uri, uint32_t& resId) const
251 {
252     std::smatch matches;
253     if (std::regex_match(uri, matches, MEDIA_RES_ID_REGEX) && matches.size() == OHOS_RESOURCE_MATCH_SIZE) {
254         resId = static_cast<uint32_t>(std::stoul(matches[1].str()));
255         return true;
256     }
257     std::smatch hapMatches;
258     if (std::regex_match(uri, hapMatches, MEDIA_HAP_RES_ID_REGEX) && hapMatches.size() == OHOS_RESOURCE_MATCH_SIZE) {
259         resId = static_cast<uint32_t>(std::stoul(hapMatches[1].str()));
260         return true;
261     }
262     return false;
263 }
264 
GetResourceId(const std::string & uri,std::string & path) const265 bool OhosFile::GetResourceId(const std::string& uri, std::string& path) const
266 {
267     std::smatch matches;
268     if (std::regex_match(uri, matches, MEDIA_HAP_RES_PATH_REGEX) && matches.size() == OHOS_RESOURCE_MATCH_SIZE) {
269         path = matches[1].str();
270         return true;
271     }
272     return false;
273 }
274 
GetResourceName(const std::string & uri,std::string & resName) const275 bool OhosFile::GetResourceName(const std::string& uri, std::string& resName) const
276 {
277     std::smatch matches;
278     if (std::regex_match(uri, matches, MEDIA_RES_NAME_REGEX) && matches.size() == OHOS_RESOURCE_MATCH_SIZE) {
279         resName = matches[1].str();
280         return true;
281     }
282     return false;
283 }
284 
OpenRawFile(BASE_NS::string_view uriIn,size_t & dataLen,std::unique_ptr<uint8_t[]> & dest)285 bool OhosFile::OpenRawFile(BASE_NS::string_view uriIn, size_t& dataLen, std::unique_ptr<uint8_t[]>& dest)
286 {
287     std::string uri(uriIn.data());
288     std::string rawFile;
289     if (GetResourceId(uri, rawFile)) {
290         auto state = fileResMgr_->GetResMgr()->GetRawFileFromHap(rawFile.c_str(), dataLen, dest);
291         if (state != OHOS::Global::Resource::SUCCESS || !dest) {
292             CORE_LOG_E("GetRawFileFromHap error, raw filename:%s, error:%u", rawFile.c_str(), state);
293             return false;
294         }
295         return true;
296     }
297     uint32_t resId = 0;
298     if (GetResourceId(uri, resId)) {
299         auto state = fileResMgr_->GetResMgr()->GetMediaDataById(resId, dataLen, dest);
300         if (state != OHOS::Global::Resource::SUCCESS || !dest) {
301             CORE_LOG_E("GetMediaDataById error, resId:%u, error:%u", resId, state);
302             return false;
303         }
304         return true;
305     }
306     std::string resName;
307     if (GetResourceName(uri, resName)) {
308         auto state = fileResMgr_->GetResMgr()->GetMediaDataByName(resName.c_str(), dataLen, dest);
309         if (state != OHOS::Global::Resource::SUCCESS || !dest) {
310             CORE_LOG_E("GetMediaDataByName error, resName:%s, error:%u", resName.c_str(), state);
311             return false;
312         }
313         return true;
314     }
315     CORE_LOG_E("load image data failed, as uri is invalid:%s", uri.c_str());
316     return false;
317 }
318 CORE_END_NAMESPACE()
319