/* * Copyright (C) 2017 The Android Open Source Project * * 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 TNT_FILAFLAT_UNFLATTENER_H #define TNT_FILAFLAT_UNFLATTENER_H #include #include #include #include namespace filaflat { // Allow read operation from an Unflattenable. All READ operation MUST go through the Unflattener // since it checks boundaries before readind. All read operations return values MUST be verified, // never assume a read will succeed. class UTILS_PUBLIC Unflattener { public: Unflattener() noexcept = default; Unflattener(const uint8_t* src, const uint8_t* end) : mSrc(src), mCursor(src), mEnd(end) { assert_invariant(src && end); } Unflattener(Unflattener const& rhs) = default; ~Unflattener() noexcept = default; bool hasData() const noexcept { return mCursor < mEnd; } inline bool willOverflow(size_t size) const noexcept { return (mCursor + size) > mEnd; } void skipAlignmentPadding() { const uint8_t padSize = (8 - (intptr_t(mCursor) % 8)) % 8; mCursor += padSize; assert_invariant(0 == (intptr_t(mCursor) % 8)); } bool read(bool* b) noexcept { if (willOverflow(1)) { return false; } *b = mCursor[0]; mCursor += 1; return true; } bool read(uint8_t* i) noexcept { if (willOverflow(1)) { return false; } *i = mCursor[0]; mCursor += 1; return true; } bool read(filament::Variant* v) noexcept { return read(&v->key); } bool read(uint16_t* i) noexcept { if (willOverflow(2)) { return false; } *i = 0; *i |= mCursor[0]; *i |= mCursor[1] << 8; mCursor += 2; return true; } bool read(uint32_t* i) noexcept { if (willOverflow(4)) { return false; } *i = 0; *i |= mCursor[0]; *i |= mCursor[1] << 8; *i |= mCursor[2] << 16; *i |= mCursor[3] << 24; mCursor += 4; return true; } bool read(uint64_t* i) noexcept { if (willOverflow(8)) { return false; } *i = 0; *i |= static_cast(mCursor[0]); *i |= static_cast(mCursor[1]) << 8; *i |= static_cast(mCursor[2]) << 16; *i |= static_cast(mCursor[3]) << 24; *i |= static_cast(mCursor[4]) << 32; *i |= static_cast(mCursor[5]) << 40; *i |= static_cast(mCursor[6]) << 48; *i |= static_cast(mCursor[7]) << 56; mCursor += 8; return true; } bool read(utils::CString* s) noexcept; bool read(const char** blob, size_t* size) noexcept; bool read(const char** s) noexcept; bool read(float* f) noexcept { if (willOverflow(4)) { return false; } uint32_t i; i = 0; i |= mCursor[0]; i |= mCursor[1] << 8; i |= mCursor[2] << 16; i |= mCursor[3] << 24; *f = reinterpret_cast(i); mCursor += 4; return true; } const uint8_t* getCursor() const noexcept { return mCursor; } void setCursor(const uint8_t* cursor) noexcept { if (mSrc <= cursor && cursor < mEnd) { mCursor = cursor; } else { mCursor = mEnd; } } private: const uint8_t* mSrc = nullptr; const uint8_t* mCursor = nullptr; const uint8_t* mEnd = nullptr; }; } //namespace filaflat #endif // TNT_FILAFLAT_UNFLATTENER_H