• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021 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 "file_format_version.h"
17 #include "file-inl.h"
18 #include "os/file.h"
19 #include "os/mem.h"
20 #include "mem/mem.h"
21 #include "panda_cache.h"
22 
23 #include "utils/hash.h"
24 #include "utils/logger.h"
25 #include "utils/utf.h"
26 #include "utils/span.h"
27 #include "zip_archive.h"
28 #include "trace/trace.h"
29 #if !PANDA_TARGET_WINDOWS
30 #include "securec.h"
31 #endif
32 
33 #include <cerrno>
34 #include <cstring>
35 
36 #include <algorithm>
37 #include <memory>
38 #include <string>
39 #include <variant>
40 #include <cstdio>
41 #include <map>
42 namespace panda::panda_file {
43 
44 #ifndef EOK
45 constexpr int EOK = 0;
46 #endif  // EOK
47 
48 // NOLINTNEXTLINE(readability-identifier-naming, modernize-avoid-c-arrays)
49 const char *ARCHIVE_FILENAME = "classes.abc";
50 // NOLINTNEXTLINE(readability-identifier-naming, modernize-avoid-c-arrays)
51 const char *ARCHIVE_SPLIT = "!/";
52 
53 const std::array<uint8_t, File::MAGIC_SIZE> File::MAGIC {'P', 'A', 'N', 'D', 'A', '\0', '\0', '\0'};
54 
55 // Name anonymous maps for perfing tools finding symbol file correctly.
56 // NOLINTNEXTLINE(readability-identifier-naming, modernize-avoid-c-arrays)
57 const char *ANONMAPNAME_PERFIX = "panda-";
58 
GetProt(panda_file::File::OpenMode mode)59 static uint32_t GetProt(panda_file::File::OpenMode mode)
60 {
61     uint32_t prot = os::mem::MMAP_PROT_READ;
62     if (mode == File::READ_WRITE) {
63         prot |= os::mem::MMAP_PROT_WRITE;
64     }
65     return prot;
66 }
67 
68 class AnonMemSet {
69 public:
70     using MemNameSet = std::map<std::string, std::string>;
71     using InsertResult = std::map<std::string, std::string>::iterator;
72 
GetInstance()73     static AnonMemSet &GetInstance()
74     {
75         static AnonMemSet anon_mem_set;
76         return anon_mem_set;
77     }
78 
Insert(const std::string & file_name,const std::string & anon_mem_name)79     InsertResult Insert(const std::string &file_name, const std::string &anon_mem_name)
80     {
81         return mem_name_set_.emplace(file_name, anon_mem_name).first;
82     }
83 
Remove(const std::string & file_name)84     void Remove(const std::string &file_name)
85     {
86         auto it = mem_name_set_.find(file_name);
87         if (it != mem_name_set_.end()) {
88             mem_name_set_.erase(it);
89         }
90     }
91 
92 private:
93     MemNameSet mem_name_set_;
94 };
95 
OpenPandaFileOrZip(std::string_view location,panda_file::File::OpenMode open_mode)96 std::unique_ptr<const File> OpenPandaFileOrZip(std::string_view location, panda_file::File::OpenMode open_mode)
97 {
98     std::string_view archive_filename = ARCHIVE_FILENAME;
99     std::size_t archive_split_index = location.find(ARCHIVE_SPLIT);
100     if (archive_split_index != std::string::npos) {
101         archive_filename = location.substr(archive_split_index + 2);  // 2 - archive split size
102         location = location.substr(0, archive_split_index);
103     }
104 
105     return OpenPandaFile(location, archive_filename, open_mode);
106 }
107 
108 // NOLINTNEXTLINE(google-runtime-references)
OpenPandaFileFromZipErrorHandler(ZipArchiveHandle & handle)109 void OpenPandaFileFromZipErrorHandler(ZipArchiveHandle &handle)
110 {
111     if (handle != nullptr) {
112         if (panda::CloseArchiveFile(handle) != ZIPARCHIVE_OK) {
113             LOG(ERROR, PANDAFILE) << "CloseArchiveFile failed!";
114         }
115     }
116 }
117 
OpenPandaFileFromZipFile(ZipArchiveHandle & handle,std::string_view location,EntryFileStat & entry,std::string_view archive_name)118 std::unique_ptr<const panda_file::File> OpenPandaFileFromZipFile(ZipArchiveHandle &handle, std::string_view location,
119                                                                  EntryFileStat &entry, std::string_view archive_name)
120 {
121     uint32_t uncompressed_length = entry.GetUncompressedSize();
122     if (uncompressed_length == 0) {
123         CloseCurrentFile(handle);
124         OpenPandaFileFromZipErrorHandler(handle);
125         LOG(ERROR, PANDAFILE) << "Panda file has zero length!";
126         return nullptr;
127     }
128 
129     size_t size_to_mmap = AlignUp(uncompressed_length, panda::os::mem::GetPageSize());
130     void *mem = os::mem::MapRWAnonymousRaw(size_to_mmap, false);
131     if (mem == nullptr) {
132         CloseCurrentFile(handle);
133         OpenPandaFileFromZipErrorHandler(handle);
134         LOG(ERROR, PANDAFILE) << "Can't mmap anonymous!";
135         return nullptr;
136     }
137     os::mem::BytePtr ptr(reinterpret_cast<std::byte *>(mem), size_to_mmap, os::mem::MmapDeleter);
138     std::stringstream ss;
139     ss << ANONMAPNAME_PERFIX << archive_name << " extracted in memory from " << location;
140     auto it = AnonMemSet::GetInstance().Insert(std::string(location), ss.str());
141     auto ret = os::mem::TagAnonymousMemory(reinterpret_cast<void *>(ptr.Get()), size_to_mmap, it->second.c_str());
142     if (ret.has_value()) {
143         CloseCurrentFile(handle);
144         OpenPandaFileFromZipErrorHandler(handle);
145         LOG(ERROR, PANDAFILE) << "Can't tag mmap anonymous!";
146         return nullptr;
147     }
148 
149     auto extract_error = ExtractToMemory(handle, reinterpret_cast<uint8_t *>(ptr.Get()), size_to_mmap);
150     if (extract_error != 0) {
151         CloseCurrentFile(handle);
152         OpenPandaFileFromZipErrorHandler(handle);
153         LOG(ERROR, PANDAFILE) << "Can't extract!";
154         return nullptr;
155     }
156 
157     os::mem::ConstBytePtr ConstPtr = ptr.ToConst();
158     return panda_file::File::OpenFromMemory(std::move(ConstPtr), location);
159 }
160 
161 // NOLINTNEXTLINE(google-runtime-references)
HandleArchive(ZipArchiveHandle & handle,FILE * fp,std::string_view location,EntryFileStat & entry,std::string_view archive_filename,panda_file::File::OpenMode open_mode)162 std::unique_ptr<const panda_file::File> HandleArchive(ZipArchiveHandle &handle, FILE *fp, std::string_view location,
163                                                       EntryFileStat &entry, std::string_view archive_filename,
164                                                       panda_file::File::OpenMode open_mode)
165 {
166     std::unique_ptr<const panda_file::File> file;
167     // compressed or not 4 aligned, use anonymous memory
168     if (entry.IsCompressed() || (entry.GetOffset() & 0x3U) != 0) {
169         file = OpenPandaFileFromZipFile(handle, location, entry, archive_filename);
170     } else {
171         LOG(INFO, PANDAFILE) << "Pandafile is uncompressed and 4 bytes aligned";
172         file = panda_file::File::OpenUncompressedArchive(fileno(fp), location, entry.GetUncompressedSize(),
173                                                          entry.GetOffset(), open_mode);
174     }
175     return file;
176 }
177 
178 // CODECHECK-NOLINTNEXTLINE(C_RULE_ID_FUNCTION_SIZE)
OpenPandaFile(std::string_view location,std::string_view archive_filename,panda_file::File::OpenMode open_mode)179 std::unique_ptr<const panda_file::File> OpenPandaFile(std::string_view location, std::string_view archive_filename,
180                                                       panda_file::File::OpenMode open_mode)
181 {
182     trace::ScopedTrace scoped_trace("Open panda file " + std::string(location));
183     uint32_t magic;
184 
185 #ifdef PANDA_TARGET_WINDOWS
186     constexpr char const *mode = "rb";
187 #else
188     constexpr char const *mode = "rbe";
189 #endif
190 
191     FILE *fp = fopen(std::string(location).c_str(), mode);
192     if (fp == nullptr) {
193         LOG(ERROR, PANDAFILE) << "Can't fopen location: " << location;
194         return nullptr;
195     }
196     fseek(fp, 0, SEEK_SET);
197     if (fread(&magic, sizeof(magic), 1, fp) != 1) {
198         fclose(fp);
199         LOG(ERROR, PANDAFILE) << "Can't read from file!(magic) " << location;
200         return nullptr;
201     }
202     fseek(fp, 0, SEEK_SET);
203     std::unique_ptr<const panda_file::File> file;
204     if (IsZipMagic(magic)) {
205         // Open Zipfile and do the extraction.
206         ZipArchiveHandle zipfile = nullptr;
207         auto open_error = OpenArchiveFile(zipfile, fp);
208         if (open_error != ZIPARCHIVE_OK) {
209             LOG(ERROR, PANDAFILE) << "Can't open archive " << location;
210             fclose(fp);
211             return nullptr;
212         }
213         bool try_default = archive_filename.empty();
214         if (!try_default) {
215             if (LocateFile(zipfile, archive_filename.data()) != ZIPARCHIVE_OK) {
216                 LOG(INFO, PANDAFILE) << "Can't find entry with name '" << archive_filename << "', will try "
217                                      << ARCHIVE_FILENAME;
218                 try_default = true;
219             }
220         }
221         if (try_default) {
222             if (LocateFile(zipfile, ARCHIVE_FILENAME) != ZIPARCHIVE_OK) {
223                 OpenPandaFileFromZipErrorHandler(zipfile);
224                 LOG(ERROR, PANDAFILE) << "Can't find entry with " << ARCHIVE_FILENAME;
225                 fclose(fp);
226                 return nullptr;
227             }
228         }
229         EntryFileStat entry = EntryFileStat();
230         if (GetCurrentFileInfo(zipfile, &entry) != ZIPARCHIVE_OK) {
231             OpenPandaFileFromZipErrorHandler(zipfile);
232             LOG(ERROR, PANDAFILE) << "GetCurrentFileInfo error";
233             fclose(fp);
234             return nullptr;
235         }
236         if (OpenCurrentFile(zipfile) != ZIPARCHIVE_OK) {
237             CloseCurrentFile(zipfile);
238             OpenPandaFileFromZipErrorHandler(zipfile);
239             LOG(ERROR, PANDAFILE) << "Can't OpenCurrentFile!";
240             fclose(fp);
241             return nullptr;
242         }
243         GetCurrentFileOffset(zipfile, &entry);
244         file = HandleArchive(zipfile, fp, location, entry, archive_filename, open_mode);
245         CloseCurrentFile(zipfile);
246         if (panda::CloseArchiveFile(zipfile) != 0) {
247             LOG(ERROR, PANDAFILE) << "CloseArchive failed!";
248             fclose(fp);
249             return nullptr;
250         }
251     } else {
252         file = panda_file::File::Open(location, open_mode);
253     }
254     fclose(fp);
255     return file;
256 }
257 
OpenPandaFileFromMemory(const void * buffer,size_t size)258 std::unique_ptr<const File> OpenPandaFileFromMemory(const void *buffer, size_t size)
259 {
260     size_t size_to_mmap = AlignUp(size, panda::os::mem::GetPageSize());
261     void *mem = os::mem::MapRWAnonymousRaw(size_to_mmap, false);
262     if (mem == nullptr) {
263         return nullptr;
264     }
265 
266     if (memcpy_s(mem, size_to_mmap, buffer, size) != EOK) {
267         PLOG(ERROR, PANDAFILE) << "Failed to copy buffer into mem'";
268     }
269 
270     os::mem::ConstBytePtr ptr(reinterpret_cast<std::byte *>(mem), size_to_mmap, os::mem::MmapDeleter);
271     if (ptr.Get() == nullptr) {
272         PLOG(ERROR, PANDAFILE) << "Failed to open panda file from memory'";
273         return nullptr;
274     }
275 
276     std::hash<void *> hash;
277     return panda_file::File::OpenFromMemory(std::move(ptr), std::to_string(hash(mem)));
278 }
279 
280 class ClassIdxIterator {
281 public:
282     using value_type = const uint8_t *;
283     using difference_type = std::ptrdiff_t;
284     using pointer = uint32_t *;
285     using reference = uint32_t &;
286     using iterator_category = std::random_access_iterator_tag;
287 
ClassIdxIterator(const File & file,const Span<const uint32_t> & span,size_t idx)288     ClassIdxIterator(const File &file, const Span<const uint32_t> &span, size_t idx)
289         : file_(file), span_(span), idx_(idx)
290     {
291     }
292 
293     ClassIdxIterator(const ClassIdxIterator &other) = default;
294     ClassIdxIterator(ClassIdxIterator &&other) = default;
295     ~ClassIdxIterator() = default;
296 
operator =(const ClassIdxIterator & other)297     ClassIdxIterator &operator=(const ClassIdxIterator &other)
298     {
299         if (&other != this) {
300             idx_ = other.idx_;
301         }
302 
303         return *this;
304     }
305 
operator =(ClassIdxIterator && other)306     ClassIdxIterator &operator=(ClassIdxIterator &&other) noexcept
307     {
308         idx_ = other.idx_;
309         return *this;
310     }
311 
operator +=(size_t n)312     ClassIdxIterator &operator+=(size_t n)
313     {
314         idx_ += n;
315         return *this;
316     }
317 
operator -=(size_t n)318     ClassIdxIterator &operator-=(size_t n)
319     {
320         idx_ -= n;
321         return *this;
322     }
323 
operator ++()324     ClassIdxIterator &operator++()
325     {
326         ++idx_;
327         return *this;
328     }
329 
operator --()330     ClassIdxIterator &operator--()
331     {
332         --idx_;
333         return *this;
334     }
335 
operator -(const ClassIdxIterator & other) const336     difference_type operator-(const ClassIdxIterator &other) const
337     {
338         return idx_ - other.idx_;
339     }
340 
operator *() const341     value_type operator*() const
342     {
343         uint32_t id = span_[idx_];
344         return file_.GetStringData(File::EntityId(id)).data;
345     }
346 
operator ==(const ClassIdxIterator & other) const347     bool operator==(const ClassIdxIterator &other) const
348     {
349         return span_.cbegin() == other.span_.cbegin() && span_.cend() == other.span_.cend() && idx_ == other.idx_;
350     }
351 
operator !=(const ClassIdxIterator & other) const352     bool operator!=(const ClassIdxIterator &other) const
353     {
354         return !(*this == other);
355     }
356 
IsValid() const357     bool IsValid() const
358     {
359         return idx_ < span_.Size();
360     }
361 
GetId() const362     uint32_t GetId() const
363     {
364         return span_[idx_];
365     }
366 
Begin(const File & file,const Span<const uint32_t> & span)367     static ClassIdxIterator Begin(const File &file, const Span<const uint32_t> &span)
368     {
369         return ClassIdxIterator(file, span, 0);
370     }
371 
End(const File & file,const Span<const uint32_t> & span)372     static ClassIdxIterator End(const File &file, const Span<const uint32_t> &span)
373     {
374         return ClassIdxIterator(file, span, span.Size());
375     }
376 
377 private:
378     const File &file_;
379     const Span<const uint32_t> &span_;
380     size_t idx_;
381 };
382 
ReadAndCheckMagic(os::file::File file)383 static bool ReadAndCheckMagic(os::file::File file)
384 {
385     std::array<uint8_t, File::MAGIC_SIZE> buf {};
386     if (!file.ReadAll(&buf[0], buf.size())) {
387         return false;
388     }
389 
390     return buf == File::MAGIC;
391 }
392 
File(std::string filename,os::mem::ConstBytePtr && base)393 File::File(std::string filename, os::mem::ConstBytePtr &&base)
394     : FILENAME(std::move(filename)),
395       FILENAME_HASH(CalcFilenameHash(FILENAME)),
396       base_(std::forward<os::mem::ConstBytePtr>(base)),
397       panda_cache_(std::make_unique<PandaCache>()),
398       UNIQ_ID(GetHash32(reinterpret_cast<const uint8_t *>(GetHeader()), sizeof(Header) / 2U))
399 {
400 }
401 
~File()402 File::~File()
403 {
404     AnonMemSet::GetInstance().Remove(FILENAME);
405 }
406 
VersionToString(const std::array<uint8_t,File::VERSION_SIZE> & array)407 inline std::string VersionToString(const std::array<uint8_t, File::VERSION_SIZE> &array)
408 {
409     std::stringstream ss;
410 
411     for (size_t i = 0; i < File::VERSION_SIZE - 1; ++i) {
412         ss << static_cast<int>(array[i]);
413         ss << ".";
414     }
415     ss << static_cast<int>(array[File::VERSION_SIZE - 1]);
416 
417     return ss.str();
418 }
419 
420 /* static */
Open(std::string_view filename,OpenMode open_mode)421 std::unique_ptr<const File> File::Open(std::string_view filename, OpenMode open_mode)
422 {
423     trace::ScopedTrace scoped_trace("Open panda file " + std::string(filename));
424     os::file::File file = os::file::Open(filename, os::file::Mode::READONLY);
425 
426     if (!file.IsValid()) {
427         PLOG(ERROR, PANDAFILE) << "Failed to open panda file '" << filename << "'";
428         return nullptr;
429     }
430 
431     os::file::FileHolder fh_holder(file);
432 
433     auto res = file.GetFileSize();
434 
435     if (!res) {
436         PLOG(ERROR, PANDAFILE) << "Failed to get size of panda file '" << filename << "'";
437         return nullptr;
438     }
439 
440     size_t size = res.Value();
441 
442     if (size < sizeof(File::Header) || !ReadAndCheckMagic(file)) {
443         LOG(ERROR, PANDAFILE) << "Invalid panda file '" << filename << "'";
444         return nullptr;
445     }
446 
447     uint32_t checksum = 0;
448     if (!file.ReadAll(&checksum, sizeof(uint32_t))) {
449         LOG(ERROR, PANDAFILE) << "Failed to read checksum of panda file '" << filename << "'";
450         return nullptr;
451     }
452 
453     std::array<uint8_t, File::VERSION_SIZE> buf {};
454     if (!file.ReadAll(&buf[0], buf.size())) {
455         return nullptr;
456     }
457     if (buf < minVersion || buf > version) {
458         LOG(ERROR, PANDAFILE) << "Unable to open file '" << filename
459                               << "' with bytecode version "  // CODECHECK-NOLINTNEXTLINE(C_RULE_ID_INDENT_CHECK)
460                               << VersionToString(buf);
461         if (buf < minVersion) {
462             LOG(ERROR, PANDAFILE)
463                 << "Minimum supported version is "  // CODECHECK-NOLINTNEXTLINE(C_RULE_ID_INDENT_CHECK)
464                 << VersionToString(minVersion);
465         } else {
466             LOG(ERROR, PANDAFILE)
467                 << "Maximum supported version is "  // CODECHECK-NOLINTNEXTLINE(C_RULE_ID_INDENT_CHECK)
468                 << VersionToString(version);
469         }
470         return nullptr;
471     }
472 
473     os::mem::ConstBytePtr ptr = os::mem::MapFile(file, GetProt(open_mode), os::mem::MMAP_FLAG_PRIVATE, size).ToConst();
474     if (ptr.Get() == nullptr) {
475         PLOG(ERROR, PANDAFILE) << "Failed to map panda file '" << filename << "'";
476         return nullptr;
477     }
478 
479     // CODECHECK-NOLINTNEXTLINE(CPP_RULE_ID_SMARTPOINTER_INSTEADOF_ORIGINPOINTER, CPP_RULE_ID_NO_USE_NEW_UNIQUE_PTR)
480     return std::unique_ptr<File>(new File(filename.data(), std::move(ptr)));
481 }
482 
OpenUncompressedArchive(int fd,const std::string_view & filename,size_t size,uint32_t offset,OpenMode open_mode)483 std::unique_ptr<const File> File::OpenUncompressedArchive(int fd, const std::string_view &filename, size_t size,
484                                                           uint32_t offset, OpenMode open_mode)
485 {
486     trace::ScopedTrace scoped_trace("Open panda file " + std::string(filename));
487     auto file = os::file::File(fd);
488     if (!file.IsValid()) {
489         PLOG(ERROR, PANDAFILE) << "OpenUncompressedArchive: Failed to open panda file '" << filename << "'";
490         return nullptr;
491     }
492 
493     if (size < sizeof(File::Header)) {
494         LOG(ERROR, PANDAFILE) << "Invalid panda file size '" << filename << "'";
495         return nullptr;
496     }
497     LOG(DEBUG, PANDAFILE) << " size=" << size << " offset=" << offset << " " << filename;
498 
499     os::mem::ConstBytePtr ptr =
500         os::mem::MapFile(file, GetProt(open_mode), os::mem::MMAP_FLAG_PRIVATE, size, offset).ToConst();
501     if (ptr.Get() == nullptr) {
502         PLOG(ERROR, PANDAFILE) << "Failed to map panda file '" << filename << "'";
503         return nullptr;
504     }
505     if (!CheckHeader(ptr, filename)) {
506         return nullptr;
507     }
508 
509     // CODECHECK-NOLINTNEXTLINE(CPP_RULE_ID_SMARTPOINTER_INSTEADOF_ORIGINPOINTER, CPP_RULE_ID_NO_USE_NEW_UNIQUE_PTR)
510     return std::unique_ptr<File>(new File(filename.data(), std::move(ptr)));
511 }
512 
CheckHeader(const os::mem::ConstBytePtr & ptr,const std::string_view & filename)513 bool CheckHeader(const os::mem::ConstBytePtr &ptr, const std::string_view &filename)
514 {
515     auto header = reinterpret_cast<const File::Header *>(ptr.Get());
516     if (header->magic != File::MAGIC) {
517         LOG(ERROR, PANDAFILE) << "Invalid panda file '" << filename << "'";
518         return false;
519     }
520 
521     return true;
522 }
523 
524 /* static */
OpenFromMemory(os::mem::ConstBytePtr && ptr)525 std::unique_ptr<const File> File::OpenFromMemory(os::mem::ConstBytePtr &&ptr)
526 {
527     auto header = reinterpret_cast<const Header *>(ptr.Get());
528     if (header->magic != File::MAGIC) {
529         LOG(ERROR, PANDAFILE) << "Invalid panda file";
530         return nullptr;
531     }
532 
533     if (header->file_size < sizeof(File::Header)) {
534         LOG(ERROR, PANDAFILE) << "Invalid panda file";
535         return nullptr;
536     }
537 
538     // CODECHECK-NOLINTNEXTLINE(CPP_RULE_ID_SMARTPOINTER_INSTEADOF_ORIGINPOINTER, CPP_RULE_ID_NO_USE_NEW_UNIQUE_PTR)
539     return std::unique_ptr<File>(new File("", std::forward<os::mem::ConstBytePtr>(ptr)));
540 }
541 
542 /* static */
OpenFromMemory(os::mem::ConstBytePtr && ptr,std::string_view filename)543 std::unique_ptr<const File> File::OpenFromMemory(os::mem::ConstBytePtr &&ptr, std::string_view filename)
544 {
545     trace::ScopedTrace scoped_trace("Open panda file from RAM " + std::string(filename));
546     auto header = reinterpret_cast<const Header *>(ptr.Get());
547 
548     if (header->magic != File::MAGIC) {
549         LOG(ERROR, PANDAFILE) << "Invalid panda file";
550         return nullptr;
551     }
552 
553     if (header->file_size < sizeof(File::Header)) {
554         LOG(ERROR, PANDAFILE) << "Invalid panda file '" << filename << "'";
555         return nullptr;
556     }
557 
558     // CODECHECK-NOLINTNEXTLINE(CPP_RULE_ID_SMARTPOINTER_INSTEADOF_ORIGINPOINTER, CPP_RULE_ID_NO_USE_NEW_UNIQUE_PTR)
559     return std::unique_ptr<File>(new File(filename.data(), std::forward<os::mem::ConstBytePtr>(ptr)));
560 }
561 
GetClassId(const uint8_t * mutf8_name) const562 File::EntityId File::GetClassId(const uint8_t *mutf8_name) const
563 {
564     auto class_idx = GetClasses();
565 
566     auto it = std::lower_bound(ClassIdxIterator::Begin(*this, class_idx), ClassIdxIterator::End(*this, class_idx),
567                                mutf8_name, utf::Mutf8Less());
568 
569     if (!it.IsValid()) {
570         return EntityId();
571     }
572 
573     if (utf::CompareMUtf8ToMUtf8(mutf8_name, *it) == 0) {
574         return EntityId(it.GetId());
575     }
576 
577     return EntityId();
578 }
579 
CalcFilenameHash(const std::string & filename)580 uint32_t File::CalcFilenameHash(const std::string &filename)
581 {
582     return GetHash32String(reinterpret_cast<const uint8_t *>(filename.c_str()));
583 }
584 
GetLiteralArraysId() const585 File::EntityId File::GetLiteralArraysId() const
586 {
587     const Header *header = GetHeader();
588     return EntityId(header->literalarray_idx_off);
589 }
590 
591 }  // namespace panda::panda_file
592