Welcome to mirror list, hosted at ThFree Co, Russian Federation.

decoder_buffer.h « core « draco « src « draco « draco « extern - git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
blob: 0559abbe415eaabae7318b2a828940a4901e5e9b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
// 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 <stdint.h>

#include <cstring>
#include <memory>

#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 <typename T>
  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<int64_t>(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 <typename T>
  bool Peek(T *out_val) {
    const size_t size_to_decode = sizeof(T);
    if (data_size_ < static_cast<int64_t>(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<int64_t>(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<const uint8_t *>(b);
      bit_buffer_end_ = bit_buffer_ + s;
    }

    // Returns number of bits decoded so far.
    inline uint64_t BitsDecoded() const {
      return static_cast<uint64_t>(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<uint64_t>(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<int>(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<int>(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_