1b1994897Sopenharmony_ci/**
2b1994897Sopenharmony_ci * Copyright (c) 2021-2024 Huawei Device Co., Ltd.
3b1994897Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
4b1994897Sopenharmony_ci * you may not use this file except in compliance with the License.
5b1994897Sopenharmony_ci * You may obtain a copy of the License at
6b1994897Sopenharmony_ci *
7b1994897Sopenharmony_ci * http://www.apache.org/licenses/LICENSE-2.0
8b1994897Sopenharmony_ci *
9b1994897Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software
10b1994897Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
11b1994897Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12b1994897Sopenharmony_ci * See the License for the specific language governing permissions and
13b1994897Sopenharmony_ci * limitations under the License.
14b1994897Sopenharmony_ci */
15b1994897Sopenharmony_ci
16b1994897Sopenharmony_ci#include <algorithm>
17b1994897Sopenharmony_ci#include <cerrno>
18b1994897Sopenharmony_ci#include <cstdio>
19b1994897Sopenharmony_ci#include <cstring>
20b1994897Sopenharmony_ci#include <map>
21b1994897Sopenharmony_ci#include <memory>
22b1994897Sopenharmony_ci#include <string>
23b1994897Sopenharmony_ci#include <variant>
24b1994897Sopenharmony_ci
25b1994897Sopenharmony_ci#include "data_protect.h"
26b1994897Sopenharmony_ci#include "file_format_version.h"
27b1994897Sopenharmony_ci#include "file-inl.h"
28b1994897Sopenharmony_ci#include "file_items.h"
29b1994897Sopenharmony_ci#include "mem/mem.h"
30b1994897Sopenharmony_ci#include "os/file.h"
31b1994897Sopenharmony_ci#include "os/filesystem.h"
32b1994897Sopenharmony_ci#include "os/mem.h"
33b1994897Sopenharmony_ci#include "panda_cache.h"
34b1994897Sopenharmony_ci#include "securec.h"
35b1994897Sopenharmony_ci#include "trace/trace.h"
36b1994897Sopenharmony_ci#include "utils/hash.h"
37b1994897Sopenharmony_ci#include "utils/logger.h"
38b1994897Sopenharmony_ci#include "utils/utf.h"
39b1994897Sopenharmony_ci#include "utils/span.h"
40b1994897Sopenharmony_ci#include "zip_archive.h"
41b1994897Sopenharmony_ci#include "zlib.h"
42b1994897Sopenharmony_ci
43b1994897Sopenharmony_cinamespace panda::panda_file {
44b1994897Sopenharmony_ci// NOLINTNEXTLINE(readability-identifier-naming, modernize-avoid-c-arrays)
45b1994897Sopenharmony_ciconst char *ARCHIVE_FILENAME = "classes.abc";
46b1994897Sopenharmony_ci// NOLINTNEXTLINE(readability-identifier-naming, modernize-avoid-c-arrays)
47b1994897Sopenharmony_ciconst char *ARCHIVE_SPLIT = "!/";
48b1994897Sopenharmony_ci
49b1994897Sopenharmony_ciconst std::array<uint8_t, File::MAGIC_SIZE> File::MAGIC {'P', 'A', 'N', 'D', 'A', '\0', '\0', '\0'};
50b1994897Sopenharmony_ci
51b1994897Sopenharmony_ci// Name anonymous maps for perfing tools finding symbol file correctly.
52b1994897Sopenharmony_ci// NOLINTNEXTLINE(readability-identifier-naming, modernize-avoid-c-arrays)
53b1994897Sopenharmony_ciconst char *ANONMAPNAME_PERFIX = "panda-";
54b1994897Sopenharmony_ci
55b1994897Sopenharmony_cios::file::Mode GetMode(panda_file::File::OpenMode open_mode)
56b1994897Sopenharmony_ci{
57b1994897Sopenharmony_ci    switch (open_mode) {
58b1994897Sopenharmony_ci        case File::READ_ONLY: {
59b1994897Sopenharmony_ci            return os::file::Mode::READONLY;
60b1994897Sopenharmony_ci        }
61b1994897Sopenharmony_ci        case File::READ_WRITE: {
62b1994897Sopenharmony_ci#ifdef PANDA_TARGET_WINDOWS
63b1994897Sopenharmony_ci            return os::file::Mode::READWRITE;
64b1994897Sopenharmony_ci#else
65b1994897Sopenharmony_ci            return os::file::Mode::READONLY;
66b1994897Sopenharmony_ci#endif
67b1994897Sopenharmony_ci        }
68b1994897Sopenharmony_ci        case File::WRITE_ONLY: {
69b1994897Sopenharmony_ci            return os::file::Mode::WRITEONLY;
70b1994897Sopenharmony_ci        }
71b1994897Sopenharmony_ci        default: {
72b1994897Sopenharmony_ci            break;
73b1994897Sopenharmony_ci        }
74b1994897Sopenharmony_ci    }
75b1994897Sopenharmony_ci
76b1994897Sopenharmony_ci    UNREACHABLE();
77b1994897Sopenharmony_ci}
78b1994897Sopenharmony_ci
79b1994897Sopenharmony_cistatic uint32_t GetProt(panda_file::File::OpenMode mode)
80b1994897Sopenharmony_ci{
81b1994897Sopenharmony_ci    uint32_t prot = os::mem::MMAP_PROT_READ;
82b1994897Sopenharmony_ci    if (mode == File::READ_WRITE) {
83b1994897Sopenharmony_ci        prot |= os::mem::MMAP_PROT_WRITE;
84b1994897Sopenharmony_ci    }
85b1994897Sopenharmony_ci    return prot;
86b1994897Sopenharmony_ci}
87b1994897Sopenharmony_ci
88b1994897Sopenharmony_ciclass AnonMemSet {
89b1994897Sopenharmony_cipublic:
90b1994897Sopenharmony_ci    using MemNameSet = std::map<std::string, std::string>;
91b1994897Sopenharmony_ci    using InsertResult = std::map<std::string, std::string>::iterator;
92b1994897Sopenharmony_ci
93b1994897Sopenharmony_ci    static AnonMemSet &GetInstance()
94b1994897Sopenharmony_ci    {
95b1994897Sopenharmony_ci        static AnonMemSet anon_mem_set;
96b1994897Sopenharmony_ci        return anon_mem_set;
97b1994897Sopenharmony_ci    }
98b1994897Sopenharmony_ci
99b1994897Sopenharmony_ci    InsertResult Insert(const std::string &file_name, const std::string &anon_mem_name)
100b1994897Sopenharmony_ci    {
101b1994897Sopenharmony_ci        return mem_name_set_.emplace(file_name, anon_mem_name).first;
102b1994897Sopenharmony_ci    }
103b1994897Sopenharmony_ci
104b1994897Sopenharmony_ci    void Remove(const std::string &file_name)
105b1994897Sopenharmony_ci    {
106b1994897Sopenharmony_ci        auto it = mem_name_set_.find(file_name);
107b1994897Sopenharmony_ci        if (it != mem_name_set_.end()) {
108b1994897Sopenharmony_ci            mem_name_set_.erase(it);
109b1994897Sopenharmony_ci        }
110b1994897Sopenharmony_ci    }
111b1994897Sopenharmony_ci
112b1994897Sopenharmony_ciprivate:
113b1994897Sopenharmony_ci    MemNameSet mem_name_set_;
114b1994897Sopenharmony_ci};
115b1994897Sopenharmony_ci
116b1994897Sopenharmony_cistd::unique_ptr<const File> OpenPandaFileOrZip(std::string_view location, panda_file::File::OpenMode open_mode)
117b1994897Sopenharmony_ci{
118b1994897Sopenharmony_ci    std::string_view archive_filename = ARCHIVE_FILENAME;
119b1994897Sopenharmony_ci    std::size_t archive_split_index = location.find(ARCHIVE_SPLIT);
120b1994897Sopenharmony_ci    if (archive_split_index != std::string::npos) {
121b1994897Sopenharmony_ci        archive_filename = location.substr(archive_split_index + 2);  // 2 - archive split size
122b1994897Sopenharmony_ci        location = location.substr(0, archive_split_index);
123b1994897Sopenharmony_ci    }
124b1994897Sopenharmony_ci
125b1994897Sopenharmony_ci    return OpenPandaFile(location, archive_filename, open_mode);
126b1994897Sopenharmony_ci}
127b1994897Sopenharmony_ci
128b1994897Sopenharmony_ci// NOLINTNEXTLINE(google-runtime-references)
129b1994897Sopenharmony_civoid OpenPandaFileFromZipErrorHandler(ZipArchiveHandle &handle)
130b1994897Sopenharmony_ci{
131b1994897Sopenharmony_ci    if (handle != nullptr) {
132b1994897Sopenharmony_ci        if (panda::CloseArchiveFile(handle) != ZIPARCHIVE_OK) {
133b1994897Sopenharmony_ci            LOG(ERROR, PANDAFILE) << "CloseArchiveFile failed!";
134b1994897Sopenharmony_ci        }
135b1994897Sopenharmony_ci    }
136b1994897Sopenharmony_ci}
137b1994897Sopenharmony_ci
138b1994897Sopenharmony_cistd::unique_ptr<const panda_file::File> OpenPandaFileFromZipFile(ZipArchiveHandle &handle, std::string_view location,
139b1994897Sopenharmony_ci                                                                 EntryFileStat &entry,
140b1994897Sopenharmony_ci                                                                 const std::string_view &archive_name)
141b1994897Sopenharmony_ci{
142b1994897Sopenharmony_ci    uint32_t uncompressed_length = entry.GetUncompressedSize();
143b1994897Sopenharmony_ci    ASSERT(uncompressed_length != 0U);
144b1994897Sopenharmony_ci
145b1994897Sopenharmony_ci    size_t size_to_mmap = AlignUp(uncompressed_length, panda::os::mem::GetPageSize());
146b1994897Sopenharmony_ci    void *mem = os::mem::MapRWAnonymousRaw(size_to_mmap, false);
147b1994897Sopenharmony_ci    if (mem == nullptr) {
148b1994897Sopenharmony_ci        LOG(ERROR, PANDAFILE) << "Can't mmap anonymous!";
149b1994897Sopenharmony_ci        return nullptr;
150b1994897Sopenharmony_ci    }
151b1994897Sopenharmony_ci    os::mem::BytePtr ptr(reinterpret_cast<std::byte *>(mem), size_to_mmap, os::mem::MmapDeleter);
152b1994897Sopenharmony_ci    std::stringstream ss;
153b1994897Sopenharmony_ci    ss << ANONMAPNAME_PERFIX << archive_name << " extracted in memory from " << location;
154b1994897Sopenharmony_ci    auto it = AnonMemSet::GetInstance().Insert(std::string(location), ss.str());
155b1994897Sopenharmony_ci    auto ret = os::mem::TagAnonymousMemory(reinterpret_cast<void *>(ptr.Get()), size_to_mmap, it->second.c_str());
156b1994897Sopenharmony_ci    if (ret.has_value()) {
157b1994897Sopenharmony_ci        LOG(ERROR, PANDAFILE) << "Can't tag mmap anonymous!";
158b1994897Sopenharmony_ci        return nullptr;
159b1994897Sopenharmony_ci    }
160b1994897Sopenharmony_ci
161b1994897Sopenharmony_ci    auto extract_error = ExtractToMemory(handle, reinterpret_cast<uint8_t *>(ptr.Get()), size_to_mmap);
162b1994897Sopenharmony_ci    if (extract_error != 0) {
163b1994897Sopenharmony_ci        LOG(ERROR, PANDAFILE) << "Can't extract!";
164b1994897Sopenharmony_ci        return nullptr;
165b1994897Sopenharmony_ci    }
166b1994897Sopenharmony_ci
167b1994897Sopenharmony_ci    os::mem::ConstBytePtr ConstPtr = ptr.ToConst();
168b1994897Sopenharmony_ci    return panda_file::File::OpenFromMemory(std::move(ConstPtr), location);
169b1994897Sopenharmony_ci}
170b1994897Sopenharmony_ci
171b1994897Sopenharmony_ci// NOLINTNEXTLINE(google-runtime-references)
172b1994897Sopenharmony_cistd::unique_ptr<const panda_file::File> HandleArchive(ZipArchiveHandle &handle, FILE *fp, std::string_view location,
173b1994897Sopenharmony_ci                                                      EntryFileStat &entry, const std::string_view &archive_filename,
174b1994897Sopenharmony_ci                                                      panda_file::File::OpenMode open_mode)
175b1994897Sopenharmony_ci{
176b1994897Sopenharmony_ci    std::unique_ptr<const panda_file::File> file;
177b1994897Sopenharmony_ci    // compressed or not 4 aligned, use anonymous memory
178b1994897Sopenharmony_ci    if (entry.IsCompressed() || (entry.GetOffset() & 0x3U) != 0) {
179b1994897Sopenharmony_ci        file = OpenPandaFileFromZipFile(handle, location, entry, archive_filename);
180b1994897Sopenharmony_ci    } else {
181b1994897Sopenharmony_ci        LOG(INFO, PANDAFILE) << "Pandafile is uncompressed and 4 bytes aligned";
182b1994897Sopenharmony_ci        file = panda_file::File::OpenUncompressedArchive(fileno(fp), location, entry.GetUncompressedSize(),
183b1994897Sopenharmony_ci                                                         entry.GetOffset(), open_mode);
184b1994897Sopenharmony_ci    }
185b1994897Sopenharmony_ci    return file;
186b1994897Sopenharmony_ci}
187b1994897Sopenharmony_ci
188b1994897Sopenharmony_cistd::unique_ptr<const panda_file::File> OpenPandaFileFromZip(FILE *fp, std::string_view location,
189b1994897Sopenharmony_ci                                                             std::string_view archive_filename,
190b1994897Sopenharmony_ci                                                             panda_file::File::OpenMode open_mode)
191b1994897Sopenharmony_ci{
192b1994897Sopenharmony_ci    // Open Zipfile and do the extraction.
193b1994897Sopenharmony_ci    ZipArchiveHandle zipfile = nullptr;
194b1994897Sopenharmony_ci    if (OpenArchiveFile(zipfile, fp) != ZIPARCHIVE_OK) {
195b1994897Sopenharmony_ci        LOG(ERROR, PANDAFILE) << "Can't open archive " << location;
196b1994897Sopenharmony_ci        return nullptr;
197b1994897Sopenharmony_ci    }
198b1994897Sopenharmony_ci    bool try_default = archive_filename.empty();
199b1994897Sopenharmony_ci    if (!try_default && LocateFile(zipfile, archive_filename.data()) != ZIPARCHIVE_OK) {
200b1994897Sopenharmony_ci        LOG(INFO, PANDAFILE) << "Can't find entry with name '" <<
201b1994897Sopenharmony_ci            archive_filename << "', will try " << ARCHIVE_FILENAME;
202b1994897Sopenharmony_ci        try_default = true;
203b1994897Sopenharmony_ci    }
204b1994897Sopenharmony_ci    if (try_default && LocateFile(zipfile, ARCHIVE_FILENAME) != ZIPARCHIVE_OK) {
205b1994897Sopenharmony_ci        OpenPandaFileFromZipErrorHandler(zipfile);
206b1994897Sopenharmony_ci        LOG(ERROR, PANDAFILE) << "Can't find entry with " << ARCHIVE_FILENAME;
207b1994897Sopenharmony_ci        return nullptr;
208b1994897Sopenharmony_ci    }
209b1994897Sopenharmony_ci
210b1994897Sopenharmony_ci    EntryFileStat entry = EntryFileStat();
211b1994897Sopenharmony_ci    if (GetCurrentFileInfo(zipfile, &entry) != ZIPARCHIVE_OK) {
212b1994897Sopenharmony_ci        OpenPandaFileFromZipErrorHandler(zipfile);
213b1994897Sopenharmony_ci        LOG(ERROR, PANDAFILE) << "GetCurrentFileInfo error";
214b1994897Sopenharmony_ci        return nullptr;
215b1994897Sopenharmony_ci    }
216b1994897Sopenharmony_ci    // check that file is not empty, otherwise crash at CloseArchiveFile
217b1994897Sopenharmony_ci    if (entry.GetUncompressedSize() == 0) {
218b1994897Sopenharmony_ci        OpenPandaFileFromZipErrorHandler(zipfile);
219b1994897Sopenharmony_ci        LOG(ERROR, PANDAFILE) << "Invalid panda file '" << (try_default ? ARCHIVE_FILENAME : archive_filename) << "'";
220b1994897Sopenharmony_ci        return nullptr;
221b1994897Sopenharmony_ci    }
222b1994897Sopenharmony_ci    if (OpenCurrentFile(zipfile) != ZIPARCHIVE_OK) {
223b1994897Sopenharmony_ci        CloseCurrentFile(zipfile);
224b1994897Sopenharmony_ci        OpenPandaFileFromZipErrorHandler(zipfile);
225b1994897Sopenharmony_ci        LOG(ERROR, PANDAFILE) << "Can't OpenCurrentFile!";
226b1994897Sopenharmony_ci        return nullptr;
227b1994897Sopenharmony_ci    }
228b1994897Sopenharmony_ci    GetCurrentFileOffset(zipfile, &entry);
229b1994897Sopenharmony_ci    std::unique_ptr<const panda_file::File> file = HandleArchive(zipfile, fp, location, entry,
230b1994897Sopenharmony_ci                                                                 archive_filename, open_mode);
231b1994897Sopenharmony_ci    CloseCurrentFile(zipfile);
232b1994897Sopenharmony_ci    OpenPandaFileFromZipErrorHandler(zipfile);
233b1994897Sopenharmony_ci    return file;
234b1994897Sopenharmony_ci}
235b1994897Sopenharmony_ci
236b1994897Sopenharmony_cistd::unique_ptr<const panda_file::File> OpenPandaFile(std::string_view location, std::string_view archive_filename,
237b1994897Sopenharmony_ci                                                      panda_file::File::OpenMode open_mode)
238b1994897Sopenharmony_ci{
239b1994897Sopenharmony_ci    trace::ScopedTrace scoped_trace("Open panda file " + std::string(location));
240b1994897Sopenharmony_ci    uint32_t magic;
241b1994897Sopenharmony_ci
242b1994897Sopenharmony_ci#ifdef PANDA_TARGET_WINDOWS
243b1994897Sopenharmony_ci    constexpr char const *mode = "rb";
244b1994897Sopenharmony_ci#else
245b1994897Sopenharmony_ci    constexpr char const *mode = "rbe";
246b1994897Sopenharmony_ci#endif
247b1994897Sopenharmony_ci
248b1994897Sopenharmony_ci    FILE *fp = fopen(std::string(location).c_str(), mode);
249b1994897Sopenharmony_ci    if (fp == nullptr) {
250b1994897Sopenharmony_ci        LOG(ERROR, PANDAFILE) << "Can't fopen location: " << location;
251b1994897Sopenharmony_ci        return nullptr;
252b1994897Sopenharmony_ci    }
253b1994897Sopenharmony_ci    (void)fseek(fp, 0, SEEK_SET);
254b1994897Sopenharmony_ci    if (fread(&magic, sizeof(magic), 1, fp) != 1) {
255b1994897Sopenharmony_ci        fclose(fp);
256b1994897Sopenharmony_ci        LOG(ERROR, PANDAFILE) << "Can't read from file!(magic) " << location;
257b1994897Sopenharmony_ci        return nullptr;
258b1994897Sopenharmony_ci    }
259b1994897Sopenharmony_ci    (void)fseek(fp, 0, SEEK_SET);
260b1994897Sopenharmony_ci    std::unique_ptr<const panda_file::File> file;
261b1994897Sopenharmony_ci    if (IsZipMagic(magic)) {
262b1994897Sopenharmony_ci        file = OpenPandaFileFromZip(fp, location, archive_filename, open_mode);
263b1994897Sopenharmony_ci    } else {
264b1994897Sopenharmony_ci        file = panda_file::File::Open(location, open_mode);
265b1994897Sopenharmony_ci    }
266b1994897Sopenharmony_ci    fclose(fp);
267b1994897Sopenharmony_ci    return file;
268b1994897Sopenharmony_ci}
269b1994897Sopenharmony_ci
270b1994897Sopenharmony_cistd::unique_ptr<const File> OpenPandaFileFromMemory(const void *buffer, size_t size, std::string tag)
271b1994897Sopenharmony_ci{
272b1994897Sopenharmony_ci    size_t size_to_mmap = AlignUp(size, panda::os::mem::GetPageSize());
273b1994897Sopenharmony_ci    void *mem = os::mem::MapRWAnonymousRaw(size_to_mmap, false);
274b1994897Sopenharmony_ci    if (mem == nullptr) {
275b1994897Sopenharmony_ci        return nullptr;
276b1994897Sopenharmony_ci    }
277b1994897Sopenharmony_ci
278b1994897Sopenharmony_ci    if (memcpy_s(mem, size_to_mmap, buffer, size) != 0) {
279b1994897Sopenharmony_ci        PLOG(ERROR, PANDAFILE) << "Failed to copy buffer into mem'";
280b1994897Sopenharmony_ci    }
281b1994897Sopenharmony_ci
282b1994897Sopenharmony_ci    if (!tag.empty()) {
283b1994897Sopenharmony_ci        if (tag == "ArkTS Code") {
284b1994897Sopenharmony_ci            std::string memAddr = std::to_string(ToUintPtr(mem));
285b1994897Sopenharmony_ci            tag = tag + ":" + memAddr;
286b1994897Sopenharmony_ci        }
287b1994897Sopenharmony_ci        auto ret = os::mem::TagAnonymousMemory(mem, size_to_mmap, tag.c_str());
288b1994897Sopenharmony_ci        if (ret.has_value()) {
289b1994897Sopenharmony_ci            PLOG(DEBUG, PANDAFILE) << "Can't tag mmap anonymous, errno: " << errno;
290b1994897Sopenharmony_ci        }
291b1994897Sopenharmony_ci    }
292b1994897Sopenharmony_ci
293b1994897Sopenharmony_ci    os::mem::ConstBytePtr ptr(reinterpret_cast<std::byte *>(mem), size_to_mmap, os::mem::MmapDeleter);
294b1994897Sopenharmony_ci    if (ptr.Get() == nullptr) {
295b1994897Sopenharmony_ci        PLOG(ERROR, PANDAFILE) << "Failed to open panda file from memory'";
296b1994897Sopenharmony_ci        return nullptr;
297b1994897Sopenharmony_ci    }
298b1994897Sopenharmony_ci    std::hash<void *> hash;
299b1994897Sopenharmony_ci    return panda_file::File::OpenFromMemory(std::move(ptr), std::to_string(hash(mem)));
300b1994897Sopenharmony_ci}
301b1994897Sopenharmony_ci
302b1994897Sopenharmony_cistd::unique_ptr<const File> OpenPandaFileFromSecureMemory(uint8_t *buffer, size_t size)
303b1994897Sopenharmony_ci{
304b1994897Sopenharmony_ci    if (buffer == nullptr) {
305b1994897Sopenharmony_ci        PLOG(ERROR, PANDAFILE) << "OpenPandaFileFromSecureMemory buffer is nullptr'";
306b1994897Sopenharmony_ci        return nullptr;
307b1994897Sopenharmony_ci    }
308b1994897Sopenharmony_ci
309b1994897Sopenharmony_ci    if (!CheckSecureMem(reinterpret_cast<uintptr_t>(buffer), size)) {
310b1994897Sopenharmony_ci        PLOG(ERROR, PANDAFILE) << "Secure memory check failed, please execute in secure memory.";
311b1994897Sopenharmony_ci        return nullptr;
312b1994897Sopenharmony_ci    }
313b1994897Sopenharmony_ci
314b1994897Sopenharmony_ci    std::byte *mem = reinterpret_cast<std::byte *>(buffer);
315b1994897Sopenharmony_ci    os::mem::ConstBytePtr ptr(mem, size, nullptr);
316b1994897Sopenharmony_ci    if (ptr.Get() == nullptr) {
317b1994897Sopenharmony_ci        PLOG(ERROR, PANDAFILE) << "Failed to open panda file from secure memory'";
318b1994897Sopenharmony_ci        return nullptr;
319b1994897Sopenharmony_ci    }
320b1994897Sopenharmony_ci
321b1994897Sopenharmony_ci    std::hash<std::byte *> hash;
322b1994897Sopenharmony_ci    return panda_file::File::OpenFromMemory(std::move(ptr), std::to_string(hash(mem)));
323b1994897Sopenharmony_ci}
324b1994897Sopenharmony_ci
325b1994897Sopenharmony_ciinline bool CheckSecureMem(uintptr_t mem, size_t size)
326b1994897Sopenharmony_ci{
327b1994897Sopenharmony_ci    static bool has_open = false;
328b1994897Sopenharmony_ci    static DataProtect start = DataProtect();
329b1994897Sopenharmony_ci    static DataProtect end = DataProtect();
330b1994897Sopenharmony_ci    uintptr_t secure_mem_start;
331b1994897Sopenharmony_ci    uintptr_t secure_mem_end;
332b1994897Sopenharmony_ci    if (!has_open) {
333b1994897Sopenharmony_ci        int fd = open(PROC_SELF_XPM_REGION_PATH, O_RDONLY);
334b1994897Sopenharmony_ci        if (fd < 0) {
335b1994897Sopenharmony_ci            LOG(ERROR, PANDAFILE) << "Can not open xpm proc file, do not check secure memory anymore.";
336b1994897Sopenharmony_ci            // No verification is performed when a file fails to be opened.
337b1994897Sopenharmony_ci            has_open = true;
338b1994897Sopenharmony_ci            return true;
339b1994897Sopenharmony_ci        }
340b1994897Sopenharmony_ci        char xpm_validate_region[XPM_PROC_LENGTH] = {0};
341b1994897Sopenharmony_ci        int ret = read(fd, xpm_validate_region, sizeof(xpm_validate_region));
342b1994897Sopenharmony_ci        if (ret <= 0) {
343b1994897Sopenharmony_ci            LOG(ERROR, PANDAFILE) << "Read xpm proc file failed";
344b1994897Sopenharmony_ci            close(fd);
345b1994897Sopenharmony_ci            return false;
346b1994897Sopenharmony_ci        }
347b1994897Sopenharmony_ci        close(fd);
348b1994897Sopenharmony_ci        if (sscanf_s(xpm_validate_region, "%lx-%lx", &secure_mem_start, &secure_mem_end) <= 0) {
349b1994897Sopenharmony_ci            LOG(ERROR, PANDAFILE) << "sscanf_s xpm validate region failed";
350b1994897Sopenharmony_ci            return false;
351b1994897Sopenharmony_ci        }
352b1994897Sopenharmony_ci        // The check is not performed when the file is already opened.
353b1994897Sopenharmony_ci        has_open = true;
354b1994897Sopenharmony_ci        LOG(DEBUG, PANDAFILE) << "Successfully open xpm region.";
355b1994897Sopenharmony_ci        start.Update(secure_mem_start);
356b1994897Sopenharmony_ci        end.Update(secure_mem_end);
357b1994897Sopenharmony_ci    }
358b1994897Sopenharmony_ci    secure_mem_start = start.GetOriginPointer();
359b1994897Sopenharmony_ci    secure_mem_end = end.GetOriginPointer();
360b1994897Sopenharmony_ci    // xpm proc does not exist, the read value is 0, and the check is not performed.
361b1994897Sopenharmony_ci    if (secure_mem_start == 0 && secure_mem_end == 0) {
362b1994897Sopenharmony_ci        LOG(ERROR, PANDAFILE) << "Secure memory check: xpm proc does not exist, do not check secure memory anymore.";
363b1994897Sopenharmony_ci        return true;
364b1994897Sopenharmony_ci    }
365b1994897Sopenharmony_ci    if (mem < secure_mem_start || (size > (std::numeric_limits<uintptr_t>::max() - mem)) ||
366b1994897Sopenharmony_ci        (mem + size) > secure_mem_end) {
367b1994897Sopenharmony_ci        LOG(ERROR, PANDAFILE) << "Secure memory check failed, mem out of secure memory region.";
368b1994897Sopenharmony_ci        return false;
369b1994897Sopenharmony_ci    }
370b1994897Sopenharmony_ci    return true;
371b1994897Sopenharmony_ci}
372b1994897Sopenharmony_ci
373b1994897Sopenharmony_ciclass ClassIdxIterator {
374b1994897Sopenharmony_cipublic:
375b1994897Sopenharmony_ci    using value_type = const uint8_t *;
376b1994897Sopenharmony_ci    using difference_type = std::ptrdiff_t;
377b1994897Sopenharmony_ci    using pointer = uint32_t *;
378b1994897Sopenharmony_ci    using reference = uint32_t &;
379b1994897Sopenharmony_ci    using iterator_category = std::random_access_iterator_tag;
380b1994897Sopenharmony_ci
381b1994897Sopenharmony_ci    ClassIdxIterator(const File &file, const Span<const uint32_t> &span, size_t idx)
382b1994897Sopenharmony_ci        : file_(file), span_(span), idx_(idx)
383b1994897Sopenharmony_ci    {
384b1994897Sopenharmony_ci    }
385b1994897Sopenharmony_ci
386b1994897Sopenharmony_ci    ClassIdxIterator(const ClassIdxIterator &other) = default;
387b1994897Sopenharmony_ci    ClassIdxIterator(ClassIdxIterator &&other) = default;
388b1994897Sopenharmony_ci    ~ClassIdxIterator() = default;
389b1994897Sopenharmony_ci
390b1994897Sopenharmony_ci    ClassIdxIterator &operator=(const ClassIdxIterator &other)
391b1994897Sopenharmony_ci    {
392b1994897Sopenharmony_ci        if (&other != this) {
393b1994897Sopenharmony_ci            idx_ = other.idx_;
394b1994897Sopenharmony_ci        }
395b1994897Sopenharmony_ci
396b1994897Sopenharmony_ci        return *this;
397b1994897Sopenharmony_ci    }
398b1994897Sopenharmony_ci
399b1994897Sopenharmony_ci    ClassIdxIterator &operator=(ClassIdxIterator &&other) noexcept
400b1994897Sopenharmony_ci    {
401b1994897Sopenharmony_ci        idx_ = other.idx_;
402b1994897Sopenharmony_ci        return *this;
403b1994897Sopenharmony_ci    }
404b1994897Sopenharmony_ci
405b1994897Sopenharmony_ci    ClassIdxIterator &operator+=(size_t n)
406b1994897Sopenharmony_ci    {
407b1994897Sopenharmony_ci        idx_ += n;
408b1994897Sopenharmony_ci        return *this;
409b1994897Sopenharmony_ci    }
410b1994897Sopenharmony_ci
411b1994897Sopenharmony_ci    ClassIdxIterator &operator-=(size_t n)
412b1994897Sopenharmony_ci    {
413b1994897Sopenharmony_ci        idx_ -= n;
414b1994897Sopenharmony_ci        return *this;
415b1994897Sopenharmony_ci    }
416b1994897Sopenharmony_ci
417b1994897Sopenharmony_ci    ClassIdxIterator &operator++()
418b1994897Sopenharmony_ci    {
419b1994897Sopenharmony_ci        ++idx_;
420b1994897Sopenharmony_ci        return *this;
421b1994897Sopenharmony_ci    }
422b1994897Sopenharmony_ci
423b1994897Sopenharmony_ci    ClassIdxIterator &operator--()
424b1994897Sopenharmony_ci    {
425b1994897Sopenharmony_ci        --idx_;
426b1994897Sopenharmony_ci        return *this;
427b1994897Sopenharmony_ci    }
428b1994897Sopenharmony_ci
429b1994897Sopenharmony_ci    difference_type operator-(const ClassIdxIterator &other)
430b1994897Sopenharmony_ci    {
431b1994897Sopenharmony_ci        return idx_ - other.idx_;
432b1994897Sopenharmony_ci    }
433b1994897Sopenharmony_ci
434b1994897Sopenharmony_ci    value_type operator*() const
435b1994897Sopenharmony_ci    {
436b1994897Sopenharmony_ci        uint32_t id = span_[idx_];
437b1994897Sopenharmony_ci        return file_.GetStringData(File::EntityId(id)).data;
438b1994897Sopenharmony_ci    }
439b1994897Sopenharmony_ci
440b1994897Sopenharmony_ci    bool IsValid() const
441b1994897Sopenharmony_ci    {
442b1994897Sopenharmony_ci        return idx_ < span_.Size();
443b1994897Sopenharmony_ci    }
444b1994897Sopenharmony_ci
445b1994897Sopenharmony_ci    uint32_t GetId() const
446b1994897Sopenharmony_ci    {
447b1994897Sopenharmony_ci        return span_[idx_];
448b1994897Sopenharmony_ci    }
449b1994897Sopenharmony_ci
450b1994897Sopenharmony_ci    static ClassIdxIterator Begin(const File &file, const Span<const uint32_t> &span)
451b1994897Sopenharmony_ci    {
452b1994897Sopenharmony_ci        return ClassIdxIterator(file, span, 0);
453b1994897Sopenharmony_ci    }
454b1994897Sopenharmony_ci
455b1994897Sopenharmony_ci    static ClassIdxIterator End(const File &file, const Span<const uint32_t> &span)
456b1994897Sopenharmony_ci    {
457b1994897Sopenharmony_ci        return ClassIdxIterator(file, span, span.Size());
458b1994897Sopenharmony_ci    }
459b1994897Sopenharmony_ci
460b1994897Sopenharmony_ciprivate:
461b1994897Sopenharmony_ci    const File &file_;
462b1994897Sopenharmony_ci    const Span<const uint32_t> &span_;
463b1994897Sopenharmony_ci    size_t idx_;
464b1994897Sopenharmony_ci};
465b1994897Sopenharmony_ci
466b1994897Sopenharmony_ciFile::File(std::string filename, os::mem::ConstBytePtr &&base)
467b1994897Sopenharmony_ci    : base_(std::forward<os::mem::ConstBytePtr>(base)),
468b1994897Sopenharmony_ci      FILENAME(std::move(filename)),
469b1994897Sopenharmony_ci      FILENAME_HASH(CalcFilenameHash(FILENAME)),
470b1994897Sopenharmony_ci#ifdef ENABLE_FULL_FILE_FIELDS
471b1994897Sopenharmony_ci      FULL_FILENAME(os::GetAbsolutePath(FILENAME)),
472b1994897Sopenharmony_ci      panda_cache_(std::make_unique<PandaCache>()),
473b1994897Sopenharmony_ci#endif
474b1994897Sopenharmony_ci      UNIQ_ID(merge_hashes(FILENAME_HASH, GetHash32(reinterpret_cast<const uint8_t *>(GetHeader()), sizeof(Header))))
475b1994897Sopenharmony_ci{
476b1994897Sopenharmony_ci}
477b1994897Sopenharmony_ci
478b1994897Sopenharmony_ciFile::~File()
479b1994897Sopenharmony_ci{
480b1994897Sopenharmony_ci    AnonMemSet::GetInstance().Remove(FILENAME);
481b1994897Sopenharmony_ci}
482b1994897Sopenharmony_ci
483b1994897Sopenharmony_ciinline std::string VersionToString(const std::array<uint8_t, File::VERSION_SIZE> &array)
484b1994897Sopenharmony_ci{
485b1994897Sopenharmony_ci    std::stringstream ss;
486b1994897Sopenharmony_ci
487b1994897Sopenharmony_ci    for (size_t i = 0; i < File::VERSION_SIZE - 1; ++i) {
488b1994897Sopenharmony_ci        ss << static_cast<int>(array[i]);
489b1994897Sopenharmony_ci        ss << ".";
490b1994897Sopenharmony_ci    }
491b1994897Sopenharmony_ci    ss << static_cast<int>(array[File::VERSION_SIZE - 1]);
492b1994897Sopenharmony_ci
493b1994897Sopenharmony_ci    return ss.str();
494b1994897Sopenharmony_ci}
495b1994897Sopenharmony_ci
496b1994897Sopenharmony_ci// We can't use default std::array's comparision operators and need to implement
497b1994897Sopenharmony_ci// own ones due to the bug in gcc: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=95189
498b1994897Sopenharmony_ciinline int CompareVersions(const std::array<uint8_t, File::VERSION_SIZE> &lhs,
499b1994897Sopenharmony_ci                           const std::array<uint8_t, File::VERSION_SIZE> &rhs)
500b1994897Sopenharmony_ci{
501b1994897Sopenharmony_ci    for (size_t i = 0; i < File::VERSION_SIZE; i++) {
502b1994897Sopenharmony_ci        if (lhs[i] == rhs[i]) {
503b1994897Sopenharmony_ci            continue;
504b1994897Sopenharmony_ci        }
505b1994897Sopenharmony_ci        return lhs[i] - rhs[i];
506b1994897Sopenharmony_ci    }
507b1994897Sopenharmony_ci    return 0;
508b1994897Sopenharmony_ci}
509b1994897Sopenharmony_ci
510b1994897Sopenharmony_ciinline bool operator<(const std::array<uint8_t, File::VERSION_SIZE> &lhs,
511b1994897Sopenharmony_ci                      const std::array<uint8_t, File::VERSION_SIZE> &rhs)
512b1994897Sopenharmony_ci{
513b1994897Sopenharmony_ci    return CompareVersions(lhs, rhs) < 0;
514b1994897Sopenharmony_ci}
515b1994897Sopenharmony_ci
516b1994897Sopenharmony_ciinline bool operator>(const std::array<uint8_t, File::VERSION_SIZE> &lhs,
517b1994897Sopenharmony_ci                      const std::array<uint8_t, File::VERSION_SIZE> &rhs)
518b1994897Sopenharmony_ci{
519b1994897Sopenharmony_ci    return CompareVersions(lhs, rhs) > 0;
520b1994897Sopenharmony_ci}
521b1994897Sopenharmony_ci
522b1994897Sopenharmony_ci/* static */
523b1994897Sopenharmony_cistd::unique_ptr<const File> File::Open(std::string_view filename, OpenMode open_mode)
524b1994897Sopenharmony_ci{
525b1994897Sopenharmony_ci    trace::ScopedTrace scoped_trace("Open panda file " + std::string(filename));
526b1994897Sopenharmony_ci    os::file::Mode mode = GetMode(open_mode);
527b1994897Sopenharmony_ci    os::file::File file = os::file::Open(filename, mode);
528b1994897Sopenharmony_ci    if (!file.IsValid()) {
529b1994897Sopenharmony_ci        PLOG(ERROR, PANDAFILE) << "Failed to open panda file '" << filename << "'";
530b1994897Sopenharmony_ci        return nullptr;
531b1994897Sopenharmony_ci    }
532b1994897Sopenharmony_ci
533b1994897Sopenharmony_ci    os::file::FileHolder fh_holder(file);
534b1994897Sopenharmony_ci
535b1994897Sopenharmony_ci    auto res = file.GetFileSize();
536b1994897Sopenharmony_ci    if (!res) {
537b1994897Sopenharmony_ci        PLOG(ERROR, PANDAFILE) << "Failed to get size of panda file '" << filename << "'";
538b1994897Sopenharmony_ci        return nullptr;
539b1994897Sopenharmony_ci    }
540b1994897Sopenharmony_ci
541b1994897Sopenharmony_ci    size_t size = res.Value();
542b1994897Sopenharmony_ci    if (size < sizeof(File::Header)) {
543b1994897Sopenharmony_ci        LOG(ERROR, PANDAFILE) << "Invalid panda file '" << filename << "' - missing or incomplete header" <<
544b1994897Sopenharmony_ci                                 ". Abc file is corrupted";
545b1994897Sopenharmony_ci        return nullptr;
546b1994897Sopenharmony_ci    }
547b1994897Sopenharmony_ci
548b1994897Sopenharmony_ci    os::mem::ConstBytePtr ptr = os::mem::MapFile(file, GetProt(open_mode), os::mem::MMAP_FLAG_PRIVATE, size).ToConst();
549b1994897Sopenharmony_ci    if (ptr.Get() == nullptr) {
550b1994897Sopenharmony_ci        PLOG(ERROR, PANDAFILE) << "Failed to map panda file '" << filename << "'";
551b1994897Sopenharmony_ci        return nullptr;
552b1994897Sopenharmony_ci    }
553b1994897Sopenharmony_ci
554b1994897Sopenharmony_ci    if (!CheckHeader(ptr, filename)) {
555b1994897Sopenharmony_ci        return nullptr;
556b1994897Sopenharmony_ci    }
557b1994897Sopenharmony_ci
558b1994897Sopenharmony_ci    return std::unique_ptr<File>(new File(filename.data(), std::move(ptr)));
559b1994897Sopenharmony_ci}
560b1994897Sopenharmony_ci
561b1994897Sopenharmony_cistd::unique_ptr<const File> File::OpenUncompressedArchive(int fd, const std::string_view &filename, size_t size,
562b1994897Sopenharmony_ci                                                          uint32_t offset, OpenMode open_mode)
563b1994897Sopenharmony_ci{
564b1994897Sopenharmony_ci    trace::ScopedTrace scoped_trace("Open panda file " + std::string(filename));
565b1994897Sopenharmony_ci    auto file = os::file::File(fd);
566b1994897Sopenharmony_ci    if (!file.IsValid()) {
567b1994897Sopenharmony_ci        PLOG(ERROR, PANDAFILE) << "OpenUncompressedArchive: Failed to open panda file '" << filename << "'";
568b1994897Sopenharmony_ci        return nullptr;
569b1994897Sopenharmony_ci    }
570b1994897Sopenharmony_ci
571b1994897Sopenharmony_ci    if (size < sizeof(File::Header)) {
572b1994897Sopenharmony_ci        LOG(ERROR, PANDAFILE) << "Invalid panda file size '" << filename << "'" << ". Abc file is corrupted";
573b1994897Sopenharmony_ci        return nullptr;
574b1994897Sopenharmony_ci    }
575b1994897Sopenharmony_ci    LOG(DEBUG, PANDAFILE) << " size=" << size << " offset=" << offset << " " << filename;
576b1994897Sopenharmony_ci
577b1994897Sopenharmony_ci    os::mem::ConstBytePtr ptr =
578b1994897Sopenharmony_ci        os::mem::MapFile(file, GetProt(open_mode), os::mem::MMAP_FLAG_PRIVATE, size, offset).ToConst();
579b1994897Sopenharmony_ci    if (ptr.Get() == nullptr) {
580b1994897Sopenharmony_ci        PLOG(ERROR, PANDAFILE) << "Failed to map panda file '" << filename << "'";
581b1994897Sopenharmony_ci        return nullptr;
582b1994897Sopenharmony_ci    }
583b1994897Sopenharmony_ci    if (!CheckHeader(ptr, filename)) {
584b1994897Sopenharmony_ci        return nullptr;
585b1994897Sopenharmony_ci    }
586b1994897Sopenharmony_ci
587b1994897Sopenharmony_ci    return std::unique_ptr<File>(new File(filename.data(), std::move(ptr)));
588b1994897Sopenharmony_ci}
589b1994897Sopenharmony_ci
590b1994897Sopenharmony_citemplate <typename T = uint32_t>
591b1994897Sopenharmony_cibool CheckHeaderElementOffset(size_t offset, size_t number, size_t file_size)
592b1994897Sopenharmony_ci{
593b1994897Sopenharmony_ci    auto number_size = number * sizeof(T);
594b1994897Sopenharmony_ci    if (offset > file_size || number_size > file_size || offset > file_size - number_size) {
595b1994897Sopenharmony_ci        return false;
596b1994897Sopenharmony_ci    }
597b1994897Sopenharmony_ci    return true;
598b1994897Sopenharmony_ci}
599b1994897Sopenharmony_ci
600b1994897Sopenharmony_cibool CheckHeader(const os::mem::ConstBytePtr &ptr, const std::string_view &filename)
601b1994897Sopenharmony_ci{
602b1994897Sopenharmony_ci    if (ptr.Get() == nullptr || ptr.GetSize() < sizeof(File::Header)) {
603b1994897Sopenharmony_ci        LOG(ERROR, PANDAFILE) << "Invalid panda file '" << filename << "'" << ". Abc file is corrupted";
604b1994897Sopenharmony_ci        return false;
605b1994897Sopenharmony_ci    }
606b1994897Sopenharmony_ci    auto header = reinterpret_cast<const File::Header *>(reinterpret_cast<uintptr_t>(ptr.Get()));
607b1994897Sopenharmony_ci    if (header->magic != File::MAGIC) {
608b1994897Sopenharmony_ci        LOG(ERROR, PANDAFILE) << "Invalid magic number" << ". Abc file is corrupted";
609b1994897Sopenharmony_ci        return false;
610b1994897Sopenharmony_ci    }
611b1994897Sopenharmony_ci
612b1994897Sopenharmony_ci    CheckFileVersion(header->version, filename);
613b1994897Sopenharmony_ci
614b1994897Sopenharmony_ci    if (header->file_size < sizeof(File::Header) || header->file_size > ptr.GetSize()) {
615b1994897Sopenharmony_ci        LOG(ERROR, PANDAFILE) << "Invalid panda file size " << header->file_size << ". Abc file is corrupted";
616b1994897Sopenharmony_ci        return false;
617b1994897Sopenharmony_ci    }
618b1994897Sopenharmony_ci
619b1994897Sopenharmony_ci    if (!CheckHeaderElementOffset<uint8_t>(header->foreign_off, header->foreign_size, header->file_size)) {
620b1994897Sopenharmony_ci        LOG(ERROR, PANDAFILE) << "Invalid panda file foreign_off " << header->foreign_off <<
621b1994897Sopenharmony_ci            " or foreign_size " << header->foreign_size << ". Abc file is corrupted";
622b1994897Sopenharmony_ci        return false;
623b1994897Sopenharmony_ci    }
624b1994897Sopenharmony_ci
625b1994897Sopenharmony_ci    if (!CheckHeaderElementOffset(header->class_idx_off, header->num_classes, header->file_size)) {
626b1994897Sopenharmony_ci        LOG(ERROR, PANDAFILE) << "Invalid panda file class_idx_off " << header->class_idx_off <<
627b1994897Sopenharmony_ci            " or num_classes " << header->num_classes << ". Abc file is corrupted";
628b1994897Sopenharmony_ci        return false;
629b1994897Sopenharmony_ci    }
630b1994897Sopenharmony_ci
631b1994897Sopenharmony_ci    if (!CheckHeaderElementOffset(header->lnp_idx_off, header->num_lnps, header->file_size)) {
632b1994897Sopenharmony_ci        LOG(ERROR, PANDAFILE) << "Invalid panda file lnp_idx_off " << header->lnp_idx_off <<
633b1994897Sopenharmony_ci            " or num_lnps " << header->num_lnps << ". Abc file is corrupted";
634b1994897Sopenharmony_ci        return false;
635b1994897Sopenharmony_ci    }
636b1994897Sopenharmony_ci
637b1994897Sopenharmony_ci    if (ContainsLiteralArrayInHeader(header->version)) {
638b1994897Sopenharmony_ci        if (!CheckHeaderElementOffset(header->literalarray_idx_off, header->num_literalarrays, header->file_size)) {
639b1994897Sopenharmony_ci            LOG(ERROR, PANDAFILE) << "Invalid panda file literalarray_idx_off " << header->literalarray_idx_off <<
640b1994897Sopenharmony_ci                                     " or num_literalarrays " << header->num_literalarrays <<
641b1994897Sopenharmony_ci                                     ". Abc file is corrupted";
642b1994897Sopenharmony_ci            return false;
643b1994897Sopenharmony_ci        }
644b1994897Sopenharmony_ci    } else {
645b1994897Sopenharmony_ci        if (header->literalarray_idx_off != INVALID_INDEX || header->num_literalarrays != INVALID_OFFSET) {
646b1994897Sopenharmony_ci            LOG(ERROR, PANDAFILE) << "Invalid panda file literalarray_idx_off " << header->literalarray_idx_off <<
647b1994897Sopenharmony_ci                                     " or num_literalarrays " << header->num_literalarrays <<
648b1994897Sopenharmony_ci                                     ", The literalarray_idx_off and num_literalarrays should be reserved." <<
649b1994897Sopenharmony_ci                                     " Abc file is corrupted";
650b1994897Sopenharmony_ci            return false;
651b1994897Sopenharmony_ci        }
652b1994897Sopenharmony_ci    }
653b1994897Sopenharmony_ci
654b1994897Sopenharmony_ci    if (!CheckHeaderElementOffset<File::IndexHeader>(header->index_section_off, header->num_indexes,
655b1994897Sopenharmony_ci        header->file_size)) {
656b1994897Sopenharmony_ci        LOG(ERROR, PANDAFILE) << "Invalid panda file index_section_off " << header->index_section_off <<
657b1994897Sopenharmony_ci            " or num_indexes " << header->num_indexes << ". Abc file is corrupted";
658b1994897Sopenharmony_ci        return false;
659b1994897Sopenharmony_ci    }
660b1994897Sopenharmony_ci
661b1994897Sopenharmony_ci    return true;
662b1994897Sopenharmony_ci}
663b1994897Sopenharmony_ci
664b1994897Sopenharmony_civoid CheckFileVersion(const std::array<uint8_t, File::VERSION_SIZE> &file_version, const std::string_view &filename)
665b1994897Sopenharmony_ci{
666b1994897Sopenharmony_ci#ifdef ERROR_AS_FATAL
667b1994897Sopenharmony_ci#define LOG_LEVEL FATAL
668b1994897Sopenharmony_ci#else
669b1994897Sopenharmony_ci#define LOG_LEVEL ERROR
670b1994897Sopenharmony_ci#endif
671b1994897Sopenharmony_ci    if (file_version == version) {
672b1994897Sopenharmony_ci        return;
673b1994897Sopenharmony_ci    }
674b1994897Sopenharmony_ci    if (file_version < minVersion) {
675b1994897Sopenharmony_ci        LOG(LOG_LEVEL, PANDAFILE) << "Unable to open file '" << filename << "' with abc file version "
676b1994897Sopenharmony_ci            << VersionToString(file_version)
677b1994897Sopenharmony_ci            << ". Minimum supported abc file version on the current system image is " << VersionToString(minVersion)
678b1994897Sopenharmony_ci            << ". Please upgrade the sdk tools to generate supported version of abc files "
679b1994897Sopenharmony_ci            << "or execute the abc file on former version of system image";
680b1994897Sopenharmony_ci    } else if (file_version > version) {
681b1994897Sopenharmony_ci        LOG(LOG_LEVEL, PANDAFILE) << "Unable to open file '" << filename << "' with abc file version "
682b1994897Sopenharmony_ci            << VersionToString(file_version)
683b1994897Sopenharmony_ci            << ". Maximum supported abc file version on the current system image is " << VersionToString(version)
684b1994897Sopenharmony_ci            << ". Please upgrade the system image or use former version of SDK tools to generate abc files";
685b1994897Sopenharmony_ci    } else if (incompatibleVersion.count(file_version) != 0) {
686b1994897Sopenharmony_ci        LOG(LOG_LEVEL, PANDAFILE) << "Unable to open file '" << filename << "' with  abc file version "
687b1994897Sopenharmony_ci            << VersionToString(file_version) << ". Current system image version is "
688b1994897Sopenharmony_ci            << VersionToString(version) << ", while abc file version is " << VersionToString(file_version)
689b1994897Sopenharmony_ci            << ". The version "<< VersionToString(file_version)
690b1994897Sopenharmony_ci            << " is not a compatible version, can't run on system image of version " << VersionToString(version)
691b1994897Sopenharmony_ci            << ". Please use sdk tools and system image in pairs "
692b1994897Sopenharmony_ci            << "and make the version of sdk tools and system image consistent";
693b1994897Sopenharmony_ci    }
694b1994897Sopenharmony_ci#undef LOG_LEVEL
695b1994897Sopenharmony_ci}
696b1994897Sopenharmony_ci/* static */
697b1994897Sopenharmony_cistd::unique_ptr<const File> File::OpenFromMemory(os::mem::ConstBytePtr &&ptr)
698b1994897Sopenharmony_ci{
699b1994897Sopenharmony_ci    if (!CheckHeader(ptr, std::string_view())) {
700b1994897Sopenharmony_ci        return nullptr;
701b1994897Sopenharmony_ci    }
702b1994897Sopenharmony_ci
703b1994897Sopenharmony_ci    return std::unique_ptr<File>(new File("", std::forward<os::mem::ConstBytePtr>(ptr)));
704b1994897Sopenharmony_ci}
705b1994897Sopenharmony_ci
706b1994897Sopenharmony_ci/* static */
707b1994897Sopenharmony_cistd::unique_ptr<const File> File::OpenFromMemory(os::mem::ConstBytePtr &&ptr, std::string_view filename)
708b1994897Sopenharmony_ci{
709b1994897Sopenharmony_ci    trace::ScopedTrace scoped_trace("Open panda file from RAM " + std::string(filename));
710b1994897Sopenharmony_ci
711b1994897Sopenharmony_ci    if (!CheckHeader(ptr, filename)) {
712b1994897Sopenharmony_ci        return nullptr;
713b1994897Sopenharmony_ci    }
714b1994897Sopenharmony_ci
715b1994897Sopenharmony_ci    return std::unique_ptr<File>(new File(filename.data(), std::forward<os::mem::ConstBytePtr>(ptr)));
716b1994897Sopenharmony_ci}
717b1994897Sopenharmony_ci
718b1994897Sopenharmony_ciFile::EntityId File::GetClassId(const uint8_t *mutf8_name) const
719b1994897Sopenharmony_ci{
720b1994897Sopenharmony_ci    auto class_hash_table = GetClassHashTable();
721b1994897Sopenharmony_ci    if (!class_hash_table.empty()) {
722b1994897Sopenharmony_ci        return GetClassIdFromClassHashTable(mutf8_name);
723b1994897Sopenharmony_ci    }
724b1994897Sopenharmony_ci
725b1994897Sopenharmony_ci    auto class_idx = GetClasses();
726b1994897Sopenharmony_ci
727b1994897Sopenharmony_ci    auto it = std::lower_bound(ClassIdxIterator::Begin(*this, class_idx), ClassIdxIterator::End(*this, class_idx),
728b1994897Sopenharmony_ci                               mutf8_name, utf::Mutf8Less());
729b1994897Sopenharmony_ci    if (!it.IsValid()) {
730b1994897Sopenharmony_ci        return EntityId();
731b1994897Sopenharmony_ci    }
732b1994897Sopenharmony_ci
733b1994897Sopenharmony_ci    if (utf::CompareMUtf8ToMUtf8(mutf8_name, *it) == 0) {
734b1994897Sopenharmony_ci        return EntityId(it.GetId());
735b1994897Sopenharmony_ci    }
736b1994897Sopenharmony_ci
737b1994897Sopenharmony_ci    return EntityId();
738b1994897Sopenharmony_ci}
739b1994897Sopenharmony_ci
740b1994897Sopenharmony_ciuint32_t File::CalcFilenameHash(const std::string &filename)
741b1994897Sopenharmony_ci{
742b1994897Sopenharmony_ci    return GetHash32String(reinterpret_cast<const uint8_t *>(filename.c_str()));
743b1994897Sopenharmony_ci}
744b1994897Sopenharmony_ci
745b1994897Sopenharmony_ciFile::EntityId File::GetLiteralArraysId() const
746b1994897Sopenharmony_ci{
747b1994897Sopenharmony_ci    const Header *header = GetHeader();
748b1994897Sopenharmony_ci    return EntityId(header->literalarray_idx_off);
749b1994897Sopenharmony_ci}
750b1994897Sopenharmony_ci
751b1994897Sopenharmony_ciFile::EntityId File::GetClassIdFromClassHashTable(const uint8_t *mutf8_name) const
752b1994897Sopenharmony_ci{
753b1994897Sopenharmony_ci    auto class_hash_table = GetClassHashTable();
754b1994897Sopenharmony_ci    auto hash = GetHash32String(mutf8_name);
755b1994897Sopenharmony_ci    auto pos = hash & (class_hash_table.size() - 1);
756b1994897Sopenharmony_ci    auto entity_pair = &class_hash_table[pos];
757b1994897Sopenharmony_ci
758b1994897Sopenharmony_ci    if (entity_pair->descriptor_hash % class_hash_table.size() != pos) {
759b1994897Sopenharmony_ci        return File::EntityId();
760b1994897Sopenharmony_ci    }
761b1994897Sopenharmony_ci
762b1994897Sopenharmony_ci    while (true) {
763b1994897Sopenharmony_ci        if (hash == entity_pair->descriptor_hash) {
764b1994897Sopenharmony_ci            auto entity_id = File::EntityId(entity_pair->entity_id_offset);
765b1994897Sopenharmony_ci            auto descriptor = GetStringData(entity_id).data;
766b1994897Sopenharmony_ci            if (entity_id.IsValid() && utf::CompareMUtf8ToMUtf8(descriptor, mutf8_name) == 0) {
767b1994897Sopenharmony_ci                return entity_id;
768b1994897Sopenharmony_ci            }
769b1994897Sopenharmony_ci        }
770b1994897Sopenharmony_ci        if (entity_pair->next_pos == 0) {
771b1994897Sopenharmony_ci            break;
772b1994897Sopenharmony_ci        }
773b1994897Sopenharmony_ci        entity_pair = &class_hash_table[entity_pair->next_pos - 1];
774b1994897Sopenharmony_ci    }
775b1994897Sopenharmony_ci
776b1994897Sopenharmony_ci    return File::EntityId();
777b1994897Sopenharmony_ci}
778b1994897Sopenharmony_ci
779b1994897Sopenharmony_ci
780b1994897Sopenharmony_cibool ContainsLiteralArrayInHeader(const std::array<uint8_t, File::VERSION_SIZE> &version)
781b1994897Sopenharmony_ci{
782b1994897Sopenharmony_ci    return panda::panda_file::IsVersionLessOrEqual(version, LAST_CONTAINS_LITERAL_IN_HEADER_VERSION);
783b1994897Sopenharmony_ci}
784b1994897Sopenharmony_ci
785b1994897Sopenharmony_cibool File::ValidateChecksum(uint32_t *cal_checksum_out) const
786b1994897Sopenharmony_ci{
787b1994897Sopenharmony_ci    constexpr uint32_t CHECKSUM_SIZE = 4U;
788b1994897Sopenharmony_ci    // The checksum calculation does not include magic or checksum, so the offset needs to be added
789b1994897Sopenharmony_ci    constexpr uint32_t FILE_CONTENT_OFFSET = File::MAGIC_SIZE + CHECKSUM_SIZE;
790b1994897Sopenharmony_ci    uint32_t file_size = GetHeader()->file_size;
791b1994897Sopenharmony_ci    uint32_t cal_checksum = adler32(1, GetBase() + FILE_CONTENT_OFFSET, file_size - FILE_CONTENT_OFFSET);
792b1994897Sopenharmony_ci
793b1994897Sopenharmony_ci    if (cal_checksum_out != nullptr) {
794b1994897Sopenharmony_ci        *cal_checksum_out = cal_checksum;
795b1994897Sopenharmony_ci    }
796b1994897Sopenharmony_ci
797b1994897Sopenharmony_ci    return GetHeader()->checksum == cal_checksum;
798b1994897Sopenharmony_ci}
799b1994897Sopenharmony_ci
800b1994897Sopenharmony_civoid File::ThrowIfWithCheck(bool cond, const std::string_view& msg, const std::string_view& tag) const
801b1994897Sopenharmony_ci{
802b1994897Sopenharmony_ci    if (UNLIKELY(cond)) {
803b1994897Sopenharmony_ci        uint32_t cal_checksum = 0;
804b1994897Sopenharmony_ci        bool is_checksum_match = ValidateChecksum(&cal_checksum);
805b1994897Sopenharmony_ci        if (!is_checksum_match) {
806b1994897Sopenharmony_ci            LOG(FATAL, PANDAFILE) << msg << ", checksum mismatch. The abc file has been corrupted. "
807b1994897Sopenharmony_ci                                         << "Expected checksum: 0x" << std::hex << GetHeader()->checksum
808b1994897Sopenharmony_ci                                         << ", Actual checksum: 0x" << std::hex << cal_checksum;
809b1994897Sopenharmony_ci        }
810b1994897Sopenharmony_ci
811b1994897Sopenharmony_ci        if (!tag.empty()) {
812b1994897Sopenharmony_ci            LOG(FATAL, PANDAFILE) << msg << ", from method: " << tag;
813b1994897Sopenharmony_ci        } else {
814b1994897Sopenharmony_ci            LOG(FATAL, PANDAFILE) << msg;
815b1994897Sopenharmony_ci        }
816b1994897Sopenharmony_ci    }
817b1994897Sopenharmony_ci}
818b1994897Sopenharmony_ci
819b1994897Sopenharmony_ci}  // namespace panda::panda_file
820