Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | File List | Namespace Members | Class Members | File Members | Related Pages

oldlzw.cpp

Go to the documentation of this file.
00001 
00009 /*
00010     This file is part of Advanced Strategic Command; http://www.asc-hq.de
00011     Copyright (C) 1994-1999  Martin Bickel  and  Marc Schellenberger
00012 
00013     This program is free software; you can redistribute it and/or modify
00014     it under the terms of the GNU General Public License as published by
00015     the Free Software Foundation; either version 2 of the License, or
00016     (at your option) any later version.
00017 
00018     This program is distributed in the hope that it will be useful,
00019     but WITHOUT ANY WARRANTY; without even the implied warranty of
00020     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00021     GNU General Public License for more details.
00022 
00023     You should have received a copy of the GNU General Public License
00024     along with this program; see the file COPYING. If not, write to the 
00025     Free Software Foundation, Inc., 59 Temple Place, Suite 330, 
00026     Boston, MA  02111-1307  USA
00027 */
00028 
00029 
00030 
00032 
00033 
00034 tlzwstreamcompression  :: tlzwstreamcompression ( void )
00035 {
00036     mode = none;
00037     initread = 0;
00038     initwrite = 0;
00039     DecodeBufferSize = 0;    
00040     DecodeBuffer = NULL;
00041     rdictionary = NULL;
00042     readcnt = 0;
00043     wdictionary = NULL;
00044 }
00045 
00046 
00047 void tlzwstreamcompression  :: LZWOut ( CodeType code )
00048 {
00049     writelzwdata ( &code, sizeof( CodeType )) ;
00050 
00051     LZWTotBytesOut += 2;
00052     LZWCurrBytesOut += 2;
00053 }
00054 
00055 
00056 
00057 
00058 /* our hashing lookup function */
00059  IndexType tlzwstreamcompression  :: LZWFind ( CodeType currcode, int in )
00060 {
00061     IndexType ndx;
00062     int step = 11, pastzero = 0;
00063 
00064     ndx = ( ( IndexType ) currcode << 8 ) | in;
00065     ndx = ndx % DICTIONARY_SIZE;
00066 
00067     for ( ;; )
00068     {
00069         if ( wdictionary[ ndx ].code == UNUSED_CODE )
00070             break;
00071         if ( wdictionary[ ndx ].parent == currcode &&
00072              wdictionary[ ndx ].c == in )
00073             break;
00074         ndx += step;
00075         if ( ndx >= DICTIONARY_SIZE)
00076         {
00077             ndx -= DICTIONARY_SIZE;
00078             pastzero += 1;
00079 
00080             /*
00081              * Next is a safety check. If the step
00082              * value and the dictionary size are
00083              * relatively prime, there should never
00084              * be a problem. However, let's not loop
00085              * too many times.
00086              */
00087 
00088             if ( pastzero > 5 )
00089                 step = 1;
00090         }
00091 
00092     }
00093     return ( ndx );
00094 }
00095 
00096 
00097  void tlzwstreamcompression  :: initreading ( void )
00098 {
00099   if ( mode == none ) {    // 1: read, 2: write
00100      char tempreadbuf[10];
00101      int tempreadbufsize = 0;
00102 
00103      int lzw = 1;
00104      int i;
00105 
00106      for (i = 0; i < strlen ( LZ_SIGNATURE ) + 3; i++) {
00107         try {
00108            readlzwdata ( &tempreadbuf[tempreadbufsize], 1 );
00109            tempreadbufsize++;
00110         } /* endtry */
00111 
00112         catch ( treadafterend ) {
00113            tempreadbufsize--;
00114            lzw = 0;
00115         } /* endcatch */
00116      }
00117 
00118      if ( lzw ) {
00119         if ( tempreadbuf[0] )
00120            lzw = 0;
00121         if ( strcmp ( &tempreadbuf[1], LZ_SIGNATURE ) ) 
00122            lzw = 0;
00123         if ( tempreadbuf[strlen ( LZ_SIGNATURE ) + 2] )
00124            lzw = 0;
00125      }
00126      if ( lzw == 1 ) {
00127         mode = reading;
00128 
00129         rdictionary = new Rdictionary [DICTIONARY_SIZE];
00130     
00131         if ( rdictionary == NULL )
00132             throw toutofmem ( DICTIONARY_SIZE * sizeof( struct Rdictionary ) );
00133      } else {
00134         lzw = 2;
00135         if ( tempreadbuf[0] )
00136            lzw = 0;
00137         if ( strcmp ( &tempreadbuf[1], RLE_SIGNATURE ) ) 
00138            lzw = 0;
00139         if ( tempreadbuf[strlen ( RLE_SIGNATURE ) + 2] )
00140            lzw = 0;
00141 
00142         if ( lzw == 2 ) {
00143            rlestartbyte = tempreadbuf[strlen ( RLE_SIGNATURE ) + 3];
00144 
00145            rlenum = 0;
00146            mode = readingrle;
00147 
00148         } else {
00149            for ( i = 0; i < tempreadbufsize; i++ )
00150               tempbuf.push ( tempreadbuf[i] );
00151 
00152            mode = readingdirect;
00153         }
00154      }
00155      initread = 1;
00156 
00157   } else
00158     if ( initwrite )
00159        throw tinvalidmode ( "tlzwstreamcompression ", tnstream::IOMode ( mode ), tnstream::reading );
00160 }
00161 
00162 
00163 
00164  void tlzwstreamcompression  :: initwriting ( void )
00165 {
00166   if ( mode == none ) {    
00167 
00168       freecode = STARTING_CODE;
00169   
00170       LZWTotBytesIn = 0;
00171       LZWTotBytesOut = 0;
00172       LZWCurrBytesIn = 0;
00173       LZWCurrBytesOut = 0;
00174   
00175       char c = 0;
00176       writelzwdata ( &c, 1 );
00177       writelzwdata ( LZ_SIGNATURE, strlen ( LZ_SIGNATURE ) + 1 );
00178       writelzwdata ( &c, 1 );
00179   
00180   
00181       wdictionary = new Wdictionary [ DICTIONARY_SIZE ];
00182                   
00183       if ( ! wdictionary )
00184           throw toutofmem ( DICTIONARY_SIZE * sizeof( struct Wdictionary ) );
00185   
00186       for ( i = 0; i < DICTIONARY_SIZE; i++ )
00187           wdictionary[ i ].code = UNUSED_CODE;
00188   
00189       currcodeloaded = 0;
00190 
00191       initwrite = 1;
00192       mode = writing;
00193 
00194   } else
00195     if ( initread )
00196        throw tinvalidmode ( "tlzwstreamcompression ", tnstream::IOMode ( mode ) , tnstream::writing );
00197 }
00198 
00199 
00200 
00201  void tlzwstreamcompression  :: writedata ( const void* buf, int size )
00202 {
00203    if ( !initwrite )
00204       initwriting();
00205 
00206    const char* buf2 = (char*) buf;
00207    int pos = 0;
00208 
00209    if ( size ) {
00210       if ( !currcodeloaded ) {
00211          currcode = buf2[pos++];
00212 
00213          LZWTotBytesIn += 1;
00214          LZWCurrBytesIn += 1;
00215          currcode &= 0xFF; /* make sure we don't sign extend */
00216 
00217          currcodeloaded = 1;
00218       }
00219 
00220       while ( pos < size )
00221       {
00222             in = buf2[pos++];
00223 
00224             LZWTotBytesIn += 1;
00225             LZWCurrBytesIn += 1;
00226             idx = LZWFind ( currcode, in );
00227             if ( wdictionary[ idx ].code == UNUSED_CODE )
00228             {
00229                 /* not a match */
00230                 LZWOut ( currcode );
00231 
00232                 /* now, update the dictionary */
00233                 if ( freecode < MAX_CODE )
00234                 {
00235                     wdictionary[ idx ].c = in;
00236                     wdictionary[ idx ].code = freecode++;
00237                     wdictionary[ idx ].parent = currcode;
00238                 }
00239                 currcode = in;
00240 
00241                 /* Had a miss; check compression efficiency */
00242                 if ( LZWCurrBytesIn >= 10000 )
00243                 {
00244                     unsigned ratio;
00245                     ratio = ( LZWCurrBytesOut * 100 ) /
00246                              LZWCurrBytesIn;
00247 
00248                     LZWCurrBytesIn = 0;
00249                     LZWCurrBytesOut = 0;
00250                     if ( ratio > LZWBestRatio )
00251                     {
00252                         if ( ratio > 50 &&
00253                              ( ratio > 90 ||
00254                              ratio > LZWLastRatio + 10 ))
00255                         {
00256                             LZWOut ( NEW_DICTIONARY );
00257                             for ( i = 0;
00258                                   i < DICTIONARY_SIZE; i++ )
00259                                 wdictionary[ i ].code =
00260                                     UNUSED_CODE;
00261                             freecode = STARTING_CODE;
00262                         }
00263                     }
00264                     else
00265                         LZWBestRatio = ratio;
00266                     LZWLastRatio = ratio;
00267                 }
00268             }
00269             else /* we match so far--keep going */
00270                 currcode = wdictionary[ idx ].code;
00271 
00272       }
00273    }
00274 }
00275 
00276 
00277 
00278  void tlzwstreamcompression  :: LZWIn ( void )
00279 {
00280     readlzwdata ( &incode, sizeof( CodeType ) );
00281     incode = SDL_SwapLE16( incode );
00282 }
00283 
00284 
00285 /* the active decompression routine */
00286  unsigned tlzwstreamcompression  :: LZWLoadBuffer ( unsigned count, CodeType code )
00287 {
00288     if ( code >= freecode )
00289        throw tbufferoverflow();
00290                    
00291     while ( code >= PRESET_CODE_MAX )
00292     {
00293         DecodeBuffer[ count++ ] = rdictionary[ code ].c;
00294         if ( count == DecodeBufferSize )
00295         {
00296             DecodeBuffer = (unsigned char *) realloc ( DecodeBuffer, DecodeBufferSize + 1000 );
00297 
00298             if ( ! DecodeBuffer )
00299                 throw toutofmem ( DecodeBufferSize + 1000 );
00300             else      
00301                 DecodeBufferSize += 1000;
00302         }
00303         code = rdictionary[ code ].parent;
00304     }
00305     DecodeBuffer[ count++ ] = code;
00306     return ( count );
00307 }
00308 
00309 
00310 
00311 int tlzwstreamcompression  :: readdata ( void* buf, int size, bool excpt  )
00312 {
00313    if ( !initread )
00314       initreading();
00315 
00316    int pos = 0;
00317    char* buf2 = (char*) buf ;
00318 
00319 
00320    if ( mode == readingdirect ) {
00321       int tp = 0;
00322       while ( pos < size  &&  tempbuf.size() )  {
00323          buf2 [pos++] = tempbuf.front();
00324          tempbuf.pop();
00325          tp++;
00326        }
00327        if ( size-pos > 0 )
00328           tp += readlzwdata ( &buf2[pos], size-pos, excpt );
00329 
00330        return tp;
00331 
00332    } else
00333 
00334 
00335 
00336    if ( mode == readingrle ) {
00337       while ( pos < size ) {
00338 
00339           if ( rlenum ) {
00340              buf2[pos++] = rledata;
00341              rlenum--;
00342           } else {
00343 
00344              // getting byte
00345 
00346              if ( !readlzwdata ( &rledata, 1, excpt ))
00347                 return pos;
00348 
00349              if ( rledata == rlestartbyte ) {
00350                 readlzwdata ( &rlenum, 1 );
00351                 if ( rlenum > 2 )
00352                    readlzwdata ( &rledata, 1 );
00353              } else
00354                 buf2[pos++] = rledata;
00355           }
00356 
00357       } /* endwhile */
00358       return pos;
00359 
00360    } else {
00361 
00362        while ( pos < size  &&  tempbuf.size() ) {
00363           buf2 [pos++] = tempbuf.front();
00364           tempbuf.pop();
00365        }
00366 
00367 
00368        if ( pos < size ) {
00369    
00370           /* prime the pump */
00371       
00372           if (!DecodeBufferSize)
00373           {
00374               DecodeBufferSize = 1000;
00375               DecodeBuffer =  (unsigned char * ) new char [ DecodeBufferSize ];
00376               if ( DecodeBuffer == NULL )
00377                   throw toutofmem ( DecodeBufferSize );
00378           }
00379       
00380       
00381           if ( !readcnt ) {
00382    
00383           priming:
00384              freecode = STARTING_CODE;
00385              LZWIn (  );
00386          
00387              if ( incode == END_OF_INPUT )
00388                  goto done;
00389    
00390              /* the first character always is itself */
00391    
00392              oldcode = incode;
00393              inchar = incode;
00394              buf2[ pos++ ] = incode;
00395    
00396           }
00397       
00398           while ( pos < size ) {
00399               LZWIn ( );
00400    
00401               if ( incode == END_OF_INPUT )
00402                   break;
00403                   
00404               if ( incode == NEW_DICTIONARY )
00405                   goto priming;
00406                   
00407               if ( incode >= freecode )
00408               {
00409                   /* We have a code that's not in our rdictionary! */
00410                   /* This can happen only one way--see text */
00411       
00412                   count = LZWLoadBuffer ( 1, oldcode );
00413       
00414                   /* Make last char same as first. Can use either */
00415                   /* inchar or the DecodeBuffer[count-1] */
00416       
00417                   DecodeBuffer[ 0 ] = inchar;
00418               }
00419               else
00420                   count = LZWLoadBuffer ( 0, incode );
00421       
00422               if ( count == 0 )
00423                  throw ASCexception();
00424                              
00425               inchar = DecodeBuffer[ count - 1 ];
00426               while ( count )
00427               {
00428                  if ( pos < size )
00429                     buf2 [pos++] = DecodeBuffer[--count];
00430                  else 
00431                     tempbuf.push ( DecodeBuffer[--count] );
00432               }
00433       
00434               /* now, update the rdictionary */
00435               if ( freecode < MAX_CODE )
00436               {
00437                   rdictionary[ freecode ].parent = oldcode;
00438                   rdictionary[ freecode ].c = inchar;
00439                   freecode += 1;
00440       
00441               }
00442               oldcode = incode;
00443           }
00444        }
00445     done:
00446       readcnt++;
00447 
00448       return pos;
00449    }
00450 
00451    // return 0;
00452 }
00453 
00454 
00455  void tlzwstreamcompression  :: close( void )
00456 {
00457    if ( mode == writing ) {
00458       LZWOut ( currcode );
00459       LZWOut ( END_OF_INPUT );
00460       mode = none;
00461    }
00462 }
00463 
00464 
00465  tlzwstreamcompression  :: ~tlzwstreamcompression ( )
00466 {
00467    if ( mode == writing )
00468       close();
00469 
00470     if ( rdictionary ) {
00471        delete[] rdictionary;
00472        rdictionary = NULL;
00473     }
00474     if ( wdictionary ) {
00475        delete[] wdictionary;
00476        wdictionary = NULL;
00477     }
00478 
00479     if ( DecodeBuffer ) {
00480        delete[] DecodeBuffer;
00481        DecodeBuffer = NULL;
00482     }
00483 
00484 }

Generated on Tue Jun 24 01:27:46 2008 for Advanced Strategic Command by  doxygen 1.4.2