' For Integers, the additional 8 bits are: 256, 512, 1024, 2048, 4096, 8192, 16384, 32768
' For Longs, the additional 16 bits are: 65536,131072,262144,524288,1048576,2097152,4194304,8388608,16777216,33554432,67108864,134217728,268435456,536870912,1073741824,2147483648
' Bits are referenced from zero, not 1. So the 1st bit is bit zero.
' To calculate the bit position values, powers of two are used: Therefore for the 1st bit position, bit 0, value is 1, 2^0 = 1
' :: For p=0 To lastBitPosition: Debug.Print p, 2^p : Next
' Integer & Long variables' high bits indicate whether or not the value is negative, not the value associated with that bit position.
' Because of this VB Integers/Longs are signed vs unsigned
' A signed Integer's min/max values range from -2^15 to 2^15-1
' An unsigned integer (C++ terms) ranges from 0 to 2^16-1. Unsigned Integers should be Longs in VB
' A signed Long's min/max values range from -2^31 to 2^31-1
' An unsigned long (C++ terms) ranges from 0 to 2^32-1. Unsigned Longs should be Doubles in VB
' A signed byte (C++ terms) values range from -2^7 to 2^7-1. Signed Bytes should be Integers/Longs in VB
' An unsigned Byte ranges from 0 to 2^8-1. VB Byte variables are always unsigned
' ... Determine min/max values
' :: Multiply bytes used by the variable type by 8 to get number of bits
' :: Is the type signed or unsigned, i.e., can variable type have negative values
' Then the calculation is:
' if Signed: min= -2^(nrBits-1), max= (2^(nrBits-1))-1
' if Unsigned: min= 0 max= (2^nrBits)-1
' Note regarding Right Shift. Some shifters out there fill negative values with zeroes, but should not.
' Shifting right is done via integer division. (3) 0011 >>1 = 0001 (1) (decimal: 3 \ 2^1 = 1)
' When a negative number is shifted: (-32768) 10000000 00000000 >>1 = 11000000 00000000 (-16384)
' decimal: -32768 \ 2^1 = -16384
' If the far left were filled with zeros, then the result 01000000 00000000 (16384) is wrong.
' Therefore, all the shifting functions allow you to choose how you want vacated bits to be filled
' there are 3 options:
' :: Fill with zeros, Fill with onex, or use Arithmetic fills (Default)
' What is Arithmetic? Fill with the high bit. For positive values, zeros, for negative, ones
' When forcing non-Arithmetic, then the term is a Logical fill
' following APIs & UDT are used for CRC functions
Private Declare Sub CopyMemory Lib "kernel32.dll" Alias "RtlMoveMemory" (ByRef Destination As Any, ByRef Source As Any, ByVal Length As Long)
Private Declare Function VarPtrArray Lib "msvbvm60.dll" Alias "VarPtr" (ByRef Ptr() As Any) As Long
Private Type SafeArrayBound
cElements As Long
lLbound As Long
End Type
Private Type SafeArray ' used as DMA overlay on a string
cDims As Integer
fFeatures As Integer
cbElements As Long
cLocks As Long
pvData As Long
rgSABound(0 To 1) As SafeArrayBound ' allows using up to 2 dimensional arrays
End Type
' following API used for ShiftBitsLeft_Array & ShiftBitsRight_Array
Private Declare Sub FillMemory Lib "kernel32.dll" Alias "RtlFillMemory" (ByRef Destination As Any, ByVal Length As Long, ByVal Fill As Byte)
Public Enum StringTypeConstants
crcANSI = 0
crcUnicode = 1
End Enum
Public Enum BitShiftWrapEnum
bitShift_Truncate = 0
bitShift_Wrap = 1
End Enum
Public Enum FillTypeConstants
fillZeros_Logical = 0
fillOnes_Logical = 1
fillArithmetic_HighBit = 2
End Enum
Private CRC32LUT() As Long
Private CRC32LUTbuilt As Boolean
Private Const MaxUnsignedLongAnd1 As Double = 4294967296#
Private Const MaxSignedLongAnd1 As Double = 2147483648#
Private Const MaskHighBit_Long As Long = &H80000000
Private Const MaskHighBit_Int As Integer = &H8000
Private Const MaskHighBit_Byte As Byte = &H80
Private Const BitCount_Long As Byte = 32
Private Const BitCount_Int As Byte = 16
Private Const BitCount_Byte As Byte = 8
Private mPO2lut(0 To 31) As Double ' 2^31 is a double not Long & used when wrapping shifts
Public Function SignedIntegerToUnsigned(ByVal theValue As Integer) As Long
' function converts a signed integer to an unsigned Long
SignedIntegerToUnsigned = (theValue And &HFFFF&)
End Function
Public Function UnsignedIntegerToSigned(ByVal theValue As Long) As Integer
' function converts a Long to a signed integer
' if the passed value contains more than 16 usable bits, we can't scrunch 16+ into a 16bit variable
If theValue < 0& Or theValue > mPO2lut(BitCount_Int) - 1& Then Exit Function ' overflow
Public Function MakeDWord2(ByVal theHiWord As Integer, ByVal theLoWord As Integer) As Long
' create a Long (4 bytes) from the passed 2 Integers (2 bytes each)
MakeDWord2 = (CLng(theHiWord) * mPO2lut(BitCount_Int)) Or (theLoWord And &HFFFF&)
End Function
Public Function MakeDWord4(ByVal theHiByte As Byte, ByVal theByte2 As Byte, ByVal theByte1 As Byte, ByVal theLoByte As Byte) As Long
' create a Long (4 bytes) from the passed 4 bytes
If (theHiByte And MaskHighBit_Byte) Then
MakeDWord4 = ((theHiByte And &H7F) * &H1000000) Or theByte2 * &H10000 Or theByte1 * &H100& Or theLoByte Or MaskHighBit_Long
Else
MakeDWord4 = theHiByte * &H1000000 Or theByte2 * &H10000 Or theByte1 * &H100& Or theLoByte
End If
End Function
Public Function MakeWord(ByVal theHiByte As Byte, ByVal theLoByte As Byte) As Integer
' create an Integer (2 bytes) from the passed 2 bytes
If theHiByte And MaskHighBit_Byte Then
MakeWord = ((theHiByte And &H7F) * &H100&) Or theLoByte Or MaskHighBit_Int
Else
MakeWord = (theHiByte * &H100&) Or theLoByte
End If
End Function
Public Function GetBit_FromLong(ByVal theValue As Long, ByVal Position0to31 As Byte) As Byte
' function returns the bit on/off from the passed value.
' Position must be 0 to max bits - 1 for the variable passed
If Position0to31 = BitCount_Long - 1& Then ' high bit requested
If (theValue And MaskHighBit_Long) Then GetBit_FromLong = 1
ElseIf Position0to31 < BitCount_Long Then
GetBit_FromLong = ((theValue And &H7FFFFFFF) \ mPO2lut(Position0to31)) And 1
End If
End Function
Public Function GetBit_FromInteger(ByVal theValue As Integer, ByVal Position0to15 As Byte) As Byte
' function returns the bit on/off from the passed value.
' Position must be 0 to max bits - 1 for the variable passed
If Position0to15 < BitCount_Int Then GetBit_FromInteger = ((theValue And &HFFFF&) \ mPO2lut(Position0to15)) And 1
End Function
Public Function GetBit_FromByte(ByVal theValue As Byte, ByVal Position0to7 As Byte) As Byte
' function returns the bit on/off from the passed value.
' Position must be 0 to max bits - 1 for the variable passed
If Position0to7 < BitCount_Byte Then GetBit_FromByte = (theValue \ mPO2lut(Position0to7)) And 1
End Function
Public Function SetBit_Long(ByRef theValue As Long, ByVal Position0to31 As Byte, ByVal TurnOn As Boolean) As Boolean
' Sets a single bit either on or off within passed Long
' Positions are from right to left
If Position0to31 = BitCount_Long - 1& Then ' playing with the high bit
If TurnOn Then
theValue = theValue Or MaskHighBit_Long
Else
theValue = theValue Xor MaskHighBit_Long
End If
SetBit_Long = True
ElseIf Position0to31 < BitCount_Long Then
If TurnOn Then
theValue = theValue Or (mPO2lut(Position0to31))
Else
theValue = theValue Xor (mPO2lut(Position0to31))
End If
SetBit_Long = True
End If
End Function
Public Function SetBit_Integer(ByRef theValue As Integer, ByVal Position0to15 As Byte, ByVal TurnOn As Boolean) As Boolean
' Sets a single bit either on or off within passed Integer
' Positions are from right to left
If Position0to15 = BitCount_Int - 1& Then ' playing with the high bit
If TurnOn Then
theValue = theValue Or MaskHighBit_Int
Else
theValue = theValue Xor MaskHighBit_Int
End If
SetBit_Integer = True
ElseIf Position0to15 < BitCount_Int Then
If TurnOn Then
theValue = theValue Or (mPO2lut(Position0to15))
Else
theValue = theValue Xor (mPO2lut(Position0to15))
End If
SetBit_Integer = True
End If
End Function
Public Function SetBit_Byte(ByRef theValue As Byte, ByVal Position0to7 As Byte, ByVal TurnOn As Boolean) As Boolean
' Sets a single bit either on or off within passed Byte
' Positions are from right to left
If Position0to7 < BitCount_Byte Then
If TurnOn Then
theValue = theValue Or (mPO2lut(Position0to7))
Else
theValue = theValue Xor (mPO2lut(Position0to7))
End If
SetBit_Byte = True
End If
End Function
Public Function SetMidBits_FromByte(ByRef destValue As Byte, ByVal fromBit0to7 As Byte, ByVal BitsLength1to8 As Byte, ByVal setValue As Byte) As Boolean
' Sets a range of consecutive bits within passed Byte, to the pased value
' Positions are from right to left
' Note: provide the unshifted values for setValue.
' Example: if you want to set the far left 2 bits on, simply provide 3 which is binary 11
Dim modMask As Long
' validate passed parameters
If fromBit0to7 < BitCount_Byte And BitsLength1to8 > 0 Then
' validate number of bits to be modified
If fromBit0to7 + BitsLength1to8 > BitCount_Byte Then BitsLength1to8 = BitCount_Byte - fromBit0to7
' validate setValue fits within the number of bits being modified (i.e, if modifying 2 bits, max value can be 3)
destValue = (destValue Xor (destValue And modMask)) Or (setValue * mPO2lut(fromBit0to7))
SetMidBits_FromByte = True
End If
End If
End Function
Public Function SetMidBits_FromLong(ByRef destValue As Long, ByVal fromBit0to31 As Byte, ByVal BitsLength1to32 As Byte, ByVal setValue As Long) As Boolean
' Sets a range of consecutive bits within passed Long, to the pased value
' Positions are from right to left
' Note: provide the unshifted values for setValue.
' Example: if you want to set the far left 2 bits on, simply provide 3 which is binary 11
Dim modMask As Long
' validate passed parameters
If fromBit0to31 < BitCount_Long And BitsLength1to32 > 0 Then
' validate number of bits to be modified
If fromBit0to31 + BitsLength1to32 > BitCount_Long Then BitsLength1to32 = BitCount_Long - fromBit0to31
' validate setValue fits within the number of bits being modified (i.e, if modifying 2 bits, max value can be 3)
If setValue < mPO2lut(BitsLength1to32) Or BitsLength1to32 = BitCount_Long Then
' now add the new bits values, shifting bits into place first
If modMask And MaskHighBit_Long Then
If (setValue \ mPO2lut(BitsLength1to32 - 1&)) Then ' the new bits value will set the high bit
destValue = destValue Or ((setValue And mPO2lut(BitsLength1to32 - 1&) - 1&) * mPO2lut(fromBit0to31)) Or MaskHighBit_Long
Else ' else the new bits value does not contain high bit
destValue = destValue Or ((setValue And mPO2lut(BitsLength1to32 - 1&) - 1&) * mPO2lut(fromBit0to31))
End If
Else ' shift & set
destValue = destValue Or (setValue * mPO2lut(fromBit0to31))
End If
SetMidBits_FromLong = True
End If
End If
End Function
Public Function SetMidBits_FromInteger(ByRef destValue As Integer, ByVal fromBit0to15 As Byte, ByVal BitsLength1to16 As Byte, ByVal setValue As Integer) As Boolean
' Sets a range of consecutive bits within passed Integer, to the pased value
' Positions are from right to left
' Note: provide the unshifted values for setValue.
' Example: if you want to set the far left 2 bits on, simply provide 3 which is binary 11
Dim modMask As Long
' validate passed parameters
If fromBit0to15 < BitCount_Int And BitsLength1to16 > 0 Then
' validate number of bits to be modified
If fromBit0to15 + BitsLength1to16 > BitCount_Int Then BitsLength1to16 = BitCount_Int - fromBit0to15
' validate setValue fits within the number of bits being modified (i.e, if modifying 2 bits, max value can be 3)
If setValue < mPO2lut(BitsLength1to16) Or BitsLength1to16 = BitCount_Int Then