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