/** * Copyright (c) 2021-2025 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 LIBPANDAFILE_HELPERS_H_ #define LIBPANDAFILE_HELPERS_H_ #include "macros.h" #include "utils/bit_helpers.h" #include "utils/leb128.h" #include "utils/logger.h" #include "utils/span.h" #include #include #include namespace ark::panda_file::helpers { constexpr size_t UINT_BYTE2_SHIFT = 8U; constexpr size_t UINT_BYTE3_SHIFT = 16U; constexpr size_t UINT_BYTE4_SHIFT = 24U; template inline auto Read(Span *sp) { constexpr size_t BYTE_WIDTH = std::numeric_limits::digits; constexpr size_t BITWIDTH = BYTE_WIDTH * WIDTH; using UnsignedType = ark::helpers::TypeHelperT; UnsignedType result = 0; for (size_t i = 0; i < WIDTH; i++) { UnsignedType tmp = static_cast((*sp)[i]) << (i * BYTE_WIDTH); result |= tmp; } *sp = sp->SubSpan(WIDTH); return result; } template <> inline auto Read(Span *sp) { auto *p = sp->data(); // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) uint16_t result = *(p++); // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic, hicpp-signed-bitwise) result |= static_cast(*p) << UINT_BYTE2_SHIFT; *sp = sp->SubSpan(sizeof(uint16_t)); return result; } template <> inline auto Read(Span *sp) { auto *p = sp->data(); // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) uint32_t result = *(p++); // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) result |= static_cast(*(p++)) << UINT_BYTE2_SHIFT; // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) result |= static_cast(*(p++)) << UINT_BYTE3_SHIFT; // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) result |= static_cast(*p) << UINT_BYTE4_SHIFT; *sp = sp->SubSpan(sizeof(uint32_t)); return result; } template inline auto Read(Span sp) { return Read(&sp); } inline uint32_t ReadULeb128(Span *sp) { uint32_t result; size_t n; [[maybe_unused]] bool isFull; std::tie(result, n, isFull) = leb128::DecodeUnsigned(sp->data()); if (!isFull) { LOG(FATAL, PANDAFILE) << "ULEB128 decode failed: input truncated or malformed"; } *sp = sp->SubSpan(n); return result; } // CC-OFFNXT(G.FUD.06) solid logic inline void SkipULeb128(Span *sp) { if ((*sp)[0U] <= leb128::PAYLOAD_MASK) { *sp = sp->SubSpan(1U); return; } if ((*sp)[1U] <= leb128::PAYLOAD_MASK) { *sp = sp->SubSpan(2U); return; } if ((*sp)[2U] <= leb128::PAYLOAD_MASK) { *sp = sp->SubSpan(3U); return; } ASSERT((*sp)[3U] <= leb128::PAYLOAD_MASK); *sp = sp->SubSpan(4U); } inline int32_t ReadLeb128(Span *sp) { int32_t result; size_t n; [[maybe_unused]] bool isFull; std::tie(result, n, isFull) = leb128::DecodeSigned(sp->data()); ASSERT(isFull); *sp = sp->SubSpan(n); return result; } template inline const uint8_t *Align(const uint8_t *ptr) { auto intptr = reinterpret_cast(ptr); uintptr_t aligned = (intptr - 1U + ALIGNMENT) & -ALIGNMENT; return reinterpret_cast(aligned); } template inline T Align(T n) { return (n - 1U + ALIGNMENT) & -ALIGNMENT; } template inline std::optional GetOptionalTaggedValue(Span sp, E tag, Span *next) { if (sp[0] == static_cast(tag)) { sp = sp.SubSpan(1); T value = static_cast(Read(&sp)); *next = sp; return value; } *next = sp; // NB! This is a workaround for https://gcc.gnu.org/bugzilla/show_bug.cgi?id=80635 // which fails Release builds for GCC 8 and 9. std::optional novalue = {}; return novalue; } template inline void EnumerateTaggedValues(Span sp, E tag, Callback cb, Span *next) { while (sp[0] == static_cast(tag)) { sp = sp.SubSpan(1); T value(Read(&sp)); cb(value); } if (next == nullptr) { return; } *next = sp; } template inline bool EnumerateTaggedValuesWithEarlyStop(Span sp, E tag, Callback cb) { while (sp[0] == static_cast(tag)) { sp = sp.SubSpan(1); T value(Read(&sp)); if (cb(value)) { return true; } } return false; } } // namespace ark::panda_file::helpers #endif // LIBPANDAFILE_HELPERS_H_