diff --git a/stream.cpp b/stream.cpp index bb64113d..80af5327 100644 --- a/stream.cpp +++ b/stream.cpp @@ -315,8 +315,12 @@ void fStream::closeStream() unzStream::unzStream (unzFile &v) { file = v; - head = NULL; - numbytes = 0; + pos_in_buf = 0; + buf_pos_in_unzipped = unztell(file); + bytes_in_buf = 0; + + // remember start pos for seeks + unzGetFilePos(file, &unz_file_start_pos); } unzStream::~unzStream (void) @@ -324,21 +328,31 @@ unzStream::~unzStream (void) return; } +size_t unzStream::buffer_remaining() +{ + return bytes_in_buf - pos_in_buf; +} + +void unzStream::fill_buffer() +{ + buf_pos_in_unzipped = unztell(file); + bytes_in_buf = unzReadCurrentFile(file, buffer, unz_BUFFSIZ); + pos_in_buf = 0; +} + int unzStream::get_char (void) { unsigned char c; - if (numbytes <= 0) + if (buffer_remaining() <= 0) { - numbytes = unzReadCurrentFile(file, buffer, unz_BUFFSIZ); - if (numbytes <= 0) + fill_buffer(); + if (bytes_in_buf <= 0) return (EOF); - head = buffer; } - c = *head; - head++; - numbytes--; + c = *(buffer + pos_in_buf); + pos_in_buf++; return ((int) c); } @@ -373,28 +387,25 @@ size_t unzStream::read (void *buf, size_t len) if (len == 0) return (len); - if (len <= numbytes) - { - memcpy(buf, head, len); - numbytes -= len; - head += len; - return (len); - } + size_t to_read = len; + uint8 *read_to = (uint8 * )buf; + do + { + size_t in_buffer = buffer_remaining(); + if (to_read <= in_buffer) + { + memcpy(read_to, buffer + pos_in_buf, to_read); + pos_in_buf += to_read; + to_read = 0; + break; + } - size_t numread = 0; - if (numbytes > 0) - { - memcpy(buf, head, numbytes); - numread += numbytes; - head = NULL; - numbytes = 0; - } + memcpy(read_to, buffer + pos_in_buf, in_buffer); + to_read -= in_buffer; + fill_buffer(); + } while (bytes_in_buf); - int l = unzReadCurrentFile(file, (uint8 *)buf + numread, len - numread); - if (l > 0) - numread += l; - - return (numread); + return (len - to_read); } // not supported @@ -405,7 +416,7 @@ size_t unzStream::write (void *buf, size_t len) size_t unzStream::pos (void) { - return (unztell(file)); + return buf_pos_in_unzipped + pos_in_buf; } size_t unzStream::size (void) @@ -415,10 +426,26 @@ size_t unzStream::size (void) return info.uncompressed_size; } -// not supported int unzStream::revert (size_t from, size_t offset) { - return -1; + size_t target_pos = from + offset; + + // new pos inside buffered data + if (target_pos >= buf_pos_in_unzipped && target_pos < buf_pos_in_unzipped + bytes_in_buf) + { + pos_in_buf = target_pos - buf_pos_in_unzipped; + } + else // outside of buffer, reset file and read until pos + { + unzGoToFilePos(file, &unz_file_start_pos); + int times_to_read = target_pos / unz_BUFFSIZ + 1; + for( int i = 0; i < times_to_read; i++) + { + fill_buffer(); + } + pos_in_buf = target_pos % unz_BUFFSIZ; + } + return 0; } void unzStream::closeStream() diff --git a/stream.h b/stream.h index ea22df0a..1539dd44 100644 --- a/stream.h +++ b/stream.h @@ -252,10 +252,15 @@ class unzStream : public Stream virtual void closeStream(); private: + void fill_buffer(); + size_t buffer_remaining(); + unzFile file; char buffer[unz_BUFFSIZ]; - char *head; - size_t numbytes; + size_t pos_in_buf; + size_t buf_pos_in_unzipped; + size_t bytes_in_buf; + unz_file_pos unz_file_start_pos; }; #endif