home *** CD-ROM | disk | FTP | other *** search
/ Loadstar 242 / 242.d81 / t.pack about < prev    next >
Encoding:
Text File  |  2004-01-01  |  12.6 KB  |  478 lines

  1. u
  2.     S T A R   P A C K E R   1 . 2
  3.              by Lee Novak
  4.  
  5.  
  6.          [ALL SECRETS REVEALED]
  7.          [{SHIFT-*}{SHIFT-*}{SHIFT-*}{SHIFT-*}{SHIFT-*}{SHIFT-*}{SHIFT-*}{SHIFT-*}{SHIFT-*}{SHIFT-*}{SHIFT-*}{SHIFT-*}{SHIFT-*}{SHIFT-*}{SHIFT-*}{SHIFT-*}{SHIFT-*}{SHIFT-*}{SHIFT-*}{SHIFT-*}]
  8.  
  9.     This article is for anyone who is
  10. interested in how this packer works.
  11. While the actual code was very
  12. difficult to write, the ideas behind
  13. it are rather simple.
  14.  
  15.     You might think: "How can a file
  16. be compressed? How can you construct
  17. a file without having all the data?"
  18. It doesn't seem possible.
  19.  
  20.     The idea I got from LS #135's
  21. article on LZS COMPRESSION was that
  22. any duplicated data can be packed.
  23. What's needed is a way to signal when
  24. something is to repeated. You also
  25. need to tell the unpacker where the
  26. original data is, and how much of it
  27. you need to repeat.
  28.  
  29.     How you go about this doesn't
  30. matter, just as long as it works! The
  31. LZS article talks of an unpacker that
  32. reads from a stream of bits only.
  33. This means that specific information
  34. (where repeat data is, etc.) might be
  35. split up between two or more bytes.
  36.  
  37.     I'm guessing that this method of
  38. varying bit-lengths provides the best
  39. compression, and maybe that's why the
  40. BIT IMPLODER is so good. But it sure
  41. sounded difficult. I didn't consider
  42. using this method for long.
  43.  
  44.  
  45.  [THE THEORY OF RARES]
  46.  [{SHIFT-*}{SHIFT-*}{SHIFT-*}{SHIFT-*}{SHIFT-*}{SHIFT-*}{SHIFT-*}{SHIFT-*}{SHIFT-*}{SHIFT-*}{SHIFT-*}{SHIFT-*}{SHIFT-*}{SHIFT-*}{SHIFT-*}{SHIFT-*}{SHIFT-*}{SHIFT-*}{SHIFT-*}]
  47.  
  48.     I knew this packer was going to
  49. use simpler byte-sized pieces of
  50. data. Every byte the unpacker would
  51. read in could have any value 0-255.
  52. At least one value must be reserved
  53. to tell the unpacker that compression
  54. information is to follow.
  55.  
  56.     What value to use? Zero? No way!
  57. There are lots of zeroes in almost
  58. every file! What about a number that
  59. is hardly ever used? Better. But some
  60. files would use this number more than
  61. others. What was needed was a custom
  62. value for each file.
  63.  
  64.     How about counting the number of
  65. occurrences for each byte? Aha! The
  66. least common byte, the RARE byte, is
  67. to signal when compression is used.
  68.  
  69.     The unpacker would read in the
  70. byte following the RARE and know it
  71. has special meaning. But there are so
  72. many possible ways that information
  73. might be packed. How would you tell
  74. the unpacker to duplicate five bytes
  75. (matches) located 117 bytes back?
  76.  
  77.     If two bytes followed the RARE,
  78. you COULD represent this information.
  79. But then, how would you tell the
  80. unpacker to copy 37 bytes located
  81. 9155 bytes back? We surely don't want
  82. to pass up the savings there! Hmm,
  83. maybe we need three bytes to follow
  84. the RARE. One byte would represent
  85. the number of matches, and the next
  86. two tell how far back to get them.
  87.  
  88.     So now, we would need FOUR bytes
  89. to signify even the shortest packing:
  90. one RARE then three bytes. So, what
  91. advantage is there in "compressing" a
  92. string of four matches? None at all.
  93. But there's bound to be lots and lots
  94. of four-byte matches in a file! Can't
  95. we use ANY of them?
  96.  
  97.     Hey, what if we use another RARE?
  98. The unpacker could check if a byte is
  99. either of these RARES, and follow a
  100. different unpacking formula for each.
  101. Why not three RARES? Okay! Why not
  102. four, or five, or even twenty RARES?
  103.  
  104.     Two problems with this. One: the
  105. unpacker code grows with each RARE
  106. you decide to add, because each RARE
  107. represents a compression all its own.
  108.  
  109.     And two: all normal, uncompressed
  110. bytes are just written to memory as-
  111. is. But sometimes, an uncompressed
  112. RARE is part of the file. On these
  113. occasions, TWO bytes are needed to
  114. represent that one byte. A RARE to
  115. say "Hey, here comes a rare!" and one
  116. byte to say "We want this one!".
  117.  
  118.     The second RARE is slightly less
  119. "rare" than the first. The third is
  120. even less so. Eventually, the bytes
  121. may become so common that it costs
  122. MORE to represent them as two bytes
  123. each than the potential savings using
  124. another type of compression may add.
  125.  
  126.  
  127.  [WHAT EACH RARE DOES]
  128.  [{SHIFT-*}{SHIFT-*}{SHIFT-*}{SHIFT-*}{SHIFT-*}{SHIFT-*}{SHIFT-*}{SHIFT-*}{SHIFT-*}{SHIFT-*}{SHIFT-*}{SHIFT-*}{SHIFT-*}{SHIFT-*}{SHIFT-*}{SHIFT-*}{SHIFT-*}{SHIFT-*}{SHIFT-*}]
  129.  
  130.     I did a lot of experimentation
  131. using different numbers of RARES and
  132. ways of packing the information. The
  133. most favorable all-purpose method of
  134. packing turned out to be one that
  135. uses the top eight RARES.
  136.  
  137.     Pretend you're an unpacker. You
  138. read along, splatting uncompressed
  139. bytes down without thought. Then you
  140. come across one of these RARE bytes.
  141. It's time to take the next byte, or
  142. bytes, more seriously. Here's EXACTLY
  143. what to do in these situations!
  144.  
  145.  RARE1, BYTE1:
  146.  
  147.     % 0000 0000
  148.       M{SHIFT-*}{SHIFT-*}{SHIFT-*}R{SHIFT-*}{SHIFT-*}{SHIFT-*}{SHIFT--}
  149.     3 matches, 3-258 bytes away
  150.  
  151.     Every possible value for BYTE1 is
  152. useful. ONE byte is saved for each
  153. 3-byte match. There were so many of
  154. these that a second RARE was added:
  155.  
  156.  RARE2, BYTE1:
  157.  
  158.     % 0000 0000
  159.       M{SHIFT-*}{SHIFT-*}{SHIFT-*}R{SHIFT-*}{SHIFT-*}{SHIFT-*}{SHIFT--}
  160.     3 matches, 259-514 bytes away
  161.  
  162.     Gathering 3-byte matches wasn't
  163. profitable after that, so all others
  164. are ignored.
  165.  
  166.  RARE3, BYTE1:
  167.  
  168.     % 0000 0000
  169.       M{SHIFT-*}{SHIFT-*}{SHIFT-*}R{SHIFT-*}{SHIFT-*}{SHIFT-*}{SHIFT--}
  170.     4 matches, 4-259 bytes away
  171.  
  172.     Each one of these saves TWO
  173. bytes. There are still larger matches
  174. close to the target string, but they
  175. are becoming less common. Time to
  176. break down the data byte into bits:
  177.  
  178.  RARE4, BYTE1:
  179.               P{SHIFT-*} 0=5 matches
  180.     % 0000 0000  1=6 matches
  181.       M{SHIFT-*}{SHIFT-*}R{SHIFT-*}{SHIFT-*}{SHIFT-*}{SHIFT--}
  182.       5-132 bytes away
  183.    or 6-133 bytes away
  184.  
  185.  RARE5, BYTE1:
  186.               P{SHIFT-*} 0=7 matches
  187.     % 0000 0000  1=8 matches
  188.       M{SHIFT-*}{SHIFT-*}R{SHIFT-*}{SHIFT-*}{SHIFT-*}{SHIFT--}
  189.       7-134 bytes away
  190.    or 8-135 bytes away
  191.  
  192.     These 2-byte compressions save
  193. between 3 and 6 bytes apiece. Things
  194. are thinning out even more now, but
  195. we still want anything that will make
  196. a profit. Let's add a data byte:
  197.  
  198.  RARE6, BYTE1, BYTE2:
  199.  
  200.     % 0000 0000   % 0000 0000
  201.       MR{SHIFT-*}{SHIFT--} MR{SHIFT-*}{SHIFT--}     M{SHIFT-*}{SHIFT-*}{SHIFT-*}R{SHIFT-*}{SHIFT-*}{SHIFT-*}{SHIFT--}
  202.        {SHIFT--}   high        low
  203.        {SHIFT--}   nybble      byte
  204.        {SHIFT--}    M{SHIFT-*}{SHIFT-*}{SHIFT-*}{SHIFT-*}{SHIFT-*}R{SHIFT-*}{SHIFT-*}{SHIFT-*}{SHIFT-*}{SHIFT-*}{SHIFT--}
  205.        {SHIFT--}  0-4095 bytes away
  206.        {SHIFT--}
  207.       4-19 matches
  208.  
  209.  RARE7, BYTE1, BYTE2:
  210.  
  211.     % 0000 0000   % 0000 0000
  212.       MR{SHIFT-*}{SHIFT--} MR{SHIFT-*}{SHIFT--}     M{SHIFT-*}{SHIFT-*}{SHIFT-*}R{SHIFT-*}{SHIFT-*}{SHIFT-*}{SHIFT--}
  213.        {SHIFT--}   high        low
  214.        {SHIFT--}   nybble      byte
  215.        {SHIFT--}    M{SHIFT-*}{SHIFT-*}{SHIFT-*}{SHIFT-*}{SHIFT-*}R{SHIFT-*}{SHIFT-*}{SHIFT-*}{SHIFT-*}{SHIFT-*}{SHIFT--}
  216.        {SHIFT--}  4096-8191 bytes away
  217.        {SHIFT--}
  218.       4-19 matches
  219.  
  220.     These 3-byte compressions save
  221. between 1 and 16 bytes apiece. We
  222. still need one more RARE to handle
  223. the rest of the possibilities:
  224.  
  225.  RARE8, BYTE1 (0):
  226.  
  227.     End of compression. RUN program.
  228.  
  229.  RARE8, BYTE1 (1-8):
  230.  
  231.     Add a specific uncompressed RARE.
  232.  
  233.  RARE8, BYTE1 (9), BYTE2:
  234.  
  235.     This unusual type of compression
  236. is for font data ONLY. If the exact
  237. REVERSE of the target string can be
  238. found exactly 1K earlier in the file,
  239. just like reversed font data, then we
  240. go back to copy 4-255 REVERSE bytes
  241. as specified in BYTE2.
  242.  
  243.     This EOR compression is probably
  244. only useful to STAR LINKED files. The
  245. cost of the related unpacking code is
  246. 34 bytes. This cost is recovered with
  247. the first 5 characters that can be
  248. packed this way!
  249.  
  250.  RARE8, BYTE1 (10-127), BYTE2, BYTE3:
  251.  
  252.     %00000000   %00000000   %00000000
  253.      {SHIFT--}M{SHIFT-*}{SHIFT-*}R{SHIFT-*}{SHIFT-*}{SHIFT--}    M{SHIFT-*}{SHIFT-*}R{SHIFT-*}{SHIFT-*}{SHIFT-*}{SHIFT--}    M{SHIFT-*}{SHIFT-*}R{SHIFT-*}{SHIFT-*}{SHIFT-*}{SHIFT--}
  254.      {SHIFT--}  5-122    high byte   low byte
  255.      {SHIFT--} matches      M{SHIFT-*}{SHIFT-*}{SHIFT-*}{SHIFT-*}{SHIFT-*}R{SHIFT-*}{SHIFT-*}{SHIFT-*}{SHIFT-*}{SHIFT-*}{SHIFT--}
  256.      {SHIFT--}            0-65535 bytes away
  257.      Malways 0
  258.  
  259.     All remaining profitable matches
  260. are compressed this way. Since using
  261. this method costs 4 bytes each time,
  262. at least 5 characters must be packed
  263. with it to save at least one byte.
  264.  
  265.  RARE8, BYTE1 (128-255), BYTE2:
  266.  
  267.     %00000000   %00000000
  268.      {SHIFT--}M{SHIFT-*}{SHIFT-*}R{SHIFT-*}{SHIFT-*}{SHIFT--}    M{SHIFT-*}{SHIFT-*}R{SHIFT-*}{SHIFT-*}{SHIFT-*}{SHIFT--}
  269.      {SHIFT--}  4-131  byte to repeat
  270.      {SHIFT--} repeats
  271.      {SHIFT--}
  272.      Malways 1
  273.  
  274.     This last one is known as RLE, or
  275. Run-Length-Encoding. It can be pretty
  276. useful for packing fonts, sprites, or
  277. anything which may have 4 or more
  278. identical bytes in a row.
  279.  
  280.     Now you know what does what, you
  281. get a better idea of the information
  282. on the packing screen. Here are the
  283. RARES one last time, with the
  284. categories they fall into:
  285.  
  286.   RARE1 - RARE5      = "short"
  287.   RARE6 - RARE7      = "medium"
  288.   RARE8 with 10-127  = "long"
  289.   RARE8 with 128-255 = "repeat"
  290.   RARE8 with 9       = "rvs font"
  291.  
  292.     The number of uncompressed RARES
  293. in the file isn't shown anywhere.
  294.  
  295.  
  296.  [TOIL AND TROUBLE]
  297.  [{SHIFT-*}{SHIFT-*}{SHIFT-*}{SHIFT-*}{SHIFT-*}{SHIFT-*}{SHIFT-*}{SHIFT-*}{SHIFT-*}{SHIFT-*}{SHIFT-*}{SHIFT-*}{SHIFT-*}{SHIFT-*}{SHIFT-*}{SHIFT-*}]
  298.  
  299.     Why is this packer so slow?
  300. Actually it's not. You won't BELIEVE
  301. how much work is going on internally!
  302. The packer begins at the end of a
  303. file and works backwards. It searches
  304. for the MOST MATCHES as CLOSE TO the
  305. target string as possible.
  306.  
  307.     The packer begins this search for
  308. each 3-byte string a certain distance
  309. back from the string. How far back it
  310. goes depends on the CRUNCH MODE:
  311.  
  312.  Crunch Mode  How Far Back
  313.  {SHIFT-*}{SHIFT-*}{SHIFT-*}{SHIFT-*}{SHIFT-*}{SHIFT-*}{SHIFT-*}{SHIFT-*}{SHIFT-*}{SHIFT-*}{SHIFT-*}  {SHIFT-*}{SHIFT-*}{SHIFT-*}{SHIFT-*}{SHIFT-*}{SHIFT-*}{SHIFT-*}{SHIFT-*}{SHIFT-*}{SHIFT-*}{SHIFT-*}{SHIFT-*}
  314.      1        1 page  (256 bytes)
  315.      2        2 pages (512 bytes)
  316.      3        4 pages (1K)
  317.      4        8 pages (2K)
  318.      5       16 pages (4K)
  319.      6       32 pages (8K)
  320.      7       64 pages (16K)
  321.      8      128 pages (32K)
  322.      9      255 pages (64K)
  323.  
  324.     These distances are strictly used
  325. unless it overshoots the beginning of
  326. the file. This is why crunch mode "9"
  327. is the best setting. It ensures that,
  328. no matter how large the file, each
  329. target string is hunted for starting
  330. right from the beginning of the file.
  331.  
  332.     At the same time, STAR PACKER
  333. keeps its eyes open for opportunities
  334. to use RLE or EOR compression.
  335.  
  336.     If the target string cannot be
  337. packed, the 3rd byte is deemed
  338. "uncompressable" and left alone. If
  339. it's a RARE byte, the packer must
  340. then move memory to make room for the
  341. extra byte needed to signal this.
  342.  
  343.     That's why the screen seems to
  344. freeze up every now and then. If you
  345. watch, you'll see the NEW SIZE bytes
  346. increase by one. This is about ALL
  347. you'll see when you try to pack an
  348. already-packed file!
  349.  
  350.     When an uncompressable byte is
  351. found, searching begins anew for the
  352. next 3-byte target string, with the
  353. byte one down from the old string.
  354. This process continues until the
  355. beginning of the file is reached!
  356.  
  357.     If the target string CAN be
  358. compressed, the packer finds the best
  359. method its RARES will allow to give
  360. the best savings. For example, a
  361. 6-byte match 185 bytes away could be
  362. packed using RARE8 (saving 2 bytes),
  363. or RARE6 (saving 3 bytes). RARE4 is
  364. just out of range and can't be used.
  365.  
  366.     This also applies to RLE and EOR
  367. packing. If there's better savings to
  368. be had by packing them as a matching
  369. sequence that appears somewhere else
  370. in the file, that's what will happen.
  371.  
  372.     The program spends LOTS of time
  373. comparing memory. The main packing
  374. loop contains sleek, streamlined code
  375. for maximum speed. Every cycle shaved
  376. off this critical code represented
  377. SECONDS in the real world, because of
  378. just how OFTEN this code executes.
  379.  
  380.     I had STAR PACKER pack files of
  381. 39, 120, 136, 199, and 156 blocks,
  382. keeping track of how many comparisons
  383. it did during the main packing loop
  384. ALONE for crunch modes 1 and 9. This
  385. gives you an idea of how much work
  386. your little Commodore is doing!
  387.  
  388.              -- NUMBER OF COMPARES --
  389.  File Name   CrunchMode1  CrunchMode9
  390. {SHIFT-*}{SHIFT-*}{SHIFT-*}{SHIFT-*}{SHIFT-*}{SHIFT-*}{SHIFT-*}{SHIFT-*}{SHIFT-*}    {SHIFT-*}{SHIFT-*}{SHIFT-*}{SHIFT-*}{SHIFT-*}{SHIFT-*}{SHIFT-*}{SHIFT-*}{SHIFT-*}{SHIFT-*}{SHIFT-*}  {SHIFT-*}{SHIFT-*}{SHIFT-*}{SHIFT-*}{SHIFT-*}{SHIFT-*}{SHIFT-*}{SHIFT-*}{SHIFT-*}{SHIFT-*}{SHIFT-*}
  391. TEXT CHARTER   1,088,380   17,446,587
  392. MUSEUM         5,123,930  169,539,568
  393. QUICKSMITH     5,872,597  337,251,893
  394. MOUSE MAKER    9,267,042  428,827,274
  395. B.RAPTOR.MOV  10,006,987  773,521,079
  396.  
  397.     Your little Commodore is working
  398. its tail off, comparing about 90,000
  399. bytes per second! A SuperCPU does
  400. about 2 MILLION compares per second!
  401. So please, show a little patience.
  402.  
  403.  
  404.  [FINAL TECHNICAL NOTES]
  405.  [{SHIFT-*}{SHIFT-*}{SHIFT-*}{SHIFT-*}{SHIFT-*}{SHIFT-*}{SHIFT-*}{SHIFT-*}{SHIFT-*}{SHIFT-*}{SHIFT-*}{SHIFT-*}{SHIFT-*}{SHIFT-*}{SHIFT-*}{SHIFT-*}{SHIFT-*}{SHIFT-*}{SHIFT-*}{SHIFT-*}{SHIFT-*}]
  406.  
  407.     The file doesn't actually get
  408. smaller until after it is all packed.
  409. It leaves "defragment" tokens all
  410. over the place and, when packing is
  411. complete, scans over the file one
  412. last time and collects the pieces.
  413.  
  414.     An error you probably will never
  415. experience is the BUFFER OVERFLOW.
  416. For this to happen, the file needs to
  417. temporarily expand 500 bytes PAST the
  418. 51K size limit. An uncompressale RARE
  419. will expand the file only ONE byte.
  420.  
  421.     Most files have only 10 to 75
  422. uncompressable RARES. The ones with
  423. more are likely to packed, anyway. I
  424. had to feed STAR PACKER a bogus file
  425. of nearly 51K that I knew it would
  426. choke on just to induce this error.
  427.  
  428.     The usual trick LOADSTAR employs
  429. to check if a file already exists is
  430. to try to rename the file as itself.
  431. The disk error channel returns either
  432. error #63 (file exists) or error #62
  433. (file not found). If the file cannot
  434. be found, that name is safe to use!
  435.  
  436.     But, what if the user tries to
  437. save the file to another PARTITION?
  438. He or she might use something like
  439. "4:my program" for a filename. By
  440. tacking on an "R0:", we accidentally
  441. force the drive to find and rename
  442. "my program" as "4:my program"!
  443.  
  444.     There needs to be a different way
  445. to check if the file already exists.
  446. STAR PACKER tries to OPEN the file
  447. for READing instead!
  448.  
  449. 10 open2,dv,2,name$+",s,r":close2
  450.  
  451.     Any partition prefix will be
  452. automatically obeyed. This tactic
  453. results in three likely responses
  454. from the error channel:
  455.  
  456.     Error #62 (file not found) means
  457. it's safe to go ahead and SAVE the
  458. file as name$.
  459.  
  460.     Error #64 (file type mismatch)
  461. means the file DOES exist, but not as
  462. a SEQuential file. The user will have
  463. to select another name.
  464.  
  465.     Error #0 (ok) means the file DOES
  466. exist, and was SEQuential, and opened
  467. properly without incident. The user
  468. will have to select another name.
  469.  
  470.     Any other error should be treated
  471. as such - tell the user immediately.
  472. A disk drive that is OFF is another
  473. matter altogether!
  474.  
  475.  
  476.  [FENDER'S POSTMUMBLE:] This program
  477. is so great I'm mumbleless.
  478.  
  479.