📄 gzio.pas
字号:
Unit gzIO;
{
Pascal unit based on gzio.c -- IO on .gz files
Copyright (C) 1995-1998 Jean-loup Gailly.
Define NO_DEFLATE to compile this file without the compression code
Pascal tranlastion based on code contributed by Francisco Javier Crespo
Copyright (C) 1998 by Jacques Nomssi Nzali
For conditions of distribution and use, see copyright notice in readme.txt
}
interface
{$I zconf.inc}
uses
{$ifdef MSDOS}
dos, strings,
{$else}
SysUtils,
{$endif}
zutil, zlib, crc, zdeflate, zinflate;
type gzFile = voidp;
type z_off_t = long;
function gzopen (path:string; mode:string) : gzFile;
function gzread (f:gzFile; buf:voidp; len:uInt) : int;
function gzgetc (f:gzfile) : int;
function gzgets (f:gzfile; buf:PChar; len:int) : PChar;
{$ifndef NO_DEFLATE}
function gzwrite (f:gzFile; buf:voidp; len:uInt) : int;
function gzputc (f:gzfile; c:char) : int;
function gzputs (f:gzfile; s:PChar) : int;
function gzflush (f:gzFile; flush:int) : int;
{$ifdef GZ_FORMAT_STRING}
function gzprintf (zfile : gzFile;
const format : string;
a : array of int); { doesn't compile }
{$endif}
{$endif}
function gzseek (f:gzfile; offset:z_off_t; whence:int) : z_off_t;
function gztell (f:gzfile) : z_off_t;
function gzclose (f:gzFile) : int;
function gzerror (f:gzFile; var errnum:Int) : string;
const
SEEK_SET {: z_off_t} = 0; { seek from beginning of file }
SEEK_CUR {: z_off_t} = 1; { seek from current position }
SEEK_END {: z_off_t} = 2;
implementation
const
Z_EOF = -1; { same value as in STDIO.H }
Z_BUFSIZE = 16384;
{ Z_PRINTF_BUFSIZE = 4096; }
gz_magic : array[0..1] of byte = ($1F, $8B); { gzip magic header }
{ gzip flag byte }
ASCII_FLAG = $01; { bit 0 set: file probably ascii text }
HEAD_CRC = $02; { bit 1 set: header CRC present }
EXTRA_FIELD = $04; { bit 2 set: extra field present }
ORIG_NAME = $08; { bit 3 set: original file name present }
COMMENT = $10; { bit 4 set: file comment present }
RESERVED = $E0; { bits 5..7: reserved }
type gz_stream = record
stream : z_stream;
z_err : int; { error code for last stream operation }
z_eof : boolean; { set if end of input file }
gzfile : file; { .gz file }
inbuf : pBytef; { input buffer }
outbuf : pBytef; { output buffer }
crc : uLong; { crc32 of uncompressed data }
msg, { error message - limit 79 chars }
path : string[79]; { path name for debugging only - limit 79 chars }
transparent : boolean; { true if input file is not a .gz file }
mode : char; { 'w' or 'r' }
startpos : long; { start of compressed data in file (header skipped) }
end;
type gz_streamp = ^gz_stream;
function destroy (var s:gz_streamp) : int; forward;
procedure check_header(s:gz_streamp); forward;
{ GZOPEN ====================================================================
Opens a gzip (.gz) file for reading or writing. As Pascal does not use
file descriptors, the code has been changed to accept only path names.
The mode parameter defaults to BINARY read or write operations ('r' or 'w')
but can also include a compression level ('w9') or a strategy: Z_FILTERED
as in 'w6f' or Z_HUFFMAN_ONLY as in 'w1h'. (See the description of
deflateInit2 for more information about the strategy parameter.)
gzopen can be used to open a file which is not in gzip format; in this
case, gzread will directly read from the file without decompression.
gzopen returns NIL if the file could not be opened (non-zero IOResult)
or if there was insufficient memory to allocate the (de)compression state
(zlib error is Z_MEM_ERROR).
============================================================================}
function gzopen (path:string; mode:string) : gzFile;
var
i : uInt;
err : int;
level : int; { compression level }
strategy : int; { compression strategy }
s : gz_streamp;
{$IFDEF MSDOS}
attr : word; { file attributes }
{$ENDIF}
{$IFNDEF NO_DEFLATE}
gzheader : array [0..9] of byte;
{$ENDIF}
begin
if (path='') or (mode='') then begin
gzopen := Z_NULL;
exit;
end;
GetMem (s,sizeof(gz_stream));
if not Assigned (s) then begin
gzopen := Z_NULL;
exit;
end;
level := Z_DEFAULT_COMPRESSION;
strategy := Z_DEFAULT_STRATEGY;
s^.stream.zalloc := NIL; { (alloc_func)0 }
s^.stream.zfree := NIL; { (free_func)0 }
s^.stream.opaque := NIL; { (voidpf)0 }
s^.stream.next_in := Z_NULL;
s^.stream.next_out := Z_NULL;
s^.stream.avail_in := 0;
s^.stream.avail_out := 0;
s^.z_err := Z_OK;
s^.z_eof := false;
s^.inbuf := Z_NULL;
s^.outbuf := Z_NULL;
s^.crc := crc32(0, Z_NULL, 0);
s^.msg := '';
s^.transparent := false;
s^.path := path; { limit to 255 chars }
s^.mode := chr(0);
for i:=1 to Length(mode) do begin
case mode[i] of
'r' : s^.mode := 'r';
'w' : s^.mode := 'w';
'0'..'9' : level := Ord(mode[i])-Ord('0');
'f' : strategy := Z_FILTERED;
'h' : strategy := Z_HUFFMAN_ONLY;
end;
end;
if (s^.mode=chr(0)) then begin
destroy(s);
gzopen := gzFile(Z_NULL);
exit;
end;
if (s^.mode='w') then begin
{$IFDEF NO_DEFLATE}
err := Z_STREAM_ERROR;
{$ELSE}
err := deflateInit2 (s^.stream, level, Z_DEFLATED, -MAX_WBITS,
DEF_MEM_LEVEL, strategy);
{ windowBits is passed < 0 to suppress zlib header }
GetMem (s^.outbuf, Z_BUFSIZE);
s^.stream.next_out := s^.outbuf;
{$ENDIF}
if (err <> Z_OK) or (s^.outbuf = Z_NULL) then begin
destroy(s);
gzopen := gzFile(Z_NULL);
exit;
end;
end
else begin
GetMem (s^.inbuf, Z_BUFSIZE);
s^.stream.next_in := s^.inbuf;
err := inflateInit2_ (s^.stream, -MAX_WBITS, ZLIB_VERSION, sizeof(z_stream));
{ windowBits is passed < 0 to tell that there is no zlib header }
if (err <> Z_OK) or (s^.inbuf = Z_NULL) then begin
destroy(s);
gzopen := gzFile(Z_NULL);
exit;
end;
end;
s^.stream.avail_out := Z_BUFSIZE;
{$IFOPT I+} {$I-} {$define IOcheck} {$ENDIF}
Assign (s^.gzfile, s^.path);
{$ifdef MSDOS}
GetFAttr(s^.gzfile, Attr);
if (DosError <> 0) and (s^.mode='w') then
ReWrite (s^.gzfile,1)
else
Reset (s^.gzfile,1);
{$else}
if (not FileExists(s^.path)) and (s^.mode='w') then
ReWrite (s^.gzfile,1)
else
Reset (s^.gzfile,1);
{$endif}
{$IFDEF IOCheck} {$I+} {$ENDIF}
if (IOResult <> 0) then begin
destroy(s);
gzopen := gzFile(Z_NULL);
exit;
end;
if (s^.mode = 'w') then begin { Write a very simple .gz header }
{$IFNDEF NO_DEFLATE}
gzheader [0] := gz_magic [0];
gzheader [1] := gz_magic [1];
gzheader [2] := Z_DEFLATED; { method }
gzheader [3] := 0; { flags }
gzheader [4] := 0; { time[0] }
gzheader [5] := 0; { time[1] }
gzheader [6] := 0; { time[2] }
gzheader [7] := 0; { time[3] }
gzheader [8] := 0; { xflags }
gzheader [9] := 0; { OS code = MS-DOS }
blockwrite (s^.gzfile, gzheader, 10);
s^.startpos := LONG(10);
{$ENDIF}
end
else begin
check_header(s); { skip the .gz header }
s^.startpos := FilePos(s^.gzfile) - s^.stream.avail_in;
end;
gzopen := gzFile(s);
end;
{ GZSETPARAMS ===============================================================
Update the compression level and strategy.
============================================================================}
function gzsetparams (f:gzfile; level:int; strategy:int) : int;
var
s : gz_streamp;
written: integer;
begin
s := gz_streamp(f);
if (s = NIL) or (s^.mode <> 'w') then begin
gzsetparams := Z_STREAM_ERROR;
exit;
end;
{ Make room to allow flushing }
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 s^.z_err := Z_ERRNO;
s^.stream.avail_out := Z_BUFSIZE;
end;
gzsetparams := deflateParams (s^.stream, level, strategy);
end;
{ GET_BYTE ==================================================================
Read a byte from a gz_stream. Updates next_in and avail_in.
Returns EOF for end of file.
IN assertion: the stream s has been sucessfully opened for reading.
============================================================================}
function get_byte (s:gz_streamp) : int;
begin
if (s^.z_eof = true) then begin
get_byte := Z_EOF;
exit;
end;
if (s^.stream.avail_in = 0) 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 s^.z_err := Z_ERRNO;
get_byte := Z_EOF;
exit;
end;
s^.stream.next_in := s^.inbuf;
end;
Dec(s^.stream.avail_in);
get_byte := s^.stream.next_in^;
Inc(s^.stream.next_in);
end;
{ GETLONG ===================================================================
Reads a Longint in LSB order from the given gz_stream.
============================================================================}
{
function getLong (s:gz_streamp) : uLong;
var
x : array [0..3] of byte;
i : byte;
c : int;
n1 : longint;
n2 : longint;
begin
for i:=0 to 3 do begin
c := get_byte(s);
if (c = Z_EOF) then s^.z_err := Z_DATA_ERROR;
x[i] := (c and $FF)
end;
n1 := (ush(x[3] shl 8)) or x[2];
n2 := (ush(x[1] shl 8)) or x[0];
getlong := (n1 shl 16) or n2;
end;
}
function getLong(s : gz_streamp) : uLong;
var
x : packed array [0..3] of byte;
c : int;
begin
{ x := uLong(get_byte(s)); - you can't do this with TP, no unsigned long }
{ the following assumes a little endian machine and TP }
x[0] := Byte(get_byte(s));
x[1] := Byte(get_byte(s));
x[2] := Byte(get_byte(s));
c := get_byte(s);
x[3] := Byte(c);
if (c = Z_EOF) then
s^.z_err := Z_DATA_ERROR;
GetLong := uLong(longint(x));
end;
{ CHECK_HEADER ==============================================================
Check the gzip header of a gz_stream opened for reading.
Set the stream mode to transparent if the gzip magic header is not present.
Set s^.err to Z_DATA_ERROR if the magic header is present but the rest of
the header is incorrect.
IN assertion: the stream s has already been created sucessfully;
s^.stream.avail_in is zero for the first time, but may be non-zero
for concatenated .gz files
============================================================================}
procedure check_header (s:gz_streamp);
var
method : int; { method byte }
flags : int; { flags byte }
len : uInt;
c : int;
begin
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -