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 #include <stdio.h>
00041 
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             throw BESInternalError( err, __FILE__, __LINE__ ) ;
00179         }
00180         
00181         if( insize > 0)  {
00182             string err = src.c_str();
00183             err += ": not in compressed format";
00184             close( srcFile ) ;
00185             close( destFile ) ;
00186             throw BESInternalError( err, __FILE__, __LINE__ ) ;
00187         }
00188         
00189         string err = "unknown error";
00190         close( srcFile ) ;
00191         close( destFile ) ;
00192         throw BESInternalError( err, __FILE__, __LINE__ ) ;
00193 
00194     }
00195 
00196 /* -------------------------------------------------------------------- */
00197 /*       handle compression                                             */
00198 /* -------------------------------------------------------------------- */
00199     maxbits = inbuf[2] & BIT_MASK;
00200     block_mode = inbuf[2] & BLOCK_MODE;
00201     maxmaxcode = MAXCODE(maxbits);      
00202     
00203     if( maxbits > BITS ) {
00204         string err = src.c_str();
00205         err += ": compressed with " ;
00206         err += maxbits ;
00207         err += " bits, can only handle";
00208         err += BITS;
00209         close( srcFile ) ;
00210         close( destFile ) ;
00211         throw BESInternalError( err, __FILE__, __LINE__ ) ;
00212     }
00213 
00214     maxcode = MAXCODE(n_bits = INIT_BITS)-1;
00215     bitmask = (1<<n_bits)-1;
00216     oldcode = -1;
00217     finchar = 0;
00218     outpos = 0;
00219     posbits = 3<<3;
00220 
00221     free_ent = ((block_mode) ? FIRST : 256);
00222 
00223     BESDEBUG( "bes", "BESUncompressZ::uncompress - entering loop" << endl);
00224    
00225     memset(codetab, 0, 256);
00226     
00227     for (code = 255 ; code >= 0 ; --code){
00228         ((unsigned char *)(htab))[code] = (unsigned char) code;
00229     }
00230 
00231     do
00232         {
00233         resetbuf:       ;
00234             {
00235                 int     i;
00236                 int     e;
00237                 int     o;
00238                 
00239                 e = insize - ( o = ( posbits >> 3 ) );
00240                 
00241                 for (i = 0 ; i < e ; ++i)
00242                     inbuf[i] = inbuf[i+o];
00243                 
00244                 insize = e;
00245                 posbits = 0;
00246             }
00247                     
00248             if( insize < sizeof( inbuf ) - BUFSIZ ) {
00249                 if( ( rsize = read( srcFile, inbuf + insize, BUFSIZ )) < 0) {
00250                     string err = "Could not read file ";
00251                     err += src.c_str() ;
00252                     close( srcFile ) ;
00253                     close( destFile ) ;
00254                     throw BESInternalError( err, __FILE__, __LINE__ ) ;
00255                 }
00256                 
00257                 insize += rsize;
00258             }
00259                     
00260             inbits = ( ( rsize > 0 ) ? ( insize - insize % n_bits ) << 3 : 
00261                        ( insize << 3 ) - ( n_bits - 1 ));
00262 
00263             while( inbits > posbits ){
00264                 if( free_ent > maxcode ) {
00265                     posbits = ( ( posbits-1 ) + 
00266                                 ( ( n_bits << 3 ) - 
00267                                   ( posbits-1 +  ( n_bits << 3)) % 
00268                                   ( n_bits<<3 ) ) 
00269                                 );
00270                                     
00271                     ++n_bits;
00272                     if( n_bits == maxbits)
00273                         maxcode = maxmaxcode;
00274                     else
00275                         maxcode = MAXCODE(n_bits)-1;
00276                     
00277                     bitmask = (1<<n_bits)-1;
00278                     goto resetbuf;
00279                 }
00280                 
00281                 unsigned char*p = &inbuf[posbits>>3];           
00282                 
00283                 code = ( ( ( (long) ( p[0] ) ) | ( ( long )( p[1] ) << 8 ) |
00284                            ( (long) ( p[2] ) << 16 ) ) >> ( posbits & 0x7 ) ) &
00285                     bitmask; 
00286                 
00287                 posbits += n_bits;                                      
00288 
00289                 
00290                 if( oldcode == -1) {
00291                     if( code >= 256) {
00292                         string err = "oldcode:-1 code: ";
00293                         err += code ;
00294                         err += " !!!! uncompress: corrupt input!!!";
00295                         close( srcFile ) ;
00296                         close( destFile ) ;
00297                         throw BESInternalError( err, __FILE__, __LINE__ ) ;
00298                     }
00299                     outbuf[outpos++] = (unsigned char)(finchar = 
00300                                                    (int)(oldcode = code));
00301                     continue;
00302                 }
00303 
00304                 /* Clear */
00305                 if( code == CLEAR && block_mode) {
00306                     memset(codetab, 0, 256);
00307                     free_ent = FIRST - 1;
00308                     posbits = ( ( posbits - 1 ) + 
00309                                 ( ( n_bits << 3 ) -
00310                                   ( posbits - 1 + ( n_bits << 3 ) ) % 
00311                                   ( n_bits<<3) ) );
00312                     maxcode = MAXCODE( n_bits = INIT_BITS ) - 1;
00313                     bitmask = ( 1 << n_bits )-1;
00314                     goto resetbuf;
00315                 }
00316                                 
00317                 incode = code;
00318                 stackp = de_stack;
00319 
00320                 /* Special case for KwKwK string.*/
00321                 if( code >= free_ent ) {
00322                     if( code > free_ent ) {
00323                         unsigned char   *p;
00324                         posbits -= n_bits;
00325                         p = &inbuf[posbits>>3];
00326                         
00327                         string err = "uncompress: corrupt input";
00328                         close( srcFile ) ;
00329                         close( destFile ) ;
00330                         throw BESInternalError( err, __FILE__, __LINE__ ) ;
00331                     }
00332                     
00333                     *--stackp = ( unsigned char )finchar;
00334                     code = oldcode;
00335                 }
00336                 
00337                 /* Generate output characters in reverse order */
00338                 while( (unsigned long)code >= (unsigned long)256) { 
00339                     *--stackp = htab[code];
00340                     code = codetab[code];
00341                 }
00342                                 
00343                 *--stackp = (unsigned char)(finchar = htab[code]);
00344                                 
00345                 /* And put them out in forward order */         
00346                 {
00347                     int i;
00348                     if( outpos+(i = (de_stack-stackp)) >= BUFSIZ) {
00349                         do  {
00350 
00351                             if( i > BUFSIZ-outpos) {
00352                                 i = BUFSIZ-outpos;      
00353                             }
00354             
00355                             if( i > 0) {
00356                                 memcpy(outbuf+outpos, stackp, i);
00357                                 outpos += i;
00358                             }
00359                                     
00360                             if( outpos >= BUFSIZ) {
00361                                 if( write(destFile, outbuf,outpos) != outpos) {
00362                                     string err = "uncompress: write eror";
00363                                     close( srcFile ) ;
00364                                     close( destFile ) ;
00365                                     throw BESInternalError( err, 
00366                                                             __FILE__, 
00367                                                             __LINE__ ) ;
00368                                 }               
00369                                 outpos = 0;
00370                             }
00371                             stackp+= i;
00372                         }
00373                         while( (i = (de_stack-stackp)) > 0) ; /* de-stack */
00374                     }
00375                     else {
00376                         memcpy(outbuf+outpos, stackp, i);
00377                         outpos += i;
00378                     }
00379                 }
00380                 /* Generate the new entry. */
00381                 if( (code = free_ent) < maxmaxcode)  {
00382                     codetab[code] = (unsigned short)oldcode;
00383                     htab[code] = (unsigned char)finchar;
00384                     free_ent = code+1;
00385                 } 
00386                 
00387                 oldcode = incode;       /* Remember previous code.      */
00388             }
00389         }
00390 
00391     while( rsize > 0); /* end of do */
00392     
00393     if( outpos > 0 && write(destFile, outbuf, outpos) != outpos) {
00394         string err = "uncompress: write eror";
00395         close( srcFile ) ;
00396         close( destFile ) ;
00397         throw BESInternalError( err, __FILE__, __LINE__ ) ;
00398     }
00399 
00400     close( srcFile ) ;
00401     close( destFile ) ;
00402 
00403     BESDEBUG( "bes", "BESUncompressZ::uncompress - end decompres" << endl);
00404 }
00405 

Generated on Sat Aug 22 06:06:22 2009 for OPeNDAP Hyrax Back End Server (BES) by  doxygen 1.6.0