123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223 |
- MODULE ZipFS; (** AUTHOR "ejz"; PURPOSE "mount a zipped file as a file-system"; *)
- IMPORT Modules, Streams, Files, Unzip, Dates;
- TYPE
- FileSystem = OBJECT (Files.FileSystem)
- VAR zip: Unzip.ZipFile;
- PROCEDURE &Init*(zip: Unzip.ZipFile);
- BEGIN
- SELF.zip := zip
- END Init;
- PROCEDURE Old0*(name: ARRAY OF CHAR): Files.File;
- VAR E: Unzip.Entry; key: LONGINT; res: WORD; F: File; F0: Files.File; W: Files.Writer;
- BEGIN {EXCLUSIVE}
- key := 0;
- E := zip.GetFirst();
- WHILE E # NIL DO
- INC(key);
- IF E.name^ = name THEN
- F0 := localFS.New0("");
- Files.OpenWriter(W, F0, 0);
- zip.Extract(E, W, res);
- W.Update();
- NEW(F);
- F.fs := SELF; F.key := key; F.E := E; F.F := F0;
- RETURN F
- END;
- E := zip.GetNext(E)
- END;
- RETURN NIL
- END Old0;
- PROCEDURE Enumerate0*(mask: ARRAY OF CHAR; flags: SET; enum: Files.Enumerator);
- VAR E: Unzip.Entry; name: Files.FileName; d, t: LONGINT;
- BEGIN {EXCLUSIVE}
- E := zip.GetFirst();
- WHILE E # NIL DO
- IF Match(mask, E.name^) THEN
- Files.JoinName(prefix, E.name^, name);
- IF Files.EnumTime IN flags THEN
- Dates.DateTimeToOberon(E.td, d, t)
- END;
- enum.PutEntry(name, {}, t, d, E.size)
- END;
- E := zip.GetNext(E)
- END
- END Enumerate0;
- PROCEDURE FileKey*(name: ARRAY OF CHAR): LONGINT;
- VAR E: Unzip.Entry; key: LONGINT;
- BEGIN {EXCLUSIVE}
- key := 0;
- E := zip.GetFirst();
- WHILE E # NIL DO
- INC(key);
- IF E.name^ = name THEN RETURN key END;
- E := zip.GetNext(E)
- END;
- RETURN 0
- END FileKey;
- PROCEDURE Finalize*;
- BEGIN {EXCLUSIVE}
- Finalize^()
- END Finalize;
- END FileSystem;
- File = OBJECT (Files.File)
- VAR F: Files.File; E: Unzip.Entry;
- PROCEDURE Set*(VAR r: Files.Rider; pos: LONGINT);
- BEGIN
- F.Set(r, pos); r.file := SELF
- END Set;
- PROCEDURE Pos*(VAR r: Files.Rider): LONGINT;
- BEGIN
- RETURN F.Pos(r)
- END Pos;
- PROCEDURE Read*(VAR r: Files.Rider; VAR x: CHAR);
- BEGIN
- F.Read(r, x)
- END Read;
- PROCEDURE ReadBytes*(VAR r: Files.Rider; VAR x: ARRAY OF CHAR; ofs, len: LONGINT);
- BEGIN
- F.ReadBytes(r, x, ofs, len)
- END ReadBytes;
- PROCEDURE Length*(): LONGINT;
- BEGIN
- RETURN F.Length()
- END Length;
- PROCEDURE GetDate*(VAR t, d: LONGINT);
- BEGIN
- Dates.DateTimeToOberon(E.td, d, t)
- END GetDate;
- PROCEDURE GetName*(VAR name: ARRAY OF CHAR);
- BEGIN
- Files.JoinName(fs.prefix, E.name^, name)
- END GetName;
- PROCEDURE Update*;
- BEGIN
- F.Update END
- Update;
- END File;
- VAR
- localFS: Files.FileSystem;
- (* Match - check if pattern matches file name; copied from DiskFS.Match and MatchPrefix *)
- PROCEDURE Match(pat, name: ARRAY OF CHAR): BOOLEAN;
- VAR pos, i0, i1, j0, j1: LONGINT; f: BOOLEAN;
- BEGIN
- f := TRUE;
- LOOP
- IF pat[pos] = 0X THEN
- pos := -1; EXIT
- ELSIF pat[pos] = "*" THEN
- IF pat[pos+1] = 0X THEN pos := -1 END;
- EXIT
- ELSIF pat[pos] # name[pos] THEN
- f := FALSE; EXIT
- END;
- INC(pos)
- END;
- IF pos # -1 THEN
- i0 := pos; j0 := pos;
- LOOP
- IF pat[i0] = "*" THEN
- INC(i0);
- IF pat[i0] = 0X THEN EXIT END
- ELSE
- IF name[j0] # 0X THEN f := FALSE END;
- EXIT
- END;
- f := FALSE;
- LOOP
- IF name[j0] = 0X THEN EXIT END;
- i1 := i0; j1 := j0;
- LOOP
- IF (pat[i1] = 0X) OR (pat[i1] = "*") THEN f := TRUE; EXIT END;
- IF pat[i1] # name[j1] THEN EXIT END;
- INC(i1); INC(j1)
- END;
- IF f THEN j0 := j1; i0 := i1; EXIT END;
- INC(j0)
- END;
- IF ~f THEN EXIT END
- END
- END;
- RETURN f & (name[0] # 0X)
- END Match;
- PROCEDURE NewFS*(context : Files.Parameters);
- VAR
- name: Files.FileName;
- F: Files.File; zip: Unzip.ZipFile; fs: FileSystem; res: WORD;
- BEGIN
- IF (Files.This(context.prefix) = NIL) THEN
- context.arg.SkipWhitespace; context.arg.String(name);
- F := Files.Old(name);
- IF F # NIL THEN
- NEW(zip, F, res);
- IF res = Streams.Ok THEN
- NEW(fs, zip);
- Files.Add(fs, context.prefix)
- ELSE
- context.error.String("ZipFS: "); context.error.String(name); context.error.String(" not a valid zip file");
- context.error.Ln;
- END
- ELSE
- context.error.String("ZipFS: "); context.error.String(name); context.error.String(" not found");
- context.error.Ln;
- END
- ELSE
- context.error.String("ZipFS: "); context.error.String(context.prefix); context.error.String(" already in use");
- context.error.Ln;
- END;
- END NewFS;
- PROCEDURE Finalization;
- VAR ft: Files.FileSystemTable; i: LONGINT;
- BEGIN
- IF Modules.shutdown = Modules.None THEN
- Files.GetList(ft);
- IF ft # NIL THEN
- FOR i := 0 TO LEN(ft^)-1 DO
- IF ft[i] IS FileSystem THEN Files.Remove(ft[i]) END
- END
- END
- END
- END Finalization;
- PROCEDURE Init;
- VAR fs: Files.FileSystemTable; i: LONGINT;
- BEGIN
- i := 0;
- Files.GetList(fs);
- WHILE (i < LEN(fs)) & ((fs[i].vol = NIL) OR (Files.ReadOnly IN fs[i].vol.flags)) DO
- INC(i) (* find a writable file system *)
- END;
- IF (i < LEN(fs)) THEN localFS := fs[i] END;
- Modules.InstallTermHandler(Finalization)
- END Init;
- BEGIN
- Init()
- END ZipFS.
- System.Free ZipFS ~
- OFSTools.Mount Test ZipFS ARM.Backup.zip ~
- OFSTools.Unmount Test
- System.Directory Test:*\d
|