HUFFDCMP.ASM 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391
  1. ;
  2. ; Command & Conquer Red Alert(tm)
  3. ; Copyright 2025 Electronic Arts Inc.
  4. ;
  5. ; This program is free software: you can redistribute it and/or modify
  6. ; it under the terms of the GNU General Public License as published by
  7. ; the Free Software Foundation, either version 3 of the License, or
  8. ; (at your option) any later version.
  9. ;
  10. ; This program is distributed in the hope that it will be useful,
  11. ; but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. ; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. ; GNU General Public License for more details.
  14. ;
  15. ; You should have received a copy of the GNU General Public License
  16. ; along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. ;
  18. ;****************************************************************************
  19. ;*
  20. ;* C O N F I D E N T I A L -- W E S T W O O D S T U D I O S
  21. ;*
  22. ;*---------------------------------------------------------------------------
  23. ;*
  24. ;* FILE
  25. ;* huffdcmp.asm
  26. ;*
  27. ;* DESCRIPTION
  28. ;* Huffman order 0 decompressor.
  29. ;*
  30. ;* PROGRAMMER
  31. ;* Denzil E. Long, Jr.
  32. ;*
  33. ;* DATE
  34. ;* May 22, 1995
  35. ;*
  36. ;*---------------------------------------------------------------------------
  37. ;*
  38. ;* PUBLIC
  39. ;* HuffDecompress - Decompress Huffman order 0 encoded data.
  40. ;* BuildHuffTree - Build the Huffman decode tree.
  41. ;*
  42. ;****************************************************************************
  43. IDEAL
  44. P386
  45. MODEL USE32 FLAT
  46. LOCALS ??
  47. STRUC TreeNode
  48. count DD ? ;Weight of the node
  49. child0 DW ? ;Child node 0
  50. child1 DW ? ;Child node 1
  51. ENDS TreeNode
  52. HUFF_EOS EQU 256
  53. CODESEG
  54. ;****************************************************************************
  55. ;*
  56. ;* NAME
  57. ;* HuffDecompress - Decompress Huffman order 0 encoded data.
  58. ;*
  59. ;* SYNOPSIS
  60. ;* Size = HuffDecompress(Data, Buffer, Length, Temp)
  61. ;*
  62. ;* long = HuffDecompress(unsigned char *, unsigned char *, long, char *);
  63. ;*
  64. ;* FUNCTION
  65. ;* Expand data that has been compressed with order 0 Huffman coding.
  66. ;* The model (counts) are extracted from the data and a decode tree is
  67. ;* built. The data is expanded by reading a bit and traversing the tree
  68. ;* until a leaf node is encountered.
  69. ;*
  70. ;* INPUTS
  71. ;* Data - Pointer to Huffman encoded data.
  72. ;* Buffer - Pointer to decompress buffer.
  73. ;* Length - Maximum decompress length.
  74. ;* Temp - Pointer to temporary working buffer. (Must be >= 5120 bytes!)
  75. ;*
  76. ;* RESULT
  77. ;* Size - Size of decompressed data.
  78. ;*
  79. ;****************************************************************************
  80. GLOBAL C HuffDecompress:NEAR
  81. PROC HuffDecompress C NEAR USES esi edi ebx ecx edx
  82. ARG data:NEAR PTR
  83. ARG buffer:NEAR PTR
  84. ARG length:DWORD
  85. ARG temp:NEAR PTR
  86. LOCAL next:DWORD
  87. ;*---------------------------------------------------------------------------
  88. ;* Read in the set of counts
  89. ;*---------------------------------------------------------------------------
  90. mov esi,[data] ;Compressed data
  91. mov ebx,[temp] ;Nodes array
  92. mov ax,[esi] ;Get first and last count
  93. xor edx,edx ;i = 0
  94. xor ecx,ecx
  95. add esi,2
  96. ??getcounts:
  97. cmp al,dl ;Reached start of run?
  98. jne ??zerocount
  99. ;* Copy the run of counts to the nodes
  100. sub ah,al ;Run length = Stop - Start
  101. xor ecx,ecx
  102. mov cl,ah
  103. xor eax,eax
  104. inc ecx ;Run length + 1
  105. ??copycounts:
  106. mov al,[esi] ;Get count
  107. inc edx ;i++
  108. mov [ebx],eax ;Write count to node
  109. inc esi
  110. add ebx,8 ;Next node
  111. dec ecx
  112. jnz ??copycounts
  113. mov ax,[esi] ;Get next start
  114. inc esi
  115. cmp al,0 ;Terminator?
  116. je short ??nextcount
  117. inc esi
  118. jmp short ??nextcount
  119. ;* Fill empty nodes with 0
  120. ??zerocount:
  121. mov [DWORD PTR ebx],ecx
  122. inc edx ;i++
  123. add ebx,8 ;Next node
  124. ??nextcount:
  125. cmp edx,256
  126. jl short ??getcounts
  127. mov [WORD PTR ebx],1
  128. mov [data],esi
  129. ;*---------------------------------------------------------------------------
  130. ;* Build the Huffman tree. All active nodes are scanned in order
  131. ;* to locate the two nodes with the minimum weights. These two
  132. ;* weights are added together and assigned a new node. The new
  133. ;* node makes the two minimum nodes into its 0 child and 1 child.
  134. ;* The two minimum nodes are then marked as inactive. This process
  135. ;* repeats until their is only one node left, which is the root.
  136. ;*---------------------------------------------------------------------------
  137. mov eax,[temp] ;Nodes array
  138. mov esi,eax
  139. add eax,(513 * 8) ;Node[513] = guaranteed maximum
  140. mov [DWORD PTR eax],-1
  141. mov [next],((HUFF_EOS + 1) * 8)
  142. ??sortnext:
  143. mov edx,(513 * 8) ;first = 513
  144. mov edi,edx ;last = 513
  145. xor ecx,ecx ;i = 0
  146. mov ebx,esi ;nodes[i]
  147. ??sortnodes:
  148. cmp [WORD PTR ebx],0 ;Only check non-zero nodes
  149. jz ??nextnode
  150. ;* nodes[i].count < nodes[first].count
  151. mov eax,[DWORD PTR esi + edx]
  152. cmp eax,[DWORD PTR ebx]
  153. jbe ??checklast
  154. mov edi,edx ;last = first
  155. mov edx,ecx ;first = i
  156. jmp short ??nextnode
  157. ;* nodes[i].count < nodes[last].count
  158. ??checklast:
  159. mov eax,[DWORD PTR esi + edi]
  160. cmp eax,[DWORD PTR ebx]
  161. jbe ??nextnode
  162. mov edi,ecx ;last = i
  163. ??nextnode:
  164. add ecx,8 ;i++
  165. add ebx,8 ;nodes[i]
  166. cmp ecx,[next]
  167. jne short ??sortnodes
  168. ;* Tree done when last = 513
  169. cmp edi,(513 * 8)
  170. je short ??decode
  171. mov ebx,[next]
  172. add ebx,esi
  173. mov [WORD PTR ebx+4],dx ;nodes[next].child0 = first
  174. mov [WORD PTR ebx+6],di ;nodes[next].child1 = last
  175. add edx,esi
  176. mov eax,[DWORD PTR edx] ;nodes[first].count
  177. add edi,esi
  178. mov [DWORD PTR ebx],eax
  179. mov ecx,[DWORD PTR edi] ;nodes[last].count
  180. xor eax,eax
  181. add [DWORD PTR ebx],ecx
  182. mov [DWORD PTR edx],eax ;nodes[first].count = 0
  183. mov [DWORD PTR edi],eax ;nodes[lats].count = 0
  184. add [next],8
  185. jmp ??sortnext
  186. ;*---------------------------------------------------------------------------
  187. ;* Expand the compressed data. As each new symbol is decoded, the
  188. ;* tree is traversed, starting at the root node, reading a bit in,
  189. ;* and taking either the child0 or child1 path. Eventually, the
  190. ;* tree winds down to a leaf node, and the corresponding symbol is
  191. ;* output. If the symbol is the HUFF_EOS symbol the process
  192. ;* terminates.
  193. ;*---------------------------------------------------------------------------
  194. ??decode:
  195. sub [next],8 ;rootnode - 1
  196. xor ecx,ecx
  197. mov esi,[data] ;Input data buffer
  198. mov al,080h ;mask = 0x80
  199. mov edi,[buffer] ;Output buffer
  200. mov ah,[esi] ;Data byte
  201. mov ebx,[temp]
  202. inc esi
  203. ??decodeloop:
  204. mov edx,[next] ;node = root
  205. ??walktree:
  206. mov ecx,4
  207. add ecx,edx
  208. test al,ah
  209. jz short ??getnode
  210. add ecx,2
  211. ??getnode:
  212. mov dx,[WORD PTR ebx + ecx] ;nodes[node].child
  213. shr al,1
  214. jnz short ??checkleaf
  215. mov ah,[esi] ;Get next data byte
  216. mov al,080h ;Reset mask
  217. inc esi
  218. ??checkleaf:
  219. cmp edx,(HUFF_EOS * 8)
  220. jg short ??walktree
  221. je short ??done
  222. shr edx,3
  223. mov [edi],dl
  224. inc edi
  225. jmp short ??decodeloop
  226. ??done:
  227. mov eax,edi
  228. sub eax,[buffer]
  229. ret
  230. ENDP HuffDecompress
  231. ;****************************************************************************
  232. ;*
  233. ;* NAME
  234. ;* BuildHuffTree - Build the Huffman decode tree.
  235. ;*
  236. ;* SYNOPSIS
  237. ;* Root = BuildHuffTree(Nodes)
  238. ;*
  239. ;* long BuildHuffTree(TreeNode *);
  240. ;*
  241. ;* FUNCTION
  242. ;* Build the Huffman tree. All active nodes are scanned in order to
  243. ;* locate the two nodes with the minimum weights. These two weights are
  244. ;* added together and assigned a new node. The new node makes the two
  245. ;* minimum nodes into its 0 child and 1 child. The two minimum nodes are
  246. ;* then marked as inactive. This process repeats until their is only one
  247. ;* node left, which is the root.
  248. ;*
  249. ;* INPUTS
  250. ;* Nodes - Pointer to array of nodes.
  251. ;*
  252. ;* RESULT
  253. ;* Root - Number of root node.
  254. ;*
  255. ;****************************************************************************
  256. GLOBAL C BuildHuffTree:NEAR
  257. PROC BuildHuffTree C NEAR USES esi edi ebx ecx edx
  258. ARG temp:NEAR PTR
  259. LOCAL next:DWORD
  260. mov eax,[temp] ;Nodes array
  261. mov esi,eax
  262. add eax,(513 * 8) ;Node[513] = guaranteed maximum
  263. mov [DWORD PTR eax],-1
  264. mov [next],((HUFF_EOS + 1) * 8)
  265. ??sortnext:
  266. mov edx,(513 * 8) ;first = 513
  267. mov edi,edx ;last = 513
  268. xor ecx,ecx ;i = 0
  269. mov ebx,esi ;nodes[i]
  270. ??sortnodes:
  271. cmp [WORD PTR ebx],0 ;Only check non-zero nodes
  272. jz ??nextnode
  273. ;* nodes[i].count < nodes[first].count
  274. mov eax,[DWORD PTR esi + edx]
  275. cmp eax,[DWORD PTR ebx]
  276. jbe ??checklast
  277. mov edi,edx ;last = first
  278. mov edx,ecx ;first = i
  279. jmp short ??nextnode
  280. ;* nodes[i].count < nodes[last].count
  281. ??checklast:
  282. mov eax,[DWORD PTR esi + edi]
  283. cmp eax,[DWORD PTR ebx]
  284. jbe ??nextnode
  285. mov edi,ecx ;last = i
  286. ??nextnode:
  287. add ecx,8 ;i++
  288. add ebx,8
  289. cmp ecx,[next]
  290. jne short ??sortnodes
  291. ;* Tree done when last = 513
  292. cmp edi,(513 * 8)
  293. je short ??done
  294. mov ebx,[next]
  295. add ebx,esi ;nodes[next]
  296. mov [WORD PTR ebx+4],dx ;nodes[next].child0 = first
  297. mov [WORD PTR ebx+6],di ;nodes[next].child1 = last
  298. add edx,esi
  299. mov eax,[DWORD PTR edx] ;nodes[first].count
  300. add edi,esi
  301. mov [DWORD PTR ebx],eax
  302. mov ecx,[DWORD PTR edi] ;nodes[last].count
  303. xor eax,eax
  304. add [DWORD PTR ebx],ecx
  305. mov [DWORD PTR edx],eax ;nodes[first].count = 0
  306. mov [DWORD PTR edi],eax ;nodes[lats].count = 0
  307. add [next],8
  308. jmp ??sortnext
  309. ??done:
  310. mov eax,[next]
  311. sub eax,8
  312. ret
  313. ENDP BuildHuffTree
  314. END