comunpress.cmn 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329
  1. # Simple compression library implementing the shitpress streaming algorithm,
  2. # which I first wrote in C. This is also usable as a standalone utility. For
  3. # use as a library push -1 onto stack before inluding this file, which will stop
  4. # running the standalone code.
  5. #
  6. # PRINCIPLE: the algorithm is very simple, it can compress sequences of length
  7. # 3 to 6 to just 2 bytes, by pushing a reference to that sequence occuring in
  8. # the output history recently (latest 63 bytes).
  9. #
  10. # NOTE: this is compatible with the original C shitpress, though the compressed
  11. # output may differ due to slight differences that were made here -- both
  12. # outputs are valid shitpress compressed format.
  13. #
  14. # by drummyfish released under CC0 1.0, public domain
  15. ~_comunpressState # 0: comp, 1: , 2: decomp , 3: decomp_marker
  16. ~_comunpressHistory:76 # when compressing first 6 are prebuffer
  17. # -1 means EOF, -2 means empty
  18. ~_comunpressHelper:0
  19. ~_comunpressHelper2:0
  20. _COMUNPRESS_MARKER: +xe0 . # special marker value, statistically unlikely
  21. # Initializes compression (pass 0) or decompression (pass 1).
  22. comunpressInit:
  23. $0 0 = -2 0 ?? >< # what to prefill history with? -2 for compression, else 0
  24. 1 |< $:_comunpressState
  25. $_comunpressHistory>_comunpressHelper
  26. 76 @' # fill history with 0s
  27. >< $0 $:_comunpressHelper ><
  28. $>_comunpressHelper
  29. --
  30. .
  31. ^ ^
  32. .
  33. _comunpressHistoryPush:
  34. $_comunpressHistory>_comunpressHelper
  35. 75 @'
  36. ><
  37. $_comunpressHelper
  38. ><
  39. $:_comunpressHelper
  40. $>_comunpressHelper
  41. ><
  42. $1 0 << ?
  43. !@
  44. .
  45. --
  46. .
  47. ^ ^
  48. .
  49. # Feeds next byte to the (de)compression algorithm. Feeding a byte with value
  50. # -1 means end of input. Returns N (possibly zero) output bytes in format -1,
  51. # byteN, ..., byte2, byte1.
  52. comunpressFeed:
  53. -1 >< # terminating -1
  54. $_comunpressState 1 |> 0 = ?
  55. # ------- COMPRESSING -------
  56. $0 -1 = ?
  57. ^
  58. # EOF: just output the rest of buffer (without compressing, KISS)
  59. $_comunpressHistory>_comunpressHelper
  60. 5 @'
  61. $_comunpressHelper
  62. $0 0 << ?
  63. ^
  64. ;
  65. $0 _COMUNPRESS_MARKER = ?
  66. ^
  67. +xff ><
  68. _COMUNPRESS_MARKER
  69. .
  70. ><
  71. .
  72. $>_comunpressHelper
  73. --
  74. .
  75. ^
  76. ;
  77. # non-EOF:
  78. _comunpressHistoryPush
  79. $_comunpressHistory>_comunpressHelper
  80. 5 $+_comunpressHelper
  81. $_comunpressHelper 0 >>= ? # ignore -1 and -2
  82. # stack: -1
  83. # now search for matches in history
  84. -1 # match_p (position)
  85. 4 @' # for match_l (length) := 3 downto 0
  86. --
  87. $0 3 + # len (6 downto 3)
  88. $_comunpressHistory>_comunpressHelper
  89. 6 $+_comunpressHelper
  90. 0 @@ # for i := 0
  91. $0 63 >= ? # up to 63
  92. !@
  93. .
  94. # stack: -1 match_p match_l len i
  95. $0 $:4 # match_p := i
  96. $1 @' # for j := len - 1 downto 0
  97. --
  98. # stack: -1 match_p match_l len i j
  99. $_comunpressHistory>_comunpressHelper2
  100. 6 $3 - $1 + $+_comunpressHelper2
  101. $_comunpressHelper2
  102. $_comunpressHelper>_comunpressHelper2
  103. $1 $+_comunpressHelper2
  104. $_comunpressHelper2
  105. != ?
  106. -1 $:5 # match_p := -1
  107. !@
  108. .
  109. .
  110. ^ # j
  111. $3 -1 != ? # match found?
  112. $3 63 = $3 3 = & ? # disallowed, would result in 0xff, reserved
  113. -1 $:4
  114. ;
  115. !@
  116. .
  117. .
  118. $>_comunpressHelper
  119. ++
  120. .
  121. ^ # i
  122. ^ # len
  123. $1 -1 != ? # match found?
  124. !@
  125. .
  126. .
  127. $1 0 >>= ? # match found?
  128. $0 3 +
  129. @'
  130. 0 _comunpressHistoryPush
  131. --
  132. .
  133. ^
  134. $_comunpressHistory>_comunpressHelper
  135. $0 3 +
  136. @'
  137. -2 $:_comunpressHelper
  138. $>_comunpressHelper
  139. --
  140. .
  141. ^
  142. # now shift the pre-buffer 1 left:
  143. $0>_comunpressHelper
  144. $_comunpressHistory>0
  145. $>0 $:1' $>0 $:1' $>0 $:1' $>0 $:1' $>0 $:1 -2
  146. $_comunpressHelper>0
  147. # encode the reference for output:
  148. 6 |< | # (match_p << 6) | match_l
  149. _COMUNPRESS_MARKER
  150. ;
  151. # no match was found, we'll just output one byte
  152. ^ ^ # match_l, match_p
  153. $_comunpressHistory>_comunpressHelper
  154. 5 $+_comunpressHelper
  155. $_comunpressHelper
  156. $0 0 << ?
  157. ^
  158. ;
  159. $0 _COMUNPRESS_MARKER = ?
  160. +xff
  161. ><
  162. .
  163. .
  164. .
  165. .
  166. .
  167. ; # =============================
  168. # ------- DECOMPRESSING -------
  169. $_comunpressState 3 = ?
  170. # state: decompressing marker
  171. $0 +xff = ?
  172. # encoded marker, output it
  173. ^
  174. _COMUNPRESS_MARKER
  175. ;
  176. # sequence reference
  177. $0 +x3f & # position
  178. $_comunpressHistory>_comunpressHelper
  179. $+_comunpressHelper
  180. 6 |> 3 + # length
  181. @'
  182. --
  183. $0
  184. $_comunpressHelper $:2
  185. $>_comunpressHelper
  186. .
  187. ^
  188. .
  189. 2 $:_comunpressState
  190. ;
  191. # state: decompressing normal
  192. $0 _COMUNPRESS_MARKER = ?
  193. ^ # output nothing
  194. 3 $:_comunpressState
  195. .
  196. # else do nothing, just leave the byte on top of stack
  197. .
  198. # push all output characters to history
  199. $0>_comunpressHelper
  200. @@
  201. $_comunpressHelper -1 = ?
  202. !@
  203. ;
  204. $<_comunpressHelper
  205. .
  206. .
  207. -1
  208. @@
  209. $>_comunpressHelper
  210. $_comunpressHelper
  211. $0 -1 = ?
  212. ^ !@
  213. .
  214. .
  215. @@
  216. $0 -1 = ?
  217. ^ !@
  218. .
  219. _comunpressHistoryPush
  220. .
  221. .
  222. .
  223. # if using as pure library you may happily remove everything below
  224. _comunpressStandalone:
  225. 0 > ?
  226. "-" = ?
  227. "x" = ?
  228. 1
  229. ;
  230. 0
  231. .
  232. ;
  233. 0
  234. .
  235. ;
  236. 0
  237. .
  238. comunpressInit
  239. 1 @ # stream loop
  240. <-
  241. <? !! ? # if EOF, feed -1
  242. ^ -1
  243. .
  244. comunpressFeed
  245. @@ # print all output chars to stdout
  246. $0 -1 = ?
  247. ^ !@
  248. .
  249. ->
  250. .
  251. <?
  252. .
  253. .
  254. $0 -1 != ?
  255. _comunpressStandalone
  256. .