-
Sep 5th, 2020, 06:22 AM
#1
Thread Starter
Frenzied Member
[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.
-
Sep 5th, 2020, 07:40 AM
#2
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.
-
Sep 5th, 2020, 07:55 AM
#3
Thread Starter
Frenzied Member
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
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|