diff --git a/src/modules/Gz/module.pmod.in b/src/modules/Gz/module.pmod.in index 611a231a341a393db90c4b5aa2052d3caa45b110..182b1eed04e74592497ba7bc6c12e3cf16d3f110 100644 --- a/src/modules/Gz/module.pmod.in +++ b/src/modules/Gz/module.pmod.in @@ -1,4 +1,4 @@ -// $Id: module.pmod.in,v 1.13 2003/04/15 13:53:16 marcus Exp $ +// $Id: module.pmod.in,v 1.14 2003/04/15 15:01:19 marcus Exp $ #pike __REAL_VERSION__ inherit @module@; @@ -11,48 +11,61 @@ class _file { static private deflate def; static private int level, strategy; static private string read_buf; - static private int file_pos, crc, write_mode; + static private int file_pos, crc, write_mode, at_eof; constant SEEK_SET = 0; constant SEEK_CUR = 1; constant SEEK_END = 2; - static int check_header() + static int check_header(string|void buf) { int magic1, magic2, method, flags, len; - if(sscanf(f->read(4), "%1c%1c%1c%1c", magic1, magic2, method, flags)!=4 || + if(!buf) buf=""; + string buf_read(int n) + { + if(sizeof(buf)<n) + buf += f->read(min(n-sizeof(buf), 10)); + string r = buf[..n-1]; + buf = buf[n..]; + return r; + }; + + if(sscanf(buf_read(4), "%1c%1c%1c%1c", magic1, magic2, method, flags)!=4 || magic1 != 0x1f || magic2 != 0x8b) return 0; if(method != 8 || (flags & 0xe0)) return 0; - if(sizeof(f->read(6)) != 6) + if(sizeof(buf_read(6)) != 6) return 0; if(flags & 4) - if(sscanf(f->read(2), "%-2c", len) != 1 || - sizeof(f->read(len)) != len) + if(sscanf(buf_read(2), "%-2c", len) != 1 || + sizeof(buf_read(len)) != len) return 0; if(flags & 8) loop: for(;;) - switch(f->read(1)) { - case 0: case "": return 0; + switch(buf_read(1)) { + case "": return 0; case "\0": break loop; } if(flags & 16) loop: for(;;) - switch(f->read(1)) { - case 0: case "": return 0; + switch(buf_read(1)) { + case "": return 0; case "\0": break loop; } if(flags & 2) - if(sizeof(f->read(2)) != 2) + if(sizeof(buf_read(2)) != 2) return 0; + + if(sizeof(buf)) + fill_read_buffer(buf); return 1; } @@ -95,7 +108,7 @@ class _file { if(write_mode) mode += "c"+(has_value(mode, 'a')? "w":"t"); } - file_pos = 0; + at_eof = file_pos = 0; crc = crc32(""); if(objectp(file)) f = file; @@ -134,21 +147,51 @@ class _file { return !oldf || oldf->close(); } + static int fill_read_buffer(string|void data) + { + if(at_eof) + return 0; + string r = data || f->read(16384); + if(!sizeof(r)) { + at_eof = 1; + return 0; + } + if(!inf) inf = inflate(-15); + string b = inf->inflate(r); + read_buf += b; + crc = crc32(b, crc); + if(b = inf->end_of_stream()) { + inf = 0; + if(sizeof(b)<8) + b += f->read(8-sizeof(b)); + sscanf(b, "%-4c%-4c", int f_crc, int f_len); +#ifdef GZ_FILE_DEBUG + werror("File: crc=%x size=%d Internal: crc=%x size=%d\n", + f_crc, f_len, crc&0xffffffff, file_pos+sizeof(read_buf)); +#endif + if(f_crc != (crc&0xffffffff)) { + // CRC error + at_eof = 1; + return 0; + } else { + crc = crc32(""); + if(!check_header(b[8..])) + at_eof = 1; + } + } + return sizeof(r); + } + //! Reads len (uncompressed) bytes from the file. //! If read is unsuccessful, 0 is returned. int|string read(int len) { - if(!inf) inf = inflate(-15); - while(sizeof(read_buf) < len) { - string r = f->read(16384); - if(!sizeof(r)) + while(sizeof(read_buf) < len) + if(!fill_read_buffer()) break; - read_buf += inf->inflate(r); - } string res = read_buf[..len-1]; read_buf = read_buf[len..]; file_pos += sizeof(res); - crc = crc32(res, crc); return res; } @@ -201,6 +244,7 @@ class _file { if(pos < file_pos) { if(!f->seek || f->seek(0)<0) return -1; + at_eof = 0; file_pos = 0; read_buf = ""; crc = crc32(""); @@ -229,13 +273,11 @@ class _file { //! 1 if EOF has been reached. int(0..1) eof() { - if(def || sizeof(read_buf)) return 0; - if(!inf) inf = inflate(-15); - string r = f->read(16384); - if(!sizeof(r)) - return 1; - read_buf = inf->inflate(r); - return !sizeof(read_buf); + if(at_eof) return 1; + if(def || write_mode || sizeof(read_buf)) return 0; + while(!sizeof(read_buf) && fill_read_buffer()) + ; + return at_eof; } //! Sets the encoding level and strategy