home *** CD-ROM | disk | FTP | other *** search
/ Amiga Format CD 28 / amigaformatcd28.iso / -seriously_amiga- / archivers / yacoder / readme < prev    next >
Text File  |  1998-05-09  |  9KB  |  170 lines

  1. $Header: /usr/people/tcl/src/uutar/RCS/README,v 1.3 1993/09/12 00:40:52 tcl Exp $
  2.  
  3. ----------- What are encode/decode?
  4.  
  5. Encode and decode are utilities which encode binary data into
  6. printable format suitable for transmission via email, posting to
  7. usenet, etc. They are intended to replace the aging uuencode and
  8. uudecode.
  9.  
  10. ----------- Features:
  11.  
  12. Encode features a very flexible encoding scheme which allows the user
  13. to specify exactly which printable characters to use in the output.
  14. The default is to use all 95 printable characters in the encoding
  15. process, as this produces the least expansion of the input data.
  16. However, for cases such as file transfer to a mainframe or to a
  17. foreign country where some characters may be modified en route, these
  18. characters can simply be removed from the output character set.
  19. Encoding is possible with as few as 2 characters in the output
  20. character set.
  21.  
  22. Regardless of how many characters are specified in the output
  23. character set, encode only expands the data by a factor very close to
  24. the theoretical limit for that number of characters. (see next
  25. section)
  26.  
  27. My implementation is simple (less than 500 lines total without
  28. comments) and efficient (runs at a speed comparable to
  29. uuencode/uudecode)
  30.  
  31. ----------- Some theory on file expansion during encoding:
  32.  
  33. The number of bits required to encode n distinct values is log2(n)
  34. (log base 2 of n). For example, to encode 256 distinct values, you
  35. need log2(256) = 8 bits. Let's think of the input file before encoding
  36. as a raw stream of bits without byte boundaries. If we want to
  37. represent this data with 256 distinct characters, we will consume 8
  38. bits of the input bitstream per output character. This is how files
  39. are normally encoded. However, if we can't use all 256 output
  40. characters, we will consume fewer than 8 input bits per output
  41. character, and thus we will require more output characters to
  42. represent the input bitstream than if we had 256 output characters.
  43. Thus, the process of encoding a binary file in printable format will
  44. necessarily expand the file. For example if we use the 95 printable
  45. characters, we'll consume an average of log2(95) = 6.57 bits in the
  46. input stream for each output character. Thus the file will be expanded
  47. by a factor of log2(256)/log2(95) = log(256)/log(95) = 1.217 or 21.7%.
  48. Note that this is a theoretical figure. In practice, we can't
  49. subdivide bits, but this figure does provide a theoretical estimate of
  50. the smallest amount of expansion we can hope to get with n output
  51. characters. In practice some coding schemes should be able to do
  52. better for select cases, but for a very large sample space of random
  53. data, no encoding scheme should ever be able to do better than this
  54. theoretical limit.
  55.  
  56. Uuencode maps 3 input characters to 4 output characters for an
  57. expansion of 33% (not including control information). Lately several
  58. encoding schemes which map 4 input characters to 5 output characters
  59. have popped up, for an expansion of 25%.
  60.  
  61. An analysis of encode shows that the average expansion over a very
  62. large input file of random data is 
  63. 8 / (pb - 2 + 2n/p)
  64. where n is the number of output characters, p is the smallest power of
  65. 2 greater than or equal to n, and pb is log2(p), or the number of bits
  66. needed to represent p values. A graph of this function for values of n
  67. from 2 to 256 shows a very close approximation of the theoretical
  68. expansion of log(256)/log(n). For example, for n = 95, the expansion
  69. factor is
  70. 8 / (7 - 2 + 2*95/128) = 1.234 or 23.4%
  71.  
  72. Note that all expansion factors given above fail to take into account
  73. the addition of newline characters to limit output width.
  74.  
  75. ----------- The encoding process:
  76.  
  77. The encoding process used by encode is simply to throw away the byte
  78. boundaries in the input bitstream and insert new byte boundaries in
  79. such a manner that there are only n distinct "tokens" in the input
  80. stream where n is the number of output characters. These tokens can
  81. then be mapped one-to-one with the output characters, both during
  82. encoding and decoding. A good example of this process is uuencode,
  83. which discards the byte boundaries which occur every 8 bits and
  84. inserts byte boundaries every 6 bits. The result is a series of tokens
  85. with a maximum of 64 possible values, each of which is mapped
  86. one-to-one with the output character set of 64 printable characters.
  87. This process is trivial for any n which is a power of two, you simply
  88. insert byte boundaries every log2(n) bits. When n is not a power of 2,
  89. however, the process is somewhat more complicated.
  90.  
  91. We can no longer insert the byte boundaries at regular intervals of b
  92. bits, since this would imply 2^b output characters. If we select b
  93. such that 2^b < n, then we aren't using all n output characters, and
  94. we're expanding the file more than necessary. On the other hand if we
  95. select b such that 2^b > n, we don't have enough output characters to
  96. encode the data. The solution is to start with the smallest b such
  97. that 2^b >= n and then eliminate some of the input tokens until there
  98. are exactly n of them, then we can map one-to-one with the output
  99. characters. Input tokens can be eliminated by taking two input tokens
  100. and combining them to form a single, shorter token. This is best
  101. explained by giving an example.
  102.  
  103. Let's say we have 6 output characters. We start with 8 input tokens:
  104. 000,001,010,011,100,101,110,111
  105. This set of tokens has the property that any input bitstream can
  106. be broken down to a series of these tokens in exactly one way.
  107. Now let's combine two of the tokens. The tokens to be combined must
  108. have identical bits except for the last bit, and the process of
  109. combining strips that bit from the tokens. e.g. 110 and 111 can be
  110. combined into the token 11, so we now have the token set
  111. 000,001,010,011,100,101,11
  112. If we combine two more tokens, 100 and 101 -> 10, we get
  113. 000,001,010,011,10,11
  114. This token set still has the property that any input bitstream can be
  115. broken down into a series of these tokens in exactly one way, and
  116. since there are 6 of them, we can map one-to-one with the output
  117. character set.
  118.  
  119. The standard for the generation of these tokens will be as follows:
  120. Start with 2^b distinct tokens of length b bits, where b is the
  121. smallest integer such that 2^b >= n, where n is the number of output
  122. characters. Then, as above, while there are more than n tokens of any
  123. length, replace the two numerically greatest b length tokens with a
  124. single b-1 length token such that the b-1 length token is equivalent
  125. to the b-1 most significant bits of either b length token. (It is
  126. asserted that at any time in the procedure, the two numerically
  127. greatest b length tokens differ only in the least significant bit).
  128.  
  129. The standard for the one-to-one mapping between tokens and output
  130. characters will be as follows: tokens will be sorted such that all b
  131. length tokens come first, in numerical order, followed by all b-1
  132. length tokens, in numerical order. Output characters will be sorted by
  133. ascii code in numerical order. A one-to-one mapping will be
  134. established between these two sets.
  135.  
  136. The standard for the checksum will be as follows: The checksum will be
  137. computed on the decoded data. It will be 32 bits wide. For each
  138. character read from the input file during encoding or written to the
  139. output file diring decoding, the checksum will first be rolled 7 bits
  140. to the left (the 7 bits which slide off the MSB end will be reinserted
  141. into the LSB end) and then the character will be xor'd onto the low
  142. order 8 bits of the checksum.
  143.  
  144. ----------- Implementation:
  145.  
  146. Decoding with this scheme is trivial: you simply map the printable
  147. character from the input to the corresponding variable length token,
  148. and then append that token to the decoded bitstream.
  149.  
  150. Encoding is a bit more tricky however, since the token length is
  151. variable, and the input bitstream has no token boundaries in it. The
  152. solution is to set up a 256 element array which is indexed by the next
  153. 8 bits in the input bitstream. Note that these 8 bits are not
  154. necessarily byte-aligned in the input file. The indexed element in the
  155. array will indicate how many bits should be consumed in the input, and
  156. what printable character to append to the output. For example, in
  157. order to recognize the token 010, all elements of the array whose
  158. index is 010xxxxx for all xxxxx should be set up to indicate that 3
  159. bits were seen and give the printable character that maps to 010. The
  160. input bitstream will then be advanced by 3 bits and the operation is
  161. repeated, using the next 8 bits to index the array again.
  162.  
  163. My implementation of this encoding process is fairly simplistic and
  164. incorporates no more than the basic functionality provided by
  165. uuencode/uudecode. It is intended primarily to introduce this encoding
  166. scheme to the public in the hopes that it will be widely adopted.
  167. Should such adoption occur, this file should be used as a standard
  168. reference for the encoding algorithm.
  169.  
  170.