dec_bit_reader.h (11484B)
1 // Copyright (c) the JPEG XL Project Authors. All rights reserved. 2 // 3 // Use of this source code is governed by a BSD-style 4 // license that can be found in the LICENSE file. 5 6 #ifndef LIB_JXL_DEC_BIT_READER_H_ 7 #define LIB_JXL_DEC_BIT_READER_H_ 8 9 // Bounds-checked bit reader; 64-bit buffer with support for deferred refills 10 // and switching to reading byte-aligned words. 11 12 #include <cstddef> 13 #include <cstdint> 14 #include <cstring> // memcpy 15 16 #ifdef __BMI2__ 17 #include <immintrin.h> 18 #endif 19 20 #include "lib/jxl/base/byte_order.h" 21 #include "lib/jxl/base/common.h" 22 #include "lib/jxl/base/compiler_specific.h" 23 #include "lib/jxl/base/status.h" 24 25 namespace jxl { 26 27 // Reads bits previously written to memory by BitWriter. Uses unaligned 8-byte 28 // little-endian loads. 29 class BitReader { 30 public: 31 static constexpr size_t kMaxBitsPerCall = 56; 32 33 // Constructs an invalid BitReader, to be overwritten before usage. 34 BitReader() 35 : buf_(0), 36 bits_in_buf_(0), 37 next_byte_{nullptr}, 38 end_minus_8_{nullptr}, 39 first_byte_(nullptr) {} 40 BitReader(const BitReader&) = delete; 41 42 // bytes need not be aligned nor padded! 43 template <class ArrayLike> 44 explicit BitReader(const ArrayLike& bytes) 45 : buf_(0), 46 bits_in_buf_(0), 47 next_byte_(bytes.data()), 48 // Assumes first_byte_ >= 8. 49 end_minus_8_(bytes.data() - 8 + bytes.size()), 50 first_byte_(bytes.data()) { 51 Refill(); 52 } 53 ~BitReader() { 54 // Close() must be called before destroying an initialized bit reader. 55 // Invalid bit readers will have a nullptr in first_byte_. 56 JXL_DASSERT(close_called_ || !first_byte_); 57 } 58 59 // Move operator needs to invalidate the other BitReader such that it is 60 // irrelevant if we call Close() on it or not. 61 BitReader& operator=(BitReader&& other) noexcept { 62 // Ensure the current instance was already closed, before we overwrite it 63 // with other. 64 JXL_DASSERT(close_called_ || !first_byte_); 65 66 JXL_DASSERT(!other.close_called_); 67 buf_ = other.buf_; 68 bits_in_buf_ = other.bits_in_buf_; 69 next_byte_ = other.next_byte_; 70 end_minus_8_ = other.end_minus_8_; 71 first_byte_ = other.first_byte_; 72 overread_bytes_ = other.overread_bytes_; 73 close_called_ = other.close_called_; 74 75 other.first_byte_ = nullptr; 76 other.next_byte_ = nullptr; 77 return *this; 78 } 79 BitReader& operator=(const BitReader& other) = delete; 80 81 // For time-critical reads, refills can be shared by multiple reads. 82 // Based on variant 4 (plus bounds-checking), see 83 // fgiesen.wordpress.com/2018/02/20/reading-bits-in-far-too-many-ways-part-2/ 84 JXL_INLINE void Refill() { 85 if (JXL_UNLIKELY(next_byte_ > end_minus_8_)) { 86 BoundsCheckedRefill(); 87 } else { 88 // It's safe to load 64 bits; insert valid (possibly nonzero) bits above 89 // bits_in_buf_. The shift requires bits_in_buf_ < 64. 90 buf_ |= LoadLE64(next_byte_) << bits_in_buf_; 91 92 // Advance by bytes fully absorbed into the buffer. 93 next_byte_ += (63 - bits_in_buf_) >> 3; 94 95 // We absorbed a multiple of 8 bits, so the lower 3 bits of bits_in_buf_ 96 // must remain unchanged, otherwise the next refill's shifted bits will 97 // not align with buf_. Set the three upper bits so the result >= 56. 98 bits_in_buf_ |= 56; 99 JXL_DASSERT(56 <= bits_in_buf_ && bits_in_buf_ < 64); 100 } 101 } 102 103 // Returns the bits that would be returned by Read without calling Advance(). 104 // It is legal to PEEK at more bits than present in the bitstream (required 105 // by Huffman), and those bits will be zero. 106 template <size_t N> 107 JXL_INLINE uint64_t PeekFixedBits() const { 108 static_assert(N <= kMaxBitsPerCall, "Reading too many bits in one call."); 109 JXL_DASSERT(!close_called_); 110 return buf_ & ((1ULL << N) - 1); 111 } 112 113 JXL_INLINE uint64_t PeekBits(size_t nbits) const { 114 JXL_DASSERT(nbits <= kMaxBitsPerCall); 115 JXL_DASSERT(!close_called_); 116 117 // Slightly faster but requires BMI2. It is infeasible to make the many 118 // callers reside between begin/end_target, especially because only the 119 // callers in dec_ans are time-critical. Therefore only enabled if the 120 // entire binary is compiled for (and thus requires) BMI2. 121 #if defined(__BMI2__) && defined(__x86_64__) 122 return _bzhi_u64(buf_, nbits); 123 #else 124 const uint64_t mask = (1ULL << nbits) - 1; 125 return buf_ & mask; 126 #endif 127 } 128 129 // Removes bits from the buffer. Need not match the previous Peek size, but 130 // the buffer must contain at least num_bits (this prevents consuming more 131 // than the total number of bits). 132 JXL_INLINE void Consume(size_t num_bits) { 133 JXL_DASSERT(!close_called_); 134 JXL_DASSERT(bits_in_buf_ >= num_bits); 135 if (JXL_CRASH_ON_ERROR) { 136 // When JXL_CRASH_ON_ERROR is defined, it is a fatal error to read more 137 // bits than available in the stream. A non-zero overread_bytes_ implies 138 // that next_byte_ is already at the end of the stream, so we don't need 139 // to check that. 140 JXL_DASSERT(bits_in_buf_ >= num_bits + overread_bytes_ * kBitsPerByte); 141 } 142 bits_in_buf_ -= num_bits; 143 buf_ >>= num_bits; 144 } 145 146 JXL_INLINE uint64_t ReadBits(size_t nbits) { 147 JXL_DASSERT(!close_called_); 148 Refill(); 149 const uint64_t bits = PeekBits(nbits); 150 Consume(nbits); 151 return bits; 152 } 153 154 template <size_t N> 155 JXL_INLINE uint64_t ReadFixedBits() { 156 JXL_DASSERT(!close_called_); 157 Refill(); 158 const uint64_t bits = PeekFixedBits<N>(); 159 Consume(N); 160 return bits; 161 } 162 163 // Equivalent to calling ReadFixedBits(1) `skip` times, but much faster. 164 // `skip` is typically large. 165 void SkipBits(size_t skip) { 166 JXL_DASSERT(!close_called_); 167 // Buffer is large enough - don't zero buf_ below. 168 if (JXL_UNLIKELY(skip <= bits_in_buf_)) { 169 Consume(skip); 170 return; 171 } 172 173 // First deduct what we can satisfy from the buffer 174 skip -= bits_in_buf_; 175 bits_in_buf_ = 0; 176 // Not enough to call Advance - that may leave some bits in the buffer 177 // which were previously ABOVE bits_in_buf. 178 buf_ = 0; 179 180 // Skip whole bytes 181 const size_t whole_bytes = skip / kBitsPerByte; 182 skip %= kBitsPerByte; 183 if (JXL_UNLIKELY(whole_bytes > 184 static_cast<size_t>(end_minus_8_ + 8 - next_byte_))) { 185 // This is already an overflow condition (skipping past the end of the bit 186 // stream). However if we increase next_byte_ too much we risk overflowing 187 // that value and potentially making it valid again (next_byte_ < end). 188 // This will set next_byte_ to the end of the stream and still consume 189 // some bits in overread_bytes_, however the TotalBitsConsumed() will be 190 // incorrect (still larger than the TotalBytes()). 191 next_byte_ = end_minus_8_ + 8; 192 skip += kBitsPerByte; 193 } else { 194 next_byte_ += whole_bytes; 195 } 196 197 Refill(); 198 Consume(skip); 199 } 200 201 size_t TotalBitsConsumed() const { 202 const size_t bytes_read = static_cast<size_t>(next_byte_ - first_byte_); 203 return (bytes_read + overread_bytes_) * kBitsPerByte - bits_in_buf_; 204 } 205 206 Status JumpToByteBoundary() { 207 const size_t remainder = TotalBitsConsumed() % kBitsPerByte; 208 if (remainder == 0) return true; 209 if (JXL_UNLIKELY(ReadBits(kBitsPerByte - remainder) != 0)) { 210 return JXL_FAILURE("Non-zero padding bits"); 211 } 212 return true; 213 } 214 215 // For interoperability with other bitreaders (for resuming at 216 // non-byte-aligned positions). 217 const uint8_t* FirstByte() const { return first_byte_; } 218 size_t TotalBytes() const { 219 return static_cast<size_t>(end_minus_8_ + 8 - first_byte_); 220 } 221 222 // Returns whether all the bits read so far have been within the input bounds. 223 // When reading past the EOF, the Read*() and Consume() functions return zeros 224 // but flag a failure when calling Close() without checking this function. 225 Status AllReadsWithinBounds() { 226 // Mark up to which point the user checked the out of bounds condition. If 227 // the user handles the condition at higher level (e.g. fetch more bytes 228 // from network, return a custom JXL_FAILURE, ...), Close() should not 229 // output a debug error (which would break tests with JXL_CRASH_ON_ERROR 230 // even when legitimately handling the situation at higher level). This is 231 // used by Bundle::CanRead. 232 checked_out_of_bounds_bits_ = TotalBitsConsumed(); 233 if (TotalBitsConsumed() > TotalBytes() * kBitsPerByte) { 234 return false; 235 } 236 return true; 237 } 238 239 // Close the bit reader and return whether all the previous reads were 240 // successful. Close must be called once. 241 Status Close() { 242 JXL_DASSERT(!close_called_); 243 close_called_ = true; 244 if (!first_byte_) return true; 245 if (TotalBitsConsumed() > checked_out_of_bounds_bits_ && 246 TotalBitsConsumed() > TotalBytes() * kBitsPerByte) { 247 return JXL_FAILURE("Read more bits than available in the bit_reader"); 248 } 249 return true; 250 } 251 252 private: 253 // Separate function avoids inlining this relatively cold code into callers. 254 JXL_NOINLINE void BoundsCheckedRefill() { 255 const uint8_t* end = end_minus_8_ + 8; 256 257 // Read whole bytes until we have [56, 64) bits (same as LoadLE64) 258 for (; bits_in_buf_ < 64 - kBitsPerByte; bits_in_buf_ += kBitsPerByte) { 259 if (next_byte_ >= end) break; 260 buf_ |= static_cast<uint64_t>(*next_byte_++) << bits_in_buf_; 261 } 262 JXL_DASSERT(bits_in_buf_ < 64); 263 264 // Add extra bytes as 0 at the end of the stream in the bit_buffer_. If 265 // these bits are read, Close() will return a failure. 266 size_t extra_bytes = (63 - bits_in_buf_) / kBitsPerByte; 267 overread_bytes_ += extra_bytes; 268 bits_in_buf_ += extra_bytes * kBitsPerByte; 269 270 JXL_DASSERT(bits_in_buf_ < 64); 271 JXL_DASSERT(bits_in_buf_ >= 56); 272 } 273 274 JXL_NOINLINE uint32_t BoundsCheckedReadByteAlignedWord() { 275 if (next_byte_ + 1 < end_minus_8_ + 8) { 276 uint32_t ret = LoadLE16(next_byte_); 277 next_byte_ += 2; 278 return ret; 279 } 280 overread_bytes_ += 2; 281 return 0; 282 } 283 284 uint64_t buf_; 285 size_t bits_in_buf_; // [0, 64) 286 const uint8_t* JXL_RESTRICT next_byte_; 287 const uint8_t* end_minus_8_; // for refill bounds check 288 const uint8_t* first_byte_; // for GetSpan 289 290 // Number of bytes past the end that were loaded into the buf_. These bytes 291 // are not read from memory, but instead assumed 0. It is an error (likely due 292 // to an invalid stream) to Consume() more bits than specified in the range 293 // passed to the constructor. 294 uint64_t overread_bytes_{0}; 295 bool close_called_{false}; 296 297 uint64_t checked_out_of_bounds_bits_{0}; 298 }; 299 300 // Closes a BitReader when the BitReaderScopedCloser goes out of scope. When 301 // closing the bit reader, if the status result was failure it sets this failure 302 // to the passed variable pointer. Typical usage. 303 // 304 // Status ret = true; 305 // { 306 // BitReader reader(...); 307 // BitReaderScopedCloser reader_closer(&reader, &ret); 308 // 309 // // ... code that can return errors here ... 310 // } 311 // // ... more code that doesn't use the BitReader. 312 // return ret; 313 314 class BitReaderScopedCloser { 315 public: 316 BitReaderScopedCloser(BitReader& reader, Status& status) 317 : reader_(&reader), status_(&status) {} 318 ~BitReaderScopedCloser() { 319 if (reader_ != nullptr) { 320 Status close_ret = reader_->Close(); 321 if (!close_ret) *status_ = close_ret; 322 } 323 } 324 BitReaderScopedCloser(const BitReaderScopedCloser&) = delete; 325 326 private: 327 BitReader* reader_; 328 Status* status_; 329 }; 330 331 } // namespace jxl 332 333 #endif // LIB_JXL_DEC_BIT_READER_H_