// zstream.cpp: implementation of the zstream class. // // Copyright (C) 2002 Tanguy Fautre // For conditions of distribution and use, // see copyright notice in zfsystem.h // ////////////////////////////////////////////////////////////////////// #include "stdafx.h" #include "zstream.h" namespace zip_file_system { using namespace std; ////////////////////////////////////////////////////////////////////// // zstream Member Functions ////////////////////////////////////////////////////////////////////// void izstream::open(const char * Filename, streamoff Offset, streamoff Size, int CompMethod) { // Change the buffer if need if (m_CompMethod == CompMethod) { if (rdbuf() != NULL) static_cast(rdbuf())->close(); } else SetCompMethod(CompMethod); // clear up the file status clear(ios::goodbit); // open the buffer switch (m_CompMethod) { case STORED: case DEFLATED: if (! (static_cast(rdbuf())->open(Filename, Offset, Size))) { setstate(ios::badbit); SetCompMethod(-1); } break; default: setstate(ios::badbit); } } zbuffer * izstream::GetRightBuffer(int CompMethod) const { switch (CompMethod) { // stored case STORED: return new zbuffer_stored; // deflated case DEFLATED: return new zbuffer_deflated; // else not supported default: return NULL; } } bool zbuffer::use(std::streamoff Offset, std::streamoff Size) { if (! m_ZipFile) return false; //Don't use a buffer already used; if (m_Used) return false; // adjust file position if (! m_ZipFile.seekg(Offset, ios::beg)) return false; setg( m_Buffer, // beginning of putback area m_Buffer, // read position m_Buffer); // end of buffer m_Buffer[0] = 0; m_Pos = -1; m_Size = Size; m_Used = true; return true; } ////////////////////////////////////////////////////////////////////// // zbuffer_stored Member Functions ////////////////////////////////////////////////////////////////////// zbuffer_stored * zbuffer_stored::open(const char * Filename, streamoff Offset, streamoff Size) { // open main compressed file m_ZipFile.open(Filename, ios::binary); if (! m_ZipFile) return NULL; // adjust file position if (! use(Offset, Size)) return NULL; m_Opened = true; m_Filename = Filename; return this; } zbuffer_stored * zbuffer_stored::close() { if (! m_Opened) return NULL; else { m_Opened = false; m_Used = false; m_ZipFile.close(); } return this; } int zbuffer_stored::overflow(int) { return EOF; } int zbuffer_stored::underflow() { // Buffer Valid? if (! m_Opened) return EOF; // Do we really need to refill it? if (gptr() < egptr()) return static_cast(* gptr()); // Refill de buffer. // Set the real position of the beginning of the buffer. if (m_Pos == streamoff(-1)) m_Pos = 0; streamoff ToRead = ((m_Size - m_Pos) < BUFFERSIZE) ? (m_Size - m_Pos) : BUFFERSIZE; if ((ToRead == 0) || (! m_ZipFile.read(m_Buffer, ToRead))) return EOF; m_Pos += ToRead; // Reset buffer pointers. setg( m_Buffer, // beginning of putback area m_Buffer, // read position m_Buffer + ToRead); // end of buffer return static_cast(m_Buffer[0]); } streampos zbuffer_stored::seekoff(streamoff off, ios::seekdir dir, ios::openmode nMode) { streamoff WantedPos = 0; // Find out the wanted position. switch (dir) { case ios_base::cur: WantedPos = m_Pos + streamoff(gptr() - eback()) + off; break; case ios_base::beg: WantedPos = off; break; case ios_base::end: WantedPos = m_Size + off; break; default: assert(false); } // Is the position valid? if ((WantedPos < 0) || (WantedPos > m_Size)) return streambuf::seekoff(off, dir, nMode); // return invalid streamoff // Is the position already within the buffer? if ((WantedPos >= m_Pos) && (WantedPos - m_Pos < egptr() - eback())) { setg(eback(), eback() + (WantedPos - m_Pos), egptr()); return WantedPos; } // Fill up the buffer at the right position. if (! m_ZipFile.seekg(WantedPos, ios::beg)) return streambuf::seekoff(off, dir, nMode); m_Pos = WantedPos; streamoff ToRead = ((m_Size - m_Pos) < BUFFERSIZE) ? (m_Size - m_Pos) : BUFFERSIZE; if (ToRead == 0) return WantedPos; if (! m_ZipFile.read(m_Buffer, ToRead)) return streambuf::seekoff(off, dir, nMode); // Set the buffer at the right position setg(m_Buffer, m_Buffer, m_Buffer + ToRead); return WantedPos; } int zbuffer_stored::sync() { return 0; } streambuf * zbuffer_stored::setbuf(char *, int) { return NULL; } ////////////////////////////////////////////////////////////////////// // zbuffer_deflated Member Functions ////////////////////////////////////////////////////////////////////// zbuffer_deflated * zbuffer_deflated::open(const char * Filename, streamoff Offset, streamoff Size) { // open main compressed file m_ZipFile.open(Filename, ios::binary); if (! m_ZipFile) return NULL; // adjust file position if (! use(Offset, Size)) return NULL; // z_stream (NULL) Initialization m_ZStream.next_in = Z_NULL; m_ZStream.avail_in = 0; m_ZStream.total_in = 0; m_ZStream.next_out = Z_NULL; m_ZStream.avail_out = 0; m_ZStream.total_out = 0; m_ZStream.zalloc = Z_NULL; m_ZStream.zfree = Z_NULL; m_ZStream.opaque = Z_NULL; // inflate routine Initialization: Window Size = -MAX_WBITS tells there are no header if (inflateInit2(&m_ZStream, -MAX_WBITS) != Z_OK) return NULL; m_Opened = true; m_StreamEnd = false; m_Pos = 0; m_CompPos = 0; m_Filename = Filename; return this; } zbuffer_deflated * zbuffer_deflated::close() { if (! m_Opened) return NULL; else { m_Opened = false; m_Used = false; m_ZipFile.close(); // z_stream unitialization. if (inflateEnd(&m_ZStream) != Z_OK) return NULL; } return this; } int zbuffer_deflated::overflow(int) { return EOF; } int zbuffer_deflated::underflow() { // Buffer Valid? if (! m_Opened) return EOF; // Do we really need to refill it? if (gptr() < egptr()) return static_cast(* gptr()); // Can we refill? if (m_StreamEnd) return EOF; streamoff ToRead; streamoff OldPos; bool BufferRefill = false; // Check input (compressed) buffer status if ((m_ZStream.avail_in == 0) && (m_CompPos < m_Size )) { ToRead = ((m_Size - m_CompPos) > BUFFERSIZE) ? BUFFERSIZE : (m_Size - m_CompPos); m_CompPos += ToRead; if (! m_ZipFile.read(m_CompBuffer, ToRead)) return EOF; m_ZStream.next_in = reinterpret_cast(m_CompBuffer); m_ZStream.avail_in = ToRead; } // Ajust start read position in output buffer at the "old" end of buffer ToRead = m_ZStream.total_out % BUFFERSIZE; OldPos = m_ZStream.total_out; // Check output (decompressed) buffer status if (m_ZStream.avail_out == 0) { BufferRefill = true; m_ZStream.next_out = reinterpret_cast(m_Buffer); m_ZStream.avail_out = BUFFERSIZE; } // Decompress (Inflate) int Result = inflate(&m_ZStream, Z_SYNC_FLUSH); // Check decompression result if (Result == Z_STREAM_END) m_StreamEnd = true; else if (Result != Z_OK) return EOF; // Set the real position of the beginning of the buffer. if (m_Pos == streamoff(-1)) m_Pos = 0; else if (BufferRefill) m_Pos += m_ZStream.total_out - OldPos; // Reset buffer pointers. setg( m_Buffer, // beginning of putback area m_Buffer + ToRead, // read position m_Buffer + ((m_ZStream.total_out - 1) % (BUFFERSIZE)) + 1); // end of buffer return static_cast(m_Buffer[ToRead]); } streampos zbuffer_deflated::seekoff(std::streamoff off, std::ios::seekdir dir, std::ios::openmode nMode) { streamoff WantedPos = 0; // Find out the wanted position. switch (dir) { case ios_base::cur: WantedPos = m_Pos + streamoff(gptr() - eback()) + off; break; case ios_base::beg: WantedPos = off; break; case ios_base::end: WantedPos = m_Size + off; break; default: assert(false); } // Is the position valid? if ((WantedPos < 0) || (WantedPos > m_Size)) return streambuf::seekoff(off, dir, nMode); // return invalid streamoff // Is the position already within the buffer? if ((WantedPos >= m_Pos) && (WantedPos - m_Pos < egptr() - eback())) { setg(eback(), eback() + (WantedPos - m_Pos), egptr()); return WantedPos; } // Found out whether we have to decompress further or if we have to reset the decompression. if (WantedPos < m_Pos) { // Reset the decompression. if (inflateReset(&m_ZStream) != Z_OK) return streambuf::seekoff(off, dir, nMode); // z_stream Reset m_ZStream.next_in = Z_NULL; m_ZStream.avail_in = 0; m_ZStream.total_in = 0; m_ZStream.next_out = Z_NULL; m_ZStream.avail_out = 0; m_ZStream.total_out = 0; } // call underflow() untill the right position is within the buffer. while (WantedPos - m_Pos >= egptr() - eback()) { setg(eback(), egptr(), egptr()); if (underflow() == EOF) return streambuf::seekoff(off, dir, nMode); } // now the position is within the buffer. setg(eback(), eback() + (WantedPos - m_Pos), egptr()); return WantedPos; } int zbuffer_deflated::sync() { return 0; } streambuf * zbuffer_deflated::setbuf(char *, int) { return NULL; } } // namespace zip_file_system