/* * Copyright (c) 2023-2024 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef ECMASCRIPT_BASE_FILE_HEADER_H #define ECMASCRIPT_BASE_FILE_HEADER_H #include "ecmascript/base/string_helper.h" #include "ecmascript/log_wrapper.h" #include "utils/bit_utils.h" #include "zlib.h" #include #include #include #include namespace panda::ecmascript::base { class FileHeaderBase { public: static constexpr size_t MAGIC_SIZE = 8; static constexpr size_t VERSION_SIZE = 4; static constexpr uint32_t CHECKSUM_END_OFFSET = MAGIC_SIZE + VERSION_SIZE + sizeof(uint32_t); static constexpr std::array MAGIC = {'P', 'A', 'N', 'D', 'A', '\0', '\0', '\0'}; using VersionType = std::array; static VersionType ToVersion(uint32_t versionNumber) { return bit_cast(ReverseBytes(versionNumber)); } static uint32_t ToVersionNumber(const VersionType &version) { return ReverseBytes(bit_cast(version)); } static bool VerifyVersion(const char *fileDesc, uint32_t currVersion, uint32_t lastVersion, bool strictMatch) { return VerifyVersion(fileDesc, ToVersion(currVersion), ToVersion(lastVersion), strictMatch); } template static std::string ConvToStr(const std::array &array) { std::string ret; for (size_t i = 0; i < size; ++i) { if (i) { ret += "."; } ret += std::to_string(array.at(i)); } return ret; } static std::optional strToVersion(const std::string& version) { std::vector versionNumber = StringHelper::SplitString(version, "."); VersionType formatVersion; if (versionNumber.size() != VERSION_SIZE) { return {}; } for (uint32_t i = 0; i < VERSION_SIZE; i++) { uint32_t result = 0; if (!StringHelper::StrToUInt32(versionNumber[i].c_str(), &result)) { return {}; } formatVersion.at(i) = static_cast(result); } return formatVersion; } static bool VerifyVersionWithoutFile(const VersionType& currVersion, const VersionType& lastVersion) { if (currVersion > lastVersion) { return true; } return false; } bool VerifyVersion(const char *fileDesc, const VersionType &lastVersion, bool strictMatch) const { if (magic_ != MAGIC) { LOG_HOST_TOOL_ERROR << "Magic mismatch, please make sure " << fileDesc << " and the source code are matched"; LOG_ECMA(ERROR) << "magic error, expected magic is " << ConvToStr(MAGIC) << ", but got " << ConvToStr(magic_); return false; } if (!VerifyVersion(fileDesc, version_, lastVersion, strictMatch)) { return false; } LOG_ECMA(DEBUG) << "Magic:" << ConvToStr(magic_) << ", version:" << InternalGetVersion(); return true; } bool CompatibleVerify(const VersionType &expectVersion) const { return version_ >= expectVersion; } VersionType GetVersion() const { return version_; } void SetVersion(VersionType version) { version_ = version; } protected: explicit FileHeaderBase(const VersionType &lastVersion) : magic_(MAGIC), version_(lastVersion) {} static bool VerifyVersion(const char *fileDesc, const VersionType &currVersion, const VersionType &lastVersion, bool strictMatch) { bool matched = strictMatch ? (currVersion == lastVersion) : (currVersion <= lastVersion); if (!matched) { LOG_HOST_TOOL_ERROR << fileDesc << " version error, expected version should be " << (strictMatch ? "equal to " : "less or equal than ") << ConvToStr(lastVersion) << ", but got " << ConvToStr(currVersion); return false; } return true; } std::string InternalGetVersion() const { return ConvToStr(version_); } bool InternalSetVersion(const std::string &version) { std::vector versionNumber = StringHelper::SplitString(version, "."); if (versionNumber.size() != VERSION_SIZE) { LOG_ECMA(ERROR) << "version: " << version << " format error"; return false; } for (uint32_t i = 0; i < VERSION_SIZE; i++) { uint32_t result = 0; if (!StringHelper::StrToUInt32(versionNumber[i].c_str(), &result)) { LOG_ECMA(ERROR) << "version: " << version << " format error"; return false; } version_.at(i) = static_cast(result); } return true; } private: std::array magic_; VersionType version_; }; class FileHeaderElastic : public FileHeaderBase { public: static constexpr uint32_t ENDIAN_VALUE = 0x12345678; void SetChecksum(uint32_t checksum) { checksum_ = checksum; } uint32_t GetChecksum() const { return checksum_; } void SetHeaderSize(uint32_t size) { headerSize_ = size; } uint32_t GetHeaderSize() const { return headerSize_; } void SetFileSize(uint32_t size) { fileSize_ = size; } uint32_t GetFileSize() const { return fileSize_; } uint32_t GetEndianTag() const { return endianTag_; } VersionType GetCompatibleAnVersion() const { return compatibleAnVersion_; } void SetCompatibleAnVersion(VersionType version) { compatibleAnVersion_ = version; } protected: explicit FileHeaderElastic(const VersionType &lastVersion) : FileHeaderBase(lastVersion) {} private: uint32_t checksum_ {0}; uint32_t fileSize_ {0}; uint32_t headerSize_ {0}; uint32_t endianTag_ {ENDIAN_VALUE}; VersionType compatibleAnVersion_; }; } // namespace panda::ecmascript::base #endif // ECMASCRIPT_BASE_FILE_HEADER_H