Reputation: 13
i want to migrate code from vb6 to vb.net. the project is very basic ( not use dll or component reference) just module
in compress function, it has been successfully. i'm very happy. but when decompress sub not success. the program was hang. i tried fix it, i found that the problem is do.. exit do..loop statement.
note: the code run successfully in vb6.
this is my code for decompress
Public Sub Decompress(ByteArray() As Byte)
Dim InpPos As Long
Dim InBitPos As Integer
Dim LowValue As Long
Dim HighValue As Long
Dim RangValue As Long
Dim MidValue As Long
Dim Value As Long
Dim mChar As Byte
Dim i As Integer
Dim Index As Integer
Dim EOF_State As Boolean
Dim TopBit As Long
Dim One(256) As Long
Dim Zero(256) As Long
Call Initiate
LowValue = 0
HighValue = (2 ^ MaxBits) - 1
TopBit = 2 ^ (MaxBits - 1)
InpPos = 0
Value = ReadBitsFromArray(ByteArray, InpPos, InBitPos, MaxBits)
Index = -1
For i = 0 To 256
One(i) = 1
Zero(i) = 1
Next
Do
mChar = 0
For i = 0 To 7
Index = (1 * (2 ^ i)) - 1 + mChar
RangValue = HighValue - LowValue
MidValue = LowValue + (RangValue * (Zero(Index) / (One(Index) + Zero(Index))))
If MidValue = LowValue Then MidValue = MidValue + 1
If MidValue = HighValue - 1 Then MidValue = MidValue - 1
If Value >= MidValue Then
mChar = (2 * mChar) + 1
LowValue = MidValue
One(Index) = One(Index) + 1
Else
mChar = 2 * mChar
HighValue = MidValue
Zero(Index) = Zero(Index) + 1
End If
Do While (HighValue And TopBit) = (LowValue And TopBit) Or LowValue > HighValue - 255
If InpPos <= UBound(ByteArray) Then
Value = (Value And (TopBit - 1)) * 2 + ReadBitsFromArray(ByteArray, InpPos, InBitPos, 1)
HighValue = (HighValue And (TopBit - 1)) * 2 + 1
LowValue = (LowValue And (TopBit - 1)) * 2
If LowValue >= HighValue Then HighValue = (2 ^ MaxBits) - 1
Else
EOF_State = True
Exit Do
End If
Loop
If EOF_State = True Then Exit Do
Next
Call AddmCharToArray(OutStream, OutPos, mChar)
Loop
ReDim Preserve OutStream(OutPos - 1)
End Sub
Private Sub Initiate()
ReDim OutStream(500)
OutPos = 0
OutBitCount = 0
OutByteBuf = 0
End Sub
Private Sub AddBitsToOutStream(Number As Integer)
OutByteBuf = OutByteBuf * 2 + Number
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
End Sub
Private Function ReadBitsFromArray(FromArray() As Byte, FromPos As Long, FromBit As Integer, NumBits As Integer) As Long
Dim i As Integer
Dim Temp As Long
For i = 1 To NumBits
Temp = Temp * 2 + (-1 * ((FromArray(FromPos) And 2 ^ (7 - FromBit)) > 0))
FromBit = FromBit + 1
If FromBit = 8 Then
If FromPos + 1 > UBound(FromArray) Then
Do While i < NumBits
Temp = Temp * 2
i = i + 1
Loop
FromPos = FromPos + 1
Exit For
End If
FromPos = FromPos + 1
FromBit = 0
End If
Next
ReadBitsFromArray = Temp
End Function
Private Sub AddmCharToArray(ToArray() As Byte, ToPos As Long, mChar As Byte)
If ToPos > UBound(ToArray) Then ReDim Preserve ToArray(ToPos + 500)
ToArray(ToPos) = mChar
ToPos = ToPos + 1
End Sub
do..exit do..
Do
mChar = 0
For i = 0 To 7
Index = (1 * (2 ^ i)) - 1 + mChar
RangValue = HighValue - LowValue
MidValue = LowValue + (RangValue * (Zero(Index) / (One(Index) + Zero(Index))))
If MidValue = LowValue Then MidValue = MidValue + 1
If MidValue = HighValue - 1 Then MidValue = MidValue - 1
If Value >= MidValue Then
mChar = (2 * mChar) + 1
LowValue = MidValue
One(Index) = One(Index) + 1
Else
mChar = 2 * mChar
HighValue = MidValue
Zero(Index) = Zero(Index) + 1
End If
Do While (HighValue And TopBit) = (LowValue And TopBit) Or LowValue > HighValue - 255
If InpPos <= UBound(ByteArray) Then
Value = (Value And (TopBit - 1)) * 2 + ReadBitsFromArray(ByteArray, InpPos, InBitPos, 1)
HighValue = (HighValue And (TopBit - 1)) * 2 + 1
LowValue = (LowValue And (TopBit - 1)) * 2
If LowValue >= HighValue Then HighValue = (2 ^ MaxBits) - 1
Else
EOF_State = True
Exit Do
End If
Loop
If EOF_State = True Then Exit Do
Next
Call AddmCharToArray(OutStream, OutPos, mChar)
Loop
sorry i cannot write english well.
Upvotes: 1
Views: 220
Reputation: 941545
Private Function ReadBitsFromArray(FromArray() As Byte, FromPos As Long, ...)
The bug is located in this function declaration. Your loop can only exit when InpPos
increments beyond the upper bound of the array, setting the EOF_State
variable to True. The loop itself doesn't increment InpPos at all. Back in VB6, it got incremented by the ReadBitsFromArray() function, FromBit = FromBit + 1
statement. But that is no longer the case in VB.NET.
An important change in VB.NET is the way arguments are passed. Old Visual Basic versions defaulted to ByRef
. A somewhat strange choice whose reasons are lost in the mist of time. It is a very expensive way to pass arguments, passing ByRef requires passing a pointer to the value instead of the value itself. And every access to the variable requires a pointer dereference. It is at least 3 times slower than passing by value on modern machines, .NET is heavily optimized to pass argument values through CPU registers instead of the stack, that can't work if the argument is passed by reference.
So VB.NET made ByVal
the default. Since you didn't declare it explicitly, the default applies and InpPos
is passed by value. Never to increment, something that's easy to see in the debugger. Fix:
Private Function ReadBitsFromArray(ByVal FromArray() As Byte, _
ByRef FromPos As Integer, _
ByVal FromBit As Integer, _
ByVal NumBits As Integer) As Integer
Note that the choice between Long and Integer is something else you will have to fret about. A VB6 Long is a VB.NET Integer. I guessed that Integer was appropriate here. Do consider the .NET GZipStream class as an alternative, it doesn't sound like you remember enough about the way it works to still be able to maintain this code.
Upvotes: 6