2 * Copyright (c) 2021-present Samsung Electronics Co., Ltd
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
23 #include "lwnode-loader.h"
25 #include "node_native_module.h"
28 using namespace LWNode;
31 namespace native_module {
37 class ArchiveFileScope {
39 ArchiveFileScope() = default;
40 ArchiveFileScope(const char* path) { open(path); }
47 void open(const char* path) {
48 if (file_ == nullptr) {
49 file_ = unzOpen(path);
53 bool isFileOpened() { return (file_ != nullptr) ? true : false; }
54 unzFile file() { return file_; }
57 unzFile file_{nullptr};
60 struct UnzFileCachedInfo {
61 unz_file_pos position{0, 0};
62 uLong uncompressedSize{0};
65 static ArchiveFileScope s_archiveFileScope;
66 static std::map<std::string, UnzFileCachedInfo> s_unzFileInfoDictionary;
68 std::string getSelfProcPath() {
69 char path[PATH_MAX + 1];
70 ssize_t length = readlink("/proc/self/exe", path, PATH_MAX);
72 ERROR_AND_ABORT("readlink fails");
75 return std::string(path);
78 bool readCurrentFileFromArchive(const unzFile file,
79 uLong uncompressedSize,
82 if (unzOpenCurrentFile(file) < 0) {
86 *fileSize = uncompressedSize;
87 *buffer = (char*)allocateStringBuffer(uncompressedSize + 1);
91 if (unzReadCurrentFile(file, *buffer, *fileSize) < 0) {
92 freeStringBuffer(buffer);
96 (*buffer)[*fileSize] = '\0';
99 unzCloseCurrentFile(file);
103 bool readFileFromArchive(const std::string& archiveFilename,
104 const std::string& filename,
107 DCHECK_NOT_NULL(buffer);
108 DCHECK_NOT_NULL(fileSize);
110 if (s_archiveFileScope.isFileOpened() == false) {
111 s_archiveFileScope.open(archiveFilename.c_str());
114 const unzFile file = s_archiveFileScope.file();
115 CHECK_NOT_NULL(file);
117 // 1.1 check if the cache on this filename exists
118 const auto& it = s_unzFileInfoDictionary.find(filename);
119 if (it != s_unzFileInfoDictionary.end()) {
120 UnzFileCachedInfo cache = it->second;
122 // 1.2 move the file position using the cached info and read the data
123 unzGoToFilePos(file, &cache.position);
124 return readCurrentFileFromArchive(
125 file, cache.uncompressedSize, buffer, fileSize);
128 // 2. read the data by searching the file position from the first one.
129 if (unzGoToFirstFile(file) < 0) {
133 bool isFileFound = false;
135 unz_file_info fileInfo;
136 char currentFileName[PATH_MAX];
138 if (unzGetCurrentFileInfo(file,
141 sizeof(currentFileName),
149 if (filename.compare(currentFileName) == 0) {
152 // 2.1 read the data from the current file poistion
153 if (readCurrentFileFromArchive(
154 file, fileInfo.uncompressed_size, buffer, fileSize) == false) {
158 // 2.2 create the cache for this file and register it to the dictionary
159 UnzFileCachedInfo cache;
160 auto result = unzGetFilePos(file, &cache.position);
161 CHECK(result == UNZ_OK);
162 cache.uncompressedSize = fileInfo.uncompressed_size;
164 s_unzFileInfoDictionary[filename] = cache;
168 } while (unzGoToNextFile(file) != UNZ_END_OF_LIST_OF_FILE);
173 FileData readFileFromArchive(std::string filename,
174 const Encoding encodingHint) {
175 CHECK(encodingHint != Encoding::kUnknown);
177 size_t bufferSize = 0;
178 char* buffer = nullptr;
180 static std::string s_externalBuiltinsPath;
182 if (s_externalBuiltinsPath.empty()) {
183 std::string executablePath = getSelfProcPath();
184 executablePath = executablePath.substr(0, executablePath.rfind('/') + 1);
185 s_externalBuiltinsPath = executablePath + LWNODE_EXTERNAL_BUILTINS_FILENAME;
188 if (readFileFromArchive(
189 s_externalBuiltinsPath, filename, &buffer, &bufferSize) == false) {
193 std::unique_ptr<void, std::function<void(void*)>> bufferHolder(
194 buffer, freeStringBuffer);
196 return Loader::createFileDataForReloadableString(
197 filename, std::move(bufferHolder), bufferSize, encodingHint);
200 bool NativeModuleLoader::IsOneByte(const char* id) {
201 const auto& it = source_.find(id);
202 if (it == source_.end()) {
205 return it->second.is_one_byte();
208 static std::string getFileNameOnArchive(const char* id) {
209 std::string filename;
210 if (strncmp(id, "internal/deps", strlen("internal/deps")) == 0) {
211 id += strlen("internal/");
220 class SourceReaderOnArchive : public SourceReaderInterface {
222 static SourceReaderOnArchive* getInstance() {
223 static SourceReaderOnArchive s_singleton;
227 FileData read(std::string filename, const Encoding encodingHint) {
228 CHECK(encodingHint != Encoding::kUnknown);
230 size_t bufferSize = 0;
231 char* buffer = nullptr;
233 static std::string s_externalBuiltinsPath;
235 if (s_externalBuiltinsPath.empty()) {
236 std::string executablePath = getSelfProcPath();
237 executablePath = executablePath.substr(0, executablePath.rfind('/') + 1);
238 s_externalBuiltinsPath =
239 executablePath + LWNODE_EXTERNAL_BUILTINS_FILENAME;
242 if (readFileFromArchive(
243 s_externalBuiltinsPath, filename, &buffer, &bufferSize) == false) {
247 std::unique_ptr<void, std::function<void(void*)>> bufferHolder(
248 buffer, freeStringBuffer);
250 return Loader::createFileDataForReloadableString(
251 filename, std::move(bufferHolder), bufferSize, encodingHint);
255 SourceReaderOnArchive() = default;
258 MaybeLocal<String> NativeModuleLoader::LoadExternalBuiltinSource(
259 Isolate* isolate, const char* id) {
260 std::string filename = getFileNameOnArchive(id);
262 auto sourceReader = SourceReaderOnArchive::getInstance();
264 FileData fileData = sourceReader->read(
265 filename, (IsOneByte(id) ? Encoding::kAscii : Encoding::kUtf16));
267 if (fileData.buffer == nullptr) {
268 ERROR_AND_ABORT("Failed to open builtins");
269 return MaybeLocal<String>();
272 return Loader::NewReloadableString(
273 isolate, Loader::ReloadableSourceData::create(fileData, sourceReader));
276 } // namespace native_module