1 /* 2 * Copyright (C) 2020 Veloman Yunkan 3 * 4 * This program is free software; you can redistribute it and/or 5 * modify it under the terms of the GNU General Public License as 6 * published by the Free Software Foundation; either version 2 of the 7 * License, or (at your option) any later version. 8 * 9 * This program is distributed in the hope that it will be useful, but 10 * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied 11 * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and 12 * NON-INFRINGEMENT. See the GNU General Public License for more details. 13 * 14 * You should have received a copy of the GNU General Public License 15 * along with this program; if not, write to the Free Software 16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 17 * 18 */ 19 20 #ifndef ZIM_DECODERSTREAMREADER_H 21 #define ZIM_DECODERSTREAMREADER_H 22 23 #include "compression.h" 24 #include "istreamreader.h" 25 26 namespace zim 27 { 28 29 template<typename Decoder> 30 class DecoderStreamReader : public IStreamReader 31 { 32 private: // constants 33 enum { CHUNK_SIZE = 1024 }; 34 35 public: // functions DecoderStreamReader(std::shared_ptr<const Reader> inputReader)36 DecoderStreamReader(std::shared_ptr<const Reader> inputReader) 37 : m_encodedDataReader(inputReader), 38 m_currentInputOffset(0), 39 m_inputBytesLeft(inputReader->size()), 40 m_encodedDataChunk(Buffer::makeBuffer(zsize_t(CHUNK_SIZE))) 41 { 42 Decoder::init_stream_decoder(&m_decoderState, nullptr); 43 readNextChunk(); 44 } 45 ~DecoderStreamReader()46 ~DecoderStreamReader() 47 { 48 Decoder::stream_end_decode(&m_decoderState); 49 } 50 51 private: // functions readNextChunk()52 void readNextChunk() 53 { 54 const auto n = std::min(zsize_t(CHUNK_SIZE), m_inputBytesLeft); 55 m_encodedDataChunk = m_encodedDataReader->get_buffer(m_currentInputOffset, n); 56 m_currentInputOffset += n; 57 m_inputBytesLeft -= n; 58 // XXX: ugly C-style cast (casting away constness) on the next line 59 m_decoderState.next_in = (unsigned char*)m_encodedDataChunk.data(); 60 m_decoderState.avail_in = m_encodedDataChunk.size().v; 61 } 62 decodeMoreBytes()63 CompStatus decodeMoreBytes() 64 { 65 CompStep step = CompStep::STEP; 66 if ( m_decoderState.avail_in == 0 ) 67 { 68 if ( m_inputBytesLeft.v == 0 ) 69 step = CompStep::FINISH; 70 else 71 readNextChunk(); 72 } 73 74 return Decoder::stream_run_decode(&m_decoderState, step); 75 } 76 readImpl(char * buf,zsize_t nbytes)77 void readImpl(char* buf, zsize_t nbytes) override 78 { 79 m_decoderState.next_out = (unsigned char*)buf; 80 m_decoderState.avail_out = nbytes.v; 81 while ( m_decoderState.avail_out != 0 ) 82 { 83 // We don't car of the return code of decodeMoreBytes. 84 // We feed (or stop feeding) the decoder based on what 85 // we need to decode and the `avail_in`. 86 // If there is a error somehow, a exception will be thrown. 87 decodeMoreBytes(); 88 } 89 } 90 91 private: // types 92 typedef typename Decoder::stream_t DecoderState; 93 94 private: // data 95 std::shared_ptr<const Reader> m_encodedDataReader; 96 offset_t m_currentInputOffset; 97 zsize_t m_inputBytesLeft; // count of bytes left in the input stream 98 DecoderState m_decoderState; 99 Buffer m_encodedDataChunk; 100 }; 101 102 } // namespace zim 103 104 #endif // ZIM_DECODERSTREAMREADER_H 105