// // (C) Jan de Vaan 2007-2010, all rights reserved. See the accompanying "License.txt" for licensed use. // #ifndef CHARLS_DECODERSTATEGY #define CHARLS_DECODERSTATEGY #include "util.h" #include "processline.h" #include // Purpose: Implements encoding to stream of bits. In encoding mode JpegLsCodec inherits from EncoderStrategy class DecoderStrategy { public: DecoderStrategy(const JlsParameters& params) : _params(params), _byteStream(nullptr), _readCache(0), _validBits(0), _position(nullptr), _nextFFPosition(nullptr), _endPosition(nullptr) { } virtual ~DecoderStrategy() = default; virtual ProcessLine* CreateProcess(ByteStreamInfo rawStreamInfo) = 0; virtual void SetPresets(const JlsCustomParameters& presets) = 0; virtual void DecodeScan(std::unique_ptr outputData, const JlsRect& size, ByteStreamInfo& compressedData, bool bCheck) = 0; void Init(ByteStreamInfo& compressedStream) { _validBits = 0; _readCache = 0; if (compressedStream.rawStream) { _buffer.resize(40000); _position = static_cast(&_buffer[0]); _endPosition = _position; _byteStream = compressedStream.rawStream; AddBytesFromStream(); } else { _byteStream = nullptr; _position = compressedStream.rawData; _endPosition = _position + compressedStream.count; } _nextFFPosition = FindNextFF(); MakeValid(); } void AddBytesFromStream() { if (!_byteStream || _byteStream->sgetc() == std::char_traits::eof()) return; std::size_t count = _endPosition - _position; if (count > 64) return; for (std::size_t i = 0; i < count; ++i) { _buffer[i] = _position[i]; } std::size_t offset = &_buffer[0] - _position; _position += offset; _endPosition += offset; _nextFFPosition += offset; std::streamsize readbytes = _byteStream->sgetn(reinterpret_cast(_endPosition), _buffer.size() - count); _endPosition += readbytes; } inlinehint void Skip(int32_t length) { _validBits -= length; _readCache = _readCache << length; } void OnLineBegin(int32_t /*cpixel*/, void* /*ptypeBuffer*/, int32_t /*pixelStride*/) { } void OnLineEnd(int32_t pixelCount, const void* ptypeBuffer, int32_t pixelStride) { _processLine->NewLineDecoded(ptypeBuffer, pixelCount, pixelStride); } void EndScan() { if ((*_position) != 0xFF) { ReadBit(); if ((*_position) != 0xFF) throw std::system_error(static_cast(charls::ApiResult::TooMuchCompressedData), CharLSCategoryInstance()); } if (_readCache != 0) throw std::system_error(static_cast(charls::ApiResult::TooMuchCompressedData), CharLSCategoryInstance()); } inlinehint bool OptimizedRead() { // Easy & fast: if there is no 0xFF byte in sight, we can read without bitstuffing if (_position < _nextFFPosition - (sizeof(bufType)-1)) { _readCache |= FromBigEndian::Read(_position) >> _validBits; int bytesToRead = (bufferbits - _validBits) >> 3; _position += bytesToRead; _validBits += bytesToRead * 8; ASSERT(_validBits >= bufferbits - 8); return true; } return false; } typedef std::size_t bufType; enum { bufferbits = sizeof( bufType ) * 8 }; void MakeValid() { ASSERT(_validBits <=bufferbits - 8); if (OptimizedRead()) return; AddBytesFromStream(); do { if (_position >= _endPosition) { if (_validBits <= 0) throw std::system_error(static_cast(charls::ApiResult::InvalidCompressedData), CharLSCategoryInstance()); return; } bufType valnew = _position[0]; if (valnew == 0xFF) { // JPEG bitstream rule: no FF may be followed by 0x80 or higher if (_position == _endPosition - 1 || (_position[1] & 0x80) != 0) { if (_validBits <= 0) throw std::system_error(static_cast(charls::ApiResult::InvalidCompressedData), CharLSCategoryInstance()); return; } } _readCache |= valnew << (bufferbits - 8 - _validBits); _position += 1; _validBits += 8; if (valnew == 0xFF) { _validBits--; } } while (_validBits < bufferbits - 8); _nextFFPosition = FindNextFF(); return; } uint8_t* FindNextFF() const { auto positionNextFF = _position; while (positionNextFF < _endPosition) { if (*positionNextFF == 0xFF) break; positionNextFF++; } return positionNextFF; } uint8_t* GetCurBytePos() const { int32_t validBits = _validBits; uint8_t* compressedBytes = _position; for (;;) { int32_t cbitLast = compressedBytes[-1] == 0xFF ? 7 : 8; if (validBits < cbitLast ) return compressedBytes; validBits -= cbitLast; compressedBytes--; } } inlinehint int32_t ReadValue(int32_t length) { if (_validBits < length) { MakeValid(); if (_validBits < length) throw std::system_error(static_cast(charls::ApiResult::InvalidCompressedData), CharLSCategoryInstance()); } ASSERT(length != 0 && length <= _validBits); ASSERT(length < 32); int32_t result = int32_t(_readCache >> (bufferbits - length)); Skip(length); return result; } inlinehint int32_t PeekByte() { if (_validBits < 8) { MakeValid(); } return _readCache >> (bufferbits - 8); } inlinehint bool ReadBit() { if (_validBits <= 0) { MakeValid(); } bool bSet = (_readCache & (bufType(1) << (bufferbits - 1))) != 0; Skip(1); return bSet; } inlinehint int32_t Peek0Bits() { if (_validBits < 16) { MakeValid(); } bufType valTest = _readCache; for (int32_t count = 0; count < 16; count++) { if ((valTest & (bufType(1) << (bufferbits - 1))) != 0) return count; valTest <<= 1; } return -1; } inlinehint int32_t ReadHighbits() { int32_t count = Peek0Bits(); if (count >= 0) { Skip(count + 1); return count; } Skip(15); for (int32_t highbits = 15; ; highbits++) { if (ReadBit()) return highbits; } } int32_t ReadLongValue(int32_t length) { if (length <= 24) return ReadValue(length); return (ReadValue(length - 24) << 24) + ReadValue(24); } protected: JlsParameters _params; std::unique_ptr _processLine; private: std::vector _buffer; std::basic_streambuf* _byteStream; // decoding bufType _readCache; int32_t _validBits; uint8_t* _position; uint8_t* _nextFFPosition; uint8_t* _endPosition; }; #endif