Make module from Trianus system added.

S3 system filen renamed with prefix eth.


Former-commit-id: 2aeddb9975
This commit is contained in:
Norayr Chilingarian 2013-10-31 22:37:05 +04:00
parent 8d3b311dd2
commit d9065fea6d
15 changed files with 441 additions and 38 deletions

View file

@ -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.