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