| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391 |
- ;
- ; Command & Conquer Red Alert(tm)
- ; Copyright 2025 Electronic Arts Inc.
- ;
- ; This program is free software: you can redistribute it and/or modify
- ; it under the terms of the GNU General Public License as published by
- ; the Free Software Foundation, either version 3 of the License, or
- ; (at your option) any later version.
- ;
- ; This program is distributed in the hope that it will be useful,
- ; but WITHOUT ANY WARRANTY; without even the implied warranty of
- ; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- ; GNU General Public License for more details.
- ;
- ; You should have received a copy of the GNU General Public License
- ; along with this program. If not, see <http://www.gnu.org/licenses/>.
- ;
- ;****************************************************************************
- ;*
- ;* 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
- ;*
- ;*---------------------------------------------------------------------------
- ;*
- ;* FILE
- ;* huffdcmp.asm
- ;*
- ;* DESCRIPTION
- ;* Huffman order 0 decompressor.
- ;*
- ;* PROGRAMMER
- ;* Denzil E. Long, Jr.
- ;*
- ;* DATE
- ;* May 22, 1995
- ;*
- ;*---------------------------------------------------------------------------
- ;*
- ;* PUBLIC
- ;* HuffDecompress - Decompress Huffman order 0 encoded data.
- ;* BuildHuffTree - Build the Huffman decode tree.
- ;*
- ;****************************************************************************
- IDEAL
- P386
- MODEL USE32 FLAT
- LOCALS ??
- STRUC TreeNode
- count DD ? ;Weight of the node
- child0 DW ? ;Child node 0
- child1 DW ? ;Child node 1
- ENDS TreeNode
- HUFF_EOS EQU 256
- CODESEG
- ;****************************************************************************
- ;*
- ;* NAME
- ;* HuffDecompress - Decompress Huffman order 0 encoded data.
- ;*
- ;* SYNOPSIS
- ;* Size = HuffDecompress(Data, Buffer, Length, Temp)
- ;*
- ;* long = HuffDecompress(unsigned char *, unsigned char *, long, char *);
- ;*
- ;* FUNCTION
- ;* Expand data that has been compressed with order 0 Huffman coding.
- ;* The model (counts) are extracted from the data and a decode tree is
- ;* built. The data is expanded by reading a bit and traversing the tree
- ;* until a leaf node is encountered.
- ;*
- ;* INPUTS
- ;* Data - Pointer to Huffman encoded data.
- ;* Buffer - Pointer to decompress buffer.
- ;* Length - Maximum decompress length.
- ;* Temp - Pointer to temporary working buffer. (Must be >= 5120 bytes!)
- ;*
- ;* RESULT
- ;* Size - Size of decompressed data.
- ;*
- ;****************************************************************************
- GLOBAL C HuffDecompress:NEAR
- PROC HuffDecompress C NEAR USES esi edi ebx ecx edx
- ARG data:NEAR PTR
- ARG buffer:NEAR PTR
- ARG length:DWORD
- ARG temp:NEAR PTR
- LOCAL next:DWORD
- ;*---------------------------------------------------------------------------
- ;* Read in the set of counts
- ;*---------------------------------------------------------------------------
- mov esi,[data] ;Compressed data
- mov ebx,[temp] ;Nodes array
- mov ax,[esi] ;Get first and last count
- xor edx,edx ;i = 0
- xor ecx,ecx
- add esi,2
- ??getcounts:
- cmp al,dl ;Reached start of run?
- jne ??zerocount
- ;* Copy the run of counts to the nodes
- sub ah,al ;Run length = Stop - Start
- xor ecx,ecx
- mov cl,ah
- xor eax,eax
- inc ecx ;Run length + 1
- ??copycounts:
- mov al,[esi] ;Get count
- inc edx ;i++
- mov [ebx],eax ;Write count to node
- inc esi
- add ebx,8 ;Next node
- dec ecx
- jnz ??copycounts
- mov ax,[esi] ;Get next start
- inc esi
- cmp al,0 ;Terminator?
- je short ??nextcount
- inc esi
- jmp short ??nextcount
- ;* Fill empty nodes with 0
- ??zerocount:
- mov [DWORD PTR ebx],ecx
- inc edx ;i++
- add ebx,8 ;Next node
- ??nextcount:
- cmp edx,256
- jl short ??getcounts
- mov [WORD PTR ebx],1
- mov [data],esi
- ;*---------------------------------------------------------------------------
- ;* Build the Huffman tree. All active nodes are scanned in order
- ;* to locate the two nodes with the minimum weights. These two
- ;* weights are added together and assigned a new node. The new
- ;* node makes the two minimum nodes into its 0 child and 1 child.
- ;* The two minimum nodes are then marked as inactive. This process
- ;* repeats until their is only one node left, which is the root.
- ;*---------------------------------------------------------------------------
-
- mov eax,[temp] ;Nodes array
- mov esi,eax
- add eax,(513 * 8) ;Node[513] = guaranteed maximum
- mov [DWORD PTR eax],-1
- mov [next],((HUFF_EOS + 1) * 8)
- ??sortnext:
- mov edx,(513 * 8) ;first = 513
- mov edi,edx ;last = 513
- xor ecx,ecx ;i = 0
- mov ebx,esi ;nodes[i]
- ??sortnodes:
- cmp [WORD PTR ebx],0 ;Only check non-zero nodes
- jz ??nextnode
- ;* nodes[i].count < nodes[first].count
- mov eax,[DWORD PTR esi + edx]
- cmp eax,[DWORD PTR ebx]
- jbe ??checklast
- mov edi,edx ;last = first
- mov edx,ecx ;first = i
- jmp short ??nextnode
- ;* nodes[i].count < nodes[last].count
- ??checklast:
- mov eax,[DWORD PTR esi + edi]
- cmp eax,[DWORD PTR ebx]
- jbe ??nextnode
- mov edi,ecx ;last = i
- ??nextnode:
- add ecx,8 ;i++
- add ebx,8 ;nodes[i]
- cmp ecx,[next]
- jne short ??sortnodes
- ;* Tree done when last = 513
- cmp edi,(513 * 8)
- je short ??decode
- mov ebx,[next]
- add ebx,esi
- mov [WORD PTR ebx+4],dx ;nodes[next].child0 = first
- mov [WORD PTR ebx+6],di ;nodes[next].child1 = last
- add edx,esi
- mov eax,[DWORD PTR edx] ;nodes[first].count
- add edi,esi
- mov [DWORD PTR ebx],eax
-
- mov ecx,[DWORD PTR edi] ;nodes[last].count
- xor eax,eax
- add [DWORD PTR ebx],ecx
- mov [DWORD PTR edx],eax ;nodes[first].count = 0
- mov [DWORD PTR edi],eax ;nodes[lats].count = 0
- add [next],8
- jmp ??sortnext
- ;*---------------------------------------------------------------------------
- ;* Expand the compressed data. As each new symbol is decoded, the
- ;* tree is traversed, starting at the root node, reading a bit in,
- ;* and taking either the child0 or child1 path. Eventually, the
- ;* tree winds down to a leaf node, and the corresponding symbol is
- ;* output. If the symbol is the HUFF_EOS symbol the process
- ;* terminates.
- ;*---------------------------------------------------------------------------
- ??decode:
- sub [next],8 ;rootnode - 1
- xor ecx,ecx
- mov esi,[data] ;Input data buffer
- mov al,080h ;mask = 0x80
- mov edi,[buffer] ;Output buffer
- mov ah,[esi] ;Data byte
- mov ebx,[temp]
- inc esi
- ??decodeloop:
- mov edx,[next] ;node = root
-
- ??walktree:
- mov ecx,4
- add ecx,edx
- test al,ah
- jz short ??getnode
- add ecx,2
- ??getnode:
- mov dx,[WORD PTR ebx + ecx] ;nodes[node].child
- shr al,1
- jnz short ??checkleaf
- mov ah,[esi] ;Get next data byte
- mov al,080h ;Reset mask
- inc esi
- ??checkleaf:
- cmp edx,(HUFF_EOS * 8)
- jg short ??walktree
- je short ??done
- shr edx,3
- mov [edi],dl
- inc edi
- jmp short ??decodeloop
- ??done:
- mov eax,edi
- sub eax,[buffer]
- ret
- ENDP HuffDecompress
- ;****************************************************************************
- ;*
- ;* NAME
- ;* BuildHuffTree - Build the Huffman decode tree.
- ;*
- ;* SYNOPSIS
- ;* Root = BuildHuffTree(Nodes)
- ;*
- ;* long BuildHuffTree(TreeNode *);
- ;*
- ;* FUNCTION
- ;* Build the Huffman tree. All active nodes are scanned in order to
- ;* locate the two nodes with the minimum weights. These two weights are
- ;* added together and assigned a new node. The new node makes the two
- ;* minimum nodes into its 0 child and 1 child. The two minimum nodes are
- ;* then marked as inactive. This process repeats until their is only one
- ;* node left, which is the root.
- ;*
- ;* INPUTS
- ;* Nodes - Pointer to array of nodes.
- ;*
- ;* RESULT
- ;* Root - Number of root node.
- ;*
- ;****************************************************************************
- GLOBAL C BuildHuffTree:NEAR
- PROC BuildHuffTree C NEAR USES esi edi ebx ecx edx
- ARG temp:NEAR PTR
-
- LOCAL next:DWORD
- mov eax,[temp] ;Nodes array
- mov esi,eax
- add eax,(513 * 8) ;Node[513] = guaranteed maximum
- mov [DWORD PTR eax],-1
- mov [next],((HUFF_EOS + 1) * 8)
- ??sortnext:
- mov edx,(513 * 8) ;first = 513
- mov edi,edx ;last = 513
- xor ecx,ecx ;i = 0
- mov ebx,esi ;nodes[i]
- ??sortnodes:
- cmp [WORD PTR ebx],0 ;Only check non-zero nodes
- jz ??nextnode
- ;* nodes[i].count < nodes[first].count
- mov eax,[DWORD PTR esi + edx]
- cmp eax,[DWORD PTR ebx]
- jbe ??checklast
- mov edi,edx ;last = first
- mov edx,ecx ;first = i
- jmp short ??nextnode
- ;* nodes[i].count < nodes[last].count
- ??checklast:
- mov eax,[DWORD PTR esi + edi]
- cmp eax,[DWORD PTR ebx]
- jbe ??nextnode
- mov edi,ecx ;last = i
- ??nextnode:
- add ecx,8 ;i++
- add ebx,8
- cmp ecx,[next]
- jne short ??sortnodes
- ;* Tree done when last = 513
- cmp edi,(513 * 8)
- je short ??done
- mov ebx,[next]
- add ebx,esi ;nodes[next]
- mov [WORD PTR ebx+4],dx ;nodes[next].child0 = first
- mov [WORD PTR ebx+6],di ;nodes[next].child1 = last
- add edx,esi
- mov eax,[DWORD PTR edx] ;nodes[first].count
- add edi,esi
- mov [DWORD PTR ebx],eax
- mov ecx,[DWORD PTR edi] ;nodes[last].count
- xor eax,eax
- add [DWORD PTR ebx],ecx
- mov [DWORD PTR edx],eax ;nodes[first].count = 0
- mov [DWORD PTR edi],eax ;nodes[lats].count = 0
- add [next],8
- jmp ??sortnext
- ??done:
- mov eax,[next]
- sub eax,8
- ret
- ENDP BuildHuffTree
- END
|