// Copyright 2016 The Draco Authors. // // 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 DRACO_CORE_DECODER_BUFFER_H_ #define DRACO_CORE_DECODER_BUFFER_H_ #include #include #include #include "draco/core/macros.h" #include "draco/draco_features.h" namespace draco { // Class is a wrapper around input data used by MeshDecoder. It provides a // basic interface for decoding either typed or variable-bit sized data. class DecoderBuffer { public: DecoderBuffer(); DecoderBuffer(const DecoderBuffer &buf) = default; DecoderBuffer &operator=(const DecoderBuffer &buf) = default; // Sets the buffer's internal data. Note that no copy of the input data is // made so the data owner needs to keep the data valid and unchanged for // runtime of the decoder. void Init(const char *data, size_t data_size); // Sets the buffer's internal data. |version| is the Draco bitstream version. void Init(const char *data, size_t data_size, uint16_t version); // Starts decoding a bit sequence. // decode_size must be true if the size of the encoded bit data was included, // during encoding. The size is then returned to out_size. // Returns false on error. bool StartBitDecoding(bool decode_size, uint64_t *out_size); // Ends the decoding of the bit sequence and return to the default // byte-aligned decoding. void EndBitDecoding(); // Decodes up to 32 bits into out_val. Can be called only in between // StartBitDecoding and EndBitDecoding. Otherwise returns false. bool DecodeLeastSignificantBits32(int nbits, uint32_t *out_value) { if (!bit_decoder_active()) { return false; } bit_decoder_.GetBits(nbits, out_value); return true; } // Decodes an arbitrary data type. // Can be used only when we are not decoding a bit-sequence. // Returns false on error. template bool Decode(T *out_val) { if (!Peek(out_val)) { return false; } pos_ += sizeof(T); return true; } bool Decode(void *out_data, size_t size_to_decode) { if (data_size_ < static_cast(pos_ + size_to_decode)) { return false; // Buffer overflow. } memcpy(out_data, (data_ + pos_), size_to_decode); pos_ += size_to_decode; return true; } // Decodes an arbitrary data, but does not advance the reading position. template bool Peek(T *out_val) { const size_t size_to_decode = sizeof(T); if (data_size_ < static_cast(pos_ + size_to_decode)) { return false; // Buffer overflow. } memcpy(out_val, (data_ + pos_), size_to_decode); return true; } bool Peek(void *out_data, size_t size_to_peek) { if (data_size_ < static_cast(pos_ + size_to_peek)) { return false; // Buffer overflow. } memcpy(out_data, (data_ + pos_), size_to_peek); return true; } // Discards #bytes from the input buffer. void Advance(int64_t bytes) { pos_ += bytes; } // Moves the parsing position to a specific offset from the beginning of the // input data. void StartDecodingFrom(int64_t offset) { pos_ = offset; } void set_bitstream_version(uint16_t version) { bitstream_version_ = version; } // Returns the data array at the current decoder position. const char *data_head() const { return data_ + pos_; } int64_t remaining_size() const { return data_size_ - pos_; } int64_t decoded_size() const { return pos_; } bool bit_decoder_active() const { return bit_mode_; } // Returns the bitstream associated with the data. Returns 0 if unknown. uint16_t bitstream_version() const { return bitstream_version_; } private: // Internal helper class to decode bits from a bit buffer. class BitDecoder { public: BitDecoder(); ~BitDecoder(); // Sets the bit buffer to |b|. |s| is the size of |b| in bytes. inline void reset(const void *b, size_t s) { bit_offset_ = 0; bit_buffer_ = static_cast(b); bit_buffer_end_ = bit_buffer_ + s; } // Returns number of bits decoded so far. inline uint64_t BitsDecoded() const { return static_cast(bit_offset_); } // Return number of bits available for decoding inline uint64_t AvailBits() const { return ((bit_buffer_end_ - bit_buffer_) * 8) - bit_offset_; } inline uint32_t EnsureBits(int k) { DRACO_DCHECK_LE(k, 24); DRACO_DCHECK_LE(static_cast(k), AvailBits()); uint32_t buf = 0; for (int i = 0; i < k; ++i) { buf |= PeekBit(i) << i; } return buf; // Okay to return extra bits } inline void ConsumeBits(int k) { bit_offset_ += k; } // Returns |nbits| bits in |x|. inline bool GetBits(int32_t nbits, uint32_t *x) { DRACO_DCHECK_GE(nbits, 0); DRACO_DCHECK_LE(nbits, 32); uint32_t value = 0; for (int32_t bit = 0; bit < nbits; ++bit) { value |= GetBit() << bit; } *x = value; return true; } private: // TODO(fgalligan): Add support for error reporting on range check. // Returns one bit from the bit buffer. inline int GetBit() { const size_t off = bit_offset_; const size_t byte_offset = off >> 3; const int bit_shift = static_cast(off & 0x7); if (bit_buffer_ + byte_offset < bit_buffer_end_) { const int bit = (bit_buffer_[byte_offset] >> bit_shift) & 1; bit_offset_ = off + 1; return bit; } return 0; } inline int PeekBit(int offset) { const size_t off = bit_offset_ + offset; const size_t byte_offset = off >> 3; const int bit_shift = static_cast(off & 0x7); if (bit_buffer_ + byte_offset < bit_buffer_end_) { const int bit = (bit_buffer_[byte_offset] >> bit_shift) & 1; return bit; } return 0; } const uint8_t *bit_buffer_; const uint8_t *bit_buffer_end_; size_t bit_offset_; }; friend class BufferBitCodingTest; const char *data_; int64_t data_size_; // Current parsing position of the decoder. int64_t pos_; BitDecoder bit_decoder_; bool bit_mode_; uint16_t bitstream_version_; }; } // namespace draco #endif // DRACO_CORE_DECODER_BUFFER_H_