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