Quantcast
Channel: VBForums
Viewing all articles
Browse latest Browse all 15952

[RESOLVED] Question about System.IO.Compression and LZW compression/decompression

$
0
0
Hi,

I have a question about the System.IO.Compression namespace:

A while back I wrote my own custom vb.net code for the purpose of compressing and decompressing data using the LZW algorithm because I needed to read/write files meant for a very old specific MS-DOS program. (Which also means I am stuck with having to use the LZW algorithm.) Given the fact there is a ton of information on the Internet about LZW which apparently is/was also used a lot elsewhere too, I managed to write these two modules:

Code:

'This class' imports and settings.
Option Compare Binary
Option Explicit On
Option Infer Off
Option Strict On

Imports System
Imports System.Collections.Generic
Imports System.Convert

'This module contains the LZW compression related procedures.
Public Module CompressLZWModule
  Public Const LZW_END As Integer = &H101%          'Contains the end of a LZW value sequence.
  Public Const LZW_MAXIMUM_BITS As Integer = &HC%    'Contains the maximum number of bits per value in a LZW sequence.
  Public Const LZW_START As Integer = &H100%        'Contains the start of a LZW value sequence.
  Public Const LZW_SYMBOL_BASE As Integer = &H102%  'Contains the lowest value used for an LZW symbol.
  Public Const LZW_SYMBOL_TOP As Integer = &HFFF%    'Contains the highest value used for an LZW symbol.
  Private Const LZW_NO_VALUE As Integer = -1        'Contains a null LZW value.

  Public ReadOnly LZW_MAXIMUM_ENTRIES As Integer = (&H1% << LZW_MAXIMUM_BITS)  'Contains the maximum number of LZW symbols possible with the maximum LZW bit count.

  'This procedure adds the specified value to the specified compressed data.
  Private Sub AddToCompressed(Compressed As List(Of Byte), BitCount As Integer, Value As Integer, ByRef Bits As Integer, ByRef Buffer As Integer)
      Try
        Buffer = Buffer Or (Value << Bits)
        Bits += BitCount
        While Bits > &H7%
            Compressed.Add(ToByte(Buffer And &HFF%))
            Buffer = Buffer >> &H8%
            Bits -= &H8%
        End While
      Catch ExceptionO As Exception
        HandleError(ExceptionO)
      End Try
  End Sub

  'This procedure compresses the specified data and returns the result.
  Public Function CompressLZW(Uncompressed As List(Of Byte)) As List(Of Byte)
      Try
        Dim BitCount As Integer = &H9%
        Dim Bits As Integer = &H0%
        Dim Buffer As New Integer
        Dim Compressed As New List(Of Byte)
        Dim LZWDictionary As Dictionary(Of Integer, LZWEntryStr) = InitializeDictionary()
        Dim PreviousValue As Integer = LZW_NO_VALUE

        AddToCompressed(Compressed, BitCount, LZW_START, Bits, Buffer)
        For Each Value As Byte In Uncompressed
            If LZWDictionary.ContainsValue(New LZWEntryStr With {.Prefix = PreviousValue, .Suffix = Value}) Then
              For Each KeyO As Integer In LZWDictionary.Keys
                  If LZWDictionary.Item(KeyO).Prefix = PreviousValue AndAlso LZWDictionary.Item(KeyO).Suffix = Value Then
                    PreviousValue = KeyO
                    Exit For
                  End If
              Next KeyO
            Else
              AddToCompressed(Compressed, BitCount, PreviousValue, Bits, Buffer)
              If LZWDictionary.Count >= LZW_MAXIMUM_ENTRIES Then
                  AddToCompressed(Compressed, BitCount, LZW_START, Bits, Buffer)
                  LZWDictionary = InitializeDictionary()
                  BitCount = &H9%
              Else
                  LZWDictionary.Add(LZWDictionary.Count, New LZWEntryStr With {.Prefix = PreviousValue, .Suffix = Value})
                  If LZWDictionary.Count > (&H1% << BitCount) Then BitCount += &H1%
              End If
              PreviousValue = Value
            End If
        Next Value

        If Not PreviousValue = LZW_NO_VALUE Then AddToCompressed(Compressed, BitCount, PreviousValue, Bits, Buffer)
        AddToCompressed(Compressed, BitCount, LZW_END, Bits, Buffer)
        If Bits > &H0% Then Compressed.Add(ToByte(Buffer And &HFF%))

        Return Compressed
      Catch ExceptionO As Exception
        HandleError(ExceptionO)
      End Try

      Return Nothing
  End Function

  'This procedure creates and returns a new LZW dictionary.
  Private Function InitializeDictionary() As Dictionary(Of Integer, LZWEntryStr)
      Try
        Dim LZWDictionary As New Dictionary(Of Integer, LZWEntryStr)

        For LZWIndex As Integer = &H0% To LZW_END
            LZWDictionary.Add(LZWIndex, New LZWEntryStr With {.Prefix = LZW_NO_VALUE, .Suffix = (LZWIndex And &HFF%)})
        Next LZWIndex

        Return LZWDictionary
      Catch ExceptionO As Exception
        HandleError(ExceptionO)
      End Try

      Return Nothing
  End Function
End Module

and:

Code:

'This class' imports and settings.
Option Compare Binary
Option Explicit On
Option Infer Off
Option Strict On

