-
Notifications
You must be signed in to change notification settings - Fork 0
/
Comp_LZW_Dynamic_Hash.bas
236 lines (222 loc) · 7.22 KB
/
Comp_LZW_Dynamic_Hash.bas
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
Attribute VB_Name = "Comp_LZW_Dynamic_Hash"
Option Explicit
'This is a 1 run method
Private MaxChars As Long
Private TempStream() As Byte
Private OutStream() As Byte
Private OutPos As Long
Private dict() As String
Private OutByteBuf As Integer
Private OutBitCount As Integer
Private ReadBitPos As Integer
Private DictPos As Integer 'de positie waar de volgende karakters worden ingevoegd
Private maxCharLenght As Byte 'Maximum stringlengte in de dictionary
Private maxDictDeep As Long 'maximaal opgeslagen woorden per dictionary
Private TotBitDeep As Integer 'totale bitlengte per karakter of karaktervolgorde
Private MaxBitDeep As Integer
Private Const StartDict As Long = 257 'startpositie van de dictionary
Private Hash As HashTable
Public Sub Compress_LZW_Dynamic_Hash(FileArray() As Byte)
Dim ByteValue As Byte
Dim TempByte As Long
Dim ExtraBits As Integer
Dim DictStr As String
Dim NewStr As String
Dim CompPos As Long
Dim DictVal As Long
Dim DictPosit As Long
Dim DictPositOld As Long
Dim FilePos As Long
Dim FileLenght As Long
Dim Temp As Long
Dim MaxDictPagesInBites As Long
Set Hash = New HashTable
MaxDictPagesInBites = CLng(1024) * DictionarySize - 1
Call Init_Dictvar(MaxDictPagesInBites)
FileLenght = UBound(FileArray)
ReDim OutStream(FileLenght + 10)
OutPos = 0
Call AddBitsToOutStream(CLng(maxCharLenght), 8)
Call AddBitsToOutStream(CLng(MaxBitDeep), 8)
FilePos = 0
CompPos = 7
DictStr = ""
ExtraBits = 0
Do Until FilePos > FileLenght
ByteValue = FileArray(FilePos)
FilePos = FilePos + 1
NewStr = DictStr & Chr(ByteValue)
DictPosit = Search(NewStr)
If DictPosit <> maxDictDeep + 1 Then
DictStr = NewStr
DictPositOld = DictPosit
Else
Call AddBitsToOutStream(DictPositOld, TotBitDeep)
Call AddToDict(NewStr, 1)
DictPositOld = ByteValue
DictStr = Chr(ByteValue)
End If
Loop
Call AddBitsToOutStream(DictPositOld, TotBitDeep)
Call AddBitsToOutStream(256, TotBitDeep)
Do While OutBitCount > 0
Call AddBitsToOutStream(0, 1)
Loop
Set Hash = Nothing
ReDim FileArray(OutPos - 1)
Call CopyMem(FileArray(0), OutStream(0), OutPos)
End Sub
Public Sub DeCompress_LZW_Dynamic_Hash(FileArray() As Byte)
Dim ReadBits As Integer
Dim DictVal As Long
Dim TempByte As Long
Dim OldKarValue As Long
Dim DeComPByte() As Byte
Dim DeCompPos As Long
Dim FilePos As Long
Dim FileLenght As Long
Dim InpPos As Long
InpPos = 0
ReadBitPos = 0
OutPos = 0
DictVal = -1
maxCharLenght = ReadBitsFromArray(FileArray, InpPos, 8)
maxDictDeep = (2 ^ ReadBitsFromArray(FileArray, InpPos, 8)) - 1
Set Hash = New HashTable
Call Init_Dictvar(maxDictDeep)
Call AddToDict2Init
'hash no longer needed so lets close the hashtable to save memory
Set Hash = Nothing
ReDim OutStream(500)
Do
OldKarValue = DictVal
DictVal = ReadBitsFromArray(FileArray, InpPos, TotBitDeep)
If DictVal = 256 Then Exit Do
If dict(DictVal) <> "" Then
Call AddASC2OutStream(dict(DictVal))
If OldKarValue <> -1 Then Call AddToDict2(dict(OldKarValue) & Left(dict(DictVal), 1), 0)
Else
Call AddToDict2(dict(OldKarValue) & Left(dict(OldKarValue), 1), 0)
Call AddASC2OutStream(dict(DictVal))
End If
Loop
OutPos = OutPos - 1
ReDim FileArray(OutPos)
Call CopyMem(FileArray(0), OutStream(0), OutPos + 1)
End Sub
Private Sub Init_Dictvar(Optional MaxDictPagesInBites As Long = 512, Optional StoreTilCharLenght As Byte = 50)
Dim X As Integer
If MaxDictPagesInBites > 65535 Then
MaxDictPagesInBites = 65535
ElseIf MaxDictPagesInBites < 255 Then
MaxDictPagesInBites = 255
End If
For X = 0 To 16
If MaxDictPagesInBites <= 2 ^ X Then
MaxDictPagesInBites = 2 ^ X
MaxBitDeep = X
Exit For
End If
Next
MaxDictPagesInBites = MaxDictPagesInBites - 1
maxCharLenght = StoreTilCharLenght
maxDictDeep = MaxDictPagesInBites
Call Clean_DictionaryVar
End Sub
Private Sub Clean_DictionaryVar()
Dim X As Long
Hash.SetSize (maxDictDeep)
For X = 0 To 255
Hash.Add Chr(X), X
Next
Call Init_DictStart
End Sub
Private Sub Init_DictStart()
DictPos = StartDict
TotBitDeep = 9
End Sub
Private Function Search(Char As String) As Long
Dim X As Variant
X = Hash.Item(Char)
If Not IsEmpty(X) Then
Search = X
Else
Search = maxDictDeep + 1
End If
End Function
Private Sub AddToDict(Char As String, Comp1Decomp0 As Byte)
If Len(Char) = 1 Or Len(Char) - 2 > maxCharLenght Then Exit Sub
If DictPos + Comp1Decomp0 >= maxDictDeep Then Call Clean_DictionaryVar
If DictPos >= (2 ^ TotBitDeep) - (1 - Comp1Decomp0) Then
TotBitDeep = TotBitDeep + 1
End If
Hash.Add Char, DictPos
DictPos = DictPos + 1
End Sub
Private Sub AddToDict2(Char As String, Comp1Decomp0 As Byte)
If Len(Char) = 1 Or Len(Char) - 2 > maxCharLenght Then Exit Sub
If DictPos + Comp1Decomp0 >= maxDictDeep Then Call Init_DictStart
If DictPos >= (2 ^ TotBitDeep) - (1 - Comp1Decomp0) Then
TotBitDeep = TotBitDeep + 1
End If
dict(DictPos) = Char
DictPos = DictPos + 1
End Sub
Private Sub AddToDict2Init()
Dim X As Long
ReDim dict(maxDictDeep)
For X = 0 To 255
dict(X) = Chr(X)
Next
For X = 256 To maxDictDeep
If dict(X) = "" Then Exit For Else dict(X) = ""
Next
Call Init_DictStart
End Sub
Private Sub AddASC2OutStream(Text As String)
Dim X As Long
If OutPos + Len(Text) > UBound(OutStream) Then ReDim Preserve OutStream(OutPos + Len(Text) + 500)
For X = 1 To Len(Text)
OutStream(OutPos) = ASC(Mid(Text, X, 1))
OutPos = OutPos + 1
Next
End Sub
'this sub will add an amount of bits into the outputstream
Private Sub AddBitsToOutStream(Number As Long, Numbits As Integer)
Dim X As Long
For X = Numbits - 1 To 0 Step -1
OutByteBuf = OutByteBuf * 2 + (-1 * ((Number And CDbl(2 ^ X)) > 0))
OutBitCount = OutBitCount + 1
If OutBitCount = 8 Then
OutStream(OutPos) = OutByteBuf
OutBitCount = 0
OutByteBuf = 0
OutPos = OutPos + 1
If OutPos > UBound(OutStream) Then
ReDim Preserve OutStream(OutPos + 500)
End If
End If
Next
End Sub
'this sub will read an amount of bits from the inputstream
Private Function ReadBitsFromArray(FromArray() As Byte, FromPos As Long, Numbits As Integer) As Long
Dim X As Integer
Dim Temp As Long
For X = 1 To Numbits
Temp = Temp * 2 + (-1 * ((FromArray(FromPos) And 2 ^ (7 - ReadBitPos)) > 0))
ReadBitPos = ReadBitPos + 1
If ReadBitPos = 8 Then
If FromPos + 1 > UBound(FromArray) Then
Do While X < Numbits
Temp = Temp * 2
X = X + 1
Loop
FromPos = FromPos + 1
Exit For
End If
FromPos = FromPos + 1
ReadBitPos = 0
End If
Next
ReadBitsFromArray = Temp
End Function