LZSS Compress/Decompress

By | 2002-06-01

This is a standard LZSS compression/decompression engine. It is written in VB for learning purposes, and should be converted to C/C++ if it is to be used with large amounts of data. It uses a dictionary compression algorithm (like ZIP,ARJ and others) and works the best on data with a lot of repetitions.

Original Author: Jesper Soderberg

Inputs

sCompData – the string to be compressed, sDecompData – the string to be decompressed

Returns

Should be obvious

Code

Option Explicit
Public Function sCompress(sCompData As String) As String
Dim lDataCount As Long
Dim lBufferStart As Long
Dim lMaxBufferSize As Long
Dim sBuffer As String
Dim lBufferOffset As Long
Dim lBufferSize As Long
Dim sDataControl As String
Dim bDataControlChar As Byte
Dim lControlCount As Long
Dim bControlPos As Byte
Dim bCompLen As Long
Dim lCompPos As Long
Dim bMaxCompLen As Long

lMaxBufferSize = 65535
bMaxCompLen = 255
lBufferStart = 0
sDataControl = ""
bDataControlChar = 0
bControlPos = 0
lControlCount = 0
If Len(sCompData) > 4 Then
sCompress = Left(sCompData, 4)
For lDataCount = 5 To Len(sCompData)
  If lDataCount > lMaxBufferSize Then
  lBufferSize = lMaxBufferSize
  lBufferStart = lDataCount - lMaxBufferSize
  Else
  lBufferSize = lDataCount - 1
  lBufferStart = 1
  End If
  sBuffer = Mid(sCompData, lBufferStart, lBufferSize)
  If Len(sCompData) - lDataCount < bMaxCompLen Then bMaxCompLen = Len(sCompData) - lDataCount
  lCompPos = 0
  For bCompLen = 3 To bMaxCompLen Step 3
  If bCompLen > bMaxCompLen Then
   bCompLen = bMaxCompLen
  End If
  lCompPos = InStr(1, sBuffer, Mid(sCompData, lDataCount, bCompLen), 0)
  If lCompPos = 0 Then
   If bCompLen > 3 Then
   While lCompPos = 0
    lCompPos = InStr(1, sBuffer, Mid(sCompData, lDataCount, bCompLen - 1), 0)
    If lCompPos = 0 Then bCompLen = bCompLen - 1
   Wend
   End If
   bCompLen = bCompLen - 1
   Exit For
  End If
  Next
  If bCompLen > bMaxCompLen And lCompPos > 0 Then
  bCompLen = bMaxCompLen
  lCompPos = InStr(1, sBuffer, Mid(sCompData, lDataCount, bCompLen), 0)
  End If
  If lCompPos > 0 Then
  lBufferOffset = lBufferSize - lCompPos + 1
  sCompress = sCompress & Chr((lBufferOffset And &HFF00) / &H100) & Chr(lBufferOffset And &HFF) & Chr(bCompLen)
  lDataCount = lDataCount + bCompLen - 1
  bDataControlChar = bDataControlChar + 2 ^ bControlPos
  Else
  sCompress = sCompress & Mid(sCompData, lDataCount, 1)
  End If
  bControlPos = bControlPos + 1
  If bControlPos = 8 Then
  sDataControl = sDataControl & Chr(bDataControlChar)
  bDataControlChar = 0
  bControlPos = 0
  End If
  lControlCount = lControlCount + 1
Next
If bControlPos <> 0 Then sDataControl = sDataControl & Chr(bDataControlChar)
sCompress = Chr((lControlCount And &H8F000000) / &H1000000) & Chr((lControlCount And &HFF0000) / &H10000) & Chr((lControlCount And &HFF00) / &H100) & Chr(lControlCount And &HFF) & Chr((Len(sDataControl) And &H8F000000) / &H1000000) & Chr((Len(sDataControl) And &HFF0000) / &H10000) & Chr((Len(sDataControl) And &HFF00) / &H100) & Chr(Len(sDataControl) And &HFF) & sDataControl & sCompress
Else
sCompress = sCompData
End If
End Function
Public Function sDecompress(sDecompData As String) As String
Dim lControlCount As Long
Dim lControlPos As Long
Dim bControlBitPos As Byte
Dim lDataCount As Long
Dim lDataPos As Long
Dim lDecompStart As Long
Dim lDecompLen As Long

If Len(sDecompData) > 4 Then
lControlCount = Asc(Left(sDecompData, 1)) * &H1000000 + Asc(Mid(sDecompData, 2, 1)) * &H10000 + Asc(Mid(sDecompData, 3, 1)) * &H100 + Asc(Mid(sDecompData, 4, 1))
lDataCount = Asc(Mid(sDecompData, 5, 1)) * &H1000000 + Asc(Mid(sDecompData, 6, 1)) * &H10000 + Asc(Mid(sDecompData, 7, 1)) * &H100 + Asc(Mid(sDecompData, 8, 1)) + 9
sDecompress = Mid(sDecompData, lDataCount, 4)
lDataCount = lDataCount + 4
bControlBitPos = 0
lControlPos = 9
For lDataPos = 1 To lControlCount
  If 2 ^ bControlBitPos = (Asc(Mid(sDecompData, lControlPos, 1)) And 2 ^ bControlBitPos) Then
  lDecompStart = Len(sDecompress) - (CLng(Asc(Mid(sDecompData, lDataCount, 1))) * &H100 + CLng(Asc(Mid(sDecompData, lDataCount + 1, 1)))) + 1
  lDecompLen = Asc(Mid(sDecompData, lDataCount + 2, 1))
  sDecompress = sDecompress & Mid(sDecompress, lDecompStart, lDecompLen)
  lDataCount = lDataCount + 3
  Else
  sDecompress = sDecompress & Mid(sDecompData, lDataCount, 1)
  lDataCount = lDataCount + 1
  End If
  bControlBitPos = bControlBitPos + 1
  If bControlBitPos = 8 Then
  bControlBitPos = 0
  lControlPos = lControlPos + 1
  End If
Next
Else
sDecompress = sDecompData
End If
End Function
'Put a two command buttons (Command1 and Command2) on to a form and paste the following on to it as well:
Option Explicit
Private Const sFileName = "c:compressthis.exe" ' the file to be compressed
Private Sub Command1_Click() 'Compress the file
Dim sReturn As String
Dim sFileData As String

Open sFileName For Binary As #1
  sFileData = Input(LOF(1), #1)
Close #1
sReturn = sCompress(sFileData)
Debug.Print Len(sReturn), Len(sFileData)

Open Left(sFileName, Len(sFileName) - 3) & "wnc" For Output As #1
  Print #1, sReturn;
Close #1
End Sub
Private Sub Command2_Click() 'Decompress the file
Dim sReturn As String
Dim sFileData As String

Open Left(sFileName, Len(sFileName) - 4) & ".wnc" For Binary As #1
  sFileData = Input(LOF(1), #1)
  sReturn = sDecompress(sFileData)
Close #1
Debug.Print Len(sReturn), Len(sFileData)

Open Left(sFileName, Len(sFileName) - 4) & "2" & Right(sFileName, 4) For Output As #1
  Print #1, sReturn;
Close #1
End Sub

Author: dwirch

Derek Wirch is a seasoned IT professional with an impressive career dating back to 1986. He brings a wealth of knowledge and hands-on experience that is invaluable to those embarking on their journey in the tech industry.

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.