mirror of
https://github.com/vishapoberon/compiler.git
synced 2026-04-06 20:22:24 +00:00
Make module from Trianus system added.
S3 system filen renamed with prefix eth.
Former-commit-id: 2aeddb9975
This commit is contained in:
parent
8d3b311dd2
commit
d9065fea6d
15 changed files with 441 additions and 38 deletions
|
|
@ -1,745 +0,0 @@
|
|||
(* ETH Oberon, Copyright 2001 ETH Zuerich Institut fuer Computersysteme, ETH Zentrum, CH-8092 Zuerich.
|
||||
Refer to the "General ETH Oberon System Source License" contract available at: http://www.oberon.ethz.ch/ *)
|
||||
|
||||
MODULE Zip; (** Stefan Walthert **)
|
||||
|
||||
IMPORT
|
||||
Files := OakFiles, Zlib, ZlibReaders, ZlibWriters;
|
||||
|
||||
CONST
|
||||
|
||||
(** result codes **)
|
||||
Ok* = 0; (** operation on zip-file was successful **)
|
||||
FileError* = -1; (** file not found **)
|
||||
NotZipArchiveError* = -2; (** file is not in zip format **)
|
||||
EntryNotFound* = -3; (** specified file was not found in zip-file **)
|
||||
EntryAlreadyExists* = -4; (** file is already stored in zip-file -> can not add specified file to zip-file **)
|
||||
NotSupportedError* = -5; (** can not extract specified file (compression method not supported/file is encrypted) **)
|
||||
DataError* = -6; (** file is corrupted **)
|
||||
BadName* = -7; (** bad file name *)
|
||||
ReaderError* = -8; (** e.g. Reader not opened before Read **)
|
||||
|
||||
(** compression levels **)
|
||||
DefaultCompression* = ZlibWriters.DefaultCompression;
|
||||
NoCompression* = ZlibWriters.NoCompression;
|
||||
BestSpeed* = ZlibWriters.BestSpeed;
|
||||
BestCompression* = ZlibWriters.BestCompression;
|
||||
|
||||
(** compression strategies **)
|
||||
DefaultStrategy* = ZlibWriters.DefaultStrategy;
|
||||
Filtered* = ZlibWriters.Filtered;
|
||||
HuffmanOnly* = ZlibWriters.HuffmanOnly;
|
||||
|
||||
(* support *)
|
||||
Supported = 0; (* can extract file *)
|
||||
IncompatibleVersion = 1; (* version needed to extract < PKZIP 1.00 *)
|
||||
Encrypted = 2; (* file is encrypted *)
|
||||
UnsupCompMethod = 3; (* file not stored or deflated *)
|
||||
|
||||
Stored = 0; (* file is stored (no compression) *)
|
||||
Deflated = 8; (* file is deflated *)
|
||||
|
||||
SupportedCompMethods = {Stored, Deflated};
|
||||
CompatibleVersions = 1; (* versions >= CompatibleVersions are supported *)
|
||||
|
||||
(* headers *)
|
||||
LocalFileHeaderSignature = 04034B50H;
|
||||
CentralFileHeaderSignature = 02014B50H;
|
||||
EndOfCentralDirSignature = 06054B50H;
|
||||
|
||||
TYPE
|
||||
Entry* = POINTER TO EntryDesc; (** description of a file stored in the zip-archive **)
|
||||
EntryDesc* = RECORD
|
||||
name-: ARRAY 256 OF CHAR; (** name of file stored in the zip-archive **)
|
||||
method: INTEGER; (* compression method *)
|
||||
time-, date-: LONGINT; (** (Oberon) time and date when file was last modified **)
|
||||
crc32: LONGINT; (* checksum of uncompressed file data *)
|
||||
compSize-, uncompSize-: LONGINT; (** size of compressed / uncompressed file **)
|
||||
intFileAttr: INTEGER; (* internal file attributes, not used in this implementation *)
|
||||
extFileAttr: LONGINT; (* external file attributes, not used in this implementation *)
|
||||
extraField (* for future expansions *), comment-: POINTER TO ARRAY OF CHAR; (** comment for this file **)
|
||||
genPurpBitFlag: INTEGER;
|
||||
support: SHORTINT;
|
||||
dataDescriptor: BOOLEAN; (* if set, data descriptor after (compressed) file data *)
|
||||
offsetLocal: LONGINT; (* offset of file header in central directory *)
|
||||
offsetFileData: LONGINT; (* offset of (compressed) file data *)
|
||||
offsetCentralDir: LONGINT; (* offset of local file header *)
|
||||
next: Entry
|
||||
END;
|
||||
|
||||
Archive* = POINTER TO ArchiveDesc; (** description of a zipfile **)
|
||||
ArchiveDesc* = RECORD
|
||||
nofEntries-: INTEGER; (** total number of files stored in the zipfile **)
|
||||
comment-: POINTER TO ARRAY OF CHAR; (** comment for zipfile **)
|
||||
file: Files.File; (* pointer to the according zip-file *)
|
||||
offset: LONGINT; (* offset of end of central dir record *)
|
||||
firstEntry, lastEntry: Entry (* first and last Entry of Archive *)
|
||||
END;
|
||||
|
||||
Reader* = POINTER TO ReaderDesc;
|
||||
ReaderDesc* = RECORD (** structure for reading from a zip-file into a buffer **)
|
||||
res-: LONGINT; (** result of last operation **)
|
||||
open: BOOLEAN;
|
||||
ent: Entry
|
||||
END;
|
||||
|
||||
UncompReader = POINTER TO UncompReaderDesc;
|
||||
UncompReaderDesc = RECORD (ReaderDesc) (* structur for reading from a uncompressed entry *)
|
||||
fr: Files.Rider;
|
||||
crc32: LONGINT; (* crc32 of uncomressed data *)
|
||||
END;
|
||||
|
||||
DefReader = POINTER TO DefReaderDesc;
|
||||
DefReaderDesc = RECORD (ReaderDesc) (* structure for reading from a deflated entry *)
|
||||
zr: ZlibReaders.Reader
|
||||
END;
|
||||
|
||||
(* length of str *)
|
||||
PROCEDURE StringLength(VAR str(* in *): ARRAY OF CHAR): LONGINT;
|
||||
VAR i, l: LONGINT;
|
||||
BEGIN
|
||||
l := LEN(str); i := 0;
|
||||
WHILE (i < l) & (str[i] # 0X) DO
|
||||
INC(i)
|
||||
END;
|
||||
RETURN i
|
||||
END StringLength;
|
||||
|
||||
(* Converts Oberon time into MS-DOS time *)
|
||||
PROCEDURE OberonToDosTime(t: LONGINT): INTEGER;
|
||||
BEGIN
|
||||
RETURN SHORT(t DIV 1000H MOD 20H * 800H + t DIV 40H MOD 40H * 20H + t MOD 40H DIV 2)
|
||||
END OberonToDosTime;
|
||||
|
||||
(* Converts Oberon date into MS-DOS time *)
|
||||
PROCEDURE OberonToDosDate(d: LONGINT): INTEGER;
|
||||
BEGIN
|
||||
RETURN SHORT((d DIV 200H + 1900 - 1980) * 200H + d MOD 200H)
|
||||
END OberonToDosDate;
|
||||
|
||||
(* Converts MS-DOS time into Oberon time *)
|
||||
PROCEDURE DosToOberonTime(t: INTEGER): LONGINT;
|
||||
BEGIN
|
||||
RETURN LONG(t) DIV 800H MOD 20H * 1000H + t DIV 20H MOD 40H * 40H + t MOD 20H * 2
|
||||
END DosToOberonTime;
|
||||
|
||||
(* Converts MS-DOS date into Oberon date *)
|
||||
PROCEDURE DosToOberonDate(d: INTEGER): LONGINT;
|
||||
BEGIN
|
||||
RETURN (LONG(d) DIV 200H MOD 80H + 1980 - 1900) * 200H + d MOD 200H
|
||||
END DosToOberonDate;
|
||||
|
||||
(* Copy len bytes from src to dst; if compCRC32 is set, then the crc 32-checksum is computed *)
|
||||
PROCEDURE Copy(VAR src, dst: Files.Rider; len: LONGINT; compCRC32: BOOLEAN; VAR crc32: LONGINT);
|
||||
CONST
|
||||
BufSize = 4000H;
|
||||
VAR
|
||||
n: LONGINT;
|
||||
buf: ARRAY BufSize OF CHAR;
|
||||
BEGIN
|
||||
IF compCRC32 THEN crc32 := Zlib.CRC32(0, buf, -1, -1) END;
|
||||
REPEAT
|
||||
IF len < BufSize THEN n := len
|
||||
ELSE n := BufSize
|
||||
END;
|
||||
Files.ReadBytes(src, buf, n);
|
||||
IF compCRC32 THEN crc32 := Zlib.CRC32(crc32, buf, 0, n - src.res) END;
|
||||
Files.WriteBytes(dst, buf, n - src.res);
|
||||
DEC(len, n)
|
||||
UNTIL len = 0
|
||||
END Copy;
|
||||
|
||||
(* Reads an Entry, r must be at the start of a file header; returns NIL if read was not successful *)
|
||||
PROCEDURE ReadEntry(VAR r: Files.Rider): Entry;
|
||||
VAR
|
||||
ent: Entry;
|
||||
intDummy, nameLen, extraLen, commentLen: INTEGER;
|
||||
longDummy: LONGINT;
|
||||
bufDummy: ARRAY 256 OF CHAR;
|
||||
BEGIN
|
||||
Files.ReadLInt(r, longDummy);
|
||||
IF longDummy = CentralFileHeaderSignature THEN
|
||||
NEW(ent);
|
||||
ent.offsetCentralDir := Files.Pos(r) - 4;
|
||||
ent.support := 0;
|
||||
Files.ReadInt(r, intDummy); (* version made by *)
|
||||
Files.ReadInt(r, intDummy); (* version needed to extract *)
|
||||
IF (intDummy MOD 100H) / 10 < CompatibleVersions THEN
|
||||
ent.support := IncompatibleVersion
|
||||
END;
|
||||
Files.ReadInt(r, ent.genPurpBitFlag); (* general purpose bit flag *)
|
||||
IF ODD(intDummy) THEN
|
||||
ent.support := Encrypted (* bit 0: if set, file encrypted *)
|
||||
END;
|
||||
ent.dataDescriptor := ODD(intDummy DIV 8); (* bit 3: data descriptor after (compressed) file data *)
|
||||
Files.ReadInt(r, ent.method); (* compression method *)
|
||||
IF (ent.support = Supported) & ~(ent.method IN SupportedCompMethods) THEN
|
||||
ent.support := UnsupCompMethod
|
||||
END;
|
||||
Files.ReadInt(r, intDummy); ent.time := DosToOberonTime(intDummy); (* last mod file time *)
|
||||
Files.ReadInt(r, intDummy); ent.date := DosToOberonDate(intDummy); (* last mod file date *)
|
||||
Files.ReadLInt(r, ent.crc32); (* crc-32 *)
|
||||
Files.ReadLInt(r, ent.compSize); (* compressed size *)
|
||||
Files.ReadLInt(r, ent.uncompSize); (* uncompressed size *)
|
||||
Files.ReadInt(r, nameLen); (* filename length *)
|
||||
Files.ReadInt(r, extraLen); (* extra field length *)
|
||||
Files.ReadInt(r, commentLen); (* file comment length *)
|
||||
Files.ReadInt(r, intDummy); (* disk number start *)
|
||||
Files.ReadInt(r, ent.intFileAttr); (* internal file attributes *)
|
||||
Files.ReadLInt(r, ent.extFileAttr); (* external file attributes *)
|
||||
Files.ReadLInt(r, ent.offsetLocal); (* relative offset of local header *)
|
||||
Files.ReadBytes(r, ent.name, nameLen); (* filename *)
|
||||
IF extraLen # 0 THEN
|
||||
NEW(ent.extraField, extraLen);
|
||||
Files.ReadBytes(r, ent.extraField^, extraLen) (* extra field *)
|
||||
END;
|
||||
IF commentLen > 0 THEN
|
||||
NEW(ent.comment, commentLen);
|
||||
Files.ReadBytes(r, ent.comment^, commentLen) (* file comment *)
|
||||
END;
|
||||
(* read extra field length in the local file header (can be different from extra field length stored in the file header...) *)
|
||||
longDummy := Files.Pos(r); (* store actual position of file reader *)
|
||||
Files.Set(r, Files.Base(r), ent.offsetLocal + 28); (* set r to position of extra field length in local file header *)
|
||||
Files.ReadInt(r, extraLen); (* extra field length *)
|
||||
ent.offsetFileData := ent.offsetLocal + 30 + nameLen + extraLen; (* compute offset of file data *)
|
||||
Files.Set(r, Files.Base(r), longDummy); (* set position of file reader to previous position *)
|
||||
IF r.eof THEN (* if file is a zip-archive, r is not at end of file *)
|
||||
ent := NIL
|
||||
END
|
||||
END;
|
||||
RETURN ent;
|
||||
END ReadEntry;
|
||||
|
||||
(* Writes a local file header *)
|
||||
PROCEDURE WriteLocalFileHeader(ent: Entry; VAR r: Files.Rider);
|
||||
BEGIN
|
||||
Files.WriteLInt(r, LocalFileHeaderSignature); (* local file header signature *)
|
||||
Files.WriteInt(r, CompatibleVersions * 10); (* version needed to extract *)
|
||||
Files.WriteInt(r, ent.genPurpBitFlag); (* general purpose bit flag *)
|
||||
Files.WriteInt(r, ent.method); (* compression method *)
|
||||
Files.WriteInt(r, OberonToDosTime(ent.time)); (* last mod file time *)
|
||||
Files.WriteInt(r, OberonToDosDate(ent.date)); (* last mod file date *)
|
||||
Files.WriteLInt(r, ent.crc32); (* crc-32 *)
|
||||
Files.WriteLInt(r, ent.compSize); (* compressed size *)
|
||||
Files.WriteLInt(r, ent.uncompSize); (* uncompressed size *)
|
||||
Files.WriteInt(r, SHORT(StringLength(ent.name))); (* filename length *)
|
||||
IF ent.extraField # NIL THEN
|
||||
Files.WriteInt(r, SHORT(LEN(ent.extraField^))) (* extra field length *)
|
||||
ELSE
|
||||
Files.WriteInt(r, 0)
|
||||
END;
|
||||
Files.WriteBytes(r, ent.name, StringLength(ent.name)); (* filename *)
|
||||
IF ent.extraField # NIL THEN
|
||||
Files.WriteBytes(r, ent.extraField^, LEN(ent.extraField^)) (* extra field *)
|
||||
END
|
||||
END WriteLocalFileHeader;
|
||||
|
||||
(* Writes file header in central directory, updates ent.offsetCentralDir *)
|
||||
PROCEDURE WriteFileHeader(ent: Entry; VAR r: Files.Rider);
|
||||
BEGIN
|
||||
ent.offsetCentralDir := Files.Pos(r);
|
||||
Files.WriteLInt(r, CentralFileHeaderSignature); (* central file header signature *)
|
||||
Files.WriteInt(r, CompatibleVersions * 10); (* version made by *)
|
||||
Files.WriteInt(r, CompatibleVersions * 10); (* version needed to extract *)
|
||||
Files.WriteInt(r, ent.genPurpBitFlag); (* general purpose bit flag *)
|
||||
Files.WriteInt(r, ent.method); (* compression method *)
|
||||
Files.WriteInt(r, OberonToDosTime(ent.time)); (* last mod file time *)
|
||||
Files.WriteInt(r, OberonToDosDate(ent.date)); (* last mod file date *)
|
||||
Files.WriteLInt(r, ent.crc32); (* crc-32 *)
|
||||
Files.WriteLInt(r, ent.compSize); (* compressed size *)
|
||||
Files.WriteLInt(r, ent.uncompSize); (* uncompressed size *)
|
||||
Files.WriteInt(r, SHORT(StringLength(ent.name))); (* filename length *)
|
||||
IF ent.extraField = NIL THEN
|
||||
Files.WriteInt(r, 0)
|
||||
ELSE
|
||||
Files.WriteInt(r, SHORT(LEN(ent.extraField^))); (* extra field length *)
|
||||
END;
|
||||
IF ent.comment = NIL THEN
|
||||
Files.WriteInt(r, 0)
|
||||
ELSE
|
||||
Files.WriteInt(r, SHORT(LEN(ent.comment^))); (* file comment length *)
|
||||
END;
|
||||
Files.WriteInt(r, 0); (* disk number start *)
|
||||
Files.WriteInt(r, ent.intFileAttr); (* internal file attributes *)
|
||||
Files.WriteLInt(r, ent.extFileAttr); (* external file attributes *)
|
||||
Files.WriteLInt(r, ent.offsetLocal); (* relative offset of local header *)
|
||||
Files.WriteBytes(r, ent.name, StringLength(ent.name)); (* filename *)
|
||||
IF ent.extraField # NIL THEN
|
||||
Files.WriteBytes(r, ent.extraField^, LEN(ent.extraField^)) (* extra field *)
|
||||
END;
|
||||
IF ent.comment # NIL THEN
|
||||
Files.WriteBytes(r, ent.comment^, LEN(ent.comment^)) (* file comment *)
|
||||
END
|
||||
END WriteFileHeader;
|
||||
|
||||
(* Writes end of central directory record *)
|
||||
PROCEDURE WriteEndOfCentDir(arc: Archive; VAR r: Files.Rider);
|
||||
VAR
|
||||
size: LONGINT;
|
||||
BEGIN
|
||||
Files.WriteLInt(r, EndOfCentralDirSignature); (* end of central dir signature *)
|
||||
Files.WriteInt(r, 0); (* number of this disk *)
|
||||
Files.WriteInt(r, 0); (* number of the disk with the start of the central directory *)
|
||||
Files.WriteInt(r, arc.nofEntries); (* total number of entries in the central dir on this disk *)
|
||||
Files.WriteInt(r, arc.nofEntries); (* total number of entries in the central dir *)
|
||||
IF arc.firstEntry # NIL THEN
|
||||
Files.WriteLInt(r, arc.offset - arc.firstEntry.offsetCentralDir) (* size of the central directory (without end of central dir record) *)
|
||||
ELSE
|
||||
Files.WriteLInt(r, 0)
|
||||
END;
|
||||
IF arc.firstEntry = NIL THEN
|
||||
Files.WriteLInt(r, arc.offset) (* offset of start of central directory with respect to the starting disk number *)
|
||||
ELSE
|
||||
Files.WriteLInt(r, arc.firstEntry.offsetCentralDir) (* offset of start of central directory with respect to the starting disk number *)
|
||||
END;
|
||||
IF arc.comment = NIL THEN
|
||||
Files.WriteInt(r, 0) (* zipfile comment length *)
|
||||
ELSE
|
||||
Files.WriteInt(r, SHORT(LEN(arc.comment^))); (* zipfile comment length *)
|
||||
Files.WriteBytes(r, arc.comment^, LEN(arc.comment^)) (* zipfile comment *)
|
||||
END
|
||||
END WriteEndOfCentDir;
|
||||
|
||||
(* Writes central directory + end of central directory record, updates arc.offset and offsetCentralDir of entries *)
|
||||
PROCEDURE WriteCentralDirectory(arc: Archive; VAR r: Files.Rider);
|
||||
VAR
|
||||
ent: Entry;
|
||||
BEGIN
|
||||
ent := arc.firstEntry;
|
||||
WHILE ent # NIL DO
|
||||
WriteFileHeader(ent, r);
|
||||
ent := ent.next
|
||||
END;
|
||||
arc.offset := Files.Pos(r);
|
||||
WriteEndOfCentDir(arc, r)
|
||||
END WriteCentralDirectory;
|
||||
|
||||
(** Returns an Archive data structure corresponding to the specified zipfile;
|
||||
possible results:
|
||||
- Ok: operation was successful
|
||||
- FileError: file with specified name does not exist
|
||||
- NotZipArchiveError: file is not a correct zipfile **)
|
||||
PROCEDURE OpenArchive*(name: ARRAY OF CHAR; VAR res: LONGINT): Archive;
|
||||
VAR
|
||||
arc: Archive;
|
||||
ent: Entry;
|
||||
f: Files.File;
|
||||
r: Files.Rider;
|
||||
longDummy: LONGINT;
|
||||
intDummy: INTEGER;
|
||||
BEGIN
|
||||
res := Ok;
|
||||
f := Files.Old(name);
|
||||
IF f = NIL THEN
|
||||
res := FileError
|
||||
ELSIF Files.Length(f) < 22 THEN
|
||||
res := NotZipArchiveError
|
||||
ELSE
|
||||
longDummy := 0;
|
||||
Files.Set(r, f, Files.Length(f) - 17);
|
||||
WHILE (longDummy # EndOfCentralDirSignature) & (Files.Pos(r) > 4) DO
|
||||
Files.Set(r, f, Files.Pos(r) - 5);
|
||||
Files.ReadLInt(r, longDummy)
|
||||
END;
|
||||
IF longDummy # EndOfCentralDirSignature THEN
|
||||
res := NotZipArchiveError
|
||||
ELSE
|
||||
NEW(arc);
|
||||
arc.file := f;
|
||||
arc.offset := Files.Pos(r) - 4;
|
||||
Files.ReadInt(r, intDummy); (* number of this disk *)
|
||||
Files.ReadInt(r, intDummy); (* number of the disk with the start of the central directory *)
|
||||
Files.ReadInt(r, intDummy); (* total number of entries in the central dir on this disk *)
|
||||
Files.ReadInt(r, arc.nofEntries); (* total number of entries in the central dir *)
|
||||
Files.ReadLInt(r, longDummy); (* size of the central directory *)
|
||||
Files.ReadLInt(r, longDummy); (* offset of start of central directory with respect to the starting disk number *)
|
||||
Files.ReadInt(r, intDummy); (* zipfile comment length *)
|
||||
IF intDummy # 0 THEN
|
||||
NEW(arc.comment, intDummy);
|
||||
Files.ReadBytes(r, arc.comment^, intDummy) (* zipfile comment *)
|
||||
END;
|
||||
IF Files.Pos(r) # Files.Length(f) THEN
|
||||
res := NotZipArchiveError;
|
||||
arc := NIL
|
||||
ELSE
|
||||
Files.Set(r, f, longDummy); (* set r on position of first file header in central dir *)
|
||||
arc.firstEntry := ReadEntry(r); arc.lastEntry := arc.firstEntry;
|
||||
ent := arc.firstEntry; intDummy := 0;
|
||||
WHILE ent # NIL DO
|
||||
arc.lastEntry := ent; INC(intDummy); (* count number of entries *)
|
||||
ent.next := ReadEntry(r);
|
||||
ent := ent.next
|
||||
END;
|
||||
IF intDummy # arc.nofEntries THEN
|
||||
res := NotZipArchiveError;
|
||||
arc := NIL
|
||||
END
|
||||
END;
|
||||
Files.Close(f)
|
||||
END
|
||||
END;
|
||||
RETURN arc
|
||||
END OpenArchive;
|
||||
|
||||
(** Returns an Archive that corresponds to a file with specified name;
|
||||
if there is already a zip-file with the same name, this already existing archive is returned;
|
||||
possible results: cf. OpenArchive **)
|
||||
PROCEDURE CreateArchive*(VAR name: ARRAY OF CHAR; VAR res: LONGINT): Archive;
|
||||
VAR
|
||||
f: Files.File;
|
||||
r: Files.Rider;
|
||||
arc: Archive;
|
||||
BEGIN
|
||||
f := Files.Old(name);
|
||||
IF f # NIL THEN
|
||||
RETURN OpenArchive(name, res)
|
||||
ELSE
|
||||
f := Files.New(name);
|
||||
NEW(arc);
|
||||
arc.file := f;
|
||||
arc.nofEntries := 0;
|
||||
arc.offset := 0;
|
||||
Files.Set(r, f, 0);
|
||||
WriteEndOfCentDir(arc, r);
|
||||
Files.Register(f);
|
||||
res := Ok;
|
||||
RETURN arc
|
||||
END
|
||||
END CreateArchive;
|
||||
|
||||
(** Returns the first entry of the Archive arc (NIL if there is no Entry) **)
|
||||
PROCEDURE FirstEntry*(arc: Archive): Entry;
|
||||
BEGIN
|
||||
IF arc = NIL THEN
|
||||
RETURN NIL
|
||||
ELSE
|
||||
RETURN arc.firstEntry
|
||||
END
|
||||
END FirstEntry;
|
||||
|
||||
(** Returns the next Entry after ent **)
|
||||
PROCEDURE NextEntry*(ent: Entry): Entry;
|
||||
BEGIN
|
||||
RETURN ent.next
|
||||
END NextEntry;
|
||||
|
||||
(** Returns the Entry that corresponds to the file with the specified name and that is stored in the Archive arc;
|
||||
possible results:
|
||||
- Ok: Operation was successful
|
||||
- NotZipArchiveError: arc is not a valid Archive
|
||||
- EntryNotFound: no Entry corresponding to name was found **)
|
||||
PROCEDURE GetEntry*(arc: Archive; VAR name: ARRAY OF CHAR; VAR res: LONGINT): Entry;
|
||||
VAR
|
||||
ent: Entry;
|
||||
BEGIN
|
||||
IF arc = NIL THEN
|
||||
res := NotZipArchiveError
|
||||
ELSE
|
||||
ent := arc.firstEntry;
|
||||
WHILE (ent # NIL) & (ent.name # name) DO
|
||||
ent := ent.next
|
||||
END;
|
||||
IF ent = NIL THEN
|
||||
res := EntryNotFound
|
||||
ELSE
|
||||
res := Ok
|
||||
END
|
||||
END;
|
||||
RETURN ent
|
||||
END GetEntry;
|
||||
|
||||
(** Uncompresses and writes the data of Entry ent to Files.Rider dst;
|
||||
possible results:
|
||||
- Ok: Data extracted
|
||||
- NotZipArchiveError: arc is not a valid zip-archive
|
||||
- EntryNotFound: ent is not an Entry of arc
|
||||
- NotSupportedError: data of ent are encrypted or compression method is not supported
|
||||
- DataError: zipfile is corrupted
|
||||
- BadName: entry has a bad file name **)
|
||||
PROCEDURE ExtractEntry*(arc: Archive; ent: Entry; VAR dst: Files.Rider; VAR res: LONGINT);
|
||||
VAR
|
||||
src: Files.Rider; crc32: LONGINT;
|
||||
BEGIN
|
||||
IF arc = NIL THEN
|
||||
res := NotZipArchiveError
|
||||
ELSIF Files.Base(dst) = NIL THEN
|
||||
res := BadName
|
||||
ELSIF (ent = NIL) OR (ent # GetEntry(arc, ent.name, res)) THEN
|
||||
res := EntryNotFound
|
||||
ELSIF ~(ent.method IN SupportedCompMethods) OR (ent.support > Supported) THEN
|
||||
res := NotSupportedError
|
||||
ELSE
|
||||
CASE ent.method OF
|
||||
| Stored:
|
||||
Files.Set(src, arc.file, ent.offsetFileData);
|
||||
Copy(src, dst, ent.uncompSize, TRUE, crc32);
|
||||
IF crc32 = ent.crc32 THEN
|
||||
res := Ok
|
||||
ELSE
|
||||
res := DataError
|
||||
END
|
||||
| Deflated:
|
||||
Files.Set(src, arc.file, ent.offsetFileData);
|
||||
ZlibReaders.Uncompress(src, dst, crc32, res);
|
||||
IF (res = ZlibReaders.Ok) & (crc32 = ent.crc32) THEN
|
||||
res := Ok
|
||||
ELSE
|
||||
res := DataError
|
||||
END
|
||||
END;
|
||||
IF res = Ok THEN
|
||||
Files.Close(Files.Base(dst));
|
||||
END
|
||||
END
|
||||
END ExtractEntry;
|
||||
|
||||
(** Reads and compresses len bytes from Files.Rider src with specified level and strategy
|
||||
and writes them to a new Entry in the Archive arc;
|
||||
possible results:
|
||||
- Ok: file was added to arc
|
||||
- NotZipArchiveError: arc is not a valid zip-archive
|
||||
- EntryAlreadyExists: there is already an Entry in arc with the same name
|
||||
- DataError: error during compression
|
||||
- BadName: src is not based on a valid file **)
|
||||
PROCEDURE AddEntry*(arc: Archive; VAR name: ARRAY OF CHAR; VAR src: Files.Rider; len: LONGINT; level, strategy: SHORTINT; VAR res: LONGINT);
|
||||
VAR
|
||||
dst: Files.Rider; ent: Entry; start: LONGINT;
|
||||
BEGIN
|
||||
IF arc = NIL THEN
|
||||
res := NotZipArchiveError
|
||||
ELSIF Files.Base(src) = NIL THEN
|
||||
res := BadName
|
||||
ELSIF (GetEntry(arc, name, res) # NIL) & (res = Ok) THEN
|
||||
res := EntryAlreadyExists
|
||||
ELSE
|
||||
NEW(ent);
|
||||
COPY(name, ent.name);
|
||||
ent.genPurpBitFlag := 0;
|
||||
IF level = NoCompression THEN
|
||||
ent.method := Stored
|
||||
ELSE
|
||||
ent.method := Deflated
|
||||
END;
|
||||
Files.GetDate(Files.Base(src), ent.time, ent.date);
|
||||
ent.uncompSize := len;
|
||||
ent.intFileAttr := 0;
|
||||
ent.extFileAttr := 0;
|
||||
ent.comment := NIL;
|
||||
ent.support := Supported;
|
||||
ent.dataDescriptor := FALSE;
|
||||
IF arc.firstEntry # NIL THEN
|
||||
ent.offsetLocal := arc.firstEntry.offsetCentralDir
|
||||
ELSE
|
||||
ent.offsetLocal := 0
|
||||
END;
|
||||
Files.Set(dst, arc.file, ent.offsetLocal);
|
||||
WriteLocalFileHeader(ent, dst);
|
||||
ent.offsetFileData := Files.Pos(dst);
|
||||
Files.Close(arc.file);
|
||||
start := Files.Pos(src);
|
||||
IF level = 0 THEN
|
||||
Copy(src, dst, len, TRUE, ent.crc32);
|
||||
ent.compSize := len;
|
||||
res := Ok
|
||||
ELSE
|
||||
ZlibWriters.Compress(src, dst, len, ent.compSize, level, strategy, ent.crc32, res);
|
||||
IF res # ZlibWriters.Ok THEN
|
||||
res := DataError
|
||||
ELSE
|
||||
res := Ok
|
||||
END
|
||||
END;
|
||||
IF res = Ok THEN
|
||||
ent.uncompSize := Files.Pos(src) - start;
|
||||
Files.Close(arc.file);
|
||||
Files.Set(dst, arc.file, ent.offsetLocal + 14);
|
||||
Files.WriteLInt(dst, ent.crc32);
|
||||
Files.WriteLInt(dst, ent.compSize);
|
||||
Files.Close(arc.file);
|
||||
IF arc.lastEntry # NIL THEN
|
||||
arc.lastEntry.next := ent
|
||||
ELSE (* archive has no entries *)
|
||||
arc.firstEntry := ent
|
||||
END;
|
||||
arc.lastEntry := ent;
|
||||
INC(arc.nofEntries);
|
||||
Files.Set(dst, arc.file, ent.offsetFileData + ent.compSize);
|
||||
WriteCentralDirectory(arc, dst);
|
||||
Files.Close(arc.file);
|
||||
res := Ok
|
||||
END;
|
||||
END
|
||||
END AddEntry;
|
||||
|
||||
(** Deletes Entry ent from Archive arc;
|
||||
Possible results:
|
||||
- Ok: ent was deleted, ent is set to NIL
|
||||
- NotZipArchiveError: arc is not a valid zip-archive
|
||||
- EntryNotFound: ent is not an Entry of Archive arc **)
|
||||
PROCEDURE DeleteEntry*(arc: Archive; VAR ent: Entry; VAR res: LONGINT);
|
||||
CONST
|
||||
BufSize = 4000H;
|
||||
VAR
|
||||
f: Files.File; r1, r2: Files.Rider;
|
||||
ent2: Entry;
|
||||
arcname: ARRAY 256 OF CHAR;
|
||||
buf: ARRAY BufSize OF CHAR;
|
||||
offset, diff: LONGINT;
|
||||
BEGIN
|
||||
IF arc = NIL THEN
|
||||
res := NotZipArchiveError
|
||||
ELSIF arc.firstEntry = NIL THEN
|
||||
res := EntryNotFound
|
||||
ELSIF arc.firstEntry = ent THEN
|
||||
offset := arc.firstEntry.offsetLocal; (* arc.firstEntry.offsetLocal = 0 *)
|
||||
IF arc.lastEntry = arc.firstEntry THEN
|
||||
arc.lastEntry := arc.firstEntry.next (* = NIL *)
|
||||
END;
|
||||
arc.firstEntry := arc.firstEntry.next;
|
||||
ent2 := arc.firstEntry;
|
||||
res := Ok
|
||||
ELSE
|
||||
ent2 := arc.firstEntry;
|
||||
WHILE (ent2.next # NIL) & (ent2.next # ent) DO
|
||||
ent2 := ent2.next
|
||||
END;
|
||||
IF ent2.next = NIL THEN
|
||||
res := EntryNotFound
|
||||
ELSE
|
||||
IF arc.lastEntry = ent2.next THEN
|
||||
arc.lastEntry := ent2
|
||||
END;
|
||||
offset := ent2.next.offsetLocal;
|
||||
ent2.next := ent2.next.next;
|
||||
ent2 := ent2.next;
|
||||
res := Ok
|
||||
END
|
||||
END;
|
||||
IF res = Ok THEN
|
||||
Files.GetName(arc.file, arcname);
|
||||
f := Files.New(arcname);
|
||||
Files.Set(r2, f, 0);
|
||||
Files.Set(r1, arc.file, 0);
|
||||
Copy(r1, r2, offset, FALSE, diff); (* no crc 32-checksum is computed -> diff used as dummy *)
|
||||
Files.Close(f);
|
||||
ASSERT(ent2 = ent.next);
|
||||
IF ent2 # NIL THEN
|
||||
Files.Set(r1, arc.file, ent2.offsetLocal);
|
||||
Copy(r1, r2, arc.firstEntry.offsetCentralDir - ent2.offsetLocal, FALSE, diff); (* arc.firstEntry can not be NIL because ent # NIL *)
|
||||
Files.Close(f);
|
||||
diff := ent2.offsetLocal - offset
|
||||
ELSE
|
||||
diff := arc.offset - offset
|
||||
END;
|
||||
WHILE (ent2 # NIL) DO (* update offsets of entries *)
|
||||
DEC(ent2.offsetLocal, diff); DEC(ent2.offsetFileData, diff); DEC(ent2.offsetCentralDir, diff);
|
||||
ent2 := ent2.next
|
||||
END;
|
||||
DEC(arc.offset, diff);
|
||||
DEC(arc.nofEntries);
|
||||
WriteCentralDirectory(arc, r2);
|
||||
Files.Register(f); arc.file := f; ent := NIL
|
||||
END
|
||||
END DeleteEntry;
|
||||
|
||||
(** open a Reader to read uncompressed data from a zip entry directly to memory **)
|
||||
PROCEDURE OpenReader*(arc: Archive; ent: Entry): Reader;
|
||||
VAR
|
||||
dummyBuf: ARRAY 1 OF CHAR;
|
||||
fr: Files.Rider;
|
||||
r: Reader;
|
||||
ur: UncompReader;
|
||||
dr: DefReader;
|
||||
BEGIN
|
||||
IF ent.support = Supported THEN
|
||||
IF ent.method = Stored THEN
|
||||
NEW(ur);
|
||||
ur.crc32 := Zlib.CRC32(0, dummyBuf, -1, -1);
|
||||
Files.Set(ur.fr, arc.file, ent.offsetFileData);
|
||||
r := ur;
|
||||
r.open := TRUE;
|
||||
r.res := Ok
|
||||
ELSIF ent.method = Deflated THEN
|
||||
Files.Set(fr, arc.file, ent.offsetFileData);
|
||||
NEW(dr);
|
||||
ZlibReaders.Open(dr.zr, FALSE, fr);
|
||||
dr.res := dr.zr.res;
|
||||
r := dr;
|
||||
r.open := TRUE
|
||||
ELSE
|
||||
NEW(r);
|
||||
r.open := FALSE;
|
||||
r.res := NotSupportedError
|
||||
END;
|
||||
ELSE
|
||||
NEW(r);
|
||||
r.open := FALSE;
|
||||
r.res := NotSupportedError
|
||||
END;
|
||||
r.ent := ent;
|
||||
RETURN r;
|
||||
END OpenReader;
|
||||
|
||||
(** read len bytes of uncompressed data into buf[offset] and return number of bytes actually read; Reader must be opened **)
|
||||
PROCEDURE ReadBytes*(r: Reader; VAR buf: ARRAY OF CHAR; offset, len: LONGINT; VAR read: LONGINT);
|
||||
VAR
|
||||
bufp: POINTER TO ARRAY OF CHAR; i: LONGINT;
|
||||
BEGIN
|
||||
IF r.open THEN
|
||||
IF r IS UncompReader THEN
|
||||
IF offset = 0 THEN
|
||||
Files.ReadBytes(r(UncompReader).fr, buf, len);
|
||||
ELSE
|
||||
NEW(bufp, len);
|
||||
Files.ReadBytes(r(UncompReader).fr, bufp^, len);
|
||||
FOR i := 0 TO len - 1 DO
|
||||
buf[offset + i] := bufp[i]
|
||||
END
|
||||
END;
|
||||
read := len - r(UncompReader).fr.res;
|
||||
r(UncompReader).crc32 := Zlib.CRC32(r(UncompReader).crc32, buf, offset, read)
|
||||
ELSIF r IS DefReader THEN
|
||||
ZlibReaders.ReadBytes(r(DefReader).zr, buf, offset, len, read);
|
||||
r.res := r(DefReader).zr.res
|
||||
END
|
||||
ELSE
|
||||
r.res := ReaderError
|
||||
END
|
||||
END ReadBytes;
|
||||
|
||||
(** read decompressed byte **)
|
||||
PROCEDURE Read*(r: Reader; VAR ch: CHAR);
|
||||
VAR
|
||||
buf: ARRAY 1 OF CHAR; read: LONGINT;
|
||||
BEGIN
|
||||
ReadBytes(r, buf, 0, 1, read);
|
||||
ch := buf[0];
|
||||
END Read;
|
||||
|
||||
(** close Reader **)
|
||||
PROCEDURE Close*(r: Reader);
|
||||
BEGIN
|
||||
IF r.open THEN
|
||||
IF r IS UncompReader THEN
|
||||
IF r(UncompReader).crc32 # r.ent.crc32 THEN
|
||||
r.res := DataError
|
||||
ELSE
|
||||
r.res := Ok
|
||||
END
|
||||
ELSIF r IS DefReader THEN
|
||||
ZlibReaders.Close(r(DefReader).zr);
|
||||
IF r(DefReader).zr.crc32 # r.ent.crc32 THEN
|
||||
r.res := DataError
|
||||
ELSE
|
||||
r.res := r(DefReader).zr.res
|
||||
END
|
||||
ELSE
|
||||
r.res := ReaderError
|
||||
END;
|
||||
r.open := FALSE
|
||||
ELSE
|
||||
r.res := ReaderError
|
||||
END
|
||||
END Close;
|
||||
|
||||
END Zip.
|
||||
Loading…
Add table
Add a link
Reference in a new issue