LCOV - code coverage report
Current view: directory - frmts/rmf - rmflzw.cpp (source / functions) Found Hit Coverage
Test: gdal_filtered.info Lines: 79 0 0.0 %
Date: 2010-01-09 Functions: 2 0 0.0 %

       1                 : /******************************************************************************
       2                 :  * $Id: rmflzw.cpp 11865 2007-08-09 11:53:57Z warmerdam $
       3                 :  *
       4                 :  * Project:  Raster Matrix Format
       5                 :  * Purpose:  Implementation of the LZW compression algorithm as used in
       6                 :  *           GIS "Panorama"/"Integratsia" raster files. Based on implementation
       7                 :  *           of Kent Williams, but heavily modified over it. The key point
       8                 :  *           in the initial implementation is a hashing algorithm.
       9                 :  * Author:   Andrey Kiselev, dron@ak4719.spb.edu
      10                 :  *
      11                 :  ******************************************************************************
      12                 :  * Copyright (c) 2007, Andrey Kiselev <dron@ak4719.spb.edu>
      13                 :  *
      14                 :  * Permission is hereby granted, free of charge, to any person obtaining a
      15                 :  * copy of this software and associated documentation files (the "Software"),
      16                 :  * to deal in the Software without restriction, including without limitation
      17                 :  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
      18                 :  * and/or sell copies of the Software, and to permit persons to whom the
      19                 :  * Software is furnished to do so, subject to the following conditions:
      20                 :  *
      21                 :  * The above copyright notice and this permission notice shall be included
      22                 :  * in all copies or substantial portions of the Software.
      23                 :  *
      24                 :  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
      25                 :  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      26                 :  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
      27                 :  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      28                 :  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
      29                 :  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
      30                 :  * DEALINGS IN THE SOFTWARE.
      31                 :  ******************************************************************************
      32                 :  * COPYRIGHT NOTICE FROM THE INITIAL IMPLEMENTATION:
      33                 :  *
      34                 :  * The programs LZWCOM and LZWUNC, both in binary executable and source forms,
      35                 :  * are in the public domain.  No warranty is given or implied, and no
      36                 :  * liability will be assumed by the author.
      37                 :  *
      38                 :  * Everyone on earth is hereby given permission to use, copy, distribute,
      39                 :  * change, mangle, destroy or otherwise employ these programs, provided they
      40                 :  * hurt no one but themselves in the process.
      41                 :  *
      42                 :  * Kent Williams
      43                 :  * Norand Inc.
      44                 :  * 550 2nd St S.E.
      45                 :  * Cedar Rapids, Iowa 52401
      46                 :  * (319) 369-3131
      47                 :  ****************************************************************************/
      48                 : 
      49                 : #include "cpl_conv.h"
      50                 : 
      51                 : #include "rmfdataset.h"
      52                 : 
      53                 : // Code marks that there is no predecessor in the string
      54                 : #define NO_PRED     0xFFFF
      55                 : 
      56                 : // We are using 12-bit codes in this particular implementation
      57                 : #define TABSIZE     4096U
      58                 : #define STACKSIZE   TABSIZE
      59                 : 
      60                 : /************************************************************************/
      61                 : /*                           LZWStringTab                               */
      62                 : /************************************************************************/
      63                 : 
      64                 : typedef struct
      65                 : {
      66                 :     int     bUsed;
      67                 :     GUInt32 iNext;          // hi bit is 'used' flag
      68                 :     GUInt32 iPredecessor;   // 12 bit code
      69                 :     GByte   iFollower;
      70                 : } LZWStringTab;
      71                 : 
      72                 : /************************************************************************/
      73                 : /*                           LZWUpdateTab()                             */
      74                 : /************************************************************************/
      75                 : 
      76               0 : static void LZWUpdateTab(LZWStringTab *poCodeTab, GUInt32 iPred, char bFoll)
      77                 : {
      78                 :     GUInt32 nNext;
      79                 : 
      80                 : /* -------------------------------------------------------------------- */
      81                 : /* Hash uses the 'mid-square' algorithm. I.E. for a hash val of n bits  */
      82                 : /* hash = middle binary digits of (key * key).  Upon collision, hash    */
      83                 : /* searches down linked list of keys that hashed to that key already.   */
      84                 : /* It will NOT notice if the table is full. This must be handled        */
      85                 : /* elsewhere                                                            */
      86                 : /* -------------------------------------------------------------------- */
      87               0 :     GUInt32 nLocal = (iPred + bFoll) | 0x0800;
      88               0 :     nLocal = (nLocal*nLocal >> 6) & 0x0FFF;      // middle 12 bits of result
      89                 : 
      90                 :     // If string is not used
      91               0 :     if (poCodeTab[nLocal].bUsed == FALSE)
      92               0 :         nNext = nLocal;
      93                 :     else
      94                 :     {
      95                 :         // If collision has occured
      96               0 :         while ( (nNext = poCodeTab[nLocal].iNext) != 0 )
      97               0 :             nLocal = nNext;
      98                 : 
      99                 :         // Search for free entry from nLocal + 101
     100               0 :         nNext = (nLocal + 101) & 0x0FFF;
     101               0 :         while ( poCodeTab[nNext].bUsed )
     102                 :         {
     103               0 :             if ( ++nNext >= TABSIZE )
     104               0 :                 nNext = 0;
     105                 :         }
     106                 : 
     107                 :         // Put new tempnext into last element in collision list
     108               0 :         poCodeTab[nLocal].iNext = nNext;
     109                 :     }
     110                 : 
     111               0 :     poCodeTab[nNext].bUsed = TRUE;
     112               0 :     poCodeTab[nNext].iNext = 0;
     113               0 :     poCodeTab[nNext].iPredecessor = iPred;
     114               0 :     poCodeTab[nNext].iFollower = bFoll;
     115               0 : }
     116                 : 
     117                 : /************************************************************************/
     118                 : /*                           LZWDecompress()                            */
     119                 : /************************************************************************/
     120                 : 
     121               0 : int RMFDataset::LZWDecompress( const GByte* pabyIn, GUInt32 nSizeIn,
     122                 :                                GByte* pabyOut, GUInt32 nSizeOut )
     123                 : {
     124               0 :     GUInt32         nCount = TABSIZE - 256;
     125                 :     GUInt32         iCode, iOldCode, iInCode;
     126               0 :     GByte           iFinChar, bLastChar=FALSE;
     127                 :     LZWStringTab    *poCodeTab;
     128                 :     int             bBitsleft;
     129                 : 
     130               0 :     if ( pabyIn == 0 ||
     131                 :          pabyOut == 0 ||
     132                 :          nSizeOut < nSizeIn ||
     133                 :          nSizeIn < 2 )
     134               0 :         return 0;
     135                 : 
     136                 :     // Allocate space for the new table and pre-fill it
     137               0 :     poCodeTab = (LZWStringTab *)CPLMalloc( TABSIZE * sizeof(LZWStringTab) );
     138               0 :     if ( !poCodeTab )
     139               0 :         return 0;
     140               0 :     memset( poCodeTab, 0, TABSIZE * sizeof(LZWStringTab) );
     141               0 :     for ( iCode = 0; iCode < 256; iCode++ )
     142               0 :         LZWUpdateTab( poCodeTab, NO_PRED, (char)iCode );
     143                 : 
     144                 :     // The first code is always known
     145               0 :     iCode = (*pabyIn++ << 4) & 0xFF0; nSizeIn--;
     146               0 :     iCode += (*pabyIn >> 4) & 0x00F;
     147               0 :     iOldCode = iCode;
     148               0 :     bBitsleft = TRUE;
     149                 : 
     150               0 :     *pabyOut++ = iFinChar = poCodeTab[iCode].iFollower; nSizeOut--;
     151                 : 
     152                 :     // Decompress the input buffer
     153               0 :     while ( nSizeIn > 0 )
     154                 :     {
     155                 :         int     bNewCode;
     156               0 :         GUInt32 nStackCount = 0;
     157                 :         GByte   abyStack[STACKSIZE];
     158               0 :         GByte   *pabyTail = abyStack + STACKSIZE;
     159                 : 
     160                 :         // Fetch 12-bit code from input stream
     161               0 :         if ( bBitsleft )
     162                 :         {
     163               0 :             iCode = ((*pabyIn++ & 0x0F) << 8) & 0xF00; nSizeIn--;
     164               0 :             if ( nSizeIn <= 0 )
     165               0 :                 break;
     166               0 :             iCode += *pabyIn++; nSizeIn--;
     167               0 :             bBitsleft = FALSE;
     168                 :         }
     169                 :         else
     170                 :         {
     171               0 :             iCode = (*pabyIn++ << 4) & 0xFF0; nSizeIn--;
     172               0 :             if ( nSizeIn <= 0 )
     173               0 :                 break;
     174               0 :             iCode += (*pabyIn >> 4) & 0x00F;
     175               0 :             bBitsleft = TRUE;
     176                 :         }
     177               0 :         iInCode = iCode;
     178                 : 
     179                 :         // Do we have unknown code?
     180               0 :         if ( poCodeTab[iCode].bUsed )
     181               0 :             bNewCode = FALSE;
     182                 :         else
     183                 :         {
     184               0 :             iCode = iOldCode;
     185               0 :             bLastChar = iFinChar;
     186               0 :             bNewCode = TRUE;
     187                 :         }
     188                 : 
     189               0 :         while ( poCodeTab[iCode].iPredecessor != NO_PRED )
     190                 :         {
     191                 :             // Stack overrun
     192               0 :             if ( nStackCount >= STACKSIZE )
     193               0 :                 goto bad;
     194                 :             // Put the decoded character into stack
     195               0 :             *(--pabyTail) = poCodeTab[iCode].iFollower; nStackCount++;
     196               0 :             iCode = poCodeTab[iCode].iPredecessor;
     197                 :         }
     198                 : 
     199               0 :         if ( !nSizeOut )
     200               0 :             goto bad;
     201                 :         // The first character
     202               0 :         *pabyOut++ = iFinChar = poCodeTab[iCode].iFollower; nSizeOut--;
     203                 : 
     204                 :         // Output buffer overrun
     205               0 :         if ( nStackCount > nSizeOut )
     206               0 :             goto bad;
     207                 : 
     208                 :         // Now copy the stack contents into output buffer. Our stack was
     209                 :         // filled in reverse order, so no need in character reordering
     210               0 :         memcpy( pabyOut, pabyTail, nStackCount );
     211               0 :         nSizeOut -= nStackCount;
     212               0 :         pabyOut += nStackCount;
     213                 : 
     214                 :         // If code isn't known
     215               0 :         if ( bNewCode )
     216                 :         {
     217                 :             // Output buffer overrun
     218               0 :             if ( !nSizeOut )
     219               0 :                 goto bad;
     220               0 :             *pabyOut++ = iFinChar = bLastChar;  // the follower char of last
     221               0 :             nSizeOut--;
     222                 :         }
     223                 : 
     224               0 :         if ( nCount > 0 )
     225                 :         {
     226               0 :             nCount--;
     227                 :             // Add code to the table
     228               0 :             LZWUpdateTab( poCodeTab, iOldCode, iFinChar );
     229                 :         }
     230                 : 
     231               0 :         iOldCode = iInCode;
     232                 :     }
     233                 : 
     234               0 :     CPLFree( poCodeTab );
     235               0 :     return 1;
     236                 : 
     237                 : bad:
     238               0 :     CPLFree( poCodeTab );
     239               0 :     return 0;
     240                 : }
     241                 : 

Generated by: LCOV version 1.7