GZip.Mod 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348
  1. MODULE GZip; (** DK **)
  2. IMPORT Streams, Files, Strings, ZlibInflate, ZlibDeflate, Zlib, ZlibBuffers, Commands;
  3. CONST
  4. WriteError = 2907;
  5. DefaultWriterSize = 4096;
  6. DefaultReaderSize = 4096;
  7. BufSize = 4000H;
  8. FileError = -1;
  9. (** compression levels **)
  10. DefaultCompression* = ZlibDeflate.DefaultCompression; NoCompression* = ZlibDeflate.NoCompression;
  11. BestSpeed* = ZlibDeflate.BestSpeed; BestCompression* = ZlibDeflate.BestCompression;
  12. (** compression strategies **)
  13. DefaultStrategy* = ZlibDeflate.DefaultStrategy; Filtered* = ZlibDeflate.Filtered; HuffmanOnly* = ZlibDeflate.HuffmanOnly;
  14. DeflateMethod = 8;
  15. (** flush values **)
  16. NoFlush* = ZlibDeflate.NoFlush;
  17. SyncFlush* = ZlibDeflate.SyncFlush;
  18. FullFlush* = ZlibDeflate.FullFlush;
  19. TYPE
  20. (** Reader for buffered reading of a file via Streams.Read* procedures. See OpenReader. *)
  21. Deflator* = OBJECT (** not sharable between multiple processes *)
  22. VAR
  23. writer: Streams.Writer;
  24. s : ZlibDeflate.Stream;
  25. res : WORD;
  26. crc32-: LONGINT; (*crc32 of uncompressed data*)
  27. out : POINTER TO ARRAY BufSize OF CHAR;
  28. flush: SHORTINT;
  29. inputsize : LONGINT;
  30. PROCEDURE WriteHeader(w: Streams.Writer);
  31. VAR
  32. i: INTEGER;
  33. BEGIN
  34. w.Char(1FX);
  35. w.Char(8BX);
  36. w.Char(CHR(DeflateMethod));
  37. FOR i := 0 TO 6 DO w.Char(0X); END;
  38. END WriteHeader;
  39. PROCEDURE &Init*(writer: Streams.Writer; level, strategy, flush: SHORTINT);
  40. BEGIN
  41. IF writer = NIL THEN
  42. res := Zlib.StreamError; RETURN;
  43. ELSE
  44. SELF.writer := writer;
  45. SELF.flush := flush;
  46. SELF.WriteHeader(writer);
  47. res := writer.res;
  48. IF res = Streams.Ok THEN
  49. ZlibDeflate.Open(s, level, strategy, FALSE);
  50. IF s.res = ZlibDeflate.Ok THEN
  51. NEW(out); ZlibBuffers.Init(s.out, out^, 0, BufSize, BufSize);
  52. crc32 := Zlib.CRC32(0, out^, -1, -1);
  53. inputsize := 0;
  54. ELSE
  55. res := s.res;
  56. END;
  57. END;
  58. END;
  59. END Init;
  60. PROCEDURE Send* (CONST buf: ARRAY OF CHAR; ofs, len: LONGINT; propagate: BOOLEAN; VAR res: WORD);
  61. VAR
  62. done : BOOLEAN;
  63. BEGIN
  64. ASSERT((0 <= ofs) & (0 <= len) & (len <= LEN(buf)), 110);
  65. IF ~SELF.s.open THEN
  66. SELF.res := Zlib.StreamError;
  67. ELSIF (SELF.res < ZlibDeflate.Ok) OR (len <= 0) THEN
  68. res := SELF.res;
  69. ELSE
  70. ZlibBuffers.Init(SELF.s.in, buf, ofs, len, len);
  71. INC(inputsize, len);
  72. WHILE (SELF.res = ZlibDeflate.Ok) & (SELF.s.in.avail # 0) DO
  73. IF (SELF.s.out.avail = 0) THEN
  74. writer.Bytes(SELF.out^, 0, BufSize);
  75. ZlibBuffers.Rewrite(SELF.s.out)
  76. END;
  77. IF SELF.res = Streams.Ok THEN
  78. ZlibDeflate.Deflate(SELF.s, SELF.flush);
  79. SELF.res := SELF.s.res
  80. END
  81. END;
  82. SELF.crc32 := Zlib.CRC32(SELF.crc32, buf, ofs, len - SELF.s.in.avail);
  83. END;
  84. res := SELF.res;
  85. IF propagate THEN
  86. ASSERT(SELF.s.in.avail = 0, 110);
  87. done := FALSE;
  88. LOOP
  89. len := BufSize - SELF.s.out.avail;
  90. IF len # 0 THEN
  91. writer.Bytes(SELF.out^, 0, len);
  92. ZlibBuffers.Rewrite(SELF.s.out)
  93. END;
  94. IF done THEN EXIT END;
  95. ZlibDeflate.Deflate(SELF.s, ZlibDeflate.Finish);
  96. IF (len = 0) & (SELF.s.res = ZlibDeflate.BufError) THEN
  97. SELF.res := Streams.Ok
  98. ELSE
  99. SELF.res := SELF.s.res
  100. END;
  101. done := (SELF.s.out.avail # 0) OR (SELF.res = ZlibDeflate.StreamEnd);
  102. IF (SELF.res # ZlibDeflate.Ok) & (SELF.res # ZlibDeflate.StreamEnd) THEN EXIT END
  103. END;
  104. ZlibDeflate.Close(SELF.s);
  105. SELF.res := SELF.s.res;
  106. writer.RawLInt(crc32);
  107. writer.RawLInt(inputsize);
  108. writer.Update();
  109. END;
  110. END Send;
  111. END Deflator;
  112. (** Reader for buffered reading of a file via Streams.Read* procedures. See OpenReader. *)
  113. Inflator* = OBJECT (** not sharable between multiple processes *)
  114. VAR
  115. reader: Streams.Reader;
  116. res: WORD;
  117. transparent : BOOLEAN;
  118. crc32-: LONGINT; (*crc32 of uncompressed data*)
  119. in : POINTER TO ARRAY BufSize OF CHAR;
  120. s: ZlibInflate.Stream;
  121. PROCEDURE &Init*(reader: Streams.Reader);
  122. BEGIN
  123. IF reader = NIL THEN
  124. res := Zlib.StreamError; RETURN;
  125. ELSE
  126. SELF.reader := reader;
  127. CheckHeader();
  128. IF (res = Streams.Ok) THEN
  129. ZlibInflate.Open(s, FALSE);
  130. IF s.res.code = ZlibInflate.Ok THEN
  131. NEW(in); ZlibBuffers.Init(s.in, in^,0, BufSize,0);
  132. crc32 := Zlib.CRC32(9, in^, -1 , -1);
  133. END;
  134. END;
  135. END;
  136. END Init;
  137. PROCEDURE Receive*(VAR buf: ARRAY OF CHAR; ofs, size, min: LONGINT; VAR len: LONGINT; VAR res: WORD);
  138. VAR
  139. intlen : LONGINT;
  140. BEGIN
  141. ASSERT((0 <= ofs) & (0 <= len) & (ofs + size <= LEN(buf)), 100);
  142. IF transparent THEN
  143. reader.Bytes(buf, ofs, size, len);
  144. IF len >= min THEN res := Streams.Ok ELSE res := Streams.EOF (* end of file *) END;
  145. ELSE
  146. IF ~s.open THEN
  147. res := Zlib.StreamError; len := 0
  148. ELSE
  149. ZlibBuffers.Init(s.out, buf, ofs, size, size);
  150. WHILE (s.out.avail # 0) & (s.res.code # Zlib.StreamEnd) DO
  151. IF s.in.avail = 0 THEN
  152. reader.Bytes(in^, 0, BufSize, intlen);
  153. ZlibBuffers.Rewind(s.in, intlen);
  154. IF s.in.avail = 0 THEN
  155. IF reader.res < 0 THEN
  156. res := FileError
  157. END
  158. END
  159. END;
  160. IF res = Zlib.Ok THEN
  161. ZlibInflate.Inflate(s, ZlibInflate.NoFlush);
  162. END
  163. END;
  164. crc32 := Zlib.CRC32(crc32, buf, ofs, size - s.out.avail);
  165. len := size - s.out.avail
  166. END;
  167. END;
  168. IF len >= min THEN res := Streams.Ok ELSE res := Streams.EOF (* end of file *)END;
  169. END Receive;
  170. PROCEDURE CheckHeader;
  171. CONST
  172. headCRC = 2; extraField = 4; origName = 8; comment = 10H; reserved = 20H;
  173. VAR
  174. ch, method, flags: CHAR; len: INTEGER;
  175. BEGIN
  176. ch := reader.Get();
  177. IF reader.res = Streams.EOF THEN
  178. res := Streams.EOF;
  179. ELSIF ch # 1FX THEN
  180. transparent := TRUE; res := Streams.Ok
  181. ELSE (* first byte of magic id ok *)
  182. ch := reader.Get();
  183. IF (reader.res = Streams.EOF) OR (ch # 8BX)THEN
  184. transparent := TRUE; res := Streams.Ok
  185. ELSE (* second byte of magic id ok *)
  186. method := reader.Get(); flags := reader.Get();
  187. IF (reader.res = Streams.EOF) OR (ORD(method) # DeflateMethod) OR (ORD(flags) >= reserved) THEN
  188. res := Zlib.DataError
  189. ELSE
  190. FOR len := 1 TO 6 DO ch := reader.Get(); END; (* skip time, xflags and OS code *)
  191. IF ODD(ORD(flags) DIV extraField) THEN (* skip extra field *)
  192. ch := reader.Get(); len := ORD(ch);
  193. ch := reader.Get(); len := len + 100H*ORD(ch);
  194. WHILE (reader.res = Streams.EOF) & (len # 0) DO
  195. ch := reader.Get(); DEC(len)
  196. END
  197. END;
  198. IF ODD(ORD(flags) DIV origName) THEN (* skip original file name *)
  199. REPEAT ch := reader.Get(); UNTIL (reader.res = Streams.EOF) OR (ch = 0X)
  200. END;
  201. IF ODD(ORD(flags) DIV comment) THEN (* skip the .gz file comment *)
  202. REPEAT ch := reader.Get(); UNTIL (reader.res = Streams.EOF) OR (ch = 0X)
  203. END;
  204. IF ODD(ORD(flags) DIV headCRC) THEN (* skip header crc *)
  205. ch := reader.Get(); ch := reader.Get();
  206. END;
  207. IF (reader.res = Streams.EOF) THEN res := Zlib.DataError
  208. ELSE res := Streams.Ok
  209. END
  210. END
  211. END
  212. END
  213. END CheckHeader;
  214. END Inflator;
  215. PROCEDURE Deflate*(in,out :Files.File; level, strategy, flush: SHORTINT);
  216. VAR
  217. d : Deflator;
  218. R: Files.Reader;
  219. W2 : Streams.Writer;
  220. W1 : Files.Writer;
  221. buf : ARRAY 16384 OF CHAR;
  222. read : LONGINT;
  223. BEGIN
  224. ASSERT((in # NIL) & (out # NIL));
  225. Files.OpenReader(R, in, 0);
  226. Files.OpenWriter(W1,out,0);
  227. NEW(d, W1 , level, strategy, flush);
  228. Streams.OpenWriter(W2, d.Send);
  229. R.Bytes(buf, 0, LEN(buf), read);
  230. WHILE (read > 0) & (W2.res = Streams.Ok) DO
  231. W2.Bytes(buf,0, read);
  232. R.Bytes(buf, 0, LEN(buf), read);
  233. END;
  234. W2.Update();
  235. END Deflate;
  236. PROCEDURE Inflate*(in,out :Files.File);
  237. VAR
  238. d : Inflator;
  239. R1 : Files.Reader;
  240. R2 : Streams.Reader;
  241. W : Files.Writer;
  242. buf : ARRAY 16384 OF CHAR;
  243. read : LONGINT;
  244. BEGIN
  245. ASSERT((in # NIL) & (out # NIL));
  246. Files.OpenReader(R1, in, 0);
  247. NEW(d,R1);
  248. Streams.OpenReader(R2, d.Receive);
  249. Files.OpenWriter(W,out,0);
  250. R2.Bytes(buf, 0, LEN(buf), read);
  251. WHILE (read > 0) & (R2.res = Streams.Ok) DO
  252. W.Bytes(buf,0, read);
  253. R2.Bytes(buf, 0, LEN(buf), read);
  254. END;
  255. W.Update();
  256. END Inflate;
  257. PROCEDURE GZip*(context:Commands.Context);
  258. VAR filename: Files.FileName; from,to: Files.File; compression, strategy: LONGINT;
  259. BEGIN
  260. IF context.arg.GetString(filename) THEN
  261. from:=Files.Old(filename);
  262. Strings.Append(filename, ".gz");
  263. to:=Files.New(filename);
  264. IF (from#NIL)&(to#NIL) THEN
  265. IF ~context.arg.GetInteger(compression,FALSE) THEN
  266. compression:=DefaultCompression;
  267. strategy:=DefaultStrategy;
  268. ELSIF ~context.arg.GetInteger(strategy,FALSE) THEN
  269. strategy:=DefaultStrategy;
  270. END;
  271. Deflate(from,to,SHORTINT(compression), SHORTINT(strategy), FullFlush(*?*));
  272. Files.Register(to);
  273. context.out.String("gzipped "); context.out.String(filename);context.out.Ln; context.out.Update;
  274. ELSE
  275. context.out.String("gzip failed for "); context.out.String(filename);context.out.Ln; context.out.Update;
  276. END;
  277. ELSE
  278. context.error.String("file not found"); context.error.Ln; context.error.Update;
  279. END;
  280. END GZip;
  281. PROCEDURE UnGZip*(context:Commands.Context);
  282. VAR filename: Files.FileName; from,to: Files.File; pos:LONGINT;
  283. BEGIN
  284. IF context.arg.GetString(filename) THEN
  285. pos:=Strings.Pos(".gz", filename);
  286. IF pos<0 THEN
  287. context.error.String("no .gz file found"); context.error.Ln; context.error.Update;
  288. ELSE
  289. from:=Files.Old(filename);
  290. filename[pos]:=0X;
  291. to:=Files.New(filename);
  292. Inflate(from,to);
  293. Files.Register(to);
  294. context.out.String("un-gzipped "); context.out.String(filename);context.out.Ln; context.out.Update;
  295. END;
  296. ELSE
  297. context.error.String("no file to UnGZip"); context.error.Ln; context.error.Update;
  298. END;
  299. END UnGZip;
  300. END GZip.
  301. GZip.GZip "../httproot/raphael-min.js" ~
  302. GZip.UnGZip "../httproot/raphael-min2.js.gz" ~