Results 1 to 3 of 3

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

  1. #1

    Thread Starter
    Frenzied Member
    Join Date
    Feb 2003
    Posts
    1,807

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

    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
    Last edited by Peter Swinkels; Sep 5th, 2020 at 06:27 AM.

  2. #2
    Super Moderator jmcilhinney's Avatar
    Join Date
    May 2005
    Location
    Sydney, Australia
    Posts
    110,297

    Re: Question about System.IO.Compression and LZW compression/decompression

    No, there is no native support. There would be third-party implementations about, some in paid components and some not. While you don't have to, if you were going to implement a compression algorithm then I would recommend replicating the type of functionality found in the DeflateStream and GZipStream classes, i.e. inherit the Stream class and then build your compression and decompression functionality into the read and write options of that.

  3. #3

    Thread Starter
    Frenzied Member
    Join Date
    Feb 2003
    Posts
    1,807

    Re: Question about System.IO.Compression and LZW compression/decompression

    Hi jmcilhinney,

    Thank you for your quick reply. I am afraid I am stuck with custom LZW code if there is no native support then. You see, the code I posted must read and write files meant for usage by a really old program.

    Guess that means this is resolved then.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  



Click Here to Expand Forum to Full Width