OPeNDAP Hyrax Back End Server (BES)  Updated for version 3.8.3
BESUncompressZ.cc
Go to the documentation of this file.
1 // BESUncompressZ.c
2 
3 // This file is part of bes, A C++ back-end server implementation framework
4 // for the OPeNDAP Data Access Protocol.
5 
6 // Copyright (c) 2004-2009 University Corporation for Atmospheric Research
7 // Author:
8 //
9 // This library is free software; you can redistribute it and/or
10 // modify it under the terms of the GNU Lesser General Public
11 // License as published by the Free Software Foundation; either
12 // version 2.1 of the License, or (at your option) any later version.
13 //
14 // This library is distributed in the hope that it will be useful,
15 // but WITHOUT ANY WARRANTY; without even the implied warranty of
16 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 // Lesser General Public License for more details.
18 //
19 // You should have received a copy of the GNU Lesser General Public
20 // License along with this library; if not, write to the Free Software
21 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 //
23 // You can contact University Corporation for Atmospheric Research at
24 // 3080 Center Green Drive, Boulder, CO 80301
25 
26 // (c) COPYRIGHT University Corporation for Atmospheric Research 2004-2005
27 // Please read the full copyright statement in the file COPYRIGHT_UCAR.
28 //
29 // Authors:
30 // dnadeau Denis Nadeau <dnadeau@pop600.gsfc.nasa.gov>
31 
32 #include "config.h"
33 
34 #include <sys/types.h>
35 #include <sys/stat.h>
36 #include <fcntl.h>
37 #if HAVE_UNISTD_H
38 #include <unistd.h>
39 #endif
40 
41 #include <cstdio>
42 #include <cstring>
43 #include <cerrno>
44 
45 #include "BESUncompressZ.h"
46 #include "BESInternalError.h"
47 #include "BESDebug.h"
48 
49 
55 void
56 BESUncompressZ::uncompress( const string &src, const string &target )
57 {
58  int srcFile = 0 ;
59  int destFile = 0 ;
60  int my_errno = 0 ;
61 
62 /* -------------------------------------------------------------------- */
63 /* Open the file to be read */
64 /* -------------------------------------------------------------------- */
65 
66  BESDEBUG( "bes", "BESUncompressZ::uncompress - src=" << src.c_str() << endl ) ;
67 
68  srcFile = open( src.c_str(), O_RDONLY ) ;
69  my_errno = errno ;
70  if( srcFile == -1 )
71  {
72  string err = "Unable to open the compressed file " + src
73  + ": " ;
74  char *serr = strerror( my_errno ) ;
75  if( serr )
76  {
77  err.append( serr ) ;
78  }
79  else
80  {
81  err.append( "unknown error occurred" ) ;
82  }
83  throw BESInternalError( err, __FILE__, __LINE__ ) ;
84  }
85 
86 /* -------------------------------------------------------------------- */
87 /* Open Output file */
88 /* -------------------------------------------------------------------- */
89  BESDEBUG( "bes", "BESUncompressZ::uncompress - target=" << target.c_str() << endl ) ;
90 
91  destFile = open( target.c_str(), O_WRONLY | O_CREAT | O_TRUNC
92  , S_IRUSR | S_IWUSR ) ;
93  if( destFile == -1)
94  {
95  string err = "Unable to create the uncompressed file "
96  + target + ": " ;
97  char *serr = strerror( my_errno ) ;
98  if( serr )
99  {
100  err.append( serr ) ;
101  }
102  else
103  {
104  err.append( "unknown error occurred" ) ;
105  }
106  close( srcFile ) ;
107  throw BESInternalError( err, __FILE__, __LINE__ ) ;
108  }
109 
110 
111 /* ==================================================================== */
112 /* Start decompress LZW inspired from ncompress-4.2.4.orig */
113 /* ==================================================================== */
114 
115  BESDEBUG( "bes", "BESUncompressZ::uncompress - start decompress" << endl) ;
116 
117 #define FIRSTBYTE (unsigned char)'\037'/* First byte of compressed file*/
118 #define SECONDBYTE (unsigned char)'\235'/* Second byte of compressed file*/
119 #define FIRST 257
120 #define BIT_MASK 0x1f
121 #define BLOCK_MODE 0x80
122 #define MAXCODE(n) (1L << (n))
123 #define BITS 16
124 #define INIT_BITS 9
125 #define CLEAR 256 /* table clear output code*/
126 #define HBITS 17 /* 50% occupancy */
127 #define HSIZE (1<<HBITS)
128 #define HMASK (HSIZE-1)
129 #define BITS 16
130 #define de_stack ((unsigned char *)&(htab[HSIZE-1]))
131 #define BYTEORDER 0000
132 #define NOALLIGN 0
133 
134  unsigned char htab[HSIZE*4];
135  unsigned short codetab[HSIZE];
136 
137  int block_mode = BLOCK_MODE;
138  int maxbits = BITS;
139  unsigned char inbuf[BUFSIZ+64]; /* Input buffer */
140  unsigned char outbuf[BUFSIZ+2048]; /* Output buffer */
141  unsigned char *stackp;
142  long int code;
143  int finchar;
144  long int oldcode;
145  long int incode;
146  int inbits;
147  int posbits;
148  int outpos;
149  int insize;
150  int bitmask;
151  long int free_ent;
152  long int maxcode;
153  long int maxmaxcode;
154  int n_bits;
155  int rsize = 0;
156 
157  insize = 0;
158 
159  BESDEBUG( "bes", "BESUncompressZ::uncompress - read file" << endl); ;
160 /* -------------------------------------------------------------------- */
161 /* Verify if the .Z file start with 0x1f and 0x9d */
162 /* -------------------------------------------------------------------- */
163  while( insize < 3 && (rsize = read(srcFile, inbuf+insize, BUFSIZ)) > 0) {
164  insize += rsize;
165  }
166  BESDEBUG( "bes", "BESUncompressZ::uncompress - insize: " << insize << endl); ;
167 
168 /* -------------------------------------------------------------------- */
169 /* Do we have compressed file? */
170 /* -------------------------------------------------------------------- */
171  if( (insize < 3) || (inbuf[0] != FIRSTBYTE) || (inbuf[1] != SECONDBYTE)) {
172  BESDEBUG( "bes", "BESUncompressZ::uncompress - not a compress file" << endl); ;
173  if( rsize < 0) {
174  string err = "Could not read file ";
175  err += src.c_str() ;
176  close( srcFile ) ;
177  close( destFile ) ;
178  remove( target.c_str() ) ;
179  throw BESInternalError( err, __FILE__, __LINE__ ) ;
180  }
181 
182  if( insize > 0) {
183  string err = src.c_str();
184  err += ": not in compressed format";
185  close( srcFile ) ;
186  close( destFile ) ;
187  remove( target.c_str() ) ;
188  throw BESInternalError( err, __FILE__, __LINE__ ) ;
189  }
190 
191  string err = "unknown error";
192  close( srcFile ) ;
193  close( destFile ) ;
194  remove( target.c_str() ) ;
195  throw BESInternalError( err, __FILE__, __LINE__ ) ;
196 
197  }
198 
199 /* -------------------------------------------------------------------- */
200 /* handle compression */
201 /* -------------------------------------------------------------------- */
202  maxbits = inbuf[2] & BIT_MASK;
203  block_mode = inbuf[2] & BLOCK_MODE;
204  maxmaxcode = MAXCODE(maxbits);
205 
206  if( maxbits > BITS ) {
207  string err = src.c_str();
208  err += ": compressed with " ;
209  err += maxbits ;
210  err += " bits, can only handle";
211  err += BITS;
212  close( srcFile ) ;
213  close( destFile ) ;
214  remove( target.c_str() ) ;
215  throw BESInternalError( err, __FILE__, __LINE__ ) ;
216  }
217 
218  maxcode = MAXCODE(n_bits = INIT_BITS)-1;
219  bitmask = (1<<n_bits)-1;
220  oldcode = -1;
221  finchar = 0;
222  outpos = 0;
223  posbits = 3<<3;
224 
225  free_ent = ((block_mode) ? FIRST : 256);
226 
227  BESDEBUG( "bes", "BESUncompressZ::uncompress - entering loop" << endl) ;
228 
229  memset(codetab, 0, 256);
230 
231  for (code = 255 ; code >= 0 ; --code){
232  ((unsigned char *)(htab))[code] = (unsigned char) code;
233  }
234 
235  do
236  {
237  resetbuf: ;
238  {
239  int i;
240  int e;
241  int o;
242 
243  e = insize - ( o = ( posbits >> 3 ) );
244 
245  for (i = 0 ; i < e ; ++i)
246  inbuf[i] = inbuf[i+o];
247 
248  insize = e;
249  posbits = 0;
250  }
251 
252  if( insize < sizeof( inbuf ) - BUFSIZ ) {
253  if( ( rsize = read( srcFile, inbuf + insize, BUFSIZ )) < 0) {
254  string err = "Could not read file ";
255  err += src.c_str() ;
256  close( srcFile ) ;
257  close( destFile ) ;
258  remove( target.c_str() ) ;
259  throw BESInternalError( err, __FILE__, __LINE__ ) ;
260  }
261 
262  insize += rsize;
263  }
264 
265  inbits = ( ( rsize > 0 ) ? ( insize - insize % n_bits ) << 3 :
266  ( insize << 3 ) - ( n_bits - 1 ));
267 
268  while( inbits > posbits ){
269  if( free_ent > maxcode ) {
270  posbits = ( ( posbits-1 ) +
271  ( ( n_bits << 3 ) -
272  ( posbits-1 + ( n_bits << 3)) %
273  ( n_bits<<3 ) )
274  );
275 
276  ++n_bits;
277  if( n_bits == maxbits)
278  maxcode = maxmaxcode;
279  else
280  maxcode = MAXCODE(n_bits)-1;
281 
282  bitmask = (1<<n_bits)-1;
283  goto resetbuf;
284  }
285 
286  unsigned char*p = &inbuf[posbits>>3];
287 
288  code = ( ( ( (long) ( p[0] ) ) | ( ( long )( p[1] ) << 8 ) |
289  ( (long) ( p[2] ) << 16 ) ) >> ( posbits & 0x7 ) ) &
290  bitmask;
291 
292  posbits += n_bits;
293 
294 
295  if( oldcode == -1) {
296  if( code >= 256) {
297  string err = "oldcode:-1 code: ";
298  err += code ;
299  err += " !!!! uncompress: corrupt input!!!";
300  close( srcFile ) ;
301  close( destFile ) ;
302  remove( target.c_str() ) ;
303  throw BESInternalError( err, __FILE__, __LINE__ ) ;
304  }
305  outbuf[outpos++] = (unsigned char)(finchar =
306  (int)(oldcode = code));
307  continue;
308  }
309 
310  /* Clear */
311  if( code == CLEAR && block_mode) {
312  memset(codetab, 0, 256);
313  free_ent = FIRST - 1;
314  posbits = ( ( posbits - 1 ) +
315  ( ( n_bits << 3 ) -
316  ( posbits - 1 + ( n_bits << 3 ) ) %
317  ( n_bits<<3) ) );
318  maxcode = MAXCODE( n_bits = INIT_BITS ) - 1;
319  bitmask = ( 1 << n_bits )-1;
320  goto resetbuf;
321  }
322 
323  incode = code;
324  stackp = de_stack;
325 
326  /* Special case for KwKwK string.*/
327  if( code >= free_ent ) {
328  if( code > free_ent ) {
329  unsigned char *p;
330  posbits -= n_bits;
331  p = &inbuf[posbits>>3];
332 
333  string err = "uncompress: corrupt input";
334  close( srcFile ) ;
335  close( destFile ) ;
336  remove( target.c_str() ) ;
337  throw BESInternalError( err, __FILE__, __LINE__ ) ;
338  }
339 
340  *--stackp = ( unsigned char )finchar;
341  code = oldcode;
342  }
343 
344  /* Generate output characters in reverse order */
345  while( (unsigned long)code >= (unsigned long)256) {
346  *--stackp = htab[code];
347  code = codetab[code];
348  }
349 
350  *--stackp = (unsigned char)(finchar = htab[code]);
351 
352  /* And put them out in forward order */
353  {
354  int i;
355  if( outpos+(i = (de_stack-stackp)) >= BUFSIZ) {
356  do {
357 
358  if( i > BUFSIZ-outpos) {
359  i = BUFSIZ-outpos;
360  }
361 
362  if( i > 0) {
363  memcpy(outbuf+outpos, stackp, i);
364  outpos += i;
365  }
366 
367  if( outpos >= BUFSIZ) {
368  if( write(destFile, outbuf,outpos) != outpos) {
369  string err = "uncompress: write eror";
370  close( srcFile ) ;
371  close( destFile ) ;
372  remove( target.c_str() ) ;
373  throw BESInternalError( err,
374  __FILE__,
375  __LINE__ ) ;
376  }
377  outpos = 0;
378  }
379  stackp+= i;
380  }
381  while( (i = (de_stack-stackp)) > 0) ; /* de-stack */
382  }
383  else {
384  memcpy(outbuf+outpos, stackp, i);
385  outpos += i;
386  }
387  }
388  /* Generate the new entry. */
389  if( (code = free_ent) < maxmaxcode) {
390  codetab[code] = (unsigned short)oldcode;
391  htab[code] = (unsigned char)finchar;
392  free_ent = code+1;
393  }
394 
395  oldcode = incode; /* Remember previous code. */
396  }
397  }
398 
399  while( rsize > 0); /* end of do */
400 
401  if( outpos > 0 && write(destFile, outbuf, outpos) != outpos) {
402  string err = "uncompress: write eror";
403  close( srcFile ) ;
404  close( destFile ) ;
405  remove( target.c_str() ) ;
406  throw BESInternalError( err, __FILE__, __LINE__ ) ;
407  }
408 
409  close( srcFile ) ;
410  close( destFile ) ;
411 
412  BESDEBUG( "bes", "BESUncompressZ::uncompress - end decompres" << endl) ;
413 }
414