diff --git a/bench/librawspeed/decompressors/UncompressedDecompressorBenchmark.cpp b/bench/librawspeed/decompressors/UncompressedDecompressorBenchmark.cpp index a01906557..edd4f9d25 100644 --- a/bench/librawspeed/decompressors/UncompressedDecompressorBenchmark.cpp +++ b/bench/librawspeed/decompressors/UncompressedDecompressorBenchmark.cpp @@ -22,6 +22,7 @@ #include "adt/Casts.h" #include "adt/Point.h" #include "bench/Common.h" +#include "bitstreams/BitStreams.h" #include "common/Common.h" #include "common/RawImage.h" #include "io/Buffer.h" diff --git a/cmake/Modules/cpu-cache-line-size.cpp b/cmake/Modules/cpu-cache-line-size.cpp index 4e3517a01..cb06406ee 100644 --- a/cmake/Modules/cpu-cache-line-size.cpp +++ b/cmake/Modules/cpu-cache-line-size.cpp @@ -1,3 +1,4 @@ +#include #include #include #include @@ -6,6 +7,10 @@ #include #endif +#if defined(__GLIBC__) +#include +#endif + #if defined(_POSIX_C_SOURCE) && defined(_SC_LEVEL1_DCACHE_LINESIZE) static std::optional get_cachelinesize_from_sysconf() { long val = ::sysconf(_SC_LEVEL1_DCACHE_LINESIZE); diff --git a/cmake/Modules/cpu-large-page-size.cpp b/cmake/Modules/cpu-large-page-size.cpp index 8c7b5a2c2..45d309386 100644 --- a/cmake/Modules/cpu-large-page-size.cpp +++ b/cmake/Modules/cpu-large-page-size.cpp @@ -1,3 +1,4 @@ +#include #include #if defined(__i386__) || defined(__x86_64__) diff --git a/fuzz/librawspeed/decompressors/UncompressedDecompressor.cpp b/fuzz/librawspeed/decompressors/UncompressedDecompressor.cpp index 22c76d81b..1a5cc4325 100644 --- a/fuzz/librawspeed/decompressors/UncompressedDecompressor.cpp +++ b/fuzz/librawspeed/decompressors/UncompressedDecompressor.cpp @@ -22,7 +22,7 @@ #include "MemorySanitizer.h" #include "adt/Casts.h" #include "adt/Point.h" -#include "common/Common.h" +#include "bitstreams/BitStreams.h" #include "common/RawImage.h" #include "common/RawspeedException.h" #include "fuzz/Common.h" @@ -54,6 +54,7 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* Data, size_t Size) { case static_cast(rawspeed::BitOrder::MSB): case static_cast(rawspeed::BitOrder::MSB16): case static_cast(rawspeed::BitOrder::MSB32): + case static_cast(rawspeed::BitOrder::JPEG): return rawspeed::BitOrder(val); default: ThrowRSE("Unknown bit order: %u", val); diff --git a/src/librawspeed/bitstreams/BitStream.h b/src/librawspeed/bitstreams/BitStream.h index c6303b865..07669d4fc 100644 --- a/src/librawspeed/bitstreams/BitStream.h +++ b/src/librawspeed/bitstreams/BitStream.h @@ -25,11 +25,12 @@ #include "adt/Bit.h" #include "adt/Casts.h" #include "adt/Invariant.h" +#include "bitstreams/BitStreams.h" #include namespace rawspeed { -template struct BitStreamTraits; +template struct BitStreamTraits; // simple 64-bit wide cache implementation that acts like a FiFo. // There are two variants: diff --git a/src/librawspeed/bitstreams/BitStreamJPEG.h b/src/librawspeed/bitstreams/BitStreamJPEG.h index ce968a229..c09945b1c 100644 --- a/src/librawspeed/bitstreams/BitStreamJPEG.h +++ b/src/librawspeed/bitstreams/BitStreamJPEG.h @@ -28,9 +28,9 @@ namespace rawspeed { -class BitStreamJPEG; +template <> struct BitStreamTraits final { + static constexpr BitOrder Tag = BitOrder::JPEG; -template <> struct BitStreamTraits final { using StreamFlow = BitStreamCacheRightInLeftOut; static constexpr bool FixedSizeChunks = false; // Stuffing byte... diff --git a/src/librawspeed/bitstreams/BitStreamLSB.h b/src/librawspeed/bitstreams/BitStreamLSB.h index c23ecc4a6..5fde89c28 100644 --- a/src/librawspeed/bitstreams/BitStreamLSB.h +++ b/src/librawspeed/bitstreams/BitStreamLSB.h @@ -28,9 +28,9 @@ namespace rawspeed { -class BitStreamLSB; +template <> struct BitStreamTraits final { + static constexpr BitOrder Tag = BitOrder::LSB; -template <> struct BitStreamTraits final { using StreamFlow = BitStreamCacheLeftInRightOut; static constexpr bool FixedSizeChunks = true; diff --git a/src/librawspeed/bitstreams/BitStreamMSB.h b/src/librawspeed/bitstreams/BitStreamMSB.h index 726d07410..45c3c26c3 100644 --- a/src/librawspeed/bitstreams/BitStreamMSB.h +++ b/src/librawspeed/bitstreams/BitStreamMSB.h @@ -28,9 +28,9 @@ namespace rawspeed { -class BitStreamMSB; +template <> struct BitStreamTraits final { + static constexpr BitOrder Tag = BitOrder::MSB; -template <> struct BitStreamTraits final { using StreamFlow = BitStreamCacheRightInLeftOut; static constexpr bool FixedSizeChunks = true; diff --git a/src/librawspeed/bitstreams/BitStreamMSB16.h b/src/librawspeed/bitstreams/BitStreamMSB16.h index 3d198c305..c194a242c 100644 --- a/src/librawspeed/bitstreams/BitStreamMSB16.h +++ b/src/librawspeed/bitstreams/BitStreamMSB16.h @@ -28,9 +28,9 @@ namespace rawspeed { -class BitStreamMSB16; +template <> struct BitStreamTraits final { + static constexpr BitOrder Tag = BitOrder::MSB16; -template <> struct BitStreamTraits final { using StreamFlow = BitStreamCacheRightInLeftOut; static constexpr bool FixedSizeChunks = true; diff --git a/src/librawspeed/bitstreams/BitStreamMSB32.h b/src/librawspeed/bitstreams/BitStreamMSB32.h index 06591ea69..20ee65c1c 100644 --- a/src/librawspeed/bitstreams/BitStreamMSB32.h +++ b/src/librawspeed/bitstreams/BitStreamMSB32.h @@ -28,9 +28,9 @@ namespace rawspeed { -class BitStreamMSB32; +template <> struct BitStreamTraits final { + static constexpr BitOrder Tag = BitOrder::MSB32; -template <> struct BitStreamTraits final { using StreamFlow = BitStreamCacheRightInLeftOut; static constexpr bool FixedSizeChunks = true; diff --git a/src/librawspeed/bitstreams/BitStreamPosition.h b/src/librawspeed/bitstreams/BitStreamPosition.h new file mode 100644 index 000000000..60c3bd275 --- /dev/null +++ b/src/librawspeed/bitstreams/BitStreamPosition.h @@ -0,0 +1,78 @@ +/* + RawSpeed - RAW file decoder. + + Copyright (C) 2024 Roman Lebedev + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#pragma once + +#include "adt/Casts.h" +#include "adt/Invariant.h" +#include "bitstreams/BitStreams.h" +#include "common/Common.h" + +namespace rawspeed { + +template struct BitStreamTraits; + +template struct BitStreamPosition { + int pos; + int fillLevel; +}; + +template struct ByteStreamPosition { + int bytePos; + int numBitsToSkip; +}; + +template + requires BitStreamTraits::FixedSizeChunks +ByteStreamPosition getAsByteStreamPosition(BitStreamPosition state) { + const int MinByteStepMultiple = BitStreamTraits::MinLoadStepByteMultiple; + + invariant(state.pos >= 0); + invariant(state.pos % MinByteStepMultiple == 0); + invariant(state.fillLevel >= 0); + + auto numBytesRemainingInCache = + implicit_cast(roundUpDivision(state.fillLevel, CHAR_BIT)); + invariant(numBytesRemainingInCache >= 0); + invariant(numBytesRemainingInCache <= state.pos); + + auto numBytesToBacktrack = implicit_cast( + roundUp(numBytesRemainingInCache, MinByteStepMultiple)); + invariant(numBytesToBacktrack >= 0); + invariant(numBytesToBacktrack <= state.pos); + invariant(numBytesToBacktrack % MinByteStepMultiple == 0); + + auto numBitsToBacktrack = CHAR_BIT * numBytesToBacktrack; + invariant(numBitsToBacktrack >= 0); + + ByteStreamPosition res; + invariant(state.pos >= numBytesToBacktrack); + res.bytePos = state.pos - numBytesToBacktrack; + invariant(numBitsToBacktrack >= state.fillLevel); + res.numBitsToSkip = numBitsToBacktrack - state.fillLevel; + + invariant(res.bytePos >= 0); + invariant(res.bytePos <= state.pos); + invariant(res.bytePos % MinByteStepMultiple == 0); + invariant(res.numBitsToSkip >= 0); + return res; +} + +} // namespace rawspeed diff --git a/src/librawspeed/bitstreams/BitStreamer.h b/src/librawspeed/bitstreams/BitStreamer.h index 38f85764d..187270637 100644 --- a/src/librawspeed/bitstreams/BitStreamer.h +++ b/src/librawspeed/bitstreams/BitStreamer.h @@ -43,7 +43,7 @@ template struct BitStreamerReplenisherBase { using size_type = int32_t; using Traits = BitStreamerTraits; - using StreamTraits = BitStreamTraits; + using StreamTraits = BitStreamTraits; Array1DRef input; int pos = 0; @@ -74,7 +74,7 @@ struct BitStreamerForwardSequentialReplenisher final : public BitStreamerReplenisherBase { using Base = BitStreamerReplenisherBase; using Traits = BitStreamerTraits; - using StreamTraits = BitStreamTraits; + using StreamTraits = BitStreamTraits; using Base::BitStreamerReplenisherBase; @@ -138,7 +138,7 @@ class BitStreamer { public: using size_type = int32_t; using Traits = BitStreamerTraits; - using StreamTraits = BitStreamTraits; + using StreamTraits = BitStreamTraits; using Cache = typename StreamTraits::StreamFlow; @@ -278,11 +278,11 @@ class BitStreamer { return getBitsNoFill(nbits); } - // This may be used to skip arbitrarily large number of *bytes*, + // This may be used to skip arbitrarily large number of *bits*, // not limited by the fill level. - void skipBytes(int nbytes) { + void skipManyBits(int nbits) { establishClassInvariants(); - int remainingBitsToSkip = 8 * nbytes; + int remainingBitsToSkip = nbits; for (; remainingBitsToSkip >= Cache::MaxGetBits; remainingBitsToSkip -= Cache::MaxGetBits) { fill(Cache::MaxGetBits); @@ -293,6 +293,14 @@ class BitStreamer { skipBitsNoFill(remainingBitsToSkip); } } + + // This may be used to skip arbitrarily large number of *bytes*, + // not limited by the fill level. + void skipBytes(int nbytes) { + establishClassInvariants(); + int nbits = 8 * nbytes; + skipManyBits(nbits); + } }; } // namespace rawspeed diff --git a/src/librawspeed/bitstreams/BitStreamerJPEG.h b/src/librawspeed/bitstreams/BitStreamerJPEG.h index 42c7c7a7a..0a45a57f5 100644 --- a/src/librawspeed/bitstreams/BitStreamerJPEG.h +++ b/src/librawspeed/bitstreams/BitStreamerJPEG.h @@ -23,12 +23,12 @@ #include "rawspeedconfig.h" #include "adt/Array1DRef.h" #include "adt/Bit.h" +#include "adt/Casts.h" #include "adt/Invariant.h" #include "bitstreams/BitStream.h" #include "bitstreams/BitStreamJPEG.h" #include "bitstreams/BitStreamer.h" #include "io/Endianness.h" -#include #include #include #include @@ -68,7 +68,7 @@ class PosOrUnknown final { class BitStreamerJPEG; template <> struct BitStreamerTraits final { - using Stream = BitStreamJPEG; + static constexpr BitOrder Tag = BitOrder::JPEG; static constexpr bool canUseWithPrefixCodeDecoder = true; diff --git a/src/librawspeed/bitstreams/BitStreamerLSB.h b/src/librawspeed/bitstreams/BitStreamerLSB.h index 2270951c7..5b809e8fb 100644 --- a/src/librawspeed/bitstreams/BitStreamerLSB.h +++ b/src/librawspeed/bitstreams/BitStreamerLSB.h @@ -29,7 +29,7 @@ namespace rawspeed { class BitStreamerLSB; template <> struct BitStreamerTraits final { - using Stream = BitStreamLSB; + static constexpr BitOrder Tag = BitOrder::LSB; // How many bytes can we read from the input per each fillCache(), at most? static constexpr int MaxProcessBytes = 4; diff --git a/src/librawspeed/bitstreams/BitStreamerMSB.h b/src/librawspeed/bitstreams/BitStreamerMSB.h index 726c0a8f8..d550ac155 100644 --- a/src/librawspeed/bitstreams/BitStreamerMSB.h +++ b/src/librawspeed/bitstreams/BitStreamerMSB.h @@ -29,7 +29,7 @@ namespace rawspeed { class BitStreamerMSB; template <> struct BitStreamerTraits final { - using Stream = BitStreamMSB; + static constexpr BitOrder Tag = BitOrder::MSB; static constexpr bool canUseWithPrefixCodeDecoder = true; diff --git a/src/librawspeed/bitstreams/BitStreamerMSB16.h b/src/librawspeed/bitstreams/BitStreamerMSB16.h index 187720355..84456ebe8 100644 --- a/src/librawspeed/bitstreams/BitStreamerMSB16.h +++ b/src/librawspeed/bitstreams/BitStreamerMSB16.h @@ -29,7 +29,7 @@ namespace rawspeed { class BitStreamerMSB16; template <> struct BitStreamerTraits final { - using Stream = BitStreamMSB16; + static constexpr BitOrder Tag = BitOrder::MSB16; // How many bytes can we read from the input per each fillCache(), at most? static constexpr int MaxProcessBytes = 4; diff --git a/src/librawspeed/bitstreams/BitStreamerMSB32.h b/src/librawspeed/bitstreams/BitStreamerMSB32.h index 8c79af5ed..cc3fa1a13 100644 --- a/src/librawspeed/bitstreams/BitStreamerMSB32.h +++ b/src/librawspeed/bitstreams/BitStreamerMSB32.h @@ -29,7 +29,7 @@ namespace rawspeed { class BitStreamerMSB32; template <> struct BitStreamerTraits final { - using Stream = BitStreamMSB32; + static constexpr BitOrder Tag = BitOrder::MSB32; static constexpr bool canUseWithPrefixCodeDecoder = true; diff --git a/src/librawspeed/bitstreams/BitStreams.h b/src/librawspeed/bitstreams/BitStreams.h new file mode 100644 index 000000000..3ff5be60b --- /dev/null +++ b/src/librawspeed/bitstreams/BitStreams.h @@ -0,0 +1,37 @@ +/* + RawSpeed - RAW file decoder. + + Copyright (C) 2009-2014 Klaus Post + Copyright (C) 2024 Roman Lebedev + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#pragma once + +#include + +namespace rawspeed { + +enum class BitOrder : uint8_t { + LSB, /* Memory order */ + MSB, /* Input is added to stack byte by byte, and output is lifted + from top */ + MSB16, /* Same as above, but 16 bits at the time */ + MSB32, /* Same as above, but 32 bits at the time */ + JPEG, /* Same as MSB, but 0xFF byte is followed by an 0x00 stuffing byte */ +}; + +} // namespace rawspeed diff --git a/src/librawspeed/bitstreams/BitVacuumer.h b/src/librawspeed/bitstreams/BitVacuumer.h index 79217a548..4f5935155 100644 --- a/src/librawspeed/bitstreams/BitVacuumer.h +++ b/src/librawspeed/bitstreams/BitVacuumer.h @@ -37,7 +37,7 @@ template class BitVacuumer { public: using Traits = BitVacuumerTraits; - using StreamTraits = BitStreamTraits; + using StreamTraits = BitStreamTraits; using Cache = typename StreamTraits::StreamFlow; diff --git a/src/librawspeed/bitstreams/BitVacuumerJPEG.h b/src/librawspeed/bitstreams/BitVacuumerJPEG.h index b682eafcb..f4f5f11b9 100644 --- a/src/librawspeed/bitstreams/BitVacuumerJPEG.h +++ b/src/librawspeed/bitstreams/BitVacuumerJPEG.h @@ -35,7 +35,7 @@ template class BitVacuumerJPEG; template struct BitVacuumerTraits> final { - using Stream = BitStreamJPEG; + static constexpr BitOrder Tag = BitOrder::JPEG; static constexpr bool canUseWithPrefixCodeEncoder = true; }; diff --git a/src/librawspeed/bitstreams/BitVacuumerLSB.h b/src/librawspeed/bitstreams/BitVacuumerLSB.h index 75473796a..04a6aeb65 100644 --- a/src/librawspeed/bitstreams/BitVacuumerLSB.h +++ b/src/librawspeed/bitstreams/BitVacuumerLSB.h @@ -29,7 +29,7 @@ template class BitVacuumerLSB; template struct BitVacuumerTraits> final { - using Stream = BitStreamLSB; + static constexpr BitOrder Tag = BitOrder::LSB; }; template diff --git a/src/librawspeed/bitstreams/BitVacuumerMSB.h b/src/librawspeed/bitstreams/BitVacuumerMSB.h index 2ea6ec40d..9b3ea6521 100644 --- a/src/librawspeed/bitstreams/BitVacuumerMSB.h +++ b/src/librawspeed/bitstreams/BitVacuumerMSB.h @@ -29,7 +29,7 @@ template class BitVacuumerMSB; template struct BitVacuumerTraits> final { - using Stream = BitStreamMSB; + static constexpr BitOrder Tag = BitOrder::MSB; static constexpr bool canUseWithPrefixCodeEncoder = true; }; diff --git a/src/librawspeed/bitstreams/BitVacuumerMSB16.h b/src/librawspeed/bitstreams/BitVacuumerMSB16.h index 2ce5096b6..f6750f0ba 100644 --- a/src/librawspeed/bitstreams/BitVacuumerMSB16.h +++ b/src/librawspeed/bitstreams/BitVacuumerMSB16.h @@ -29,7 +29,7 @@ template class BitVacuumerMSB16; template struct BitVacuumerTraits> final { - using Stream = BitStreamMSB16; + static constexpr BitOrder Tag = BitOrder::MSB16; }; template diff --git a/src/librawspeed/bitstreams/BitVacuumerMSB32.h b/src/librawspeed/bitstreams/BitVacuumerMSB32.h index 4a65d6976..7b759910a 100644 --- a/src/librawspeed/bitstreams/BitVacuumerMSB32.h +++ b/src/librawspeed/bitstreams/BitVacuumerMSB32.h @@ -29,7 +29,7 @@ template class BitVacuumerMSB32; template struct BitVacuumerTraits> final { - using Stream = BitStreamMSB32; + static constexpr BitOrder Tag = BitOrder::MSB32; static constexpr bool canUseWithPrefixCodeEncoder = true; }; diff --git a/src/librawspeed/bitstreams/CMakeLists.txt b/src/librawspeed/bitstreams/CMakeLists.txt index 83d93b16c..9e9952aa3 100644 --- a/src/librawspeed/bitstreams/CMakeLists.txt +++ b/src/librawspeed/bitstreams/CMakeLists.txt @@ -8,6 +8,7 @@ FILE(GLOB SOURCES "BitStreamMSB.h" "BitStreamMSB16.h" "BitStreamMSB32.h" + "BitStreamPosition.h" "BitStreamer.cpp" "BitStreamer.h" "BitStreamerJPEG.h" @@ -15,6 +16,7 @@ FILE(GLOB SOURCES "BitStreamerMSB.h" "BitStreamerMSB16.h" "BitStreamerMSB32.h" + "BitStreams.h" "BitVacuumer.h" "BitVacuumerJPEG.h" "BitVacuumerLSB.h" diff --git a/src/librawspeed/common/Common.h b/src/librawspeed/common/Common.h index b195d09d0..0ee4aa5c9 100644 --- a/src/librawspeed/common/Common.h +++ b/src/librawspeed/common/Common.h @@ -199,12 +199,4 @@ inline std::array to_array(const std::vector& v) { return a; } -enum class BitOrder : uint8_t { - LSB, /* Memory order */ - MSB, /* Input is added to stack byte by byte, and output is lifted - from top */ - MSB16, /* Same as above, but 16 bits at the time */ - MSB32, /* Same as above, but 32 bits at the time */ -}; - } // namespace rawspeed diff --git a/src/librawspeed/decoders/ArwDecoder.cpp b/src/librawspeed/decoders/ArwDecoder.cpp index e3bca18ac..b6479edab 100644 --- a/src/librawspeed/decoders/ArwDecoder.cpp +++ b/src/librawspeed/decoders/ArwDecoder.cpp @@ -26,6 +26,7 @@ #include "adt/Invariant.h" #include "adt/NORangesSet.h" #include "adt/Point.h" +#include "bitstreams/BitStreams.h" #include "common/Common.h" #include "common/RawImage.h" #include "common/RawspeedException.h" diff --git a/src/librawspeed/decoders/DcsDecoder.cpp b/src/librawspeed/decoders/DcsDecoder.cpp index 76336e93d..3d6c39de9 100644 --- a/src/librawspeed/decoders/DcsDecoder.cpp +++ b/src/librawspeed/decoders/DcsDecoder.cpp @@ -21,7 +21,7 @@ #include "decoders/DcsDecoder.h" #include "adt/Point.h" -#include "common/Common.h" +#include "bitstreams/BitStreams.h" #include "common/RawImage.h" #include "decoders/RawDecoderException.h" #include "decoders/SimpleTiffDecoder.h" diff --git a/src/librawspeed/decoders/ErfDecoder.cpp b/src/librawspeed/decoders/ErfDecoder.cpp index cb28dba3b..c2516c698 100644 --- a/src/librawspeed/decoders/ErfDecoder.cpp +++ b/src/librawspeed/decoders/ErfDecoder.cpp @@ -21,7 +21,7 @@ #include "decoders/ErfDecoder.h" #include "adt/Point.h" -#include "common/Common.h" +#include "bitstreams/BitStreams.h" #include "common/RawImage.h" #include "decoders/RawDecoderException.h" #include "decoders/SimpleTiffDecoder.h" diff --git a/src/librawspeed/decoders/KdcDecoder.cpp b/src/librawspeed/decoders/KdcDecoder.cpp index af9cc3e2e..56cbead83 100644 --- a/src/librawspeed/decoders/KdcDecoder.cpp +++ b/src/librawspeed/decoders/KdcDecoder.cpp @@ -23,7 +23,7 @@ #include "adt/Casts.h" #include "adt/NORangesSet.h" #include "adt/Point.h" -#include "common/Common.h" +#include "bitstreams/BitStreams.h" #include "common/RawImage.h" #include "decoders/RawDecoderException.h" #include "decompressors/UncompressedDecompressor.h" diff --git a/src/librawspeed/decoders/MefDecoder.cpp b/src/librawspeed/decoders/MefDecoder.cpp index dda9422c3..d1bf4feef 100644 --- a/src/librawspeed/decoders/MefDecoder.cpp +++ b/src/librawspeed/decoders/MefDecoder.cpp @@ -21,7 +21,7 @@ #include "decoders/MefDecoder.h" #include "adt/Point.h" -#include "common/Common.h" +#include "bitstreams/BitStreams.h" #include "common/RawImage.h" #include "decoders/RawDecoderException.h" #include "decoders/SimpleTiffDecoder.h" diff --git a/src/librawspeed/decoders/MosDecoder.cpp b/src/librawspeed/decoders/MosDecoder.cpp index 47cc1b6e9..d1ccc1a03 100644 --- a/src/librawspeed/decoders/MosDecoder.cpp +++ b/src/librawspeed/decoders/MosDecoder.cpp @@ -22,6 +22,7 @@ #include "decoders/MosDecoder.h" #include "adt/Casts.h" #include "adt/Point.h" +#include "bitstreams/BitStreams.h" #include "common/Common.h" #include "common/RawImage.h" #include "decoders/AbstractTiffDecoder.h" diff --git a/src/librawspeed/decoders/MrwDecoder.cpp b/src/librawspeed/decoders/MrwDecoder.cpp index a6ce7de6f..4cc53372c 100644 --- a/src/librawspeed/decoders/MrwDecoder.cpp +++ b/src/librawspeed/decoders/MrwDecoder.cpp @@ -22,7 +22,7 @@ #include "decoders/MrwDecoder.h" #include "adt/Point.h" -#include "common/Common.h" +#include "bitstreams/BitStreams.h" #include "common/RawImage.h" #include "decoders/RawDecoderException.h" #include "decompressors/UncompressedDecompressor.h" diff --git a/src/librawspeed/decoders/NakedDecoder.cpp b/src/librawspeed/decoders/NakedDecoder.cpp index c5ad85fd2..8db53a3e3 100644 --- a/src/librawspeed/decoders/NakedDecoder.cpp +++ b/src/librawspeed/decoders/NakedDecoder.cpp @@ -22,7 +22,7 @@ #include "decoders/NakedDecoder.h" #include "adt/Optional.h" #include "adt/Point.h" -#include "common/Common.h" +#include "bitstreams/BitStreams.h" #include "common/RawImage.h" #include "decoders/RawDecoder.h" #include "decoders/RawDecoderException.h" diff --git a/src/librawspeed/decoders/NakedDecoder.h b/src/librawspeed/decoders/NakedDecoder.h index d2e844318..a206024a8 100644 --- a/src/librawspeed/decoders/NakedDecoder.h +++ b/src/librawspeed/decoders/NakedDecoder.h @@ -21,7 +21,7 @@ #pragma once -#include "common/Common.h" +#include "bitstreams/BitStreams.h" #include "common/RawImage.h" #include "decoders/RawDecoder.h" #include diff --git a/src/librawspeed/decoders/NefDecoder.cpp b/src/librawspeed/decoders/NefDecoder.cpp index 4982be6dc..4d9b30f3a 100644 --- a/src/librawspeed/decoders/NefDecoder.cpp +++ b/src/librawspeed/decoders/NefDecoder.cpp @@ -26,6 +26,7 @@ #include "adt/Casts.h" #include "adt/Point.h" #include "bitstreams/BitStreamerMSB.h" +#include "bitstreams/BitStreams.h" #include "common/Common.h" #include "common/RawImage.h" #include "decoders/RawDecoderException.h" diff --git a/src/librawspeed/decoders/OrfDecoder.cpp b/src/librawspeed/decoders/OrfDecoder.cpp index 69937541b..b4d283815 100644 --- a/src/librawspeed/decoders/OrfDecoder.cpp +++ b/src/librawspeed/decoders/OrfDecoder.cpp @@ -27,6 +27,7 @@ #include "adt/NORangesSet.h" #include "adt/Point.h" #include "bitstreams/BitStreamerMSB.h" +#include "bitstreams/BitStreams.h" #include "common/Common.h" #include "common/RawImage.h" #include "decoders/RawDecoderException.h" diff --git a/src/librawspeed/decoders/PefDecoder.cpp b/src/librawspeed/decoders/PefDecoder.cpp index 4adac9a04..a5820bde3 100644 --- a/src/librawspeed/decoders/PefDecoder.cpp +++ b/src/librawspeed/decoders/PefDecoder.cpp @@ -25,6 +25,7 @@ #include "adt/Casts.h" #include "adt/Optional.h" #include "adt/Point.h" +#include "bitstreams/BitStreams.h" #include "common/Common.h" #include "common/RawImage.h" #include "decoders/RawDecoderException.h" diff --git a/src/librawspeed/decoders/RafDecoder.cpp b/src/librawspeed/decoders/RafDecoder.cpp index dd4e61246..62a5a3efe 100644 --- a/src/librawspeed/decoders/RafDecoder.cpp +++ b/src/librawspeed/decoders/RafDecoder.cpp @@ -24,7 +24,7 @@ #include "adt/Array2DRef.h" #include "adt/Casts.h" #include "adt/Point.h" -#include "common/Common.h" +#include "bitstreams/BitStreams.h" #include "common/RawImage.h" #include "decoders/RawDecoderException.h" #include "decompressors/FujiDecompressor.h" diff --git a/src/librawspeed/decoders/RawDecoder.cpp b/src/librawspeed/decoders/RawDecoder.cpp index ee752d335..72f4537b4 100644 --- a/src/librawspeed/decoders/RawDecoder.cpp +++ b/src/librawspeed/decoders/RawDecoder.cpp @@ -25,6 +25,7 @@ #include "adt/Array2DRef.h" #include "adt/Casts.h" #include "adt/Point.h" +#include "bitstreams/BitStreams.h" #include "common/Common.h" #include "common/RawImage.h" #include "decompressors/UncompressedDecompressor.h" diff --git a/src/librawspeed/decoders/RawDecoder.h b/src/librawspeed/decoders/RawDecoder.h index 08a39b3e7..a33f6d4a8 100644 --- a/src/librawspeed/decoders/RawDecoder.h +++ b/src/librawspeed/decoders/RawDecoder.h @@ -22,7 +22,7 @@ #pragma once #include "adt/Point.h" -#include "common/Common.h" +#include "bitstreams/BitStreams.h" #include "common/RawImage.h" #include "io/Buffer.h" #include "metadata/Camera.h" diff --git a/src/librawspeed/decoders/Rw2Decoder.cpp b/src/librawspeed/decoders/Rw2Decoder.cpp index 6f5f316b4..752a10cf0 100644 --- a/src/librawspeed/decoders/Rw2Decoder.cpp +++ b/src/librawspeed/decoders/Rw2Decoder.cpp @@ -23,6 +23,7 @@ #include "adt/Array1DRef.h" #include "adt/Array2DRef.h" #include "adt/Point.h" +#include "bitstreams/BitStreams.h" #include "common/Common.h" #include "common/RawImage.h" #include "decoders/RawDecoderException.h" diff --git a/src/librawspeed/decoders/SrwDecoder.cpp b/src/librawspeed/decoders/SrwDecoder.cpp index 64ea1bbc9..b1771a381 100644 --- a/src/librawspeed/decoders/SrwDecoder.cpp +++ b/src/librawspeed/decoders/SrwDecoder.cpp @@ -21,7 +21,7 @@ #include "decoders/SrwDecoder.h" #include "adt/Point.h" -#include "common/Common.h" +#include "bitstreams/BitStreams.h" #include "decoders/RawDecoderException.h" #include "decompressors/SamsungV0Decompressor.h" #include "decompressors/SamsungV1Decompressor.h" diff --git a/src/librawspeed/decoders/StiDecoder.cpp b/src/librawspeed/decoders/StiDecoder.cpp index 6ed43f4cc..75df52ffe 100644 --- a/src/librawspeed/decoders/StiDecoder.cpp +++ b/src/librawspeed/decoders/StiDecoder.cpp @@ -20,7 +20,7 @@ #include "decoders/StiDecoder.h" #include "adt/Point.h" -#include "common/Common.h" +#include "bitstreams/BitStreams.h" #include "common/RawImage.h" #include "decoders/RawDecoderException.h" #include "decompressors/HasselbladLJpegDecoder.h" diff --git a/src/librawspeed/decoders/ThreefrDecoder.cpp b/src/librawspeed/decoders/ThreefrDecoder.cpp index adf398815..8a68bc6a6 100644 --- a/src/librawspeed/decoders/ThreefrDecoder.cpp +++ b/src/librawspeed/decoders/ThreefrDecoder.cpp @@ -22,7 +22,7 @@ #include "decoders/ThreefrDecoder.h" #include "adt/Casts.h" #include "adt/Point.h" -#include "common/Common.h" +#include "bitstreams/BitStreams.h" #include "common/RawImage.h" #include "decoders/RawDecoderException.h" #include "decompressors/HasselbladLJpegDecoder.h" diff --git a/src/librawspeed/decompressors/AbstractDngDecompressor.cpp b/src/librawspeed/decompressors/AbstractDngDecompressor.cpp index 9f9117856..391b9406a 100644 --- a/src/librawspeed/decompressors/AbstractDngDecompressor.cpp +++ b/src/librawspeed/decompressors/AbstractDngDecompressor.cpp @@ -25,6 +25,7 @@ #include "adt/Casts.h" #include "adt/Invariant.h" #include "adt/Point.h" +#include "bitstreams/BitStreams.h" #include "common/Common.h" #include "common/RawImage.h" #include "decoders/RawDecoderException.h" diff --git a/src/librawspeed/decompressors/LJpegDecoder.h b/src/librawspeed/decompressors/LJpegDecoder.h index 699d99eb3..fed76104d 100644 --- a/src/librawspeed/decompressors/LJpegDecoder.h +++ b/src/librawspeed/decompressors/LJpegDecoder.h @@ -20,6 +20,7 @@ #pragma once +#include "adt/Point.h" #include "decompressors/AbstractLJpegDecoder.h" #include diff --git a/src/librawspeed/decompressors/LJpegDecompressor.h b/src/librawspeed/decompressors/LJpegDecompressor.h index f729e2c92..69c77739f 100644 --- a/src/librawspeed/decompressors/LJpegDecompressor.h +++ b/src/librawspeed/decompressors/LJpegDecompressor.h @@ -22,6 +22,7 @@ #pragma once #include "adt/Array1DRef.h" +#include "adt/Array2DRef.h" #include "adt/Point.h" #include "bitstreams/BitStreamerJPEG.h" #include "codes/PrefixCodeDecoder.h" diff --git a/src/librawspeed/decompressors/UncompressedDecompressor.cpp b/src/librawspeed/decompressors/UncompressedDecompressor.cpp index c873df48b..45f96f916 100644 --- a/src/librawspeed/decompressors/UncompressedDecompressor.cpp +++ b/src/librawspeed/decompressors/UncompressedDecompressor.cpp @@ -29,6 +29,7 @@ #include "bitstreams/BitStreamerMSB.h" #include "bitstreams/BitStreamerMSB16.h" #include "bitstreams/BitStreamerMSB32.h" +#include "bitstreams/BitStreams.h" #include "common/Common.h" #include "common/FloatingPoint.h" #include "common/RawImage.h" @@ -115,6 +116,16 @@ UncompressedDecompressor::UncompressedDecompressor( if (inputPitchBytes < 1) ThrowRDE("Input pitch is non-positive"); + switch (order) { + case BitOrder::LSB: + case BitOrder::MSB: + case BitOrder::MSB16: + case BitOrder::MSB32: + break; + case BitOrder::JPEG: + ThrowRDE("JPEG bit order not supported."); + } + uint32_t w = size.x; uint32_t h = size.y; uint32_t cpp = mRaw->getCpp(); diff --git a/src/librawspeed/decompressors/UncompressedDecompressor.h b/src/librawspeed/decompressors/UncompressedDecompressor.h index 627ba1c59..15aeb46ae 100644 --- a/src/librawspeed/decompressors/UncompressedDecompressor.h +++ b/src/librawspeed/decompressors/UncompressedDecompressor.h @@ -23,7 +23,7 @@ #pragma once #include "adt/Point.h" -#include "common/Common.h" +#include "bitstreams/BitStreams.h" #include "common/RawImage.h" #include "decompressors/AbstractDecompressor.h" #include "io/ByteStream.h" diff --git a/test/librawspeed/bitstreams/BitVacuumerLSBTest.cpp b/test/librawspeed/bitstreams/BitVacuumerLSBTest.cpp index 4b3c053a3..e80319bf1 100644 --- a/test/librawspeed/bitstreams/BitVacuumerLSBTest.cpp +++ b/test/librawspeed/bitstreams/BitVacuumerLSBTest.cpp @@ -20,9 +20,13 @@ #include "bitstreams/BitVacuumerLSB.h" #include "adt/Array1DRef.h" +#include "adt/Bit.h" #include "adt/Casts.h" #include "adt/PartitioningOutputIterator.h" +#include "bitstreams/BitStreamPosition.h" #include "bitstreams/BitStreamerLSB.h" +#include "common/Common.h" +#include #include #include #include @@ -250,6 +254,62 @@ TEST(BitVacuumerLSBTest, LoadPos) { } } +TEST(BitVacuumerLSBTest, DependencyBreaking) { + std::vector bitstream; + + using BitStreamer = BitStreamerLSB; + using BitStreamerTraits = BitStreamer::Traits; + + constexpr int numByteElts = 256; + + { + auto bsInserter = PartitioningOutputIterator(std::back_inserter(bitstream)); + using BitVacuumer = BitVacuumerLSB; + auto bv = BitVacuumer(bsInserter); + + for (int e = 0; e != numByteElts + BitStreamerTraits::MaxProcessBytes; ++e) + bv.put(e, 8); + } + constexpr int numBitsTotal = CHAR_BIT * numByteElts; + + auto fullInput = + Array1DRef(bitstream.data(), implicit_cast(bitstream.size())); + + for (int numBitsToSkip = 0; numBitsToSkip <= numBitsTotal; ++numBitsToSkip) { + const int numBitsRemaining = numBitsTotal - numBitsToSkip; + auto bsRef = BitStreamer(fullInput); + bsRef.fill(); + bsRef.skipManyBits(numBitsToSkip); + + BitStreamPosition state; + state.pos = bsRef.getInputPosition(); + state.fillLevel = bsRef.getFillLevel(); + const auto bsPos = getAsByteStreamPosition(state); + + auto rebasedInput = + fullInput.getCrop(bsPos.bytePos, fullInput.size() - bsPos.bytePos) + .getAsArray1DRef(); + auto bsRebased = BitStreamer(rebasedInput); + if (bsPos.numBitsToSkip != 0) + bsRebased.skipBits(bsPos.numBitsToSkip); + + int numSubByteBitsRemaining = numBitsRemaining % CHAR_BIT; + int numBytesRemaining = numBitsRemaining / CHAR_BIT; + if (numSubByteBitsRemaining != 0) { + const auto expectedVal = extractHighBits( + numBitsToSkip / CHAR_BIT, numSubByteBitsRemaining, CHAR_BIT); + ASSERT_THAT(bsRef.getBits(numSubByteBitsRemaining), expectedVal); + ASSERT_THAT(bsRebased.getBits(numSubByteBitsRemaining), expectedVal); + } + + for (int i = 0; i != numBytesRemaining; ++i) { + const auto expectedVal = roundUpDivision(numBitsToSkip, CHAR_BIT) + i; + ASSERT_THAT(bsRef.getBits(8), expectedVal); + ASSERT_THAT(bsRebased.getBits(8), expectedVal); + } + } +} + } // namespace } // namespace rawspeed diff --git a/test/librawspeed/bitstreams/BitVacuumerMSB16Test.cpp b/test/librawspeed/bitstreams/BitVacuumerMSB16Test.cpp index 26864f9f3..a6eeeaf11 100644 --- a/test/librawspeed/bitstreams/BitVacuumerMSB16Test.cpp +++ b/test/librawspeed/bitstreams/BitVacuumerMSB16Test.cpp @@ -20,9 +20,13 @@ #include "bitstreams/BitVacuumerMSB16.h" #include "adt/Array1DRef.h" +#include "adt/Bit.h" #include "adt/Casts.h" #include "adt/PartitioningOutputIterator.h" +#include "bitstreams/BitStreamPosition.h" #include "bitstreams/BitStreamerMSB16.h" +#include "common/Common.h" +#include #include #include #include @@ -247,6 +251,62 @@ TEST(BitVacuumerMSB16Test, LoadPos) { } } +TEST(BitVacuumerMSB16Test, DependencyBreaking) { + std::vector bitstream; + + using BitStreamer = BitStreamerMSB16; + using BitStreamerTraits = BitStreamer::Traits; + + constexpr int numByteElts = 256; + + { + auto bsInserter = PartitioningOutputIterator(std::back_inserter(bitstream)); + using BitVacuumer = BitVacuumerMSB16; + auto bv = BitVacuumer(bsInserter); + + for (int e = 0; e != numByteElts + BitStreamerTraits::MaxProcessBytes; ++e) + bv.put(e, 8); + } + constexpr int numBitsTotal = CHAR_BIT * numByteElts; + + auto fullInput = + Array1DRef(bitstream.data(), implicit_cast(bitstream.size())); + + for (int numBitsToSkip = 0; numBitsToSkip <= numBitsTotal; ++numBitsToSkip) { + const int numBitsRemaining = numBitsTotal - numBitsToSkip; + auto bsRef = BitStreamer(fullInput); + bsRef.fill(); + bsRef.skipManyBits(numBitsToSkip); + + BitStreamPosition state; + state.pos = bsRef.getInputPosition(); + state.fillLevel = bsRef.getFillLevel(); + const auto bsPos = getAsByteStreamPosition(state); + + auto rebasedInput = + fullInput.getCrop(bsPos.bytePos, fullInput.size() - bsPos.bytePos) + .getAsArray1DRef(); + auto bsRebased = BitStreamer(rebasedInput); + if (bsPos.numBitsToSkip != 0) + bsRebased.skipBits(bsPos.numBitsToSkip); + + int numSubByteBitsRemaining = numBitsRemaining % CHAR_BIT; + int numBytesRemaining = numBitsRemaining / CHAR_BIT; + if (numSubByteBitsRemaining != 0) { + const auto expectedVal = extractLowBits( + numBitsToSkip / CHAR_BIT, numSubByteBitsRemaining); + ASSERT_THAT(bsRef.getBits(numSubByteBitsRemaining), expectedVal); + ASSERT_THAT(bsRebased.getBits(numSubByteBitsRemaining), expectedVal); + } + + for (int i = 0; i != numBytesRemaining; ++i) { + const auto expectedVal = roundUpDivision(numBitsToSkip, CHAR_BIT) + i; + ASSERT_THAT(bsRef.getBits(8), expectedVal); + ASSERT_THAT(bsRebased.getBits(8), expectedVal); + } + } +} + } // namespace } // namespace rawspeed diff --git a/test/librawspeed/bitstreams/BitVacuumerMSB32Test.cpp b/test/librawspeed/bitstreams/BitVacuumerMSB32Test.cpp index d75b52fea..d37e0fa03 100644 --- a/test/librawspeed/bitstreams/BitVacuumerMSB32Test.cpp +++ b/test/librawspeed/bitstreams/BitVacuumerMSB32Test.cpp @@ -20,9 +20,13 @@ #include "bitstreams/BitVacuumerMSB32.h" #include "adt/Array1DRef.h" +#include "adt/Bit.h" #include "adt/Casts.h" #include "adt/PartitioningOutputIterator.h" +#include "bitstreams/BitStreamPosition.h" #include "bitstreams/BitStreamerMSB32.h" +#include "common/Common.h" +#include #include #include #include @@ -250,6 +254,62 @@ TEST(BitVacuumerMSB32Test, LoadPos) { } } +TEST(BitVacuumerMSB32Test, DependencyBreaking) { + std::vector bitstream; + + using BitStreamer = BitStreamerMSB32; + using BitStreamerTraits = BitStreamer::Traits; + + constexpr int numByteElts = 256; + + { + auto bsInserter = PartitioningOutputIterator(std::back_inserter(bitstream)); + using BitVacuumer = BitVacuumerMSB32; + auto bv = BitVacuumer(bsInserter); + + for (int e = 0; e != numByteElts + BitStreamerTraits::MaxProcessBytes; ++e) + bv.put(e, 8); + } + constexpr int numBitsTotal = CHAR_BIT * numByteElts; + + auto fullInput = + Array1DRef(bitstream.data(), implicit_cast(bitstream.size())); + + for (int numBitsToSkip = 0; numBitsToSkip <= numBitsTotal; ++numBitsToSkip) { + const int numBitsRemaining = numBitsTotal - numBitsToSkip; + auto bsRef = BitStreamer(fullInput); + bsRef.fill(); + bsRef.skipManyBits(numBitsToSkip); + + BitStreamPosition state; + state.pos = bsRef.getInputPosition(); + state.fillLevel = bsRef.getFillLevel(); + const auto bsPos = getAsByteStreamPosition(state); + + auto rebasedInput = + fullInput.getCrop(bsPos.bytePos, fullInput.size() - bsPos.bytePos) + .getAsArray1DRef(); + auto bsRebased = BitStreamer(rebasedInput); + if (bsPos.numBitsToSkip != 0) + bsRebased.skipBits(bsPos.numBitsToSkip); + + int numSubByteBitsRemaining = numBitsRemaining % CHAR_BIT; + int numBytesRemaining = numBitsRemaining / CHAR_BIT; + if (numSubByteBitsRemaining != 0) { + const auto expectedVal = extractLowBits( + numBitsToSkip / CHAR_BIT, numSubByteBitsRemaining); + ASSERT_THAT(bsRef.getBits(numSubByteBitsRemaining), expectedVal); + ASSERT_THAT(bsRebased.getBits(numSubByteBitsRemaining), expectedVal); + } + + for (int i = 0; i != numBytesRemaining; ++i) { + const auto expectedVal = roundUpDivision(numBitsToSkip, CHAR_BIT) + i; + ASSERT_THAT(bsRef.getBits(8), expectedVal); + ASSERT_THAT(bsRebased.getBits(8), expectedVal); + } + } +} + } // namespace } // namespace rawspeed diff --git a/test/librawspeed/bitstreams/BitVacuumerMSBTest.cpp b/test/librawspeed/bitstreams/BitVacuumerMSBTest.cpp index 35869b05d..dbbf9a56d 100644 --- a/test/librawspeed/bitstreams/BitVacuumerMSBTest.cpp +++ b/test/librawspeed/bitstreams/BitVacuumerMSBTest.cpp @@ -20,9 +20,13 @@ #include "bitstreams/BitVacuumerMSB.h" #include "adt/Array1DRef.h" +#include "adt/Bit.h" #include "adt/Casts.h" #include "adt/PartitioningOutputIterator.h" +#include "bitstreams/BitStreamPosition.h" #include "bitstreams/BitStreamerMSB.h" +#include "common/Common.h" +#include #include #include #include @@ -250,6 +254,62 @@ TEST(BitVacuumerMSBTest, LoadPos) { } } +TEST(BitVacuumerMSBTest, DependencyBreaking) { + std::vector bitstream; + + using BitStreamer = BitStreamerMSB; + using BitStreamerTraits = BitStreamer::Traits; + + constexpr int numByteElts = 256; + + { + auto bsInserter = PartitioningOutputIterator(std::back_inserter(bitstream)); + using BitVacuumer = BitVacuumerMSB; + auto bv = BitVacuumer(bsInserter); + + for (int e = 0; e != numByteElts + BitStreamerTraits::MaxProcessBytes; ++e) + bv.put(e, 8); + } + constexpr int numBitsTotal = CHAR_BIT * numByteElts; + + auto fullInput = + Array1DRef(bitstream.data(), implicit_cast(bitstream.size())); + + for (int numBitsToSkip = 0; numBitsToSkip <= numBitsTotal; ++numBitsToSkip) { + const int numBitsRemaining = numBitsTotal - numBitsToSkip; + auto bsRef = BitStreamer(fullInput); + bsRef.fill(); + bsRef.skipManyBits(numBitsToSkip); + + BitStreamPosition state; + state.pos = bsRef.getInputPosition(); + state.fillLevel = bsRef.getFillLevel(); + const auto bsPos = getAsByteStreamPosition(state); + + auto rebasedInput = + fullInput.getCrop(bsPos.bytePos, fullInput.size() - bsPos.bytePos) + .getAsArray1DRef(); + auto bsRebased = BitStreamer(rebasedInput); + if (bsPos.numBitsToSkip != 0) + bsRebased.skipBits(bsPos.numBitsToSkip); + + int numSubByteBitsRemaining = numBitsRemaining % CHAR_BIT; + int numBytesRemaining = numBitsRemaining / CHAR_BIT; + if (numSubByteBitsRemaining != 0) { + const auto expectedVal = extractLowBits( + numBitsToSkip / CHAR_BIT, numSubByteBitsRemaining); + ASSERT_THAT(bsRef.getBits(numSubByteBitsRemaining), expectedVal); + ASSERT_THAT(bsRebased.getBits(numSubByteBitsRemaining), expectedVal); + } + + for (int i = 0; i != numBytesRemaining; ++i) { + const auto expectedVal = roundUpDivision(numBitsToSkip, CHAR_BIT) + i; + ASSERT_THAT(bsRef.getBits(8), expectedVal); + ASSERT_THAT(bsRebased.getBits(8), expectedVal); + } + } +} + } // namespace } // namespace rawspeed