1/*%
2% l1zip.psm -- /FlateDecode image data implementation for /PSL1
3% by pts@fazekas.hu at Sun Sep 22 01:01:00 CEST 2002
4% formerly flatedecode.psm -- please run faltedecode_eps_helper.sh...
5% by pts@fazekas.hu at Fri Sep 20 23:31:36 CEST 2002
6% -- Sat Sep 21 01:11:10 CEST 2002
7% doesn't work -- Sat Sep 21 02:52:36 CEST 2002
8% disallow preread==8, allow preread==0 WORKS -- Sat Sep 21 20:22:07 CEST 2002
9% derived from statecat.psm -- a stateful, faster minimalistic zcat (gzip -cd)
10%   implementation, implemented in pure PostScript LanguageLevel1 (Run
11%   through cpp (C preprocessor) to get the PostScript file
12% statecat.psm by pts@fazekas.hu
13% originally rcm.c
14% original author: Ron McFarland <rcm@one.net>, 1996
15% formally muzcat.c (at Tue Dec 25 11:07:47 CET 2001)
16% based on statecat.ps.3 by pts@fazekas.hu
17% rewritten, restructured and extended at Tue Dec 25 21:00:33 CET 2001
18% translated to PostScript except fvWork at Tue Dec 25 23:11:31 CET 2001
19% translated to PostScript altogether at Thu Dec 27 01:10:58 CET 2001
20% translation works with `cat random.file.gz random.file.gz'' at Thu Dec 27 14:19:36 CET 2001
21% Thu Dec 27 18:37:03 CET 2001:
22%   statecat.ps: 1071960 ms user time (249.293 times slower than gunzip)
23% function inlining at Thu Dec 27 21:51:45 CET 2001
24% shorter keywords at Thu Dec 27 23:52:46 CET 2001
25% at Sat Feb 23 17:05:43 CET 2002:
26%   statecat.ps originally: 5388 bytes
27%   after eliminate-NULLs trick: 5349 bytes
28%   after anti-32768... trick 5229 bytes
29%   5041
30%*/
31/*
32% Imp: more efficient optimize CFG_FMT_ZLIB_ONLY
33% Imp: do `F closefile', `T closefile' in %<True>
34% Not: don't inline TE_read for USE_HEXD (15*5 bytes for ACSO0g is not tolerable)
35% OK : verify a85_getc for really eating EOD (~>) chars
36% OK : find and catalogize `|' and other one-char abbrs
37% OK : shorter operator names (i.e `E' for `def', as in test_vm_eps.eps)
38% OK : shorter var names (such as `preread', `past')
39% Not: make global vars numbered, not named...
40% OK : make constU[]-3 a string, not an array
41% OK : make constW, constP, constL strings, not arrays
42% Imp: inline all except fvMktree (too long), fvFree (recursive) and fvWork (too long)
43% OK : verify, examine StateCatDict (45)
44% OK : find unused vars (such as `moo') in StateCatDict
45% OK : is constM or 1<< faster?? (decided 1<<)
46% OK : anti-`/z 42 eq', ensure `eq' compares numbers (INT_EQ)
47% OK : verify if/ifelse for ENDIF
48% OK : verify direction of `for's
49% OK : eliminate `stopped' context because it catches errors
50% OK : clear stack before `exit'
51% OK : verify `/name' against `name'; grep m@/@
52% OK : verify that `}' is followed by correct if|ifelse|def|bind|stopped|loop|for
53%
54% Typical error: syntax: /^#/
55% Typical error: syntax: m@/ +\w@
56% Typical error: mispelling
57% Typical error: missing `pop' at `dup ... eq{exit}if'
58% Typical error: missing `for|if|...' after '}'
59*/
60
61#include "psmlib.psm"
62
63#if USE_A85D
64#else
65  #if USE_HEXD
66  #else
67    #define USE_BINARY 1
68  #endif
69#endif
70
71#if USE_NO_BIND
72  #define BIND_DEF def
73#else
74  #define BIND_DEF bind def
75#endif
76
77/* --- .pin begins */
78
79%<Head>
80%!PS-Adobe-3.0`E
81%%Inflater: pts@fazekas.hu l1zip.psm
82%%Pages: 1
83`X%%DocumentData: `B
84%%LanguageLevel: 1
85`I%%EndComments
86%%Page: 1 1
87%</Head>
88
89%<Open>
90save`s `R
91%</Open>
92
93/* 88 dict dup /TokDict exch def begin */
94%<Abbr acount=26 xcount=62>
95begin
96%</Abbr>
97
98%<A x "load def"/>  % best to make it first
99%<A E def/>         % best to make it second
100
101%<A + add/>
102%<A , and/>
103%<A - sub/>
104%<A . lt/>
105%<A : for/>
106%<A ; getinterval/>
107%<A = eq/>
108%<A @ loop/>
109%<A A currentfile/>
110%<A H 32768/> /*!=LZW*/
111%<A J 32767/> /*!=LZW*/
112%<A O pop/>
113%<A X exit/>
114%<A a packedarray/>
115%<A b bitshift/>
116%<A c exch/>
117%<A g get/>
118%<A y copy/>
119%<A i ifelse/>
120%<A j if/>
121%<A t put/>
122%<A u dup/>
123%<A ~ ne/>
124#if 0 /* important in LZW, but not in Flate */
125  %<A * gt/>
126  %<A L length/>
127  %<A r read/>
128  %<A s string/>
129#endif
130#if USE_A85D
131%<D d a85_getc/>
132%<D S xS/>
133%<D D xD/>
134%<D C xC/>
135#endif
136#if USE_HEXD
137%<D d .hexd.un/>
138%<A S readhexstring/>
139%<D D .hexd.un/>
140%<D C .hexd./>
141#endif
142#if USE_BINARY
143%<D d .binary.un/>
144#if USE_PALETTE
145%<A S readstring/>
146#endif
147%<D D .binary.un/>
148%<D C .binary.un/>
149#endif
150
151#if USE_SHORT_NAMES
152% Free for short names: *?\^_`| BFGIKLMNPQRTUVWYZ efhklmnopqrsvwz
153% Numerical comments denote # calls or # accesses
154% : B: TokSubs
155%<D F Bary/> /* F must be overridden with array to avoid early TokSubs */
156% : G
157%<D I fxIgnore8/> % ? + 3
158%<D K Sbuf/>
159%<D L fvFree/> % 5
160%<D M fvMktree/> % 5
161%<D N .N./>
162%<D P preread/>
163%<D Q mQ/> % 6
164%<D R fxRead8/> % 6
165%<D T Gary/> /* T must be overridden with array to avoid early TokSubs */
166%<D U fvFree/> % 5
167%<D V fvMktree/> % 5
168%<D Y fxRead16/> % 7 /* formerly: C */
169%<D W oP/> % 4
170%<D Z .Z./>
171%<D e oO/> % 7
172%<D f .f./>
173%<D h .h./>
174%<D k fxSkip/> % 4
175%<D l constZ19/> % 3
176%<D m mode/>
177%<D n mF/> % 6
178%<D o .o./>
179%<D p .p./>
180%<D q .q./>
181%<D r fvRead/> % 10
182%<D s past/>
183%<D v .v./>
184%<D w tY/> % 6
185%<D z Tvar/>
186/* %<D z fxIgnore8z/> % 3 */ /* not a function anymore */
187%<D * fvWork/> % 1
188%<D _ fxRead8EOF/> % 1
189%<D ? Dvar/>
190%<D | fvMain/>
191#endif
192
193%<TokSubs name=B inlining=0/>
194
195#if USE_CURRENTFILE
196  #define STDIN currentfile
197#endif
198
199%<Test>
200#if USE_DEBUG2
201/FP /fileposition x
202#endif
203
204#if USE_BINARY
205  {mark /F currentfile/FlateDecode filter def}stopped
206#endif
207#if USE_A85D
208  {mark /T currentfile/ASCII85Decode filter def /F T/FlateDecode filter def}stopped
209#endif
210#if USE_HEXD
211  {mark /T currentfile/ASCIIHexDecode filter def /F T/FlateDecode filter def}stopped
212#endif
213/Z exch def cleartomark
214/G{`i}def % image, imagemask or `false 3 colorimage`
215`w `h `b[1 0 0 -1 0 `h]
216#if USE_TRUE
217true
218#else
219Z
220#endif
221%</Test>
222
223%<S len=32768>
22432768 string dup /Sbuf exch def
225%</S>
226
227%<True>
228  fvMain
229%</True>
230
231%<False>
232F G
233F closefile
234#if !USE_BINARY
235T closefile
236#endif
237%</False>
238
239#define ZZZ_ASET(aname,idx,b) aname idx b put
240#define ZZZ_AREF(aname,idx) aname idx get
241#define PASS
242#define GLOBAL_VAR0(t,name)
243#define SLOCAL_VAR0(t,name)
244#define GLOBAL_VAR(t,name) /name null def
245#define SLOCAL_VAR(t,name) /name null def
246#define GLOBAL_ARRAY(t,name,size) /name size t def
247#define LOCAL_VAR(a,b)
248
249#if 0 /* LINE_DEBUG */
250#define put (put:__LINE__) === put
251#define get (get:__LINE__) === get
252#endif
253
254%<Defs>
255% Imp: F closefile, T closefile
256/* We must define constants and global arrays first. */
257
258#define NULL 0
259#define NODESIZE 1998 /* NODESIZE%3==0 */
260/** Binary (Huffman) tree of nodes. */
261GLOBAL_ARRAY(array,N,NODESIZE)
262/**
263 * Contains the code word lengths used for Huffman code generation in
264 * fvMktree(). 320==288+32. 320 is large enough to hold both the code lengths
265 * of the literal--length (288) and the distance (32) Huffman trees -- and
266 * large enough to hold the auxilary Huffman tree (used for building the
267 * real tree) of length 19.
268 */
269GLOBAL_ARRAY(array,Z,320)
270GLOBAL_ARRAY(array,Bary,17)
271GLOBAL_ARRAY(array,Gary,17)
272#if CFG_NO_VAR_S
273#else
274GLOBAL_ARRAY(string,Sbuf,32768)
275#endif
276/constZ19 0 0 0 0 0  0 0 0 0 0  0 0 0 0 0  0 0 0 0  19 packedarray def
277#if USE_HEXD
278  /C(.)def
279#endif
280
281{ /* We start declaring functions inside the brace */
282
283#define constW   { 16 17 18 0 8 7 9 6 10 5 11 4 12 3 13 2 14 1 15 }  /* 19 packedarray def */
284#define constU   { 3 4 5 6 7 8 9 10 11 13 15 17 19 23 27 31 35 43 51 59 67 83 99 115 131 163 195 227 258 }  /* 29 packedarray def */
285#define constP   { 0 0 0 0 0 0 0 0 1 1 1 1 2 2 2 2 3 3 3 3 4 4 4 4 5 5 5 5 0 }  /* 29 packedarray def */
286#define constQ   { 1 2 3 4 5 7 9 13 17 25 33 49 65 97 129 193 257 385 513 769 1025 1537 2049 3073 4097 6145 8193 12289 16385 24577 }  /* 30 packedarray def */
287#define constL   { 0 0 0 0 1 1 2 2 3 3 4 4 5 5 6 6 7 7 8 8 9 9 10 10 11 11 12 12 13 13 }  /* 30 packedarray def */
288#if 0
289#define constM   { 0 1 3 7 15 31 63 127 255 511 1023 2047 4095 8191 }  /* 14 packedarray def */
290#endif
291
292#if USE_A85D
293  GLOBAL_VAR0(SINT32,xS) /* Variable `xS' was formerly called: `sx' */
294  GLOBAL_VAR0(SINT32,xD) /* Variable `xD' was formerly called: `dx' */
295  GLOBAL_VAR0(SINT32,xC) /* Variable `xC' was formerly called: `c0' */
296  /** - a85_getc <0..255|511>
297   * Reads a char from `currentfile' as /ASCII85Decode
298   */
299  /a85_getc{ % Simple getchar() of ASCII85Decode filter :-)), formerly /d
300    PSM_A85_GETC
301  }BIND_DEF
302#endif
303
304#if USE_NO_EOF
305  #define my_getchar() TE_read( )
306  #define my_ignorechar() TE_read(pop)
307#else
308  #define my_getchar() TE_read() {511}ifelse
309  #define my_ignorechar() TE_read(pop) if
310#endif
311
312
313/** Index of the first free node in <code>N</code>. */
314GLOBAL_VAR0(WORD,Dvar)
315
316GLOBAL_VAR0(WORD,Tvar) /* index (in S) of the first free position, [0..32767] */
317
318/* GLOBAL_VAR(NODEN,no) -- unused */
319/* GLOBAL_VAR(WORD,roo) -- unused */
320/* GLOBAL_VAR(WORD,rf) -- unused */
321/* GLOBAL_VAR(WORD,moo) -- unused */
322/* GLOBAL_VAR(WORD,mo) -- unused */
323/* GLOBAL_VAR(WORD,oooo) -- unused */
324/* GLOBAL_VAR(WORD,x) -- unused */
325GLOBAL_VAR0(WORD,mQ)
326GLOBAL_VAR0(WORD,mF)
327GLOBAL_VAR0(WORD,o)
328GLOBAL_VAR0(WORD,q)
329GLOBAL_VAR0(WORD,mode) /* MODE_* */
330GLOBAL_VAR0(WORD,tY) /* FMT_*; formerly ty */
331GLOBAL_VAR0(WORD,oO)
332GLOBAL_VAR0(WORD,oP)
333GLOBAL_VAR0(WORD,f)
334GLOBAL_VAR0(WORD,p)
335GLOBAL_VAR0(WORD,v)
336GLOBAL_VAR0(WORD,h)
337
338
339#define AREF_S(idx) AREF(Sbuf,idx)
340#define ASET_S(idx,val) ASET(Sbuf,idx,val)
341
342/* Reading Operations:
343
344-- fxRead8(): read a 8-bit byte at byte boundary
345-- fxRead16z(): read a 16-bit word at byte boundary, MSB first (ZIP)
346-- fxRead16(): read a 16-bit word at byte boundary, LSB first (normal)
347-- fxSkip(): skip to next byte boundary
348-- fxRead1(): read 1 bit (for Huffman)
349-- fvRead(): read any amount of bits (0..13), LSB first
350*/
351
352/* Dat: FlateDecode bit packing order is: (b7*128+...+b0)+(b15*128+...+b8)
353
354/** char, 0..255 */
355SLOCAL_VAR0(WORD,preread)
356/** -1..-8: bits of bufread[pos] already read */
357SLOCAL_VAR0(WORD,past)
358
359% static void fxInit(void) {
360% /fxInit {
361#define fxInit \
362  /preread 0 def \
363  /past -8 def
364% }BIND_DEF
365
366/* #define ASSERT_PREREAD_NOT_EOF() preread 255 gt ASSERT_FALSE_POP((unexpected eof)) */
367#define ASSERT_NOT_EOF(val) ASSERT_TRUE(val dup 255 and eq,(non-EOF expected))
368#define ASSERT_PREREAD_NOT_EOF() ASSERT_NOT_EOF(preread)
369
370/** reads 0..13 bits */
371% static WORD fvRead(WORD arg) {
372/fvRead {
373  DEBUG(dup (==> fvRead\() exch 42 string cvs concatstrings (\)\n) concatstrings)
374  DEBUG((    past=) past neg 42 string cvs concatstrings
375        ( preread=) preread 42 string cvs concatstrings
376        (\n) concatstrings concatstrings)
377  dup 0 INT_NE{
378    ASSERT_PREREAD_NOT_EOF()
379    past
380    % Stack: arg -opast
381    dup preread exch bitshift exch % SHR
382    % Stack: arg preread>>opast opast
383    dup 3 index sub
384    % Stack: arg ret==:preread>>-opast -opast -past==:-opast-arg
385    dup -8 ge{
386      /past exch def % BUG fixed at Thu Dec 27 14:53:53 CET 2001
387      pop
388      % Stack: arg ret
389    }{
390      ASSERT_TRUE(dup -9 le,(-past>=9))
391      /preread my_getchar() def
392      ASSERT_PREREAD_NOT_EOF()
393      dup -16 ge{ /* _GT_ */
394        8 add /past exch def
395        8 add
396        % Stack: arg ret==:preread>>opast 8-opast
397        preread exch bitshift % SHL
398        add
399        % Stack: arg ret''
400      }{
401        16 add /past exch def
402        8 add 2 copy
403        % Stack: arg retold 8-opast ret 8-opast
404        preread exch bitshift add % SHL
405        % Stack: arg retold 8-opast ret''
406        /preread my_getchar() def % BUG fixed at Thu Dec 27 15:40:53 CET 2001
407        ASSERT_TRUE(past -1 le,(-past>=1))
408        ASSERT_TRUE(past -4 ge,(-past<=4))
409        ASSERT_PREREAD_NOT_EOF()
410        exch 8 add preread exch bitshift add
411        % Stack: arg retold ret''
412        exch pop
413        % Stack: arg ret''
414      }ifelse
415    }ifelse
416    % Stack: arg ret
417    % exch constM exch get and  % ret&=((1<<arg)-1);
418    % ^^^ BUG (re)-fixed at Thu Dec 27 14:50:49 CET 2001
419    exch 1 exch bitshift 1 sub and
420  }if
421  DEBUG(dup (<-- fvRead=) exch 42 string cvs concatstrings (\n) concatstrings)
422  % (%stderr) (w) file (<fvRead\n) writestring
423  % fvRead(0)==0 implicitly assumed
424}BIND_DEF
425
426% static WORD fxRead1(void) {
427% /fxRead1{
428#define fxRead1 \
429  ASSERT_PREREAD_NOT_EOF() \
430  past dup -8 INT_EQ{ \
431    pop \
432    /preread my_getchar() def \
433    /past -1 def \
434    preread 1 and \
435    /* Stack: ret */ \
436  }{ \
437    dup 1 sub /past exch def \
438    preread exch bitshift 1 and \
439    /* Stack: ret */ \
440  }ifelse
441% }BIND_DEF
442
443#if 0 /* old style past==0, inline only speed-critical functions */
444  % static void fxSkip(void) {
445  % /fxSkip{
446  #define fxSkip \
447    past 0 INT_NE{ \
448      ASSERT_PREREAD_NOT_EOF() \
449      /preread my_getchar() def \
450      /past 0 def \
451    }if
452  % }BIND_DEF
453
454  % static WORD fxRead16(void) {
455  % /fxRead16{
456  #define fxRead16 \
457    ASSERT_TRUE(past 0 INT_EQ,(past==0)) \
458    ASSERT_PREREAD_NOT_EOF() \
459    preread \
460    /* Stack: ret */ \
461    my_getchar() dup /preread exch def \
462    ASSERT_PREREAD_NOT_EOF() \
463    8 bitshift \
464    add \
465    /preread my_getchar() def
466  % }BIND_DEF
467
468  % static WORD fxRead8(void) {
469  % /fxRead8{
470  #define fxRead8 \
471    ASSERT_TRUE(past 0 INT_EQ,(past==0)) \
472    ASSERT_PREREAD_NOT_EOF() \
473    preread \
474    /* Stack: ret */ \
475    /preread my_getchar() def
476  % }BIND_DEF
477
478  % static void fxIgnore8(WORD how_many_bytes) {
479  #define fxIgnore8 \
480    ASSERT_TRUE(dup 0 gt,(fxIgnore8arg>0)) \
481    ASSERT_TRUE(past 0 INT_EQ,(past==0)) \
482    ASSERT_PREREAD_NOT_EOF() \
483    -1 2 {pop my_ignorechar()}for \
484    /preread my_getchar() def
485
486  #define fxIgnore8z \
487    ASSERT_TRUE(past 0 INT_EQ,(past==0)) \
488    ASSERT_PREREAD_NOT_EOF() \
489    dup 0 INT_NE{ \
490      -1 2 {pop DEBUG2((fI8z)===) my_ignorechar()}for \
491      /preread my_getchar() def \
492    }{pop}ifelse
493
494  % static WORD fxRead8EOF(void) {
495  % /fxRead8EOF{
496  #define fxRead8EOF \
497    ASSERT_TRUE(past 0 INT_EQ,(past==0)) \
498    preread \
499    /* Stack: ret */ \
500    /preread my_getchar() def
501  % }BIND_DEF
502#else
503  #if 0
504    /* old-style: past==0 */
505    % static void fxSkip(void) {
506    /fxSkip{
507      past 0 INT_NE{
508        ASSERT_PREREAD_NOT_EOF()
509        /preread my_getchar() def
510        /past 0 def
511      }if
512    }BIND_DEF
513    % static WORD fxRead8(void) {
514    /fxRead8{
515      ASSERT_TRUE(past 0 INT_EQ,(past==0))
516      ASSERT_PREREAD_NOT_EOF()
517      preread
518      /* Stack: ret */
519      /preread my_getchar() def
520    }BIND_DEF
521    /fxIgnore8z{
522      % Same as void fxIgnore8(WORD how_many_bytes), but allow 0 as arg
523      ASSERT_TRUE(past 0 INT_EQ,(past==0))
524      ASSERT_PREREAD_NOT_EOF()
525      dup 0 INT_NE{
526        -1 2 {pop DEBUG2((fI8z)===)  my_ignorechar()}for
527        /preread my_getchar() def
528      }{pop}ifelse
529    }BIND_DEF
530    /fxRead8EOF{
531      ASSERT_TRUE(past 0 INT_EQ,(past==0))
532      preread
533      /* Stack: ret */
534      /preread my_getchar() def
535    }BIND_DEF
536  #else
537    #define fxSkip /past -8 def
538    #define fxRead8 \
539      ASSERT_TRUE(past -8 INT_EQ,(past==-8)) \
540      my_getchar() ASSERT_NOT_EOF(dup)
541    % }BIND_DEF
542    #define fxRead8EOF \
543      ASSERT_TRUE(past -8 INT_EQ,(past==-8)) \
544      my_getchar()
545    % }BIND_DEF
546  #endif
547
548  % static WORD fxRead16(void) {
549  /fxRead16{
550    ASSERT_TRUE(past -8 INT_EQ,(past==-8))
551    my_getchar() ASSERT_NOT_EOF(dup)
552    my_getchar() ASSERT_NOT_EOF(dup)
553    8 bitshift add
554  }BIND_DEF
555
556  % static void fxIgnore8(WORD how_many_bytes) {
557  /fxIgnore8{
558    ASSERT_TRUE(dup 0 gt,(fxIgnore8arg>0))
559    ASSERT_TRUE(past -8 INT_EQ,(past==-8))
560    ASSERT_PREREAD_NOT_EOF()
561    {my_getchar() ASSERT_NOT_EOF(dup) pop }repeat
562  }BIND_DEF
563  #define fxIgnore8z fxIgnore8
564#endif
565
566#define fvReadq fvRead
567/** Reads an uint16 from the ZIP file */
568#define fxRead16z fxRead16
569
570/**
571 * Allocates a new node and initializes it with empty content. This function
572 * lets us get rid of the global variable F (which was buggily uninitialized
573 * in the original scm.c).
574 * @return pointer to the newly allocated node
575 * @whichcode -1
576 */
577% DEFUN_0(NODEN,fvNalloc)
578% /fvNalloc{
579#define fvNalloc \
580  /* GLOBAL_REF(N) */ \
581  /* GLOBAL_REF(Dvar) */ \
582  /* LOCAL_VAR(NODEN,no) */ /* the first/next free node */ \
583  /* FUNCODE */ \
584  Dvar \
585  /* Stack: no */ \
586  ASSERT_TRUE(dup NODESIZE lt,(Dvar<NODESIZE)) \
587  dup N exch get  /Dvar exch def  /* SET(Dvar,AREF(N,no)); % not free anymore */ \
588  dup N exch NULL put  /* ASET(N,no,NULL); */ /* clear; the other two fields are already cleared */ \
589  /* Stack: no */
590% }BIND_DEF
591
592/**
593 * Frees the Huffman tree originating from <code>root</code> recursively.
594 * Used <code>I</code> as input only.
595 * Moved <code>I</code> into a argeter.
596 * @param arg root node index in N
597 */
598% DEFUN_1_VOID(fvFree,NODEN)
599/fvFree{
600  % GLOBAL_REF(N)
601  % GLOBAL_REF(Dvar)
602  N exch  dup NULL INT_NE{
603    2 copy       get fvFree
604    2 copy 1 add get fvFree  % fvFree(AREF(N,arg+1));
605    2 copy 1 add NULL put    % ASET(N,arg+1,NULL); /* clear */
606    2 copy 2 add 0 put       % ASET(N,arg+2,0); /* clear */
607    2 copy       Dvar put    % ASET(N,arg,Dvar); /* link to the beginning of the free list */
608    /Dvar exch def  pop      % SET(Dvar,arg); /* set it free */
609  }{
610    % BUG fixed at Thu Dec 27 11:52:59 CET 2001
611    pop pop
612  }ifelse
613}BIND_DEF
614
615/**
616 * Goes down (descends) enough levels in the binary tree of (struct node)s.
617 * Reads numbers from input encoded as a Huffman tree represented by the
618 * (struct node)s.
619 * Called only from 2 places.
620 * Used <code>I</code> as both input and output, but the output is never used
621 * in the program. So I've put <code>I</code> to a argument.
622 * @param arg root is only for input
623 * @whichcode 3
624 */
625% DEFUN_1(WORD,fvDescend,NODEN)
626% /fvDescend{
627#define fvDescend \
628  /* GLOBAL_REF(N) */ \
629  /* FUNCODE */ \
630  DEBUG(dup (==> fvDescend\() exch 42 string cvs concatstrings (\)\n) concatstrings) \
631  N exch \
632  { /* Stack: N arg */ \
633    2 copy get NULL INT_EQ{exit}if   /* WHILE(NE(NULL,AREF(N,arg))) */ \
634    2 copy fxRead1 add get exch pop  /* SET(arg,AREF(N,arg+fxRead1())); */ \
635  }loop /* ENDWHILE */ \
636  /* Stack: N arg */ \
637  2 add get \
638  DEBUG(dup (<-- fvDescend=) exch 42 string cvs concatstrings (\n) concatstrings) \
639  /* RETURN(fvDescend,AREF(N,arg+2)) */ /* arg->value; */
640% }BIND_DEF
641
642/**
643 * Allocates new (struct node)s. This is the Huffman tree
644 * builder. It reads the global array <code>Z</code>: the code lengths have
645 * been already stored there.
646 * Used <code>I</code> as output only, so I moved it to the return value.
647 * @param arg the number of entries (codes) of the Huffman tree to be built
648 * @return the root of the Huffman tree just built
649 * @whichcode 5
650 */
651% DEFUN_1(NODEN,fvMktree,WORD)
652/fvMktree{  % BUG fixed at Thu Dec 27 11:54:02 CET 2001
653  % GLOBAL_REF(B)
654  % GLOBAL_REF(G)
655  % GLOBAL_REF(N)
656  % GLOBAL_REF(Z)
657  % LOCAL_VAR(WORD,moo)
658  % LOCAL_VAR(WORD,mQ)
659  % LOCAL_VAR(WORD,mo)
660  % LOCAL_VAR(WORD,mF)
661  % FUNCODE
662  constZ19 0 17 getinterval Bary copy pop % OK to copy packedarray -> array
663  % Stack: arg
664  Bary Z 0 1  4 index 1 sub
665  % Stack: arg Bary Z 0 1 arg-1
666  { % Stack: arg Bary Z moo
667    3 copy get
668    % Stack: arg Bary Z moo Bary Z[moo]
669    2 copy get 1 add put
670    % Stack: arg Bary Z moo
671    pop
672  }for  % WHILE(LT(moo,arg)) INCR(AREF(Bary,AREF(Z,moo))); INCR(moo); ENDWHILE
673  % Stack: arg Bary Z
674  pop  0 0 put  % ASET(Bary,0,0);
675  Gary 0 0 put  % ASET(Gary,0,0);
676  % Stack: arg
677  Gary Bary 0 1 15   % SET(moo,0); WHILE(LT(moo,16))
678  { % Stack: arg Gary Bary moo
679    2 copy get
680    % Stack: arg Gary Bary moo Bary[moo]
681    3 index 2 index get
682    % Stack: arg Gary Bary moo Bary[moo] Gary[moo]
683    add dup add % BUG fixed at Thu Dec 27 15:05:51 CET 2001
684    % Stack: arg Gary Bary moo 2*(Bary[moo]+Gary[moo])
685    3 index exch  2 index 1 add exch
686    % Stack: arg Gary Bary moo Gary moo+1 2*(Bary[moo]+Gary[moo])
687    % ASET(Gary, moo+1,TWICE(AREF(Gary,moo)+AREF(Bary,moo)));
688    put pop
689  }for % BUG fixed at Thu Dec 27 14:59:52 CET 2001
690  % Stack: arg Gary Bary
691  pop pop
692  /* Dat: anode is the ->left pointer of the Sentinel node */
693  N 3 0 put  % ASET(N,3,NULL); /* anode=NULL; */
694  % Stack: arg
695  1 sub 0 exch 1 exch{  % SET(moo,0); WHILE(LT(moo,arg))
696    % Stack: moo
697    dup Z exch get dup 0 INT_NE{  % IF(NZ(AREF(Z,moo)))
698      % Stack: moo Z[moo]
699      % /* WORD o, f; */ /* struct node **f; */
700      dup Gary exch get /mQ exch def  % SET(mQ,AREF(Gary,AREF(Z,moo)));
701      % Stack: moo Z[moo]
702      dup Gary exch 2 copy
703      % Stack: moo Z[moo] Gary Z[moo] Gary Z[moo]
704      get 1 add put  % INCR(AREF(Gary,AREF(Z,moo)));
705      % Stack: moo Z[moo]
706      /mF 3 def % SET(mF,3); /* mF=&anode; */ % BUG fixed at Thu Dec 27 12:03:31 CET 2001
707      % SET(mo,AREF(Z,moo));
708      1 sub  -1 0
709      % Stack: moo Z[moo]-1 -1 0
710      { % WHILE(NZ(mo));  DECR(mo);
711        % Stack: moo mo
712        N mF get NULL INT_EQ{
713          N mF fvNalloc put
714        }if  % IF(EQ(AREF(N,mF),NULL));  ASET(N,mF,fvNalloc NOARGS); ENDIF
715        1 exch bitshift mQ and 0 INT_EQ{0}{1}ifelse
716        N mF get add
717        /mF exch def  % SET(mF,AREF(N,mF)+TAND_P(mQ,SHL(1,mo)));
718        % Stack: moo
719      }for
720      N exch
721      % Stack: N moo
722      N mF 2 copy fvNalloc put  % ASET(N,mF,fvNalloc NOARGS);
723      get 2 add
724      % Stack: N moo AREF(N,mF)+2
725      exch put  % ASET(N,AREF(N,mF)+2,moo); /* (*f)->value=moo; */
726      % Stack: -
727    }{pop pop}ifelse  % ENDIF
728  }for
729  % Stack: -
730  N 3 get
731}BIND_DEF
732
733
734#define FMT_ZLIB         120
735#define FMT_STOP         4 /* stop processing and flush STDIN */
736#if CFG_FMT_ZLIB_ONLYX
737#else
738#define FMT_ZIP_STORED   0 /* file is stored, not Deflated in ZIP file */
739#define FMT_GZIP         31
740#define FMT_NONE         3
741#define FMT_ZIP_DEFLATED 8
742#endif
743
744#define MODE_BOS   0 /* at beginning of (sub)file */
745#define MODE_MOB   1 /* at middle of a DEFLATE block */
746#define MODE_REP   2 /* printing a repeating string in a DEFLATE block */
747#define MODE_BOB   3 /* at the beginning of a block, just before BFINAL and BTYPE */
748#define MODE_COPY1 4 /* copying from input to output (a stored block) */
749#if CFG_FMT_ZLIB_ONLYX
750#else
751#define MODE_ZSTO  5 /* copying from input to output (FMT_ZIP_STORED) */
752#endif
753
754/**
755 * Root of the literal--length Huffman tree in <code>N</code>
756 * (see RFC 1951). Its length is at most 288 with values 0..287. Values
757 * 286 and 287 are invalid. A value in 0..255 means a literal byte, a
758 * value of 256 indicates end-of-block, and a
759 * value in 257..285 is a prefix (with 29 possible values) of a length
760 * in 3..258. See subsubsection 3.2.5 of RFC 1951.
761 */
762SLOCAL_VAR0(NODEN,v)
763/**
764 * Root of the distance Huffman tree in <code>N</code> (see RFC 1951).
765 * Its length is at most 32 with values 0..31. Values 30 and 31 are invalid.
766 * A value of 0..29 is a prefix (with 30 possible values) of a distance in
767 * 1..32768. See subsubsection 3.2.5 of RFC 1951.
768 */
769SLOCAL_VAR0(NODEN,h)
770
771
772#define SLIDEE dup 32767 INT_EQ{pop 0}{1 add}ifelse
773
774#if CFG_FMT_ZLIB_ONLY
775#define fvAFB \
776  DEBUG2((f0:__LINE__) ===only) DEBUG2(currentfile FP ===) \
777  /mode MODE_BOS def \
778  /tY FMT_STOP def /* force EOF */ \
779  fxSkip \
780  DEBUG2((f1:__LINE__) ===only) DEBUG2(currentfile FP ===) \
781  4 fxIgnore8z \
782  DEBUG2((f2:__LINE__) ===only) DEBUG2(currentfile FP ===)
783#else
784% static void fvAFB(void) {
785% /fvAFB{ /* after final block (BFINAL) */
786#define fvAFB \
787   \
788  /mode MODE_BOS def  /* SET(mode,MODE_BOS); */ \
789  fxSkip  /* fxSkip(); */ \
790  /* ^^^ skip till we reach byte boundary. fvRead! 0..7 bits */ \
791  tY FMT_GZIP INT_EQ{  /* IF(EQ(tY,FMT_GZIP)) */ \
792    /* CRC32 and ISIZE remaining */ \
793    /* vvv IGNORE fxRead16(); IGNORE fxRead16(); IGNORE fxRead16(); IGNORE fxRead16(); */ \
794    8 \
795  }{ \
796    tY FMT_ZLIB INT_EQ{  /* ELSE_IF(EQ(tY,FMT_ZLIB)) */ \
797      /* ADLER32 remaining */ \
798      4 \
799    }{0}ifelse \
800  }ifelse \
801  fxIgnore8z
802% }BIND_DEF
803#endif /* CFG_FMT_ZLIB_ONLY */
804
805/** Reads data from input, uncompresses and saves it to Sbuf. Sbuf.length==32768.
806 * Saves 32768 bytes into Sbuf unless EOF prevents it. After return, the caller
807 * may read Sbuf, but it may not modify it.
808 * @return length to be saved to Sbuf
809 */
810% static WORD fvWork(void) {
811/fvWork{
812  % GLOBAL_REF(J)
813  % GLOBAL_REF(Y)
814  % GLOBAL_REF(Tvar)
815  % GLOBAL_REF(N)
816  % GLOBAL_REF(Dvar)
817  { % `{'': establish fake loop context for return
818    mode MODE_REP INT_EQ{ %  IF(EQ(mode,MODE_REP))
819      ASSERT_TRUE(Tvar 0 INT_EQ,(Tvar==0))
820      ASSERT_TRUE(f 258 le,(f<=258))
821      % /* f==0 is OK now */
822      Tvar oO
823      1 1 f{  % WHILE(NZ(f)) -- inverse for
824        pop
825        % Stack: Tvar oO
826        Sbuf 3 copy exch get
827        % Stack: Tvar oO Sbuf Tvar S[oO]
828        put  % ASET_S(Tvar,AREF_S(oO));
829        SLIDEE  % SLIDE(oO);
830        exch 1 add exch  % INCR(Tvar);
831        % DECR(f);
832      }for  % ENDWHILE
833      pop /Tvar exch def
834      /mode MODE_MOB def
835    }{
836      mode MODE_COPY1 INT_EQ{  % ELSE_IF(EQ(mode,MODE_COPY1))
837        % /* Now: f: copy count unsinged word16 */
838        ASSERT_TRUE(Tvar 0 INT_EQ,(Tvar==0))
839        % /* f==0 is OK now */
840        f 32767 gt{ /* _GT_ */ % IF((unsigned short)f>=32768)
841          ASSERT_TRUE(f 32768 sub f 32767 and eq,((f&32767)==f-32768))
842          /f f 32767 and def
843          0 1 32767{  % WHILE(NE((unsigned short)Tvar,32768))
844            Sbuf exch fxRead8 put  % ASET_S(Tvar,fxRead8());
845            % INCR(T);
846            % DECR(f);
847          }for  % ENDWHILE
848          /Tvar 0 def  % SET(Tvar,0);
849          % Stack: -
850          ASSERT_TRUE(mode MODE_COPY INT_EQ,(mode==MODE_COPY1))
851          % bbb111
852          32768 exit  % return (WORD)32768; outside loops
853        }{  % ELSE
854          Sbuf Tvar  1 1 f{  % WHILE(NZ(f)) -- inverse for
855            pop
856            % Stack: Sbuf Tvar
857            2 copy fxRead8 put  % ASET_S(Tvar,fxRead8());
858            1 add  % INCR(Tvar);
859          }for % ENDWHILE
860          /Tvar exch def  pop
861          % /mode MODE_BOB def  % SET(mode,MODE_BOB); % BUG fixed at Thu Dec 27 14:16:57 CET 2001
862          o 0 INT_NE{  % IF(NZ(o))
863            fvAFB  % goto on_bos; SET(mode,MODE_BOS);
864          }{  % ELSE
865            /mode MODE_BOB def  % SET(mode,MODE_BOB); % beginning of next block
866          }ifelse  % ENDIF
867        }ifelse  % ENDIF
868      }
869#if CFG_FMT_ZLIB_ONLY
870      if
871#else
872       {mode MODE_ZSTO INT_EQ{  % ELSE_IF(EQ(mode,MODE_ZSTO))
873          % /* Now: f: copy count low unsinged word16, oP: high unsigned word16 */
874          % /* Now: oo: 0..1 flag for decrementing oP */
875          ASSERT_TRUE(Tvar 0 INT_EQ,(Tvar==0))
876          % /* f==0 is OK now */
877          f 32767 gt{ /* _GT_ */ % IF((unsigned short)f>=32768)
878            ASSERT_TRUE(f 32768 sub f 32767 and eq,((f&32767)==f-32768))
879            /f f 32767 and def
880            0 1 32767{  % WHILE(NE((unsigned short)Tvar,32768))
881              Sbuf exch fxRead8 put  % ASET_S(Tvar,fxRead8());
882              % INCR(Tvar);
883              % DECR(f);
884            }for  % ENDWHILE
885            /Tvar 0 def  % SET(Tvar,0);
886            % Stack: -
887            ASSERT_TRUE(mode MODE_ZSTO INT_EQ,(mode==MODE_ZSTO))
888            % bbb222
889            32768 exit  % return (WORD)32768;  outside loops
890          }{
891            oP 0 INT_NE{  % ELSE_IF(NZ(oP))
892              0 1 32767{  % WHILE(NE((unsigned short)Tvar,32768))
893                Sbuf exch fxRead8 put  % ASET_S(Tvar,fxRead8());
894                % INCR(Tvar);
895                % DECR(f);
896              }for  % ENDWHILE
897              /Tvar 0 def  % SET(Tvar,0);
898              % Stack: -
899              oO 0 INT_NE{  % IF(NZ(oO))
900                /oP oP 1 sub def  % DECR(oP);
901                /oO 0 def  % SET(oO,0);
902              }{  % ELSE
903                /oO 1 def  % SET(oO,1);
904              }ifelse
905              ASSERT_TRUE(mode MODE_ZSTO INT_EQ,(mode==MODE_ZSTO))
906              % bbb333
907              32768 exit  % return (WORD)32768; outside loops
908            }{  % ELSE
909              Sbuf Tvar  1 1 f{  % WHILE(NZ(f)) -- inverse for
910                pop
911                % Stack: Sbuf Tvar
912                2 copy fxRead8 put  % ASET_S(Tvar,fxRead8());
913                1 add  % INCR(Tvar);
914              }for % ENDWHILE
915              /Tvar exch def   pop
916              /mode MODE_BOS def  % SET(mode,MODE_BOS);
917            }ifelse  % oO!=0
918          }ifelse  % f>=32768
919        }if  % MODE==MODE_ZSTO
920      }ifelse  % MODE==MODE_COPY1
921#endif /* CFG_FMT_ZLIB_ONLY */
922    }ifelse  % MODE==MODE_REP
923    -1 exit % don''t return yet
924  }loop
925  % Stack: retval||-1
926
927  { % big-big MODE_MOB||MODE_BOB||MODE_BOS loop
928   #ifndef NDEBUG
929    % mode ===only ( big-big\n) print
930   #endif
931    ASSERT_TRUE(mode MODE_MOB INT_EQ  mode MODE_BOB INT_EQ  mode MODE_BOS INT_EQ  or or,(MODE_MOB||MODE_BOB||MODE_BOS))
932
933    % Stack: retval||-1
934    dup -1 INT_NE{%ccc999
935      exit}if
936    mode MODE_MOB INT_EQ{  % IF(EQ(mode,MODE_MOB)); mode_mob:
937      ASSERT_TRUE(dup -1 INT_EQ,(was -1))
938      pop % -1
939      /**
940       * Uncompresses the data block with the Huffman codes set up.
941       *
942       * Reads at most 33 bits per entry. Unfortunately the block can be of
943       * arbitrary length (terminated by an entry of 256).
944       */
945      % /* vvv reads 0..15 bits, see subsubsection 3.2.7 of RFC 1951 */
946      {
947        % Dat: most of the time is spent inside fvDescend, fvRead and
948        %      inside this loop
949        v fvDescend dup 256 INT_EQ{pop -1 exit}if  % WHILE(NE(oo, 256))
950        dup 257 lt{  % IF(LT(oO,257))
951          % /* ^^^ BUG corrected */
952          Sbuf exch Tvar exch put  % ASET_S(Tvar,oO);
953
954          % Stack: -
955          % vvv SLIDE(Tvar); /* Tvar++; Tvar&=32767; */
956          % vvv if (Tvar==0) return (WORD)32768; /* remain in MODE_MOB */
957          Tvar 32767 INT_EQ{
958            /Tvar 0 def
959            % bbb444
960            32768 exit % return % in big-big-loop and MOB-loop
961          }if
962          /Tvar Tvar 1 add def
963        }{  % ELSE
964          257 sub  % SUB(oO,257);
965          % Stack: oO
966          dup constU exch get
967          exch constP exch get fvRead
968          add /f exch def  % SET(f,AREF(constU,oO) + fvRead(AREF(constP,oO))); /* fvRead! 0..5 bits */
969          ASSERT_TRUE(3 f le  f 258 le  and,(3<=f && f<=258))
970          h fvDescend  % SET(oO,fvDescend(h));
971          dup constQ exch get
972          exch constL exch get fvRead
973          add  % SET(oO,AREF(constQ,oO) + fvRead(AREF(constL,oO))); /* fvRead! 0..13 bits */
974          Tvar exch sub 32767 and  % /* oO = oO <= Tvar ? Tvar - oO : 32768 - oO + Tvar; */
975
976          f 32768 Tvar sub sub dup 0 lt{ % IF((unsigned short)f<32768-(unsigned short)Tvar)
977            pop
978            % Stack: oO
979            Tvar exch  1 1 f{  % WHILE(NZ(f)) -- inverse for
980              pop
981              % Stack: Tvar oO
982              Sbuf 3 copy exch get
983              % Stack: Tvar oO Sbuf Tvar S[oO]
984              put  % ASET_S(Tvar,AREF_S(oO));
985              SLIDEE  % SLIDE(oO);
986              exch 1 add exch  % INCR(Tvar);
987              % DECR(f);
988            }for  % ENDWHILE
989            % Dat: oO doesn''t have to be remembered here
990            pop  /Tvar exch def
991            % Stack: -
992            ASSERT_TRUE(Tvar 32768 lt,(Tvar<32768))
993          }{  % ELSE
994            /f exch def % SUB(f,32768-Tvar);
995            % Stack: oO
996            Tvar 1 32767{  % WHILE(NE((unsigned short)Tvar,32768))
997              % Stack: oO Tvar
998              exch
999              % Stack: Tvar oO
1000              Sbuf 3 copy exch get
1001              % Stack: Tvar oO Sbuf Tvar S[oO]
1002              put  % ASET_S(Tvar,AREF_S(oO));
1003              SLIDEE  % SLIDE(oO);
1004              exch pop  % INCR(Tvar);
1005            }for  % ENDWHILE
1006            /oO exch def
1007            % Stack: -
1008            /Tvar 0 def  % SET(Tvar,0);
1009            /mode MODE_REP def  % SET(mode,MODE_REP);
1010            % bbb555
1011            32768 exit % return (WORD)32768; % in big-big-loop and MOB-loop
1012          }ifelse  % ENDIF
1013        }ifelse  % ENDIF
1014      }loop  % ENDWHILE
1015      % Stack: retval||-1
1016      dup -1 INT_EQ{ % BUG fixed at Thu Dec 27 15:52:18 CET 2001
1017        v fvFree  % fvFree(v);
1018        h fvFree  % fvFree(h);
1019        o 0 INT_NE{  % IF(NZ(o))
1020          fvAFB  % goto on_bos; SET(mode,MODE_BOS);
1021        }{  % ELSE
1022          /mode MODE_BOB def  % SET(mode,MODE_BOB); % beginning of next block
1023        }ifelse  % ENDIF
1024      }if
1025    }if  % ENDIF
1026    % Stack: retval||-1
1027    dup -1 INT_NE{%ccc888
1028      exit}if  pop
1029
1030    DEBUG2((;)===)
1031
1032    mode MODE_BOB INT_EQ{  % WHILE(EQ(mode,MODE_BOB)); mode_bob:
1033      DEBUG(counttomark 42 string cvs)
1034      DEBUG(( kope\n))
1035      % assert(mode==MODE_BOB);
1036      /o fxRead1  def % SET(o,fxRead1()); /* BFINAL: 1 iff this is the last data block */
1037      /q 2 fvRead def % SET(q,fvRead(2)); /* BTYPE: block type; 0=stored, 1=fixed Huff, 2=dyn Huff */
1038      % #if NDEBUG
1039      % #else
1040      %  fprintf(stderr, "MODE_BOB o=%d q=%d %ld\n", o, q, ftell(stdin));
1041      % #endif
1042      DEBUG((MODE:BOB o=)  o 42 string cvs
1043            ( q=) q 42 string cvs
1044            ( ) Stdin fileposition 42 string cvs
1045            (\n) concatstrings concatstrings concatstrings
1046                 concatstrings concatstrings concatstrings)
1047      ASSERT_TRUE(q 0 INT_EQ  q 1 INT_EQ  q 2 INT_EQ  or or,(q==0 || q==1 || q==2))
1048      q 0 INT_NE{  % IF(NZ(q))
1049        /**
1050         * Now: q==BTYPE, q==1 or q==2. (BTYPE==3 means error). Handles
1051         * compressed data blocks, see subsubsection 3.2.5 of RFC 1951.
1052         */
1053        q 1 INT_EQ{  % IF(EQ(q,1))
1054          /**
1055           * Initializes the fixed Huffman codes for BTYPE==1.
1056           */
1057          % /* WORD oO; */
1058          287 -1 0{  % SET(oO,288); WHILE(NZ(oO)); DECR(oO);
1059            Z exch  dup 144 lt{8}{dup 256 lt{9}
1060              {dup 280 lt{7}{8}ifelse}ifelse}ifelse  put
1061            /* ^^^ AREF(Z,oO) = oO < 144 ? 8
1062                  : oO < 256 ? 9
1063                  : oO < 280 ? 7
1064                  : 8; */
1065          }for  % ENDWHILE
1066          /v 288 fvMktree def  % SET(v,fvMktree(288));
1067          0 1 31{Z exch 5 put}for  % SET(f,0); WHILE(LT(f,32)) ASET(Z,f,5); INCR(f); ENDWHILE
1068          /h 32 fvMktree def  % SET(h,fvMktree(32));
1069        }{  % ELSE
1070          /**
1071           * Reads dynamic Huffman codes for BTYPE==2.
1072           *
1073           * Maximum read: 5+5+4+3*19+7*289 == 2094 bits
1074           */
1075          ASSERT_TRUE(q 2 INT_EQ,(q==2))
1076          % /* WORD oO, oP, oPo, f, p, x, v; */
1077          /p 5 fvRead 257 add def  % SET(p, fvRead(5) + 257); /* HLIT: 257..286 (287--289 are unused) */
1078          /oO 5 fvRead 1 add def  % SET(oO, fvRead(5) + 1); /* HDIST: 1..32 */
1079          /v 4 fvRead 4 add def  % SET(v, fvRead(4) + 4); /* HCLEN: 4..19 */ /* small v */
1080          constZ19 Z copy pop  % WHILE(LT(oO,19)) ASET(Z,AREF(constW,oO), 0); INCR(oO); ENDWHILE
1081          0 1 v 1 sub{
1082            Z exch  constW exch get  3 fvRead  put  % WHILE(LT(oO,v))  ASET(Z,AREF(constW,oO), fvRead(3)); INCR(oO); ENDWHILE /* small v */
1083          }for
1084          % Stack: - (verified)
1085          /v 19 fvMktree def  % SET(v,fvMktree(19));
1086          /oP 0 def  % SET(oP,0);
1087          % Stack: -
1088          Z 0 { % SET(oO,0); WHILE(LT(oO,p + oO))
1089            % Stack: Z oO
1090            dup p oO add ge{exit}if
1091            v fvDescend  % SET(oPo,fvDescend(v));
1092            % Stack: Z oO oPo
1093            dup 16 INT_EQ{
1094              pop oP /f 2 fvRead 3 add def  % SET(oPo,oP); SET(f,3+fvRead(2));
1095            }{
1096              dup 17 INT_EQ{
1097                pop 0 /f 3 fvRead 3 add def  % SET(oPo,0); SET(f,3+fvRead(3));
1098              }{
1099                dup 18 INT_EQ{
1100                  pop 0 /f 7 fvRead 11 add def  % SET(oPo,0); SET(f,11+fvRead(7));
1101                }{
1102                  dup /oP exch def  /f 1 def  % SET(oP,oPo); SET(f,1);
1103                }ifelse
1104              }ifelse
1105            }ifelse
1106            % Stack: Z oO oPo
1107            1 1 f{ % SET(q,f); WHILE(NZ(q))
1108              pop % BUG fixed at Thu Dec 27 12:17:58 CET 2001
1109              3 copy put  % ASET(Z,oO,oPo);
1110              exch 1 add exch  % INCR(oO);
1111              % DECR(q);
1112            }for  % ENDWHILE
1113            pop % oPo, BUG fixed at Thu Dec 27 12:18:47 CET 2001
1114          }loop  % ENDWHILE
1115          % Stack: Z oO''==p+oO
1116          pop pop
1117          v fvFree  % fvFree(v);
1118          /v p fvMktree def  % SET(v,fvMktree(p));
1119          % Stack: -
1120          % /* vvv No need for array copy, just change/pass the pointer to Z... */
1121          oO 1 sub -1 0{  % SET(oO'',oO); WHILE(NZ(oO'')) DECR(oO'');
1122            Z exch dup
1123            % Stack: Z oO'' oO''
1124            p add Z exch get  put  % ASET(Z,oO'',AREF(Z,oO'' + p));
1125          }for  % ENDWHILE
1126          /h oO fvMktree def  % SET(h,fvMktree(x));
1127        }ifelse  % ENDIF
1128        /mode MODE_MOB def  % SET(mode,MODE_MOB);
1129        % goto mode_mob;
1130      }{ % ELSE /* inline: fv(..., 7); */
1131
1132        /**
1133         * Copies a block of input to output (mostly) verbatim. This is for
1134         * BTYPE==0, non-compressed block, subsubsection 3.2.4 of RFC 1951.
1135         * (We need non-compressed because
1136         * some blocks cannot be compressed effectively, so gzip inserts them
1137         * as is.)
1138         * @whichcode 7
1139         */
1140        fxSkip  % fxSkip();
1141        % /* ^^^ skip till we reach byte boundary. fvRead! 0..7 bits */
1142        /f fxRead16 def  % SET(f,fxRead16()); /* length of block: 0..65535 */
1143        % #if NDEBUG
1144        % #else
1145        %  fprintf(stderr, "COPY1_BLK=%d Tvar=%d\n", f, Tvar);
1146        % #endif
1147        2 fxIgnore8  % IGNORE fxRead16(); /* one's complement of length; ignored */
1148
1149        f 32768 Tvar sub sub dup 0 lt{ % IF((unsigned short)f<32768-(unsigned short)Tvar)
1150          pop
1151          Sbuf Tvar  1 1 f{  % WHILE(NZ(f)) -- inverse for
1152            pop
1153            % Stack: Sbuf Tvar
1154            2 copy fxRead8 put  % ASET_S(Tvar,fxRead8());
1155            1 add  % INCR(Tvar);
1156          }for % ENDWHILE
1157          /Tvar exch def  pop
1158          ASSERT_TRUE(mode MODE_BOB INT_EQ,(mode==MODE_BOB))
1159          ASSERT_TRUE(Tvar 32768 lt,(Tvar<32768))
1160        }{  % ELSE
1161          % /* Even if f>=32768 */
1162          /f exch def % SUB(f,32768-Tvar);
1163          Tvar 1 32767{  % WHILE(NE((unsigned short)Tvar,32768))
1164            Sbuf exch fxRead8 put  % ASET_S(Tvar,fxRead8());
1165            % INCR(Tvar);
1166            % DECR(f);
1167          }for  % ENDWHILE
1168          /Tvar 0 def  % SET(Tvar,0);
1169          /mode MODE_COPY1 def  % SET(mode,MODE_REP);
1170          % bbb666
1171          DEBUG(counttomark 42 string cvs)
1172          DEBUG(( whata\n))
1173          % trtr
1174          ASSERT_TRUE(counttomark 0 eq,(seccounttomark==0))
1175          DEBUG((whatb\n))
1176          32768 exit  % return (WORD)32768; % exit from big-big loop
1177        }ifelse  % ENDIF
1178        o 0 INT_NE{fvAFB}if % IF(NZ(o)); fvAFB(); ENDIF
1179        DEBUG( counttomark 42 string cvs)
1180        DEBUG((pikula\n))
1181      }ifelse  % ENDIF
1182    }if  % ENDWHILE /* MODE_BOB */
1183    % Stack: -
1184
1185    mode MODE_BOS INT_EQ{
1186      DEBUG(counttomark 42 string cvs)
1187      DEBUG(( booski\n))
1188      DEBUG2((boost)===only)
1189      DEBUG2(currentfile FP ===)
1190      {
1191        DEBUG(counttomark 42 string cvs)
1192        DEBUG(( boosbe\n))
1193        tY FMT_STOP INT_EQ{ % WHILE(NE(tY,FMT_STOP))
1194          Tvar 0 INT_NE{  % /* Flush unwritten buffer. */
1195            Tvar% BUG fixed at Thu Dec 27 14:05:32 CET 2001
1196            /Tvar 0 def
1197            % Stack: Tvar_old
1198          }{0}ifelse
1199          % ccc777
1200          exit % return % in big-big loop and BOS-loop
1201        }if
1202        % /* SET(oO,0); SET(oP,0); */ /* avoid GCC warnings */
1203        % /* fxInit(); */ /* assert(Y==0); SET(J,0); SET(Y,0); */
1204        /v NULL def /h NULL def  % SET(v,NULL); SET(h,NULL);
1205        % N 0 NULL put  N 1 NULL put  N 2 0 put  % ASET(N,0,NULL); ASET(N,1,NULL); ASET(N,2,0); /* the NULL node is initially empty */
1206        % N 3 NULL put  N 4 NULL put  N 5 0 put  % ASET(N,3,NULL); ASET(N,4,NULL); ASET(N,5,0); /* the Sentinel node is initially empty */
1207        constZ19 N copy pop % eliminate-NULLs trick: overwrites 1st >=6 elements of N
1208        /Dvar 6 def  % SET(Dvar,6); /* first free node is 6. `0' is NULL, `3' is Sentinel */
1209        6{  % SET(o,Dvar);
1210          dup NODESIZE ge{pop exit}if  % WHILE (LT(o,NODESIZE))
1211          dup N exch dup 3 add put  1 add  % ASET(N,o,o+3);  INCR(o); /* next free node is next node */
1212          dup N exch NULL      put  1 add  % ASET(N,o,NULL); INCR(o); /* empty RIGHT */
1213          dup N exch 0         put  1 add  % ASET(N,o,0);    INCR(o); /* empty NVAL */
1214        }loop  % ENDWHILE
1215        % Stack: -
1216        fxRead8EOF dup /tY exch def  % SET(tY,fxRead8EOF()); /* read first byte of the header */
1217        % tY  kkkkkkkkkk
1218        dup 511 INT_EQ{  % IF(EQ(tY,511)) /* EOF */
1219          /tY FMT_STOP def  % SET(tY,FMT_STOP);
1220        }{
1221#if CFG_FMT_ZLIB_ONLY
1222            1 fxIgnore8  % IGNORE fxRead8(); /* skip second header byte: 0x01 or 0x5e or 0x9c or 0xda */
1223#else
1224          dup FMT_ZLIB INT_EQ{  % ELSE_IF(EQ(tY,120)) /* ZLIB format */
1225            1 fxIgnore8  % IGNORE fxRead8(); /* skip second header byte: 0x01 or 0x5e or 0x9c or 0xda */
1226            % /* SET(tY,FMT_ZLIB); */
1227          }{
1228            dup 80 INT_EQ{  % ELSE_IF(EQ(tY,80)) /* ZIP format */
1229              1 fxIgnore8  % IGNORE fxRead8(); /* skip second header byte: 0x48 */
1230              /tY FMT_NONE def  % SET(tY,FMT_NONE);
1231              fxRead8  % SET(o,fxRead8());
1232              dup 3 INT_EQ{ % IF(EQ(o,3)) /* Local file header */
1233                % fxRead8 pop   % IGNORE fxRead8(); /* skip: 0x04 */
1234                % fxRead16 pop  % IGNORE fxRead16(); /* skip: version needed to extract file (0x0020) */
1235                % fxRead16 pop  % IGNORE fxRead16(); /* LOCFLG flags */
1236                5 fxIgnore8
1237                /tY fxRead8 def  % SET(tY,fxRead8()); /* lower half of compression method */
1238                ASSERT_TRUE(tY FMT_ZIP_STORED INT_EQ  tY FMT_ZIP_DEFLATED INT_EQ or,(ty==FMT_ZIP_STORED || ty==FMT_ZIP_DEFLATED))
1239                % ^^^ BUG fixed at Thu Dec 27 20:55:52 CET 2001
1240                % fxRead8 pop   % IGNORE fxRead8(); /* upper half of compression method */
1241                % fxRead16 pop  fxRead16 pop % IGNORE fxRead16(); IGNORE fxRead16(); /* file modification time in MS-DOS format */
1242                % fxRead16 pop  fxRead16 pop % IGNORE fxRead16(); IGNORE fxRead16(); /* some kind of CRC-32 */
1243                9 fxIgnore8
1244                /f   fxRead16z def  % SET(f,  fxRead16z());  /* lower compressed file size */
1245                /oP fxRead16z def  % SET(oP,fxRead16z()); /* higher compressed file size */
1246                4 fxIgnore8 % fxRead16 pop  fxRead16 pop % IGNORE fxRead16(); IGNORE fxRead16(); /* uncompressed file size */
1247                fxRead16z      % SET(oO,fxRead16z()); /* length of filename */
1248                fxRead16z add  % SET(q,fxRead16z()); /* length of extra field */
1249                % WHILE(NZ(oO)) IGNORE fxRead8(); DECR(oO); ENDWHILE /* file name */
1250                % WHILE(NZ(q)) IGNORE fxRead8(); DECR(q); ENDWHILE /* extra field */
1251                % -1 1{fxRead8 pop}for
1252                fxIgnore8z
1253              }{
1254                dup 7 INT_EQ{  % ELSE_IF(EQ(o,7)) /* Extended local header of previous file in ZIP */
1255                  % 1 1 13{fxRead8 pop}for  % SET(o,0); WHILE(LT(o,13)) IGNORE fxRead8(); INCR(o); ENDWHILE /* BUGFIX: was 15 */
1256                  13 fxIgnore8
1257                }{
1258                  dup 5 INT_EQ{  % ELSE_IF(EQ(o,5)) /* End of Central Directory Structure in ZIP */
1259                    /* fprintf(stderr,"EOCDS\n"); */
1260                    % 1 1 17{fxRead8 pop}for  % SET(o,0); WHILE(LT(o,17)) IGNORE fxRead8(); INCR(o); ENDWHILE
1261                    17 fxIgnore8
1262                    fxRead16z  % SET(o,fxRead16z()); /* CML: archive comment length */
1263                    % -1 1{fxRead8 pop}for  % WHILE (NZ(o)) IGNORE fxRead8(); DECR(o); ENDWHILE
1264                    fxIgnore8z
1265                  }{
1266                    dup 1 INT_EQ{  % ELSE_IF(EQ(o,1)) /* Central Directory Structure */
1267                      /* fprintf(stderr,"CDS\n"); */
1268                      % 1 1 25{fxRead8 pop}for  % SET(oO,0); WHILE(LT(oO,25)) IGNORE fxRead8(); INCR(oO); ENDWHILE
1269                      25 fxIgnore8
1270                      fxRead16z      % SET(f,fxRead16z()); /* LEN: length of file name */
1271                      fxRead16z add  % SET(o,fxRead16z()); /* XLN: length of extra field */
1272                      fxRead16z add  % SET(q,fxRead16z()); /* CML: length of file comment */
1273                      % fxRead16 pop  fxRead16 pop  fxRead16 pop
1274                      % fxRead16 pop  fxRead16 pop  fxRead16 pop
1275                      % ^^^ SET(oO,0); WHILE(LT(oO,12)) IGNORE fxRead8(); INCR(oO); ENDWHILE
1276                      12 fxIgnore8
1277                      fxIgnore8z
1278                      % ^^^ WHILE(NZ(f)) IGNORE fxRead8(); DECR(f); ENDWHILE /* file name */
1279                      %     WHILE(NZ(o)) IGNORE fxRead8(); DECR(o); ENDWHILE /* extra field */
1280                      %     WHILE(NZ(q)) IGNORE fxRead8(); DECR(q); ENDWHILE /* file comment */
1281                    }if % o==1
1282                  }ifelse % o==5
1283                }ifelse % o==7
1284              }ifelse % o==3   % ENDIF /* IF ZIP structure sub-type */
1285              % Stack: tY_old o
1286              pop
1287            }{
1288              dup 31 INT_EQ{  % ELSE_IF(EQ(tY,31)) /* gzip/RFC 1952 format */
1289                /* fprintf(stderr,"gzip!\n"); */
1290                /* SET(tY,FMT_GZIP); */
1291                /* The most simple gzip header (10 bytes):
1292                 * ID1   hex 0x1f == dec 31 == FMT_GZIP
1293                 * ID2   hex 0x8b
1294                 * CM    hex 0x08
1295                 * FLG   hex 0x00
1296                 * MTIME hex 0x00, 0x00, 0x00, 0x00 (1 Jan 1970, UNIX epoch)
1297                 * XFL   hex 0x00
1298                 * OS    hex 0xff
1299                 * After that comes the compressed data stream.
1300                 * After that comes the CRC32 and ISIZE (byte aligned? ?)
1301                 */
1302                2 fxIgnore8 % fxRead16 pop  % IGNORE fxRead16(); /* ignore ID2 and CM */
1303                % kkkkkkkkkl
1304                fxRead8  % SET(o,fxRead8()); /* FLG */
1305                % fxRead16 pop  fxRead16 pop  % IGNORE fxRead16(); IGNORE fxRead16(); /* ignore MTIME */
1306                % fxRead16 pop  % IGNORE fxRead16(); /* ignore XFL, OS */
1307                6 fxIgnore8
1308                % Stack: o==FLG
1309                dup 2 and 0 INT_NE{  % IF(TAND_P(o,2)) /* GCONT: skip part number of continuation */
1310                  %fxRead16 pop  % IGNORE fxRead16();
1311                  2 fxIgnore8
1312                }if  % ENDIF
1313                dup 4 and 0 INT_NE{  % IF(TAND_P(o,4)) /* ignore FEXTRA */
1314                  fxRead16 fxIgnore8
1315                  % 1 1 fxRead16{fxRead8 pop}for
1316                  % SET(q,fxRead16());
1317                  % WHILE(NZ(q)) IGNORE fxRead8(); DECR(q); ENDWHILE
1318                }if  % ENDIF
1319                dup 8 and 0 INT_NE{  % IF(TAND_P(o,8))
1320                  {fxRead8 0 INT_EQ{exit}if}loop  % WHILE(NZ(fxRead8())); PASS; ENDWHILE
1321                }if  % ENDIF /* ignore FNAME */
1322                dup 17 and 0 INT_NE{  % IF(TAND_P(o,16))
1323                  {fxRead8 0 INT_EQ{exit}if}loop  % WHILE(NZ(fxRead8())); PASS; ENDWHILE
1324                }if  % ENDIF /* ignore FCOMMENT */
1325                dup 32 and 0 INT_NE{  % IF(TAND_P(o,32)) /* skip encryption header */
1326                  % fxRead16 pop  fxRead16 pop  fxRead16 pop
1327                  % fxRead16 pop  fxRead16 pop  fxRead16 pop
1328                  % SET(f,0); WHILE(LT(f,12)) IGNORE fxRead8(); INCR(f); ENDWHILE
1329                  12 fxIgnore8
1330                }if  % ENDIF
1331                % Stack: tY o
1332                pop
1333              }if % tY==31 (gzip/RFC 1952 format)
1334            }ifelse % tY==80 (ZIP format)
1335          }ifelse % tY==FMT_ZLIB
1336#endif /* CFG_FMT_ZLIB_ONLY */
1337        }ifelse % tY==511  % ENDIF /* IF file format */
1338        % Stack: tY_old
1339        pop
1340        % /* fprintf(stderr,"tY=%d\n", tY); */
1341        % tY bbbbbc
1342#if CFG_FMT_ZLIB_ONLYX
1343          /* FMT_ZIP_STORED can become alive somehow... */
1344          tY FMT_STOP INT_NE tY 3 INT_NE and{
1345            /mode MODE_BOB def  % SET(mode,MODE_BOB);
1346            -1 exit  % goto mode_bob;
1347          }if
1348#else
1349        tY FMT_ZIP_STORED INT_EQ{  % IF(EQ(tY,FMT_ZIP_STORED))
1350          % /* fprintf(stderr,"ZIP_STORED oO=%d oP=%d\n", oO, oP); */
1351          /oO 0 def  % SET(oO,0);
1352          f 32768 Tvar sub sub dup 0 lt{ % IF((unsigned short)f<32768-(unsigned short)Tvar)
1353            pop
1354            Sbuf Tvar  1 1 f{  % WHILE(NZ(f)) -- inverse for
1355              pop
1356              % Stack: Sbuf Tvar
1357              2 copy fxRead8 put  % ASET_S(Tvar,fxRead8());
1358              1 add  % INCR(Tvar);
1359            }for % ENDWHILE
1360            /Tvar exch def  pop
1361            ASSERT_TRUE(Tvar 32768 lt,(Tvar<32768))
1362            oP 0 INT_NE{
1363              /mode MODE_ZSTO def
1364              % ccc555
1365              Tvar exit  % in big-big loop and BOS-loop
1366            }if
1367            % ^^^ IF(NZ(oP));  mode=MODE_ZSTO;  return Tvar;  ENDIF
1368            ASSERT_TRUE(mode MODE_BOS INT_EQ,(mode==MODE_BOS))
1369          }{  % ELSE
1370            % /* Even if f>=32768 */
1371            /f exch def % SUB(f,32768-Tvar);
1372            Tvar 1 32767{  % WHILE(NE((unsigned short)Tvar,32768))
1373              Sbuf exch fxRead8 put  % ASET_S(Tvar,fxRead8());
1374              % INCR(Tvar);
1375              % DECR(f);
1376            }for  % ENDWHILE
1377            /Tvar 0 def  % SET(Tvar,0);
1378            /mode MODE_ZSTO def  % SET(mode,MODE_REP);
1379            % bbb777
1380            32768 exit  % return (WORD)32768; % in big-big loop and BOS-loop
1381          }ifelse  % ENDIF
1382        }{
1383          tY FMT_STOP INT_NE  tY FMT_NONE INT_NE and{
1384            /mode MODE_BOB def  % SET(mode,MODE_BOB);
1385            -1 exit  % goto mode_bob;
1386          }if
1387        }ifelse  % ENDIF
1388#endif /* CFG_FMT_ZLIB_ONLY */
1389      }loop  % ENDWHILE /* outermost WHILE(NE(tY,FMT_STOP)) */
1390      % Stack: retval
1391    }{-1}ifelse % mode==MODE_BOS
1392    % Stack: retval
1393  }loop % big-big MODE_MOB||MODE_BOB||MODE_BOS loop
1394  % Stack: retval
1395}BIND_DEF  % ENDFUN
1396
1397% Stdin already set
1398#if 0
1399% /fvInitAll{
1400#define fvInitAll \
1401  fxInit \
1402  /tY FMT_NONE def \
1403  /mode MODE_BOS def \
1404  /Tvar 0 def /* make the round buffer empty */ \
1405  TE_init
1406% }BIND_DEF
1407#else
1408/fvMain{
1409  % /XXX
1410  % STDIN read
1411  % STDIN C readhexstring
1412  % pop 0 get true_action
1413  % TE_read(===)
1414
1415  TE_init % must be called _before_ fxInit
1416  fxInit
1417  /tY FMT_NONE def
1418  /mode MODE_BOS def
1419  /Tvar 0 def
1420  % /Tvar 0 def  Tvar === quit
1421  { Sbuf 0 fvWork getinterval } /G load exec
1422  TE_read_eod % make sure that mEOD has been read
1423}BIND_DEF
1424#endif
1425
1426} /* We close the brace of declared functions */
1427%</Defs>
1428
1429%<Data>
1430%%BeginData:
1431exec
1432`S
1433%%EndData
1434end restore showpage
1435%%Trailer
1436%%EOF
1437%</Data>
1438
1439%%EOF
1440