1/*
2 * Copyright (c) 2023-2024 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#ifndef ECMASCRIPT_BASE_FILE_HEADER_H
17#define ECMASCRIPT_BASE_FILE_HEADER_H
18
19#include "ecmascript/base/string_helper.h"
20#include "ecmascript/log_wrapper.h"
21#include "utils/bit_utils.h"
22#include "zlib.h"
23
24#include <array>
25#include <optional>
26#include <stddef.h>
27#include <stdint.h>
28
29namespace panda::ecmascript::base {
30class FileHeaderBase {
31public:
32    static constexpr size_t MAGIC_SIZE = 8;
33    static constexpr size_t VERSION_SIZE = 4;
34    static constexpr uint32_t CHECKSUM_END_OFFSET = MAGIC_SIZE + VERSION_SIZE + sizeof(uint32_t);
35    static constexpr std::array<uint8_t, MAGIC_SIZE> MAGIC = {'P', 'A', 'N', 'D', 'A', '\0', '\0', '\0'};
36    using VersionType = std::array<uint8_t, VERSION_SIZE>;
37
38    static VersionType ToVersion(uint32_t versionNumber)
39    {
40        return bit_cast<VersionType>(ReverseBytes(versionNumber));
41    }
42
43    static uint32_t ToVersionNumber(const VersionType &version)
44    {
45        return ReverseBytes(bit_cast<uint32_t>(version));
46    }
47
48    static bool VerifyVersion(const char *fileDesc, uint32_t currVersion, uint32_t lastVersion, bool strictMatch)
49    {
50        return VerifyVersion(fileDesc, ToVersion(currVersion), ToVersion(lastVersion), strictMatch);
51    }
52
53    template <size_t size>
54    static std::string ConvToStr(const std::array<uint8_t, size> &array)
55    {
56        std::string ret;
57        for (size_t i = 0; i < size; ++i) {
58            if (i) {
59                ret += ".";
60            }
61            ret += std::to_string(array.at(i));
62        }
63        return ret;
64    }
65
66    static std::optional<VersionType> strToVersion(const std::string& version)
67    {
68        std::vector<std::string> versionNumber = StringHelper::SplitString(version, ".");
69        VersionType formatVersion;
70        if (versionNumber.size() != VERSION_SIZE) {
71            return {};
72        }
73        for (uint32_t i = 0; i < VERSION_SIZE; i++) {
74            uint32_t result = 0;
75            if (!StringHelper::StrToUInt32(versionNumber[i].c_str(), &result)) {
76                return {};
77            }
78            formatVersion.at(i) = static_cast<uint8_t>(result);
79        }
80        return formatVersion;
81    }
82
83    static bool VerifyVersionWithoutFile(const VersionType& currVersion, const VersionType& lastVersion)
84    {
85        if (currVersion > lastVersion) {
86            return true;
87        }
88        return false;
89    }
90
91    bool VerifyVersion(const char *fileDesc, const VersionType &lastVersion, bool strictMatch) const
92    {
93        if (magic_ != MAGIC) {
94            LOG_HOST_TOOL_ERROR << "Magic mismatch, please make sure " << fileDesc
95                                << " and the source code are matched";
96            LOG_ECMA(ERROR) << "magic error, expected magic is " << ConvToStr(MAGIC) << ", but got "
97                            << ConvToStr(magic_);
98            return false;
99        }
100        if (!VerifyVersion(fileDesc, version_, lastVersion, strictMatch)) {
101            return false;
102        }
103        LOG_ECMA(DEBUG) << "Magic:" << ConvToStr(magic_) << ", version:" << InternalGetVersion();
104        return true;
105    }
106
107    bool CompatibleVerify(const VersionType &expectVersion) const
108    {
109        return version_ >= expectVersion;
110    }
111
112    VersionType GetVersion() const
113    {
114        return version_;
115    }
116
117    void SetVersion(VersionType version)
118    {
119        version_ = version;
120    }
121
122protected:
123    explicit FileHeaderBase(const VersionType &lastVersion) : magic_(MAGIC), version_(lastVersion) {}
124
125    static bool VerifyVersion(const char *fileDesc, const VersionType &currVersion, const VersionType &lastVersion,
126                              bool strictMatch)
127    {
128        bool matched = strictMatch ? (currVersion == lastVersion) : (currVersion <= lastVersion);
129        if (!matched) {
130            LOG_HOST_TOOL_ERROR << fileDesc << " version error, expected version should be "
131                                << (strictMatch ? "equal to " : "less or equal than ") << ConvToStr(lastVersion)
132                                << ", but got " << ConvToStr(currVersion);
133            return false;
134        }
135        return true;
136    }
137
138    std::string InternalGetVersion() const
139    {
140        return ConvToStr(version_);
141    }
142
143    bool InternalSetVersion(const std::string &version)
144    {
145        std::vector<std::string> versionNumber = StringHelper::SplitString(version, ".");
146        if (versionNumber.size() != VERSION_SIZE) {
147            LOG_ECMA(ERROR) << "version: " << version << " format error";
148            return false;
149        }
150        for (uint32_t i = 0; i < VERSION_SIZE; i++) {
151            uint32_t result = 0;
152            if (!StringHelper::StrToUInt32(versionNumber[i].c_str(), &result)) {
153                LOG_ECMA(ERROR) << "version: " << version << " format error";
154                return false;
155            }
156            version_.at(i) = static_cast<uint8_t>(result);
157        }
158        return true;
159    }
160
161private:
162    std::array<uint8_t, MAGIC_SIZE> magic_;
163    VersionType version_;
164};
165
166class FileHeaderElastic : public FileHeaderBase {
167public:
168    static constexpr uint32_t ENDIAN_VALUE = 0x12345678;
169    void SetChecksum(uint32_t checksum)
170    {
171        checksum_ = checksum;
172    }
173
174    uint32_t GetChecksum() const
175    {
176        return checksum_;
177    }
178
179    void SetHeaderSize(uint32_t size)
180    {
181        headerSize_ = size;
182    }
183
184    uint32_t GetHeaderSize() const
185    {
186        return headerSize_;
187    }
188
189    void SetFileSize(uint32_t size)
190    {
191        fileSize_ = size;
192    }
193
194    uint32_t GetFileSize() const
195    {
196        return fileSize_;
197    }
198
199    uint32_t GetEndianTag() const
200    {
201        return endianTag_;
202    }
203
204    VersionType GetCompatibleAnVersion() const
205    {
206        return compatibleAnVersion_;
207    }
208
209    void SetCompatibleAnVersion(VersionType version)
210    {
211        compatibleAnVersion_ = version;
212    }
213
214protected:
215    explicit FileHeaderElastic(const VersionType &lastVersion) : FileHeaderBase(lastVersion) {}
216
217private:
218    uint32_t checksum_ {0};
219    uint32_t fileSize_ {0};
220    uint32_t headerSize_ {0};
221    uint32_t endianTag_ {ENDIAN_VALUE};
222    VersionType compatibleAnVersion_;
223};
224}  // namespace panda::ecmascript::base
225#endif  // ECMASCRIPT_BASE_FILE_HEADER_H
226