OPeNDAP Hyrax Back End Server (BES)
Updated for version 3.8.3
|
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