Imports System
Imports System.Collections.Generic
Imports System.Convert
Imports System.Linq

'This module contains the LZW decompression related procedures.
Public Module DecompressLZWModule
  'This procedure adds the specified entry to the specified LZW dictionary.
  Private Sub AddDictionaryEntry(Prefix As Integer, Suffix As Integer, ByRef DictionaryIndex As Integer, DictionaryO As List(Of LZWEntryStr))
      Try
        DictionaryO(DictionaryIndex) = New LZWEntryStr With {.Prefix = Prefix, .Suffix = Suffix}
        DictionaryIndex += &H1%
      Catch ExceptionO As Exception
        HandleError(ExceptionO)
      End Try
  End Sub

  'This procedure creates and returns a new LZW dictionary.
  Private Function InitializeDictionary() As List(Of LZWEntryStr)
      Try
        Dim DictionaryO As List(Of LZWEntryStr) = Nothing

        DictionaryO = New List(Of LZWEntryStr)

        For Index As Integer = &H0% To LZW_MAXIMUM_ENTRIES - &H1%
            DictionaryO.Add(New LZWEntryStr With {.Prefix = -1, .Suffix = If(Index < LZW_START, Index, -1)})
        Next Index

        Return DictionaryO
      Catch ExceptionO As Exception
        HandleError(ExceptionO)
      End Try

      Return Nothing
  End Function

  'This procedure decompresses the specified LZW data and returns the result.
  Public Function DecompressLZW(Compressed As List(Of Byte)) As List(Of Byte)
      Try
        Dim Buffer As New List(Of Byte)
        Dim Decompressed As New List(Of Byte)
        Dim DictionaryO As List(Of LZWEntryStr) = InitializeDictionary()
        Dim Parent As Integer = -1
        Dim BitsPerValue As Integer = &H9%
        Dim BitsUsed As Integer = &H0%
        Dim DictionaryIndex As Integer = LZW_SYMBOL_BASE
        Dim Literal As New Integer
        Dim Value As Integer = &H0%

        For Each ByteO As Byte In Compressed
            For Bit As Integer = &H0% To &H7%
              Value = Value Or ((ByteO >> Bit) And &H1%) << BitsUsed
              BitsUsed += &H1%
              If BitsUsed >= BitsPerValue Then
                  If Value = LZW_END Then
                    Exit For
                  ElseIf Value = LZW_START Then
                    DictionaryO = InitializeDictionary()
                    BitsPerValue = &H9%
                    DictionaryIndex = LZW_SYMBOL_BASE
                    Parent = -1
                  Else
                    If Value < DictionaryIndex Then
                        If Parent = -1 Then
                          Decompressed.Add(ToByte(Value))
                        Else
                          Buffer = GetBuffer(Value, DictionaryO)
                          Literal = Buffer.First
                          Decompressed.AddRange(Buffer)
                          AddDictionaryEntry(Parent, Literal, DictionaryIndex, DictionaryO)
                        End If
                    Else
                        Buffer = GetBuffer(Parent, DictionaryO)
                        Literal = Buffer.First
                        Decompressed.AddRange(Buffer)
                        Decompressed.Add(ToByte(Literal))
                        AddDictionaryEntry(Parent, Literal, DictionaryIndex, DictionaryO)
                    End If
                    Parent = Value
                  End If
                  BitsUsed = &H0%
                  Value = &H0%
                  If (&H1% << BitsPerValue) = DictionaryIndex AndAlso DictionaryIndex < LZW_MAXIMUM_ENTRIES Then BitsPerValue += &H1%
              End If
            Next Bit
        Next ByteO

        Return Decompressed
      Catch ExceptionO As Exception
        HandleError(ExceptionO)
      End Try

      Return Nothing
  End Function

  'This procedure decompresses a sequence of LZW literals and returns the result.
  Private Function GetBuffer(Value As Integer, DictionaryO As List(Of LZWEntryStr)) As List(Of Byte)
      Try
        Dim Buffer As New List(Of Byte)

        Do While Value > LZW_START
            Buffer.Add(ToByte(DictionaryO(Value).Suffix And &HFF%))
            Value = DictionaryO(Value).Prefix
        Loop

        Buffer.Add(ToByte(Value And &HFF%))
        Buffer.Reverse()

        Return Buffer
      Catch ExceptionO As Exception
        HandleError(ExceptionO)
      End Try

      Return Nothing
  End Function
End Module

As you can see these are moderately large modules. Now as to my question, does anyone know whether the System.IO.Compression namespace contains methods suited for compressing or decompressing LZW data? I have done a few Google searches, and found a lot references to the usage of this namespace and other unrelated stuff, but nothing that looked usable to me in my case.

The .NET framework is so large I wouldn't be surprised if I had unnecessarily replicated functionality already present. On a somewhat related side note: I have found I did this several times before and found I could erase several stretches of code by simply taking advantage of what already was present. Minor rant: the size of the framework, sluggish Visual Studio object browser and massive amount of information on the Internet do make it easy to overlook some functionality.

In short:
Does the System.IO.Compression namespace or any other.NET namespace support the LZW algorithm?

yours,
Peter Swinkels

Viewing all articles
Browse latest Browse all 15952

Latest Images

Trending Articles



Latest Images

<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>