ZipFS.Mod 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223
  1. MODULE ZipFS; (** AUTHOR "ejz"; PURPOSE "mount a zipped file as a file-system"; *)
  2. IMPORT Modules, Streams, Files, Unzip, Dates;
  3. TYPE
  4. FileSystem = OBJECT (Files.FileSystem)
  5. VAR zip: Unzip.ZipFile;
  6. PROCEDURE &Init*(zip: Unzip.ZipFile);
  7. BEGIN
  8. SELF.zip := zip
  9. END Init;
  10. PROCEDURE Old0*(name: ARRAY OF CHAR): Files.File;
  11. VAR E: Unzip.Entry; key: LONGINT; res: WORD; F: File; F0: Files.File; W: Files.Writer;
  12. BEGIN {EXCLUSIVE}
  13. key := 0;
  14. E := zip.GetFirst();
  15. WHILE E # NIL DO
  16. INC(key);
  17. IF E.name^ = name THEN
  18. F0 := localFS.New0("");
  19. Files.OpenWriter(W, F0, 0);
  20. zip.Extract(E, W, res);
  21. W.Update();
  22. NEW(F);
  23. F.fs := SELF; F.key := key; F.E := E; F.F := F0;
  24. RETURN F
  25. END;
  26. E := zip.GetNext(E)
  27. END;
  28. RETURN NIL
  29. END Old0;
  30. PROCEDURE Enumerate0*(mask: ARRAY OF CHAR; flags: SET; enum: Files.Enumerator);
  31. VAR E: Unzip.Entry; name: Files.FileName; d, t: LONGINT;
  32. BEGIN {EXCLUSIVE}
  33. E := zip.GetFirst();
  34. WHILE E # NIL DO
  35. IF Match(mask, E.name^) THEN
  36. Files.JoinName(prefix, E.name^, name);
  37. IF Files.EnumTime IN flags THEN
  38. Dates.DateTimeToOberon(E.td, d, t)
  39. END;
  40. enum.PutEntry(name, {}, t, d, E.size)
  41. END;
  42. E := zip.GetNext(E)
  43. END
  44. END Enumerate0;
  45. PROCEDURE FileKey*(name: ARRAY OF CHAR): LONGINT;
  46. VAR E: Unzip.Entry; key: LONGINT;
  47. BEGIN {EXCLUSIVE}
  48. key := 0;
  49. E := zip.GetFirst();
  50. WHILE E # NIL DO
  51. INC(key);
  52. IF E.name^ = name THEN RETURN key END;
  53. E := zip.GetNext(E)
  54. END;
  55. RETURN 0
  56. END FileKey;
  57. PROCEDURE Finalize*;
  58. BEGIN {EXCLUSIVE}
  59. Finalize^()
  60. END Finalize;
  61. END FileSystem;
  62. File = OBJECT (Files.File)
  63. VAR F: Files.File; E: Unzip.Entry;
  64. PROCEDURE Set*(VAR r: Files.Rider; pos: LONGINT);
  65. BEGIN
  66. F.Set(r, pos); r.file := SELF
  67. END Set;
  68. PROCEDURE Pos*(VAR r: Files.Rider): LONGINT;
  69. BEGIN
  70. RETURN F.Pos(r)
  71. END Pos;
  72. PROCEDURE Read*(VAR r: Files.Rider; VAR x: CHAR);
  73. BEGIN
  74. F.Read(r, x)
  75. END Read;
  76. PROCEDURE ReadBytes*(VAR r: Files.Rider; VAR x: ARRAY OF CHAR; ofs, len: LONGINT);
  77. BEGIN
  78. F.ReadBytes(r, x, ofs, len)
  79. END ReadBytes;
  80. PROCEDURE Length*(): LONGINT;
  81. BEGIN
  82. RETURN F.Length()
  83. END Length;
  84. PROCEDURE GetDate*(VAR t, d: LONGINT);
  85. BEGIN
  86. Dates.DateTimeToOberon(E.td, d, t)
  87. END GetDate;
  88. PROCEDURE GetName*(VAR name: ARRAY OF CHAR);
  89. BEGIN
  90. Files.JoinName(fs.prefix, E.name^, name)
  91. END GetName;
  92. PROCEDURE Update*;
  93. BEGIN
  94. F.Update END
  95. Update;
  96. END File;
  97. VAR
  98. localFS: Files.FileSystem;
  99. (* Match - check if pattern matches file name; copied from DiskFS.Match and MatchPrefix *)
  100. PROCEDURE Match(pat, name: ARRAY OF CHAR): BOOLEAN;
  101. VAR pos, i0, i1, j0, j1: LONGINT; f: BOOLEAN;
  102. BEGIN
  103. f := TRUE;
  104. LOOP
  105. IF pat[pos] = 0X THEN
  106. pos := -1; EXIT
  107. ELSIF pat[pos] = "*" THEN
  108. IF pat[pos+1] = 0X THEN pos := -1 END;
  109. EXIT
  110. ELSIF pat[pos] # name[pos] THEN
  111. f := FALSE; EXIT
  112. END;
  113. INC(pos)
  114. END;
  115. IF pos # -1 THEN
  116. i0 := pos; j0 := pos;
  117. LOOP
  118. IF pat[i0] = "*" THEN
  119. INC(i0);
  120. IF pat[i0] = 0X THEN EXIT END
  121. ELSE
  122. IF name[j0] # 0X THEN f := FALSE END;
  123. EXIT
  124. END;
  125. f := FALSE;
  126. LOOP
  127. IF name[j0] = 0X THEN EXIT END;
  128. i1 := i0; j1 := j0;
  129. LOOP
  130. IF (pat[i1] = 0X) OR (pat[i1] = "*") THEN f := TRUE; EXIT END;
  131. IF pat[i1] # name[j1] THEN EXIT END;
  132. INC(i1); INC(j1)
  133. END;
  134. IF f THEN j0 := j1; i0 := i1; EXIT END;
  135. INC(j0)
  136. END;
  137. IF ~f THEN EXIT END
  138. END
  139. END;
  140. RETURN f & (name[0] # 0X)
  141. END Match;
  142. PROCEDURE NewFS*(context : Files.Parameters);
  143. VAR
  144. name: Files.FileName;
  145. F: Files.File; zip: Unzip.ZipFile; fs: FileSystem; res: WORD;
  146. BEGIN
  147. IF (Files.This(context.prefix) = NIL) THEN
  148. context.arg.SkipWhitespace; context.arg.String(name);
  149. F := Files.Old(name);
  150. IF F # NIL THEN
  151. NEW(zip, F, res);
  152. IF res = Streams.Ok THEN
  153. NEW(fs, zip);
  154. Files.Add(fs, context.prefix)
  155. ELSE
  156. context.error.String("ZipFS: "); context.error.String(name); context.error.String(" not a valid zip file");
  157. context.error.Ln;
  158. END
  159. ELSE
  160. context.error.String("ZipFS: "); context.error.String(name); context.error.String(" not found");
  161. context.error.Ln;
  162. END
  163. ELSE
  164. context.error.String("ZipFS: "); context.error.String(context.prefix); context.error.String(" already in use");
  165. context.error.Ln;
  166. END;
  167. END NewFS;
  168. PROCEDURE Finalization;
  169. VAR ft: Files.FileSystemTable; i: LONGINT;
  170. BEGIN
  171. IF Modules.shutdown = Modules.None THEN
  172. Files.GetList(ft);
  173. IF ft # NIL THEN
  174. FOR i := 0 TO LEN(ft^)-1 DO
  175. IF ft[i] IS FileSystem THEN Files.Remove(ft[i]) END
  176. END
  177. END
  178. END
  179. END Finalization;
  180. PROCEDURE Init;
  181. VAR fs: Files.FileSystemTable; i: LONGINT;
  182. BEGIN
  183. i := 0;
  184. Files.GetList(fs);
  185. WHILE (i < LEN(fs)) & ((fs[i].vol = NIL) OR (Files.ReadOnly IN fs[i].vol.flags)) DO
  186. INC(i) (* find a writable file system *)
  187. END;
  188. IF (i < LEN(fs)) THEN localFS := fs[i] END;
  189. Modules.InstallTermHandler(Finalization)
  190. END Init;
  191. BEGIN
  192. Init()
  193. END ZipFS.
  194. System.Free ZipFS ~
  195. OFSTools.Mount Test ZipFS ARM.Backup.zip ~
  196. OFSTools.Unmount Test
  197. System.Directory Test:*\d