📄 huffmancoding.bas
字号:
'If this was left uncompressed, this will be easy.
If Left(Text, 4) = "HE0" & vbCr Then
HuffmanDecode = Mid(Text, 5)
Exit Function
End If
'If this is any version other than 2, we'll bow out.
If Left(Text, 4) <> "HE2" & vbCr Then
Err.Raise vbObjectError, "HuffmanDecode()", _
"The data either was not compressed with HE2 or is corrupt"
End If
Text = Mid(Text, 5)
'Extract the ASCII character bit-code table's byte length.
Pos = InStr(1, Text, vbCr)
If Pos = 0 Then
Err.Raise vbObjectError, "HuffmanDecode()", _
"The data either was not compressed with HE2 or is corrupt"
End If
On Error Resume Next
TextLen = Left(Text, Pos - 1)
If Err.Number <> 0 Then
On Error GoTo 0
Err.Raise vbObjectError, "HuffmanDecode()", _
"The header is corrupt"
End If
On Error GoTo 0
Text = Mid(Text, Pos + 1)
Temp = Left(Text, TextLen)
Text = Mid(Text, TextLen + 1)
'Now extract the ASCII character bit-code table.
Set HTRootNode = NewNode
Pos = 1
While Pos <= Len(Temp)
Char = Asc(Mid(Temp, Pos, 1))
Pos = Pos + 1
Bits = StringToBits(Pos, Temp)
Set HTNode = HTRootNode
For j = 0 To UBound(Bits)
If Bits(j) = 1 Then
If HTNode(htnLeftSubtree) Is Nothing Then
S HTNode, htnLeftSubtree, NewNode
End If
Set HTNode = HTNode(htnLeftSubtree)
Else
If HTNode(htnRightSubtree) Is Nothing Then
S HTNode, htnRightSubtree, NewNode
End If
Set HTNode = HTNode(htnRightSubtree)
End If
Next
S HTNode, htnIsLeaf, True
S HTNode, htnAsciiCode, Chr(Char)
S HTNode, htnBitCode, Bits
Wend
'Extract the checksum.
CheckSum = Asc(Left(Text, 1))
Text = Mid(Text, 2)
'Extract the length of the original string.
Pos = InStr(1, Text, vbCr)
If Pos = 0 Then
Err.Raise vbObjectError, "HuffmanDecode()", _
"The header is corrupt"
End If
On Error Resume Next
SourceLen = Left(Text, Pos - 1)
If Err.Number <> 0 Then
On Error GoTo 0
Err.Raise vbObjectError, "HuffmanDecode()", _
"The header is corrupt"
End If
On Error GoTo 0
Text = Mid(Text, Pos + 1)
TextLen = Len(Text)
'Now that we've processed the header, let's decode the actual data.
i = 1
BitPos = -1
Set HTNode = HTRootNode
Temp = ""
While CharsFound < SourceLen
If BitPos = -1 Then
If i > TextLen Then
Err.Raise vbObjectError, "HuffmanDecode()", _
"Expecting more bytes in data stream"
End If
Char = Asc(Mid(Text, i, 1))
i = i + 1
End If
BitPos = BitPos + 1
If (Char And 2 ^ BitPos) > 0 Then
Set HTNode = HTNode(htnLeftSubtree)
Else
Set HTNode = HTNode(htnRightSubtree)
End If
If HTNode Is Nothing Then
'Uh oh. We've followed the tree to a Huffman tree to a dead
'end, which won't happen unless the data is corrupt.
Err.Raise vbObjectError, "HuffmanDecode()", _
"The header (lookup table) is corrupt"
End If
If HTNode(htnIsLeaf) Then
Temp = Temp & HTNode(htnAsciiCode)
If Len(Temp) > 1024 Then
HuffmanDecode = HuffmanDecode & Temp
Temp = ""
End If
CharsFound = CharsFound + 1
Set HTNode = HTRootNode
End If
If BitPos >= 7 Then BitPos = -1
Wend
If Len(Temp) > 0 Then
HuffmanDecode = HuffmanDecode & Temp
End If
If i <= TextLen Then
Err.Raise vbObjectError, "HuffmanDecode()", _
"Found extra bytes at end of data stream"
End If
'Verify data to check for corruption.
If Len(HuffmanDecode) <> SourceLen Then
Err.Raise vbObjectError, "HuffmanDecode()", _
"Data corrupt because check sums do not match"
End If
Char = 0
For i = 1 To SourceLen
Char = Char Xor Asc(Mid(HuffmanDecode, i, 1))
Next
If Char <> CheckSum Then
Err.Raise vbObjectError, "HuffmanDecode()", _
"Data corrupt because check sums do not match"
End If
End Function
'----------------------------------------------------------------
' Everything below here is only for supporting the two main
' routines above.
'----------------------------------------------------------------
'Follows the tree, now built, to its end leaf nodes, where the
'character codes are, in order to tell those character codes
'what their bit string representations are.
Private Sub AttachBitCodes(BitStrings, HTNode As Collection, ByVal Bits)
If HTNode Is Nothing Then Exit Sub
If HTNode(htnIsLeaf) Then
S HTNode, htnBitCode, Bits
Set BitStrings(Asc(HTNode(htnAsciiCode))) = HTNode
Else
ReDim Preserve Bits(UBound(Bits) + 1)
Bits(UBound(Bits)) = 1
AttachBitCodes BitStrings, HTNode(htnLeftSubtree), Bits
Bits(UBound(Bits)) = 0
AttachBitCodes BitStrings, HTNode(htnRightSubtree), Bits
End If
End Sub
'Turns a string of '0' and '1' characters into a string of bytes
'containing the bits, preceeded by 1 byte indicating the
'number of bits represented.
Private Function BitsToString(Bits) As String
Dim Char As Byte, i As Long
BitsToString = Chr(UBound(Bits) + 1) 'Number of bits
For i = 0 To UBound(Bits)
If i Mod 8 = 0 Then
If i > 0 Then BitsToString = BitsToString & Chr(Char)
Char = 0
End If
If Bits(i) = 1 Then 'Bit value = 1
'Mask the bit into its proper position in the byte
Char = Char + 2 ^ (i Mod 8)
End If
Next
BitsToString = BitsToString & Chr(Char)
End Function
'The opposite of BitsToString() function.
Private Function StringToBits(StartPos As Long, Bytes As String)
Dim Char As Byte, i As Long, BitCount As Long, Bits
Bits = Array()
BitCount = Asc(Mid(Bytes, StartPos, 1))
StartPos = StartPos + 1
For i = 0 To BitCount - 1
If i Mod 8 = 0 Then
Char = Asc(Mid(Bytes, StartPos, 1))
StartPos = StartPos + 1
End If
ReDim Preserve Bits(UBound(Bits) + 1)
If (Char And 2 ^ (i Mod 8)) > 0 Then 'Bit value = 1
Bits(UBound(Bits)) = 1
Else 'Bit value = 0
Bits(UBound(Bits)) = 0
End If
Next
StringToBits = Bits
End Function
'Remove the specified item and put the specified value in its place.
Private Sub S(Col As Collection, Index As HuffmanTreeNodeParts, Value)
Col.Remove Index
If Index > Col.Count Then
Col.Add Value
Else
Col.Add Value, , Index
End If
End Sub
'Creates a new Huffman tree node with the default values set.
Private Function NewNode() As Collection
Dim Node As New Collection
Node.Add 0 'htnWeight
Node.Add False 'htnIsLeaf
Node.Add Chr(0) 'htnAsciiCode
Node.Add "" 'htnBitCode
Node.Add Nothing 'htnLeftSubtree
Node.Add Nothing 'htnRightSubtree
Set NewNode = Node
End Function
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -