OPeNDAP Hyrax Back End Server (BES) Updated for version 3.8.3

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-2009 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 Atmospheric 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 <cstdio>
00042 #include <cstring>
00043 #include <cerrno>
00044 
00045 #include "BESUncompressZ.h"
00046 #include "BESInternalError.h"
00047 #include "BESDebug.h"
00048 
00049 
00055 void
00056 BESUncompressZ::uncompress( const string &src, const string &target )
00057 {
00058     int srcFile = 0 ;
00059     int destFile = 0 ;
00060     int my_errno = 0 ;
00061 
00062 /* -------------------------------------------------------------------- */
00063 /*      Open the file to be read                                        */
00064 /* -------------------------------------------------------------------- */
00065 
00066     BESDEBUG( "bes", "BESUncompressZ::uncompress - src=" << 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=" << target.c_str() << endl ) ;
00090 
00091     destFile = open( target.c_str(), O_WRONLY | O_CREAT | O_TRUNC
00092                      , S_IRUSR | S_IWUSR ) ;
00093     if( destFile == -1)
00094     {
00095         string err = "Unable to create the uncompressed file "
00096                      + target + ": " ;
00097         char *serr = strerror( my_errno ) ;
00098         if( serr )
00099         {
00100             err.append( serr ) ;
00101         }
00102         else
00103         {
00104             err.append( "unknown error occurred" ) ;
00105         }
00106         close( srcFile ) ;
00107         throw BESInternalError( err, __FILE__, __LINE__ ) ;
00108     }
00109 
00110 
00111 /* ==================================================================== */
00112 /*      Start decompress LZW inspired from ncompress-4.2.4.orig         */
00113 /* ==================================================================== */
00114 
00115     BESDEBUG( "bes", "BESUncompressZ::uncompress - start decompress" << endl) ;
00116 
00117 #define FIRSTBYTE       (unsigned char)'\037'/* First byte of compressed file*/
00118 #define SECONDBYTE      (unsigned char)'\235'/* Second byte of compressed file*/
00119 #define FIRST           257
00120 #define BIT_MASK        0x1f
00121 #define BLOCK_MODE      0x80    
00122 #define MAXCODE(n)      (1L << (n))
00123 #define BITS            16      
00124 #define INIT_BITS       9       
00125 #define CLEAR           256             /* table clear output code*/
00126 #define HBITS           17                      /* 50% occupancy */
00127 #define HSIZE           (1<<HBITS)
00128 #define HMASK           (HSIZE-1)
00129 #define BITS            16
00130 #define de_stack        ((unsigned char *)&(htab[HSIZE-1]))
00131 #define BYTEORDER       0000
00132 #define NOALLIGN        0
00133 
00134     unsigned char       htab[HSIZE*4];
00135     unsigned short      codetab[HSIZE];
00136 
00137     int block_mode = BLOCK_MODE; 
00138     int maxbits = BITS;         
00139     unsigned char       inbuf[BUFSIZ+64];       /* Input buffer */
00140     unsigned char       outbuf[BUFSIZ+2048];    /* Output buffer */
00141     unsigned char       *stackp;
00142     long int             code;
00143     int                  finchar;
00144     long int             oldcode;
00145     long int             incode;
00146     int                  inbits;
00147     int                  posbits;
00148     int                  outpos;
00149     int                  insize;
00150     int                  bitmask;
00151     long int             free_ent;
00152     long int             maxcode;
00153     long int             maxmaxcode;
00154     int                  n_bits;
00155     int                   rsize;
00156 
00157     insize = 0;
00158     
00159     BESDEBUG( "bes", "BESUncompressZ::uncompress - read file" << endl);      ;
00160 /* -------------------------------------------------------------------- */
00161 /*       Verify if the .Z file start with 0x1f and 0x9d                 */
00162 /* -------------------------------------------------------------------- */
00163     while( insize < 3 && (rsize = read(srcFile, inbuf+insize, BUFSIZ)) > 0) {
00164         insize += rsize;
00165     }
00166     BESDEBUG( "bes", "BESUncompressZ::uncompress - insize: " << insize << endl);  ;
00167 
00168 /* -------------------------------------------------------------------- */
00169 /*       Do we have compressed file?                                    */
00170 /* -------------------------------------------------------------------- */
00171     if( (insize < 3) || (inbuf[0] != FIRSTBYTE) || (inbuf[1] != SECONDBYTE)) {
00172         BESDEBUG( "bes", "BESUncompressZ::uncompress - not a compress file" << endl);      ;
00173         if( rsize < 0) {
00174             string err = "Could not read file ";
00175             err += src.c_str() ;
00176             close( srcFile ) ;
00177             close( destFile ) ;
00178             remove( target.c_str() ) ;
00179             throw BESInternalError( err, __FILE__, __LINE__ ) ;
00180         }
00181         
00182         if( insize > 0)  {
00183             string err = src.c_str();
00184             err += ": not in compressed format";
00185             close( srcFile ) ;
00186             close( destFile ) ;
00187             remove( target.c_str() ) ;
00188             throw BESInternalError( err, __FILE__, __LINE__ ) ;
00189         }
00190         
00191         string err = "unknown error";
00192         close( srcFile ) ;
00193         close( destFile ) ;
00194         remove( target.c_str() ) ;
00195         throw BESInternalError( err, __FILE__, __LINE__ ) ;
00196 
00197     }
00198 
00199 /* -------------------------------------------------------------------- */
00200 /*       handle compression                                             */
00201 /* -------------------------------------------------------------------- */
00202     maxbits = inbuf[2] & BIT_MASK;
00203     block_mode = inbuf[2] & BLOCK_MODE;
00204     maxmaxcode = MAXCODE(maxbits);      
00205     
00206     if( maxbits > BITS ) {
00207         string err = src.c_str();
00208         err += ": compressed with " ;
00209         err += maxbits ;
00210         err += " bits, can only handle";
00211         err += BITS;
00212         close( srcFile ) ;
00213         close( destFile ) ;
00214         remove( target.c_str() ) ;
00215         throw BESInternalError( err, __FILE__, __LINE__ ) ;
00216     }
00217 
00218     maxcode = MAXCODE(n_bits = INIT_BITS)-1;
00219     bitmask = (1<<n_bits)-1;
00220     oldcode = -1;
00221     finchar = 0;
00222     outpos = 0;
00223     posbits = 3<<3;
00224 
00225     free_ent = ((block_mode) ? FIRST : 256);
00226 
00227     BESDEBUG( "bes", "BESUncompressZ::uncompress - entering loop" << endl) ;
00228    
00229     memset(codetab, 0, 256);
00230     
00231     for (code = 255 ; code >= 0 ; --code){
00232         ((unsigned char *)(htab))[code] = (unsigned char) code;
00233     }
00234 
00235     do
00236         {
00237         resetbuf:       ;
00238             {
00239                 int     i;
00240                 int     e;
00241                 int     o;
00242                 
00243                 e = insize - ( o = ( posbits >> 3 ) );
00244                 
00245                 for (i = 0 ; i < e ; ++i)
00246                     inbuf[i] = inbuf[i+o];
00247                 
00248                 insize = e;
00249                 posbits = 0;
00250             }
00251                     
00252             if( insize < sizeof( inbuf ) - BUFSIZ ) {
00253                 if( ( rsize = read( srcFile, inbuf + insize, BUFSIZ )) < 0) {
00254                     string err = "Could not read file ";
00255                     err += src.c_str() ;
00256                     close( srcFile ) ;
00257                     close( destFile ) ;
00258                     remove( target.c_str() ) ;
00259                     throw BESInternalError( err, __FILE__, __LINE__ ) ;
00260                 }
00261                 
00262                 insize += rsize;
00263             }
00264                     
00265             inbits = ( ( rsize > 0 ) ? ( insize - insize % n_bits ) << 3 : 
00266                        ( insize << 3 ) - ( n_bits - 1 ));
00267 
00268             while( inbits > posbits ){
00269                 if( free_ent > maxcode ) {
00270                     posbits = ( ( posbits-1 ) + 
00271                                 ( ( n_bits << 3 ) - 
00272                                   ( posbits-1 +  ( n_bits << 3)) % 
00273                                   ( n_bits<<3 ) ) 
00274                                 );
00275                                     
00276                     ++n_bits;
00277                     if( n_bits == maxbits)
00278                         maxcode = maxmaxcode;
00279                     else
00280                         maxcode = MAXCODE(n_bits)-1;
00281                     
00282                     bitmask = (1<<n_bits)-1;
00283                     goto resetbuf;
00284                 }
00285                 
00286                 unsigned char*p = &inbuf[posbits>>3];           
00287                 
00288                 code = ( ( ( (long) ( p[0] ) ) | ( ( long )( p[1] ) << 8 ) |
00289                            ( (long) ( p[2] ) << 16 ) ) >> ( posbits & 0x7 ) ) &
00290                     bitmask; 
00291                 
00292                 posbits += n_bits;                                      
00293 
00294                 
00295                 if( oldcode == -1) {
00296                     if( code >= 256) {
00297                         string err = "oldcode:-1 code: ";
00298                         err += code ;
00299                         err += " !!!! uncompress: corrupt input!!!";
00300                         close( srcFile ) ;
00301                         close( destFile ) ;
00302                         remove( target.c_str() ) ;
00303                         throw BESInternalError( err, __FILE__, __LINE__ ) ;
00304                     }
00305                     outbuf[outpos++] = (unsigned char)(finchar = 
00306                                                    (int)(oldcode = code));
00307                     continue;
00308                 }
00309 
00310                 /* Clear */
00311                 if( code == CLEAR && block_mode) {
00312                     memset(codetab, 0, 256);
00313                     free_ent = FIRST - 1;
00314                     posbits = ( ( posbits - 1 ) + 
00315                                 ( ( n_bits << 3 ) -
00316                                   ( posbits - 1 + ( n_bits << 3 ) ) % 
00317                                   ( n_bits<<3) ) );
00318                     maxcode = MAXCODE( n_bits = INIT_BITS ) - 1;
00319                     bitmask = ( 1 << n_bits )-1;
00320                     goto resetbuf;
00321                 }
00322                                 
00323                 incode = code;
00324                 stackp = de_stack;
00325 
00326                 /* Special case for KwKwK string.*/
00327                 if( code >= free_ent ) {
00328                     if( code > free_ent ) {
00329                         unsigned char   *p;
00330                         posbits -= n_bits;
00331                         p = &inbuf[posbits>>3];
00332                         
00333                         string err = "uncompress: corrupt input";
00334                         close( srcFile ) ;
00335                         close( destFile ) ;
00336                         remove( target.c_str() ) ;
00337                         throw BESInternalError( err, __FILE__, __LINE__ ) ;
00338                     }
00339                     
00340                     *--stackp = ( unsigned char )finchar;
00341                     code = oldcode;
00342                 }
00343                 
00344                 /* Generate output characters in reverse order */
00345                 while( (unsigned long)code >= (unsigned long)256) { 
00346                     *--stackp = htab[code];
00347                     code = codetab[code];
00348                 }
00349                                 
00350                 *--stackp = (unsigned char)(finchar = htab[code]);
00351                                 
00352                 /* And put them out in forward order */         
00353                 {
00354                     int i;
00355                     if( outpos+(i = (de_stack-stackp)) >= BUFSIZ) {
00356                         do  {
00357 
00358                             if( i > BUFSIZ-outpos) {
00359                                 i = BUFSIZ-outpos;      
00360                             }
00361             
00362                             if( i > 0) {
00363                                 memcpy(outbuf+outpos, stackp, i);
00364                                 outpos += i;
00365                             }
00366                                     
00367                             if( outpos >= BUFSIZ) {
00368                                 if( write(destFile, outbuf,outpos) != outpos) {
00369                                     string err = "uncompress: write eror";
00370                                     close( srcFile ) ;
00371                                     close( destFile ) ;
00372                                     remove( target.c_str() ) ;
00373                                     throw BESInternalError( err, 
00374                                                             __FILE__, 
00375                                                             __LINE__ ) ;
00376                                 }               
00377                                 outpos = 0;
00378                             }
00379                             stackp+= i;
00380                         }
00381                         while( (i = (de_stack-stackp)) > 0) ; /* de-stack */
00382                     }
00383                     else {
00384                         memcpy(outbuf+outpos, stackp, i);
00385                         outpos += i;
00386                     }
00387                 }
00388                 /* Generate the new entry. */
00389                 if( (code = free_ent) < maxmaxcode)  {
00390                     codetab[code] = (unsigned short)oldcode;
00391                     htab[code] = (unsigned char)finchar;
00392                     free_ent = code+1;
00393                 } 
00394                 
00395                 oldcode = incode;       /* Remember previous code.      */
00396             }
00397         }
00398 
00399     while( rsize > 0); /* end of do */
00400     
00401     if( outpos > 0 && write(destFile, outbuf, outpos) != outpos) {
00402         string err = "uncompress: write eror";
00403         close( srcFile ) ;
00404         close( destFile ) ;
00405         remove( target.c_str() ) ;
00406         throw BESInternalError( err, __FILE__, __LINE__ ) ;
00407     }
00408 
00409     close( srcFile ) ;
00410     close( destFile ) ;
00411 
00412     BESDEBUG( "bes", "BESUncompressZ::uncompress - end decompres" << endl) ;
00413 }
00414