home *** CD-ROM | disk | FTP | other *** search
/ Planet Source Code Jumbo …e CD Visual Basic 1 to 7 / 4_2005-2006.ISO / data / Zips / Real_3D_Di1974452182006.psc / cGifReader.cls < prev    next >
Text File  |  2006-02-17  |  23KB  |  785 lines

  1. VERSION 1.0 CLASS
  2. BEGIN
  3.   MultiUse = -1  'True
  4.   Persistable = 0  'NotPersistable
  5.   DataBindingBehavior = 0  'vbNone
  6.   DataSourceBehavior  = 0  'vbNone
  7.   MTSTransactionMode  = 0  'NotAnMTSObject
  8. END
  9. Attribute VB_Name = "cGifReader"
  10. Attribute VB_GlobalNameSpace = False
  11. Attribute VB_Creatable = True
  12. Attribute VB_PredeclaredId = False
  13. Attribute VB_Exposed = False
  14. '=========================================================================
  15. '
  16. '   VB Gif Library Project
  17. '   Copyright (c) 2003 Vlad Vissoultchev
  18. '
  19. '   GIF87a/89a reader. Implements an LZW decoder. Warning! use of this
  20. '     code in commercial applications may fall under patent claims
  21. '     from Unisys which are holding patents on LZW algorithm.
  22. '
  23. '=========================================================================
  24. Option Explicit
  25. Private Const MODULE_NAME As String = "cGifReader"
  26.  
  27. '=========================================================================
  28. ' Events
  29. '=========================================================================
  30.  
  31. Event Progress(ByVal CurrentLine As Long)
  32. Event ImageComplete()
  33.  
  34. '=========================================================================
  35. ' API
  36. '=========================================================================
  37.  
  38. Private Declare Sub CopyMemory Lib "Kernel32" Alias "RtlMoveMemory" (Destination As Any, Source As Any, ByVal Length As Long)
  39. Private Declare Sub FillMemory Lib "Kernel32" Alias "RtlFillMemory" (Destination As Any, ByVal Length As Long, ByVal Fill As Byte)
  40.  
  41. '=========================================================================
  42. ' Constants and member variables
  43. '=========================================================================
  44.  
  45. Private Const ERR_INVALID_GIF_FILE      As String = "Invalid GIF file"
  46. Private Const ERR_UNEXPECTED_BLOCK      As String = "Unexpected image block"
  47. Private Const ERR_PAST_END_OF_STACK     As String = "Past end of stack (stacksize=4000)"
  48. Private Const ERR_INVALID_LZW_CODE      As String = "Invalid LZW code encountered"
  49. Private Const ERR_INPUT_PAST_EOF        As String = "Input past end of file"
  50. Private Const STR_GIF87A                As String = "GIF87a"
  51. Private Const STR_GIF89A                As String = "GIF89a"
  52. Private Const MAX_BITS                  As Long = 12
  53. Private Const TABLE_SIZE                As Long = 2 ^ MAX_BITS
  54.  
  55. '--- look-up table 'powers-of-two'
  56. Private m_aPOT(-1 To 31)            As Long
  57. '--- GIF file
  58. Private m_nFile                     As Integer
  59. Private m_sFileName                 As String
  60. Private m_lFirstFrameLoc            As Long
  61. Private m_bEOF                      As Boolean
  62. '--- for GIF content
  63. Private m_uHeader                   As UcsGifHeader
  64. Private m_uImageDesc                As UcsGifImageDescriptor
  65. Private m_uGraphicControl           As UcsGifGraphicControl
  66. Private m_lFrameIndex               As Long
  67. '--- for current frame buffers
  68. Private m_aImageBits()              As Byte
  69. Private m_aGlobalLut(0 To 767)      As Byte '--- 767 = 3 * 256 - 1
  70. Private m_aImageLut(0 To 767)       As Byte
  71. '--- for LZW decoder
  72. Private m_lInitBits                 As Long
  73. Private m_lClearTable               As Long
  74. Private m_lInputBitCount            As Long
  75. Private m_lInputBitBuffer           As Long
  76. Private m_lCurrentBits              As Long
  77. Private m_lMaxCode                  As Long
  78. Private m_lSubBlockSize             As Long
  79. Private m_aPrefixCode(0 To TABLE_SIZE) As Long
  80. Private m_aAppendChar(0 To TABLE_SIZE) As Byte
  81.  
  82. Private Type UcsGifHeader
  83.     aSigVersion(0 To 5)     As Byte
  84.     nScreenWidth            As Integer
  85.     nScreenHeight           As Integer
  86.     bFlags                  As Byte
  87.     bBackgroungColor        As Byte
  88.     bAspectRatio            As Byte
  89. End Type
  90.  
  91. Private Type UcsGifImageDescriptor
  92.     nImageLeft              As Integer
  93.     nImageTop               As Integer
  94.     nImageWidth             As Integer
  95.     nImageHeight            As Integer
  96.     bFlags                  As Byte
  97. End Type
  98.  
  99. Private Type UcsGifGraphicControl
  100.     cbSize                  As Byte
  101.     bFlags                  As Byte
  102.     nDelayTime              As Integer
  103.     bTransparentColor       As Byte
  104.     bTerminator             As Byte
  105. End Type
  106.  
  107. Private Enum UcsGifFlags
  108.     '--- for header flags
  109.     ucsGflGlobalLut = &H80
  110.     ucsGflColorResolution = &H70
  111.     ucsGflGlobalLutSorted = &H4
  112.     ucsGflGlobalLutSize = &H7
  113.     '--- for image descriptor flags
  114.     ucsGflLocalLut = &H80
  115.     ucsGflInterlace = &H40
  116.     ucsGflLocalLutSorted = &H20
  117.     ucsGflLocalLutSize = &H7
  118.     '--- for graphics control
  119.     ucsGflDisposalMethod = &H1C
  120.     ucsGflUserInput = &H2
  121.     ucsGflTransparentColor = &H1
  122. End Enum
  123.  
  124. Private Enum UcsGifFileBlock
  125.     ucsGblImageBlock = &H2C         '--- ","
  126.     ucsGblExtension = &H21          '--- "!"
  127.     ucsGblTrailer = &H3B            '--- ";"
  128. End Enum
  129.  
  130. Private Enum UcsGifExtensionType
  131.     ucsGexGraphicsControl = &HF9    '--- transparency etc. extension
  132. End Enum
  133.  
  134. Public Enum UcsGifDisposalMethod
  135.     ucsDsmNotSpecified
  136.     ucsDsmDontDispose
  137.     ucsDsmRestoreBackground
  138.     ucsDsmRestorePrevious
  139. End Enum
  140.  
  141. '=========================================================================
  142. ' Error management
  143. '=========================================================================
  144.  
  145. Private Sub RaiseError(sFunction As String)
  146.  
  147.     With Err
  148.         ' .Raise .Number, MODULE_NAME & "." & sFunction & IIf(Erl <> 0, "(" & Erl & ")", "") & vbCrLf _
  149.             & .Source, .Description, .HelpFile, .HelpContext
  150.     End With 'ERR
  151.  
  152. End Sub
  153.  
  154. Private Sub PrintError(sFunction As String)
  155.  
  156.     Debug.Print MODULE_NAME; "."; sFunction; IIf(Erl <> 0, "(" & Erl & ")", ""); ": "; Err.Description
  157.  
  158. End Sub
  159.  
  160. '=========================================================================
  161. ' Properties
  162. '=========================================================================
  163.  
  164. Property Get filename() As String ':( Missing Scope
  165.  
  166.     filename = m_sFileName
  167.  
  168. End Property
  169.  
  170. Property Get SigVersion() As String ':( Missing Scope
  171.  
  172.     SigVersion = StrConv(m_uHeader.aSigVersion, vbUnicode)
  173.  
  174. End Property
  175.  
  176. Property Get HasGlobalLut() As Boolean ':( Missing Scope
  177.  
  178.     HasGlobalLut = (pvGetFlag(m_uHeader.bFlags, ucsGflGlobalLut) <> 0)
  179.  
  180. End Property
  181.  
  182. Property Get ScreenWidth() As Long ':( Missing Scope
  183.  
  184.     ScreenWidth = m_uHeader.nScreenWidth
  185.  
  186. End Property
  187.  
  188. Property Get ScreenHeight() As Long ':( Missing Scope
  189.  
  190.     ScreenHeight = m_uHeader.nScreenHeight
  191.  
  192. End Property
  193.  
  194. Property Get BackgroundColor() As Long ':( Missing Scope
  195.  
  196.     BackgroundColor = RGB(m_aImageLut(3 * m_uHeader.bBackgroungColor), _
  197.                       m_aImageLut(3 * m_uHeader.bBackgroungColor + 1), _
  198.                       m_aImageLut(3 * m_uHeader.bBackgroungColor + 2))
  199.  
  200. End Property
  201.  
  202. Property Get BackgroundIndex() As Long ':( Missing Scope
  203.  
  204.     BackgroundIndex = m_uHeader.bBackgroungColor
  205.  
  206. End Property
  207.  
  208. Property Get GlobalLutSize() As Long ':( Missing Scope
  209.  
  210.     GlobalLutSize = m_aPOT(1 + pvGetFlag(m_uHeader.bFlags, ucsGflGlobalLutSize))
  211.  
  212. End Property
  213.  
  214. Property Get IsInterlaced() As Boolean ':( Missing Scope
  215.  
  216.     IsInterlaced = (pvGetFlag(m_uImageDesc.bFlags, ucsGflInterlace) <> 0)
  217.  
  218. End Property
  219.  
  220. Property Get HasLocalLut() As Boolean ':( Missing Scope
  221.  
  222.     HasLocalLut = (pvGetFlag(m_uImageDesc.bFlags, ucsGflLocalLut) <> 0)
  223.  
  224. End Property
  225.  
  226. Property Get LocalLutSize() As Long ':( Missing Scope
  227.  
  228.     LocalLutSize = m_aPOT(1 + pvGetFlag(m_uImageDesc.bFlags, ucsGflLocalLutSize))
  229.  
  230. End Property
  231.  
  232. Property Get ImageLeft() As Long ':( Missing Scope
  233.  
  234.     ImageLeft = m_uImageDesc.nImageLeft
  235.  
  236. End Property
  237.  
  238. Property Get ImageTop() As Long ':( Missing Scope
  239.  
  240.     ImageTop = m_uImageDesc.nImageTop
  241.  
  242. End Property
  243.  
  244. Property Get ImageWidth() As Long ':( Missing Scope
  245.  
  246.     ImageWidth = m_uImageDesc.nImageWidth
  247.  
  248. End Property
  249.  
  250. Property Get ImageHeight() As Long ':( Missing Scope
  251.  
  252.     ImageHeight = m_uImageDesc.nImageHeight
  253.  
  254. End Property
  255.  
  256. Property Get IsTransparent() As Boolean ':( Missing Scope
  257.  
  258.     IsTransparent = (pvGetFlag(m_uGraphicControl.bFlags, ucsGflTransparentColor) <> 0)
  259.  
  260. End Property
  261.  
  262. Property Get TransparentColor() As Long ':( Missing Scope
  263.  
  264.     TransparentColor = RGB(m_aImageLut(3 * m_uGraphicControl.bTransparentColor), _
  265.                        m_aImageLut(3 * m_uGraphicControl.bTransparentColor + 1), _
  266.                        m_aImageLut(3 * m_uGraphicControl.bTransparentColor + 2))
  267.  
  268. End Property
  269.  
  270. Property Get TransparentIndex() As Long ':( Missing Scope
  271.  
  272.     TransparentIndex = m_uGraphicControl.bTransparentColor
  273.  
  274. End Property
  275.  
  276. '--- note: usually this is interpreted as 'gif animation is looped'
  277. Property Get UserInput() As Boolean ':( Missing Scope
  278.  
  279.     UserInput = (pvGetFlag(m_uGraphicControl.bFlags, ucsGflUserInput) <> 0)
  280.  
  281. End Property
  282.  
  283. Property Get DisposalMethod() As UcsGifDisposalMethod ':( Missing Scope
  284.  
  285.     DisposalMethod = pvGetFlag(m_uGraphicControl.bFlags, ucsGflDisposalMethod)
  286.  
  287. End Property
  288.  
  289. Property Get ImageLut() As Byte() ':( Missing Scope
  290.  
  291.     ImageLut = m_aImageLut
  292.  
  293. End Property
  294.  
  295. Property Get ImageBits() As Byte() ':( Missing Scope
  296.  
  297.     ImageBits = m_aImageBits
  298.  
  299. End Property
  300.  
  301. Property Get FrameIndex() As Long ':( Missing Scope
  302.  
  303.     FrameIndex = m_lFrameIndex
  304.  
  305. End Property
  306.  
  307. Property Get EOF() As Boolean ':( Missing Scope
  308.  
  309.     EOF = m_bEOF
  310.  
  311. End Property
  312.  
  313. Property Get DelayTime() As Long ':( Missing Scope
  314.  
  315.     DelayTime = m_uGraphicControl.nDelayTime
  316.  
  317. End Property
  318.  
  319. '=========================================================================
  320. ' Methods
  321. '=========================================================================
  322.  
  323. Private Function pvFileExists(sFilename As String) As Boolean
  324.  
  325.     On Error Resume Next
  326.       pvFileExists = (GetAttr(sFilename) <> -1)
  327.     On Error GoTo 0
  328.  
  329. End Function
  330.  
  331. Public Function Init(sFilename As String) As Boolean
  332.  
  333.   Const FUNC_NAME     As String = "Init"
  334.   Dim lIdx            As Long
  335.   Dim bColor          As Boolean
  336.     
  337.     On Error GoTo EH
  338.     '--- init/clear member vars
  339.     m_sFileName = sFilename
  340.     FillMemory m_uImageDesc, Len(m_uImageDesc), 0
  341.     FillMemory m_uGraphicControl, Len(m_uGraphicControl), 0
  342.     m_lFrameIndex = -1
  343.     m_bEOF = False
  344.     '--- check if file exists
  345.     If Not pvFileExists(sFilename) Then
  346.         Exit Function '>---> Bottom
  347.     End If
  348.     '--- open file (first close previous)
  349.     pvCloseFile
  350.     m_nFile = FreeFile()
  351.     Open filename For Binary Shared As #m_nFile
  352.     '--- get file header
  353.     pvReadBuffer VarPtr(m_uHeader), Len(m_uHeader) '--- 13
  354.     If SigVersion <> STR_GIF87A And SigVersion <> STR_GIF89A Then
  355.         Err.Raise vbObject, , ERR_INVALID_GIF_FILE
  356.     End If
  357.     '--- get global LUT
  358.     If HasGlobalLut Then
  359.         pvReadBuffer VarPtr(m_aGlobalLut(0)), 3 * GlobalLutSize
  360.     End If
  361.     m_lFirstFrameLoc = Seek(m_nFile)
  362.     '--- success
  363.     Init = True
  364.  
  365. Exit Function
  366.  
  367. EH:
  368.     RaiseError FUNC_NAME
  369.  
  370. End Function
  371.  
  372. Public Function MoveNext() As Boolean
  373.  
  374.   Const FUNC_NAME     As String = "MoveNext"
  375.    
  376.     On Error GoTo EH
  377.     '--- check if anything's left
  378.     If m_nFile = 0 Or m_bEOF Then
  379.         Exit Function '>---> Bottom
  380.     End If
  381.     Do While True
  382.         Select Case pvReadByte()
  383.           Case ucsGblImageBlock
  384.             m_lFrameIndex = m_lFrameIndex + 1
  385.             '--- get image desc
  386.             pvReadBuffer VarPtr(m_uImageDesc), Len(m_uImageDesc) '--- 9
  387.             '--- get image LUT
  388.             If HasLocalLut Then
  389.                 pvReadBuffer VarPtr(m_aImageLut(0)), 3 * LocalLutSize
  390.               Else 'HASLOCALLUT = 0
  391.                 CopyMemory m_aImageLut(0), m_aGlobalLut(0), 3 * 256
  392.             End If
  393.             '--- init vars for LZW decoding
  394.             m_lInitBits = pvReadByte() + 1
  395.             m_lClearTable = m_aPOT(m_lInitBits - 1)
  396.             m_lInputBitCount = 0
  397.             m_lInputBitBuffer = 0
  398.             m_lCurrentBits = m_lInitBits
  399.             m_lMaxCode = m_aPOT(m_lCurrentBits) - 1
  400.             m_lSubBlockSize = 0
  401.             ReDim m_aImageBits(0 To ImageWidth * ImageHeight)
  402.             pvLzwExpand m_aImageBits, UBound(m_aImageBits)
  403.             '--- read to the end of block
  404.             Do
  405.                 '--- skip to the end end of sub-block
  406.                 Do While m_lSubBlockSize > 0
  407.                     pvReadSubBlockByte
  408.                 Loop
  409.                 '--- check for block terminator
  410.                 m_lSubBlockSize = pvReadByte()
  411.             Loop While m_lSubBlockSize > 0
  412.             RaiseEvent ImageComplete
  413.             Exit Do '>---> Loop
  414.           Case ucsGblExtension
  415.             '--- look for 'Graphic Control Label' extension
  416.             Select Case pvReadByte()
  417.               Case ucsGexGraphicsControl
  418.                 '--- fill member struct
  419.                 pvReadBuffer VarPtr(m_uGraphicControl), Len(m_uGraphicControl)
  420.               Case Else
  421.                 '--- unknown extension
  422.                 pvSkipBlock
  423.             End Select
  424.           Case ucsGblTrailer
  425.             m_bEOF = True
  426.             Exit Function '>---> Bottom
  427.           Case 0 '--- silence this just in case
  428.             Debug.Print MODULE_NAME; "."; FUNC_NAME; ": "; ERR_UNEXPECTED_BLOCK; " = 0"
  429.           Case Else
  430.             Err.Raise vbObjectError + 1, , ERR_UNEXPECTED_BLOCK
  431.         End Select
  432.     Loop
  433.     '--- success
  434.     MoveNext = True
  435.  
  436. Exit Function
  437.  
  438. EH:
  439.     m_bEOF = True
  440.     RaiseError FUNC_NAME
  441.  
  442. End Function
  443.  
  444. Public Function MoveFirst() As Boolean
  445.  
  446.   Const FUNC_NAME     As String = "MoveFirst"
  447.     
  448.     On Error GoTo EH
  449.     '--- state check
  450.     If m_nFile = 0 Then
  451.         Exit Function '>---> Bottom
  452.     End If
  453.     Seek #m_nFile, m_lFirstFrameLoc
  454.     m_lFrameIndex = -1
  455.     m_bEOF = False
  456.     '--- success
  457.     MoveFirst = True
  458.  
  459. Exit Function
  460.  
  461. EH:
  462.     RaiseError FUNC_NAME
  463.  
  464. End Function
  465.  
  466. Public Function MoveLast() As Long
  467.  
  468.   Const FUNC_NAME     As String = "MoveLast"
  469.     
  470.     On Error GoTo EH
  471.     '--- state check
  472.     If m_nFile = 0 Then
  473.         Exit Function '>---> Bottom
  474.     End If
  475.     If Not EOF Then
  476.         Do While True
  477.             Select Case pvReadByte()
  478.               Case ucsGblImageBlock
  479.                 m_lFrameIndex = m_lFrameIndex + 1
  480.                 pvReadBuffer VarPtr(m_uImageDesc), Len(m_uImageDesc) '--- 9
  481.                 If HasLocalLut Then
  482.                     pvReadBuffer VarPtr(m_aImageLut(0)), 3 * LocalLutSize
  483.                 End If
  484.                 pvReadByte '--- initial bits
  485.                 pvSkipBlock
  486.               Case ucsGblExtension
  487.                 pvReadByte '--- extension type
  488.                 pvSkipBlock
  489.               Case ucsGblTrailer
  490.                 m_bEOF = True
  491.                 Exit Do '>---> Loop
  492.               Case 0
  493.               Case Else
  494.                 Err.Raise vbObjectError + 1, , ERR_UNEXPECTED_BLOCK
  495.             End Select
  496.         Loop
  497.     End If
  498.     '--- success
  499.     MoveLast = True
  500.  
  501. Exit Function
  502.  
  503. EH:
  504.     RaiseError FUNC_NAME
  505.  
  506. End Function
  507.  
  508. '= private ===============================================================
  509.  
  510. Private Function pvGetFlag(ByVal lFlags As Long, ByVal lMask As UcsGifFlags) As Long
  511.  
  512.     If lMask > 0 Then
  513.         pvGetFlag = (lFlags And lMask)
  514.         Do While (lMask And 1) = 0
  515.             lMask = lMask \ 2
  516.             pvGetFlag = pvGetFlag \ 2
  517.         Loop
  518.     End If
  519.  
  520. End Function
  521.  
  522. Private Function pvPadScanline(ByVal lOffset As Long)
  523.  
  524.   '--- DIB section horizontal scanline padding to dword
  525.  
  526.     pvPadScanline = (lOffset + 3) And (Not 3)
  527.  
  528. End Function
  529.  
  530. '= I/O handling ==========================================================
  531.  
  532. Private Function pvReadByte() As Byte
  533.  
  534.   Const FUNC_NAME     As String = "pvReadByte"
  535.     
  536.     On Error GoTo EH
  537.     If VBA.EOF(m_nFile) Then
  538.         Err.Raise vbObjectError + 4, , ERR_INPUT_PAST_EOF
  539.     End If
  540.     Get #m_nFile, , pvReadByte
  541.  
  542. Exit Function
  543.  
  544. EH:
  545.     RaiseError FUNC_NAME
  546.  
  547. End Function
  548.  
  549. Private Sub pvReadBuffer(ByVal pAddr As Long, ByVal lSize)
  550.  
  551.   Const FUNC_NAME     As String = "pvReadBuffer"
  552.   Dim lIdx            As Long
  553.     
  554.     On Error GoTo EH
  555.     '--- read from stream to local buffer
  556.     ReDim aBuf(0 To lSize) As Byte
  557.     For lIdx = 0 To lSize - 1
  558.         aBuf(lIdx) = pvReadByte()
  559.     Next lIdx
  560.     '--- copy if necessary
  561.     If pAddr <> 0 Then
  562.         CopyMemory ByVal pAddr, aBuf(0), lSize
  563.     End If
  564.  
  565. Exit Sub
  566.  
  567. EH:
  568.     RaiseError FUNC_NAME
  569.  
  570. End Sub
  571.  
  572. Private Function pvReadSubBlockByte() As Byte
  573.  
  574.   Const FUNC_NAME     As String = "pvReadSubBlockByte"
  575.     
  576.     On Error GoTo EH
  577.     If m_lSubBlockSize <= 0 Then
  578.         m_lSubBlockSize = pvReadByte()
  579.         '--- workaround for 3D Studio R4's non-compliant GIFs
  580.         If m_lSubBlockSize = 0 Then
  581.             m_lSubBlockSize = 256
  582.         End If
  583.     End If
  584.     pvReadSubBlockByte = pvReadByte()
  585.     m_lSubBlockSize = m_lSubBlockSize - 1
  586.  
  587. Exit Function
  588.  
  589. EH:
  590.     RaiseError FUNC_NAME
  591.  
  592. End Function
  593.  
  594. Private Sub pvCloseFile()
  595.  
  596.   Const FUNC_NAME     As String = "pvCloseFile"
  597.     
  598.     On Error GoTo EH
  599.     If m_nFile <> 0 Then
  600.         Close #m_nFile
  601.         m_nFile = 0
  602.     End If
  603.  
  604. Exit Sub
  605.  
  606. EH:
  607.     RaiseError FUNC_NAME
  608.  
  609. End Sub
  610.  
  611. Private Sub pvSkipBlock()
  612.  
  613.     Do
  614.         m_lSubBlockSize = pvReadByte()
  615.         Seek #m_nFile, Seek(m_nFile) + m_lSubBlockSize
  616.     Loop While m_lSubBlockSize > 0
  617.  
  618. End Sub
  619.  
  620. '= LZW decompressor ======================================================
  621.  
  622. Private Function pvLzwReadCode() As Long
  623.  
  624.   Const FUNC_NAME     As String = "pvLzwReadCode"
  625.     
  626.     On Error GoTo EH
  627.     Do While m_lInputBitCount < m_lCurrentBits
  628.         m_lInputBitBuffer = m_lInputBitBuffer Or (pvReadSubBlockByte() * m_aPOT(m_lInputBitCount))
  629.         m_lInputBitCount = m_lInputBitCount + 8
  630.     Loop
  631.     pvLzwReadCode = m_lInputBitBuffer And (m_aPOT(m_lCurrentBits) - 1)
  632.     m_lInputBitBuffer = m_lInputBitBuffer \ m_aPOT(m_lCurrentBits)
  633.     m_lInputBitCount = m_lInputBitCount - m_lCurrentBits
  634.  
  635. Exit Function
  636.  
  637. EH:
  638.     RaiseError FUNC_NAME
  639.  
  640. End Function
  641.  
  642. Private Function pvLzwDecodeString(aStack() As Byte, ByVal lIdx As Long, _
  643.                                    ByVal lCode As Long) As Long
  644.  
  645.   Const FUNC_NAME     As String = "pvLzwDecodeString"
  646.     
  647.     On Error GoTo EH
  648.     Do While lCode >= m_lClearTable
  649.         aStack(lIdx) = m_aAppendChar(lCode)
  650.         lIdx = lIdx + 1
  651.         lCode = m_aPrefixCode(lCode)
  652.         If lIdx > UBound(aStack) Then
  653.             Err.Raise vbObjectError + 2, , ERR_PAST_END_OF_STACK
  654.         End If
  655.     Loop
  656.     aStack(lIdx) = lCode
  657.     pvLzwDecodeString = lIdx
  658.  
  659. Exit Function
  660.  
  661. EH:
  662.     RaiseError FUNC_NAME
  663.  
  664. End Function
  665.  
  666. Private Sub pvLzwExpand(aBuffer() As Byte, ByVal lBufSize)
  667.  
  668.   Const FUNC_NAME     As String = "pvLzwExpand"
  669.   Dim lIdx            As Long
  670.   Dim lNewCode        As Long
  671.   Dim lOldCode        As Long
  672.   Dim lNextCode       As Long
  673.   Dim bCharacter      As Byte
  674.   Dim bClearFlag      As Boolean
  675.   Dim aStack(0 To 4000) As Byte
  676.   Dim lStackIdx       As Long
  677.   Dim lPrevProgess    As Long
  678.     
  679.     On Error GoTo EH
  680.     lNextCode = m_lClearTable + 2 '--- first code = m_lClearTable + 2
  681.     bClearFlag = True
  682.     lNewCode = pvLzwReadCode()
  683.     Do While lIdx < lBufSize
  684.         lNewCode = pvLzwReadCode()
  685.         '--- check for terminator
  686.         If lNewCode = m_lClearTable + 1 Then '--- terminator = m_lClearTable + 1
  687.             Exit Sub '>---> Bottom
  688.         End If
  689.         If bClearFlag Then
  690.             bClearFlag = False
  691.             lOldCode = lNewCode
  692.             bCharacter = lNewCode
  693.             aBuffer(lIdx) = bCharacter
  694.             lIdx = lIdx + 1
  695.           ElseIf lNewCode = m_lClearTable Then 'BCLEARFLAG = 0
  696.             bClearFlag = True
  697.             m_lCurrentBits = m_lInitBits
  698.             m_lMaxCode = m_aPOT(m_lCurrentBits) - 1
  699.             lNextCode = m_lClearTable + 2 '--- first code = m_lClearTable + 2
  700.           Else 'NOT LNEWCODE...
  701.             '--- decode string
  702.             If lNewCode < lNextCode Then
  703.                 lStackIdx = pvLzwDecodeString(aStack, 0, lNewCode)
  704.               ElseIf lNewCode = lNextCode Then 'NOT LNEWCODE...
  705.                 aStack(0) = bCharacter
  706.                 lStackIdx = pvLzwDecodeString(aStack, 1, lOldCode)
  707.               Else 'NOT LNEWCODE...
  708.                 Err.Raise vbObjectError + 3, , ERR_INVALID_LZW_CODE
  709.             End If
  710.             '--- save first char
  711.             bCharacter = aStack(lStackIdx)
  712.             '--- reverse copy stack
  713.             Do While lStackIdx >= 0
  714.                 aBuffer(lIdx) = aStack(lStackIdx)
  715.                 lStackIdx = lStackIdx - 1
  716.                 lIdx = lIdx + 1
  717.             Loop
  718.             '--- keep char table up-to-date
  719.             m_aPrefixCode(lNextCode) = lOldCode
  720.             m_aAppendChar(lNextCode) = bCharacter
  721.             lNextCode = lNextCode + 1
  722.             '--- expand code bitsize if max reached
  723.             If lNextCode > m_lMaxCode Then
  724.                 If m_lCurrentBits < MAX_BITS Then
  725.                     m_lCurrentBits = m_lCurrentBits + 1
  726.                     m_lMaxCode = m_aPOT(m_lCurrentBits) - 1
  727.                 End If
  728.             End If
  729.             lOldCode = lNewCode
  730.         End If
  731.         '--- report progress
  732.         lStackIdx = lIdx \ ImageWidth
  733.         If lStackIdx >= lPrevProgess + 10 Then
  734.             RaiseEvent Progress(lStackIdx)
  735.             lPrevProgess = lStackIdx
  736.         End If
  737.     Loop
  738.  
  739. Exit Sub
  740.  
  741. EH:
  742.     RaiseError FUNC_NAME
  743.  
  744. End Sub
  745.  
  746. '=========================================================================
  747. ' Base class events
  748. '=========================================================================
  749.  
  750. Private Sub Class_Initialize()
  751.  
  752.   Dim lIdx            As Long
  753.     
  754.     '--- init look-up table for fast 2 ^ x
  755.     m_aPOT(-1) = 0
  756.     m_aPOT(0) = 1
  757.     For lIdx = 1 To 30
  758.         m_aPOT(lIdx) = 2 * m_aPOT(lIdx - 1)
  759.     Next lIdx
  760.     m_aPOT(31) = &H80000000
  761.  
  762. End Sub
  763.  
  764. Private Sub Class_Terminate()
  765.  
  766.   Dim lErrNum         As Long
  767.   Dim sErrSrc         As String
  768.   Dim sErrDesc        As String
  769.     
  770.     '--- preserve error info and try not to throw one
  771.     '--- best practices: "destructors are never throwing an exception"
  772.     lErrNum = Err.Number
  773.     sErrSrc = Err.Source
  774.     sErrDesc = Err.Description
  775.     On Error Resume Next
  776.       pvCloseFile
  777.     On Error GoTo 0
  778.     Err.Number = lErrNum
  779.     Err.Source = sErrSrc
  780.     Err.Description = sErrDesc
  781.  
  782. End Sub
  783.  
  784. ':) Ulli's VB Code Formatter V2.3.18 (17/2/2006 13:50:19) 126 + 645 = 771 Lines
  785.