1b1994897Sopenharmony_ci/**
2b1994897Sopenharmony_ci * Copyright (c) 2021-2022 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#ifndef LIBPANDAFILE_HELPERS_H
17b1994897Sopenharmony_ci#define LIBPANDAFILE_HELPERS_H
18b1994897Sopenharmony_ci
19b1994897Sopenharmony_ci#include "macros.h"
20b1994897Sopenharmony_ci#include "utils/bit_helpers.h"
21b1994897Sopenharmony_ci#include "utils/leb128.h"
22b1994897Sopenharmony_ci#include "utils/logger.h"
23b1994897Sopenharmony_ci#include "utils/span.h"
24b1994897Sopenharmony_ci
25b1994897Sopenharmony_ci#include <cstdint>
26b1994897Sopenharmony_ci#include <exception>
27b1994897Sopenharmony_ci#include <limits>
28b1994897Sopenharmony_ci#include <optional>
29b1994897Sopenharmony_ci
30b1994897Sopenharmony_cinamespace panda::panda_file::helpers {
31b1994897Sopenharmony_ci
32b1994897Sopenharmony_ciconstexpr size_t UINT_BYTE2_SHIFT = 8U;
33b1994897Sopenharmony_ciconstexpr size_t UINT_BYTE3_SHIFT = 16U;
34b1994897Sopenharmony_ciconstexpr size_t UINT_BYTE4_SHIFT = 24U;
35b1994897Sopenharmony_ciconstexpr const char *INVALID_SPAN_OFFSET = "Invalid span offset";
36b1994897Sopenharmony_ci
37b1994897Sopenharmony_ciclass FileAccessException : public std::exception {
38b1994897Sopenharmony_cipublic:
39b1994897Sopenharmony_ci    explicit FileAccessException(const char *msg) : msg_(msg) {}
40b1994897Sopenharmony_ci    explicit FileAccessException(const std::string_view &msg) : msg_(msg) {}
41b1994897Sopenharmony_ci    const char *what() const noexcept override
42b1994897Sopenharmony_ci    {
43b1994897Sopenharmony_ci        return msg_.c_str();
44b1994897Sopenharmony_ci    }
45b1994897Sopenharmony_ci
46b1994897Sopenharmony_ciprivate:
47b1994897Sopenharmony_ci    std::string msg_;
48b1994897Sopenharmony_ci};
49b1994897Sopenharmony_ci
50b1994897Sopenharmony_ci#ifndef SUPPORT_KNOWN_EXCEPTION
51b1994897Sopenharmony_ci#define THROW_IF(cond, msg)              \
52b1994897Sopenharmony_ci    if (UNLIKELY(cond)) {                \
53b1994897Sopenharmony_ci        LOG(FATAL, PANDAFILE) << (msg);  \
54b1994897Sopenharmony_ci    }
55b1994897Sopenharmony_ci#else
56b1994897Sopenharmony_ci#define THROW_IF(cond, msg)                       \
57b1994897Sopenharmony_ci    if (UNLIKELY(cond)) {                         \
58b1994897Sopenharmony_ci        throw helpers::FileAccessException(msg);  \
59b1994897Sopenharmony_ci    }
60b1994897Sopenharmony_ci#endif
61b1994897Sopenharmony_ci
62b1994897Sopenharmony_citemplate <size_t width>
63b1994897Sopenharmony_ciinline auto Read(Span<const uint8_t> *sp)
64b1994897Sopenharmony_ci{
65b1994897Sopenharmony_ci    constexpr size_t BYTE_WIDTH = std::numeric_limits<uint8_t>::digits;
66b1994897Sopenharmony_ci    constexpr size_t BITWIDTH = BYTE_WIDTH * width;
67b1994897Sopenharmony_ci    using unsigned_type = panda::helpers::TypeHelperT<BITWIDTH, false>;
68b1994897Sopenharmony_ci
69b1994897Sopenharmony_ci    unsigned_type result = 0;
70b1994897Sopenharmony_ci    THROW_IF(sp->Size() < width, INVALID_SPAN_OFFSET);
71b1994897Sopenharmony_ci
72b1994897Sopenharmony_ci    for (size_t i = 0; i < width; i++) {
73b1994897Sopenharmony_ci        unsigned_type tmp = static_cast<unsigned_type>((*sp)[i]) << (i * BYTE_WIDTH);
74b1994897Sopenharmony_ci        result |= tmp;
75b1994897Sopenharmony_ci    }
76b1994897Sopenharmony_ci    *sp = sp->SubSpan(width);
77b1994897Sopenharmony_ci    return result;
78b1994897Sopenharmony_ci}
79b1994897Sopenharmony_ci
80b1994897Sopenharmony_citemplate <>
81b1994897Sopenharmony_ciinline auto Read<sizeof(uint16_t)>(Span<const uint8_t> *sp)
82b1994897Sopenharmony_ci{
83b1994897Sopenharmony_ci    uint16_t result = 0;
84b1994897Sopenharmony_ci    THROW_IF(sp->Size() < sizeof(uint16_t), INVALID_SPAN_OFFSET);
85b1994897Sopenharmony_ci
86b1994897Sopenharmony_ci    auto *p = sp->data();
87b1994897Sopenharmony_ci    // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
88b1994897Sopenharmony_ci    result = *(p++);
89b1994897Sopenharmony_ci    // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic, hicpp-signed-bitwise)
90b1994897Sopenharmony_ci    result |= static_cast<uint16_t>(*p) << UINT_BYTE2_SHIFT;
91b1994897Sopenharmony_ci    *sp = sp->SubSpan(sizeof(uint16_t));
92b1994897Sopenharmony_ci    return result;
93b1994897Sopenharmony_ci}
94b1994897Sopenharmony_ci
95b1994897Sopenharmony_citemplate <>
96b1994897Sopenharmony_ciinline auto Read<sizeof(uint32_t)>(Span<const uint8_t> *sp)
97b1994897Sopenharmony_ci{
98b1994897Sopenharmony_ci    uint32_t result = 0;
99b1994897Sopenharmony_ci    THROW_IF(sp->Size() < sizeof(uint32_t), INVALID_SPAN_OFFSET);
100b1994897Sopenharmony_ci
101b1994897Sopenharmony_ci    auto *p = sp->data();
102b1994897Sopenharmony_ci    // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
103b1994897Sopenharmony_ci    result = *(p++);
104b1994897Sopenharmony_ci    // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
105b1994897Sopenharmony_ci    result |= static_cast<uint32_t>(*(p++)) << UINT_BYTE2_SHIFT;
106b1994897Sopenharmony_ci    // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
107b1994897Sopenharmony_ci    result |= static_cast<uint32_t>(*(p++)) << UINT_BYTE3_SHIFT;
108b1994897Sopenharmony_ci    // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
109b1994897Sopenharmony_ci    result |= static_cast<uint32_t>(*p) << UINT_BYTE4_SHIFT;
110b1994897Sopenharmony_ci    *sp = sp->SubSpan(sizeof(uint32_t));
111b1994897Sopenharmony_ci    return result;
112b1994897Sopenharmony_ci}
113b1994897Sopenharmony_ci
114b1994897Sopenharmony_citemplate <size_t width>
115b1994897Sopenharmony_ciinline auto Read(Span<const uint8_t> sp)
116b1994897Sopenharmony_ci{
117b1994897Sopenharmony_ci    return Read<width>(&sp);
118b1994897Sopenharmony_ci}
119b1994897Sopenharmony_ci
120b1994897Sopenharmony_ciinline uint32_t ReadULeb128(Span<const uint8_t> *sp)
121b1994897Sopenharmony_ci{
122b1994897Sopenharmony_ci    THROW_IF(sp->Size() == 0U, INVALID_SPAN_OFFSET);
123b1994897Sopenharmony_ci
124b1994897Sopenharmony_ci    uint32_t result;
125b1994897Sopenharmony_ci    size_t n;
126b1994897Sopenharmony_ci    bool is_full;
127b1994897Sopenharmony_ci    std::tie(result, n, is_full) = leb128::DecodeUnsigned<uint32_t>(sp->data());
128b1994897Sopenharmony_ci    THROW_IF(!is_full || sp->Size() < n, INVALID_SPAN_OFFSET);
129b1994897Sopenharmony_ci    *sp = sp->SubSpan(n);
130b1994897Sopenharmony_ci    return result;
131b1994897Sopenharmony_ci}
132b1994897Sopenharmony_ci
133b1994897Sopenharmony_ciinline void SkipULeb128(Span<const uint8_t> *sp)
134b1994897Sopenharmony_ci{
135b1994897Sopenharmony_ci    if (sp->Size() > 0U && (*sp)[0U] <= leb128::PAYLOAD_MASK) {
136b1994897Sopenharmony_ci        *sp = sp->SubSpan(1U);
137b1994897Sopenharmony_ci        return;
138b1994897Sopenharmony_ci    }
139b1994897Sopenharmony_ci
140b1994897Sopenharmony_ci    if (sp->Size() > 1U && (*sp)[1U] <= leb128::PAYLOAD_MASK) {
141b1994897Sopenharmony_ci        *sp = sp->SubSpan(2U);
142b1994897Sopenharmony_ci        return;
143b1994897Sopenharmony_ci    }
144b1994897Sopenharmony_ci
145b1994897Sopenharmony_ci    if (sp->Size() > 2U && (*sp)[2U] <= leb128::PAYLOAD_MASK) {
146b1994897Sopenharmony_ci        *sp = sp->SubSpan(3U);
147b1994897Sopenharmony_ci        return;
148b1994897Sopenharmony_ci    }
149b1994897Sopenharmony_ci
150b1994897Sopenharmony_ci    if (sp->Size() > 3U && (*sp)[3U] <= leb128::PAYLOAD_MASK) {
151b1994897Sopenharmony_ci        *sp = sp->SubSpan(4U);
152b1994897Sopenharmony_ci    }
153b1994897Sopenharmony_ci}
154b1994897Sopenharmony_ci
155b1994897Sopenharmony_ciinline int32_t ReadLeb128(Span<const uint8_t> *sp)
156b1994897Sopenharmony_ci{
157b1994897Sopenharmony_ci    uint32_t result;
158b1994897Sopenharmony_ci    size_t n;
159b1994897Sopenharmony_ci    bool is_full;
160b1994897Sopenharmony_ci    std::tie(result, n, is_full) = leb128::DecodeSigned<int32_t>(sp->data());
161b1994897Sopenharmony_ci    THROW_IF(!is_full || sp->Size() < n, INVALID_SPAN_OFFSET);
162b1994897Sopenharmony_ci    *sp = sp->SubSpan(n);
163b1994897Sopenharmony_ci    return result;
164b1994897Sopenharmony_ci}
165b1994897Sopenharmony_ci
166b1994897Sopenharmony_citemplate <size_t alignment>
167b1994897Sopenharmony_ciinline const uint8_t *Align(const uint8_t *ptr)
168b1994897Sopenharmony_ci{
169b1994897Sopenharmony_ci    auto intptr = reinterpret_cast<uintptr_t>(ptr);
170b1994897Sopenharmony_ci    uintptr_t aligned = (intptr - 1U + alignment) & -alignment;
171b1994897Sopenharmony_ci    return reinterpret_cast<const uint8_t *>(aligned);
172b1994897Sopenharmony_ci}
173b1994897Sopenharmony_ci
174b1994897Sopenharmony_citemplate <size_t alignment, class T>
175b1994897Sopenharmony_ciinline T Align(T n)
176b1994897Sopenharmony_ci{
177b1994897Sopenharmony_ci    return (n - 1U + alignment) & -alignment;
178b1994897Sopenharmony_ci}
179b1994897Sopenharmony_ci
180b1994897Sopenharmony_citemplate <class T, class E>
181b1994897Sopenharmony_ciinline std::optional<T> GetOptionalTaggedValue(Span<const uint8_t> sp, E tag, Span<const uint8_t> *next)
182b1994897Sopenharmony_ci{
183b1994897Sopenharmony_ci    // NB! This is a workaround for https://gcc.gnu.org/bugzilla/show_bug.cgi?id=80635
184b1994897Sopenharmony_ci    // which fails Release builds for GCC 8 and 9.
185b1994897Sopenharmony_ci    std::optional<T> novalue = {};
186b1994897Sopenharmony_ci    if (UNLIKELY(sp.Size() == 0U)) {
187b1994897Sopenharmony_ci        return novalue;
188b1994897Sopenharmony_ci    }
189b1994897Sopenharmony_ci
190b1994897Sopenharmony_ci    if (sp[0] == static_cast<uint8_t>(tag)) {
191b1994897Sopenharmony_ci        sp = sp.SubSpan(1);
192b1994897Sopenharmony_ci        T value = static_cast<T>(Read<sizeof(T)>(&sp));
193b1994897Sopenharmony_ci        *next = sp;
194b1994897Sopenharmony_ci        return value;
195b1994897Sopenharmony_ci    }
196b1994897Sopenharmony_ci    *next = sp;
197b1994897Sopenharmony_ci
198b1994897Sopenharmony_ci    return novalue;
199b1994897Sopenharmony_ci}
200b1994897Sopenharmony_ci
201b1994897Sopenharmony_citemplate <class T, class E, class Callback>
202b1994897Sopenharmony_ciinline void EnumerateTaggedValues(Span<const uint8_t> sp, E tag, Callback cb, Span<const uint8_t> *next)
203b1994897Sopenharmony_ci{
204b1994897Sopenharmony_ci    while (sp.Size() > 0U && sp[0] == static_cast<uint8_t>(tag)) {
205b1994897Sopenharmony_ci        sp = sp.SubSpan(1);
206b1994897Sopenharmony_ci        T value(Read<sizeof(T)>(&sp));
207b1994897Sopenharmony_ci        cb(value);
208b1994897Sopenharmony_ci    }
209b1994897Sopenharmony_ci
210b1994897Sopenharmony_ci    if (next == nullptr) {
211b1994897Sopenharmony_ci        return;
212b1994897Sopenharmony_ci    }
213b1994897Sopenharmony_ci
214b1994897Sopenharmony_ci    *next = sp;
215b1994897Sopenharmony_ci}
216b1994897Sopenharmony_ci
217b1994897Sopenharmony_citemplate <class T, class E, class Callback>
218b1994897Sopenharmony_ciinline bool EnumerateTaggedValuesWithEarlyStop(Span<const uint8_t> sp, E tag, Callback cb)
219b1994897Sopenharmony_ci{
220b1994897Sopenharmony_ci    while (sp.Size() > 0U && sp[0] == static_cast<uint8_t>(tag)) {
221b1994897Sopenharmony_ci        sp = sp.SubSpan(1);
222b1994897Sopenharmony_ci        T value(Read<sizeof(T)>(&sp));
223b1994897Sopenharmony_ci        if (cb(value)) {
224b1994897Sopenharmony_ci            return true;
225b1994897Sopenharmony_ci        }
226b1994897Sopenharmony_ci    }
227b1994897Sopenharmony_ci
228b1994897Sopenharmony_ci    return false;
229b1994897Sopenharmony_ci}
230b1994897Sopenharmony_ci
231b1994897Sopenharmony_ci}  // namespace panda::panda_file::helpers
232b1994897Sopenharmony_ci
233b1994897Sopenharmony_ci#endif  // LIBPANDAFILE_HELPERS_H
234