📄 gzio.pas
字号:
{ Check the gzip magic header }
for len := 0 to 1 do begin
c := get_byte(s);
if (c <> gz_magic[len]) then begin
if (len <> 0) then begin
Inc(s^.stream.avail_in);
Dec(s^.stream.next_in);
end;
if (c <> Z_EOF) then begin
Inc(s^.stream.avail_in);
Dec(s^.stream.next_in);
s^.transparent := TRUE;
end;
if (s^.stream.avail_in <> 0) then s^.z_err := Z_OK
else s^.z_err := Z_STREAM_END;
exit;
end;
end;
method := get_byte(s);
flags := get_byte(s);
if (method <> Z_DEFLATED) or ((flags and RESERVED) <> 0) then begin
s^.z_err := Z_DATA_ERROR;
exit;
end;
for len := 0 to 5 do get_byte(s); { Discard time, xflags and OS code }
if ((flags and EXTRA_FIELD) <> 0) then begin { skip the extra field }
len := uInt(get_byte(s));
len := len + (uInt(get_byte(s)) shr 8);
{ len is garbage if EOF but the loop below will quit anyway }
while (len <> 0) and (get_byte(s) <> Z_EOF) do Dec(len);
end;
if ((flags and ORIG_NAME) <> 0) then begin { skip the original file name }
repeat
c := get_byte(s);
until (c = 0) or (c = Z_EOF);
end;
if ((flags and COMMENT) <> 0) then begin { skip the .gz file comment }
repeat
c := get_byte(s);
until (c = 0) or (c = Z_EOF);
end;
if ((flags and HEAD_CRC) <> 0) then begin { skip the header crc }
get_byte(s);
get_byte(s);
end;
if (s^.z_eof = true) then
s^.z_err := Z_DATA_ERROR
else
s^.z_err := Z_OK;
end;
{ DESTROY ===================================================================
Cleanup then free the given gz_stream. Return a zlib error code.
Try freeing in the reverse order of allocations.
============================================================================}
function destroy (var s:gz_streamp) : int;
begin
destroy := Z_OK;
if not Assigned (s) then begin
destroy := Z_STREAM_ERROR;
exit;
end;
if (s^.stream.state <> NIL) then begin
if (s^.mode = 'w') then begin
{$IFDEF NO_DEFLATE}
destroy := Z_STREAM_ERROR;
{$ELSE}
destroy := deflateEnd(s^.stream);
{$ENDIF}
end
else if (s^.mode = 'r') then begin
destroy := inflateEnd(s^.stream);
end;
end;
if (s^.path <> '') then begin
{$I-}
close(s^.gzfile);
{$I+}
if (IOResult <> 0) then destroy := Z_ERRNO;
end;
if (s^.z_err < 0) then destroy := s^.z_err;
if Assigned (s^.inbuf) then
FreeMem(s^.inbuf, Z_BUFSIZE);
if Assigned (s^.outbuf) then
FreeMem(s^.outbuf, Z_BUFSIZE);
FreeMem(s, sizeof(gz_stream));
end;
{ GZREAD ====================================================================
Reads the given number of uncompressed bytes from the compressed file.
If the input file was not in gzip format, gzread copies the given number
of bytes into the buffer.
gzread returns the number of uncompressed bytes actually read
(0 for end of file, -1 for error).
============================================================================}
function gzread (f:gzFile; buf:voidp; len:uInt) : int;
var
s : gz_streamp;
start : pBytef;
next_out : pBytef;
n : uInt;
crclen : uInt; { Buffer length to update CRC32 }
filecrc : uLong; { CRC32 stored in GZIP'ed file }
filelen : uLong; { Total lenght of uncompressed file }
bytes : integer; { bytes actually read in I/O blockread }
total_in : uLong;
total_out : uLong;
begin
s := gz_streamp(f);
start := pBytef(buf); { starting point for crc computation }
if (s = NIL) or (s^.mode <> 'r') then begin
gzread := Z_STREAM_ERROR;
exit;
end;
if (s^.z_err = Z_DATA_ERROR) or (s^.z_err = Z_ERRNO) then begin
gzread := -1;
exit;
end;
if (s^.z_err = Z_STREAM_END) then begin
gzread := 0; { EOF }
exit;
end;
s^.stream.next_out := pBytef(buf);
s^.stream.avail_out := len;
while (s^.stream.avail_out <> 0) do begin
if (s^.transparent = true) then begin
{ Copy first the lookahead bytes: }
n := s^.stream.avail_in;
if (n > s^.stream.avail_out) then n := s^.stream.avail_out;
if (n > 0) then begin
zmemcpy(s^.stream.next_out, s^.stream.next_in, n);
inc (s^.stream.next_out, n);
inc (s^.stream.next_in, n);
dec (s^.stream.avail_out, n);
dec (s^.stream.avail_in, n);
end;
if (s^.stream.avail_out > 0) then begin
blockread (s^.gzfile, s^.stream.next_out^, s^.stream.avail_out, bytes);
dec (s^.stream.avail_out, uInt(bytes));
end;
dec (len, s^.stream.avail_out);
inc (s^.stream.total_in, uLong(len));
inc (s^.stream.total_out, uLong(len));
gzread := int(len);
exit;
end; { IF transparent }
if (s^.stream.avail_in = 0) and (s^.z_eof = false) then begin
{$I-}
blockread (s^.gzfile, s^.inbuf^, Z_BUFSIZE, s^.stream.avail_in);
{$I+}
if (s^.stream.avail_in = 0) then begin
s^.z_eof := true;
if (IOResult <> 0) then begin
s^.z_err := Z_ERRNO;
break;
end;
end;
s^.stream.next_in := s^.inbuf;
end;
s^.z_err := inflate(s^.stream, Z_NO_FLUSH);
if (s^.z_err = Z_STREAM_END) then begin
crclen := 0;
next_out := s^.stream.next_out;
while (next_out <> start ) do begin
dec (next_out);
inc (crclen); { Hack because Pascal cannot substract pointers }
end;
{ Check CRC and original size }
s^.crc := crc32(s^.crc, start, crclen);
start := s^.stream.next_out;
filecrc := getLong (s);
filelen := getLong (s);
if (s^.crc <> filecrc) or (s^.stream.total_out <> filelen)
then s^.z_err := Z_DATA_ERROR
else begin
{ Check for concatenated .gz files: }
check_header(s);
if (s^.z_err = Z_OK) then begin
total_in := s^.stream.total_in;
total_out := s^.stream.total_out;
inflateReset (s^.stream);
s^.stream.total_in := total_in;
s^.stream.total_out := total_out;
s^.crc := crc32 (0, Z_NULL, 0);
end;
end; {IF-THEN-ELSE}
end;
if (s^.z_err <> Z_OK) or (s^.z_eof = true) then break;
end; {WHILE}
crclen := 0;
next_out := s^.stream.next_out;
while (next_out <> start ) do begin
dec (next_out);
inc (crclen); { Hack because Pascal cannot substract pointers }
end;
s^.crc := crc32 (s^.crc, start, crclen);
gzread := int(len - s^.stream.avail_out);
end;
{ GZGETC ====================================================================
Reads one byte from the compressed file.
gzgetc returns this byte or -1 in case of end of file or error.
============================================================================}
function gzgetc (f:gzfile) : int;
var c:byte;
begin
if (gzread (f,@c,1) = 1) then gzgetc := c else gzgetc := -1;
end;
{ GZGETS ====================================================================
Reads bytes from the compressed file until len-1 characters are read,
or a newline character is read and transferred to buf, or an end-of-file
condition is encountered. The string is then Null-terminated.
gzgets returns buf, or Z_NULL in case of error.
The current implementation is not optimized at all.
============================================================================}
function gzgets (f:gzfile; buf:PChar; len:int) : PChar;
var
b : PChar; { start of buffer }
bytes : Int; { number of bytes read by gzread }
gzchar : char; { char read by gzread }
begin
if (buf = Z_NULL) or (len <= 0) then begin
gzgets := Z_NULL;
exit;
end;
b := buf;
repeat
dec (len);
bytes := gzread (f, buf, 1);
gzchar := buf^;
inc (buf);
until (len = 0) or (bytes <> 1) or (gzchar = Chr(13));
buf^ := Chr(0);
if (b = buf) and (len > 0) then gzgets := Z_NULL else gzgets := b;
end;
{$IFNDEF NO_DEFLATE}
{ GZWRITE ===================================================================
Writes the given number of uncompressed bytes into the compressed file.
gzwrite returns the number of uncompressed bytes actually written
(0 in case of error).
============================================================================}
function gzwrite (f:gzfile; buf:voidp; len:uInt) : int;
var
s : gz_streamp;
written : integer;
begin
s := gz_streamp(f);
if (s = NIL) or (s^.mode <> 'w') then begin
gzwrite := Z_STREAM_ERROR;
exit;
end;
s^.stream.next_in := pBytef(buf);
s^.stream.avail_in := len;
while (s^.stream.avail_in <> 0) do begin
if (s^.stream.avail_out = 0) then begin
s^.stream.next_out := s^.outbuf;
blockwrite (s^.gzfile, s^.outbuf^, Z_BUFSIZE, written);
if (written <> Z_BUFSIZE) then begin
s^.z_err := Z_ERRNO;
break;
end;
s^.stream.avail_out := Z_BUFSIZE;
end;
s^.z_err := deflate(s^.stream, Z_NO_FLUSH);
if (s^.z_err <> Z_OK) then break;
end; {WHILE}
s^.crc := crc32(s^.crc, buf, len);
gzwrite := int(len - s^.stream.avail_in);
end;
{ ===========================================================================
Converts, formats, and writes the args to the compressed file under
control of the format string, as in fprintf. gzprintf returns the number of
uncompressed bytes actually written (0 in case of error).
}
{$IFDEF GZ_FORMAT_STRING}
function gzprintf (zfile : gzFile;
const format : string;
a : array of int) : int;
var
buf : array[0..Z_PRINTF_BUFSIZE-1] of char;
len : int;
begin
{$ifdef HAS_snprintf}
snprintf(buf, sizeof(buf), format, a1, a2, a3, a4, a5, a6, a7, a8,
a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20);
{$else}
sprintf(buf, format, a1, a2, a3, a4, a5, a6, a7, a8,
a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20);
{$endif}
len := strlen(buf); { old sprintf doesn't return the nb of bytes written }
if (len <= 0) return 0;
gzprintf := gzwrite(file, buf, len);
end;
{$ENDIF}
{ GZPUTC ====================================================================
Writes c, converted to an unsigned char, into the compressed file.
gzputc returns the value that was written, or -1 in case of error.
============================================================================}
function gzputc (f:gzfile; c:char) : int;
begin
if (gzwrite (f,@c,1) = 1) then
{$IFDEF FPC}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -