BESUncompressZ.cc

Go to the documentation of this file.
00001 // BESUncompressZ.c
00002 
00003 // This file is part of bes, A C++ back-end server implementation framework
00004 // for the OPeNDAP Data Access Protocol.
00005 
00006 // Copyright (c) 2004,2005 University Corporation for Atmospheric Research
00007 // Author:
00008 //
00009 // This library is free software; you can redistribute it and/or
00010 // modify it under the terms of the GNU Lesser General Public
00011 // License as published by the Free Software Foundation; either
00012 // version 2.1 of the License, or (at your option) any later version.
00013 // 
00014 // This library is distributed in the hope that it will be useful,
00015 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00016 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00017 // Lesser General Public License for more details.
00018 // 
00019 // You should have received a copy of the GNU Lesser General Public
00020 // License along with this library; if not, write to the Free Software
00021 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00022 //
00023 // You can contact University Corporation for Atmospheric Research at
00024 // 3080 Center Green Drive, Boulder, CO 80301
00025  
00026 // (c) COPYRIGHT University Corporation for Atmostpheric Research 2004-2005
00027 // Please read the full copyright statement in the file COPYRIGHT_UCAR.
00028 //
00029 // Authors:
00030 //      dnadeau     Denis Nadeau <dnadeau@pop600.gsfc.nasa.gov>
00031 
00032 #include "config.h"
00033 
00034 #include <sys/types.h>
00035 #include <sys/stat.h>
00036 #include <fcntl.h>
00037 #if HAVE_UNISTD_H
00038 #include <unistd.h>
00039 #endif
00040 
00041 #include <cstring>
00042 #include <cerrno>
00043 
00044 #include "BESUncompressZ.h"
00045 #include "BESInternalError.h"
00046 #include "BESDebug.h"
00047 
00048 
00054 void
00055 BESUncompressZ::uncompress( const string &src, const string &target )
00056 {
00057     int srcFile = 0 ;
00058     int destFile = 0 ;
00059     int my_errno = 0 ;
00060 
00061 /* -------------------------------------------------------------------- */
00062 /*      Open the file to be read                                        */
00063 /* -------------------------------------------------------------------- */
00064 
00065     BESDEBUG( "bes", "BESUncompressZ::uncompress - src=" 
00066               << src.c_str() << endl ) ;
00067 
00068     srcFile = open( src.c_str(), O_RDONLY ) ;
00069     my_errno = errno ;
00070     if( srcFile == -1 )
00071     {
00072         string err = "Unable to open the compressed file " + src
00073                      + ": " ;
00074         char *serr = strerror( my_errno ) ;
00075         if( serr )
00076         {
00077             err.append( serr ) ;
00078         }
00079         else
00080         {
00081             err.append( "unknown error occurred" ) ;
00082         }
00083         throw BESInternalError( err, __FILE__, __LINE__ ) ;
00084     }
00085 
00086 /* -------------------------------------------------------------------- */
00087 /*      Open Output file                                                */
00088 /* -------------------------------------------------------------------- */
00089     BESDEBUG( "bes", "BESUncompressZ::uncompress - target=" 
00090               << target.c_str() << endl ) ;
00091 
00092     destFile = open( target.c_str(), O_WRONLY | O_CREAT | O_TRUNC
00093                      , S_IRUSR | S_IWUSR ) ;
00094     if( destFile == -1)
00095     {
00096         string err = "Unable to create the uncompressed file "
00097                      + target + ": " ;
00098         char *serr = strerror( my_errno ) ;
00099         if( serr )
00100         {
00101             err.append( serr ) ;
00102         }
00103         else
00104         {
00105             err.append( "unknown error occurred" ) ;
00106         }
00107         close( srcFile ) ;
00108         throw BESInternalError( err, __FILE__, __LINE__ ) ;
00109     }
00110 
00111 
00112 /* ==================================================================== */
00113 /*      Start decompress LZW inspired from ncompress-4.2.4.orig         */
00114 /* ==================================================================== */
00115 
00116     BESDEBUG( "bes", "BESUncompressZ::uncompress - start decompress" << endl);
00117 
00118 #define FIRSTBYTE       (unsigned char)'\037'/* First byte of compressed file*/
00119 #define SECONDBYTE      (unsigned char)'\235'/* Second byte of compressed file*/
00120 #define FIRST           257
00121 #define BIT_MASK        0x1f
00122 #define BLOCK_MODE      0x80    
00123 #define MAXCODE(n)      (1L << (n))
00124 #define BITS            16      
00125 #define INIT_BITS       9       
00126 #define CLEAR           256             /* table clear output code*/
00127 #define HBITS           17                      /* 50% occupancy */
00128 #define HSIZE           (1<<HBITS)
00129 #define HMASK           (HSIZE-1)
00130 #define BITS            16
00131 #define de_stack        ((unsigned char *)&(htab[HSIZE-1]))
00132 #define BYTEORDER       0000
00133 #define NOALLIGN        0
00134 
00135     unsigned char       htab[HSIZE*4];
00136     unsigned short      codetab[HSIZE];
00137 
00138     int block_mode = BLOCK_MODE; 
00139     int maxbits = BITS;         
00140     unsigned char       inbuf[BUFSIZ+64];       /* Input buffer */
00141     unsigned char       outbuf[BUFSIZ+2048];    /* Output buffer */
00142     unsigned char       *stackp;
00143     long int             code;
00144     int                  finchar;
00145     long int             oldcode;
00146     long int             incode;
00147     int                  inbits;
00148     int                  posbits;
00149     int                  outpos;
00150     int                  insize;
00151     int                  bitmask;
00152     long int             free_ent;
00153     long int             maxcode;
00154     long int             maxmaxcode;
00155     int                  n_bits;
00156     int                   rsize;
00157 
00158     insize = 0;
00159     
00160     BESDEBUG( "bes", "BESUncompressZ::uncompress - read file" << endl);     
00161 /* -------------------------------------------------------------------- */
00162 /*       Verify if the .Z file start with 0x1f and 0x9d                 */
00163 /* -------------------------------------------------------------------- */
00164     while( insize < 3 && (rsize = read(srcFile, inbuf+insize, BUFSIZ)) > 0) {
00165         insize += rsize;
00166     }
00167     BESDEBUG( "bes", "BESUncompressZ::uncompress - insize: " << insize << endl); 
00168 
00169 /* -------------------------------------------------------------------- */
00170 /*       Do we have compressed file?                                    */
00171 /* -------------------------------------------------------------------- */
00172     if( (insize < 3) || (inbuf[0] != FIRSTBYTE) || (inbuf[1] != SECONDBYTE)) {
00173         BESDEBUG( "bes", "BESUncompressZ::uncompress - not a compress file"
00174                          << endl);     
00175         if( rsize < 0) {
00176             string err = "Could not read file ";
00177             err += src.c_str() ;
00178             close( srcFile ) ;
00179             close( destFile ) ;
00180             throw BESInternalError( err, __FILE__, __LINE__ ) ;
00181         }
00182         
00183         if( insize > 0)  {
00184             string err = src.c_str();
00185             err += ": not in compressed format";
00186             close( srcFile ) ;
00187             close( destFile ) ;
00188             throw BESInternalError( err, __FILE__, __LINE__ ) ;
00189         }
00190         
00191         string err = "unknown error";
00192         close( srcFile ) ;
00193         close( destFile ) ;
00194         throw BESInternalError( err, __FILE__, __LINE__ ) ;
00195 
00196     }
00197 
00198 /* -------------------------------------------------------------------- */
00199 /*       handle compression                                             */
00200 /* -------------------------------------------------------------------- */
00201     maxbits = inbuf[2] & BIT_MASK;
00202     block_mode = inbuf[2] & BLOCK_MODE;
00203     maxmaxcode = MAXCODE(maxbits);      
00204     
00205     if( maxbits > BITS ) {
00206         string err = src.c_str();
00207         err += ": compressed with " ;
00208         err += maxbits ;
00209         err += " bits, can only handle";
00210         err += BITS;
00211         close( srcFile ) ;
00212         close( destFile ) ;
00213         throw BESInternalError( err, __FILE__, __LINE__ ) ;
00214     }
00215 
00216     maxcode = MAXCODE(n_bits = INIT_BITS)-1;
00217     bitmask = (1<<n_bits)-1;
00218     oldcode = -1;
00219     finchar = 0;
00220     outpos = 0;
00221     posbits = 3<<3;
00222 
00223     free_ent = ((block_mode) ? FIRST : 256);
00224 
00225     BESDEBUG( "bes", "BESUncompressZ::uncompress - entering loop" << endl);
00226    
00227     memset(codetab, 0, 256);
00228     
00229     for (code = 255 ; code >= 0 ; --code){
00230         ((unsigned char *)(htab))[code] = (unsigned char) code;
00231     }
00232 
00233     do
00234         {
00235         resetbuf:       ;
00236             {
00237                 int     i;
00238                 int     e;
00239                 int     o;
00240                 
00241                 e = insize - ( o = ( posbits >> 3 ) );
00242                 
00243                 for (i = 0 ; i < e ; ++i)
00244                     inbuf[i] = inbuf[i+o];
00245                 
00246                 insize = e;
00247                 posbits = 0;
00248             }
00249                     
00250             if( insize < sizeof( inbuf ) - BUFSIZ ) {
00251                 if( ( rsize = read( srcFile, inbuf + insize, BUFSIZ )) < 0) {
00252                     string err = "Could not read file ";
00253                     err += src.c_str() ;
00254                     close( srcFile ) ;
00255                     close( destFile ) ;
00256                     throw BESInternalError( err, __FILE__, __LINE__ ) ;
00257                 }
00258                 
00259                 insize += rsize;
00260             }
00261                     
00262             inbits = ( ( rsize > 0 ) ? ( insize - insize % n_bits ) << 3 : 
00263                        ( insize << 3 ) - ( n_bits - 1 ));
00264 
00265             while( inbits > posbits ){
00266                 if( free_ent > maxcode ) {
00267                     posbits = ( ( posbits-1 ) + 
00268                                 ( ( n_bits << 3 ) - 
00269                                   ( posbits-1 +  ( n_bits << 3)) % 
00270                                   ( n_bits<<3 ) ) 
00271                                 );
00272                                     
00273                     ++n_bits;
00274                     if( n_bits == maxbits)
00275                         maxcode = maxmaxcode;
00276                     else
00277                         maxcode = MAXCODE(n_bits)-1;
00278                     
00279                     bitmask = (1<<n_bits)-1;
00280                     goto resetbuf;
00281                 }
00282                 
00283                 unsigned char*p = &inbuf[posbits>>3];           
00284                 
00285                 code = ( ( ( (long) ( p[0] ) ) | ( ( long )( p[1] ) << 8 ) |
00286                            ( (long) ( p[2] ) << 16 ) ) >> ( posbits & 0x7 ) ) &
00287                     bitmask; 
00288                 
00289                 posbits += n_bits;                                      
00290 
00291                 
00292                 if( oldcode == -1) {
00293                     if( code >= 256) {
00294                         string err = "oldcode:-1 code: ";
00295                         err += code ;
00296                         err += " !!!! uncompress: corrupt input!!!";
00297                         close( srcFile ) ;
00298                         close( destFile ) ;
00299                         throw BESInternalError( err, __FILE__, __LINE__ ) ;
00300                     }
00301                     outbuf[outpos++] = (unsigned char)(finchar = 
00302                                                    (int)(oldcode = code));
00303                     continue;
00304                 }
00305 
00306                 /* Clear */
00307                 if( code == CLEAR && block_mode) {
00308                     memset(codetab, 0, 256);
00309                     free_ent = FIRST - 1;
00310                     posbits = ( ( posbits - 1 ) + 
00311                                 ( ( n_bits << 3 ) -
00312                                   ( posbits - 1 + ( n_bits << 3 ) ) % 
00313                                   ( n_bits<<3) ) );
00314                     maxcode = MAXCODE( n_bits = INIT_BITS ) - 1;
00315                     bitmask = ( 1 << n_bits )-1;
00316                     goto resetbuf;
00317                 }
00318                                 
00319                 incode = code;
00320                 stackp = de_stack;
00321 
00322                 /* Special case for KwKwK string.*/
00323                 if( code >= free_ent ) {
00324                     if( code > free_ent ) {
00325                         unsigned char   *p;
00326                         posbits -= n_bits;
00327                         p = &inbuf[posbits>>3];
00328                         
00329                         string err = "uncompress: corrupt input";
00330                         close( srcFile ) ;
00331                         close( destFile ) ;
00332                         throw BESInternalError( err, __FILE__, __LINE__ ) ;
00333                     }
00334                     
00335                     *--stackp = ( unsigned char )finchar;
00336                     code = oldcode;
00337                 }
00338                 
00339                 /* Generate output characters in reverse order */
00340                 while( (unsigned long)code >= (unsigned long)256) { 
00341                     *--stackp = htab[code];
00342                     code = codetab[code];
00343                 }
00344                                 
00345                 *--stackp = (unsigned char)(finchar = htab[code]);
00346                                 
00347                 /* And put them out in forward order */         
00348                 {
00349                     int i;
00350                     if( outpos+(i = (de_stack-stackp)) >= BUFSIZ) {
00351                         do  {
00352 
00353                             if( i > BUFSIZ-outpos) {
00354                                 i = BUFSIZ-outpos;      
00355                             }
00356             
00357                             if( i > 0) {
00358                                 memcpy(outbuf+outpos, stackp, i);
00359                                 outpos += i;
00360                             }
00361                                     
00362                             if( outpos >= BUFSIZ) {
00363                                 if( write(destFile, outbuf,outpos) != outpos) {
00364                                     string err = "uncompress: write eror";
00365                                     close( srcFile ) ;
00366                                     close( destFile ) ;
00367                                     throw BESInternalError( err, 
00368                                                             __FILE__, 
00369                                                             __LINE__ ) ;
00370                                 }               
00371                                 outpos = 0;
00372                             }
00373                             stackp+= i;
00374                         }
00375                         while( (i = (de_stack-stackp)) > 0) ; /* de-stack */
00376                     }
00377                     else {
00378                         memcpy(outbuf+outpos, stackp, i);
00379                         outpos += i;
00380                     }
00381                 }
00382                 /* Generate the new entry. */
00383                 if( (code = free_ent) < maxmaxcode)  {
00384                     codetab[code] = (unsigned short)oldcode;
00385                     htab[code] = (unsigned char)finchar;
00386                     free_ent = code+1;
00387                 } 
00388                 
00389                 oldcode = incode;       /* Remember previous code.      */
00390             }
00391         }
00392 
00393     while( rsize > 0); /* end of do */
00394     
00395     if( outpos > 0 && write(destFile, outbuf, outpos) != outpos) {
00396         string err = "uncompress: write eror";
00397         close( srcFile ) ;
00398         close( destFile ) ;
00399         throw BESInternalError( err, __FILE__, __LINE__ ) ;
00400     }
00401 
00402     close( srcFile ) ;
00403     close( destFile ) ;
00404 
00405     BESDEBUG( "bes", "BESUncompressZ::uncompress - end decompres" << endl);
00406 }
00407 

Generated on Tue Mar 4 23:13:36 2008 for OPeNDAP Back End Server (BES) by  doxygen 1.5.1