bes  Updated for version 3.20.10
BESUncompress3Z.cc
1 // BESUncompress3Z.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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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 "BESUncompress3Z.h"
46 #include "BESInternalError.h"
47 #include "BESDebug.h"
48 
49 using std::endl;
50 using std::string;
51 
57 void BESUncompress3Z::uncompress(const string &src, int fd)
58 {
59  int srcFile = 0;
60  int my_errno = 0;
61 
62  /* -------------------------------------------------------------------- */
63  /* Open the file to be read */
64  /* -------------------------------------------------------------------- */
65 
66  BESDEBUG( "bes", "BESUncompress3Z::uncompress - src=" << src.c_str() << endl );
67 
68  srcFile = open(src.c_str(), O_RDONLY);
69  my_errno = errno;
70  if (srcFile == -1) {
71  string err = "Unable to open the compressed file " + src + ": ";
72  char *serr = strerror(my_errno);
73  if (serr) {
74  err.append(serr);
75  }
76  else {
77  err.append("unknown error occurred");
78  }
79  throw BESInternalError(err, __FILE__, __LINE__);
80  }
81 
82  /* ==================================================================== */
83  /* Start decompress LZW inspired from ncompress-4.2.4.orig */
84  /* ==================================================================== */
85 
86  BESDEBUG( "bes", "BESUncompress3Z::uncompress - start decompress" << endl);
87 
88 #define FIRSTBYTE (unsigned char)'\037'/* First byte of compressed file*/
89 #define SECONDBYTE (unsigned char)'\235'/* Second byte of compressed file*/
90 #define FIRST 257
91 #define BIT_MASK 0x1f
92 #define BLOCK_MODE 0x80
93 #define MAXCODE(n) (1L << (n))
94 #define BITS 16
95 #define INIT_BITS 9
96 #define CLEAR 256 /* table clear output code*/
97 #define HBITS 17 /* 50% occupancy */
98 #define HSIZE (1<<HBITS)
99 #define HMASK (HSIZE-1)
100 #define BITS 16
101 #define de_stack ((unsigned char *)&(htab[HSIZE-1]))
102 #define BYTEORDER 0000
103 #define NOALLIGN 0
104 
105  unsigned char htab[HSIZE * 4];
106  unsigned short codetab[HSIZE];
107 
108  int block_mode = BLOCK_MODE;
109  int maxbits = BITS;
110  unsigned char inbuf[BUFSIZ + 64]; /* Input buffer */
111  unsigned char outbuf[BUFSIZ + 2048]; /* Output buffer */
112  unsigned char *stackp;
113  long int code;
114  int finchar;
115  long int oldcode;
116  long int incode;
117  int inbits;
118  int posbits;
119  int outpos;
120  int insize;
121  int bitmask;
122  long int free_ent;
123  long int maxcode;
124  long int maxmaxcode;
125  int n_bits;
126  int rsize = 0;
127 
128  insize = 0;
129 
130  BESDEBUG( "bes", "BESUncompress3Z::uncompress - read file" << endl);;
131  /* -------------------------------------------------------------------- */
132  /* Verify if the .Z file start with 0x1f and 0x9d */
133  /* -------------------------------------------------------------------- */
134  while (insize < 3 && (rsize = read(srcFile, inbuf + insize, BUFSIZ)) > 0) {
135  insize += rsize;
136  }
137  BESDEBUG( "bes", "BESUncompress3Z::uncompress - insize: " << insize << endl);;
138 
139  /* -------------------------------------------------------------------- */
140  /* Do we have compressed file? */
141  /* -------------------------------------------------------------------- */
142  if ((insize < 3) || (inbuf[0] != FIRSTBYTE) || (inbuf[1] != SECONDBYTE)) {
143  BESDEBUG( "bes", "BESUncompress3Z::uncompress - not a compress file" << endl);;
144  if (rsize < 0) {
145  string err = "Could not read file ";
146  err += src.c_str();
147  close(srcFile);
148  throw BESInternalError(err, __FILE__, __LINE__);
149  }
150 
151  if (insize > 0) {
152  string err = src.c_str();
153  err += ": not in compressed format";
154  close(srcFile);
155  throw BESInternalError(err, __FILE__, __LINE__);
156  }
157 
158  string err = "unknown error";
159  close(srcFile);
160  throw BESInternalError(err, __FILE__, __LINE__);
161 
162  }
163 
164  /* -------------------------------------------------------------------- */
165  /* handle compression */
166  /* -------------------------------------------------------------------- */
167  maxbits = inbuf[2] & BIT_MASK;
168  block_mode = inbuf[2] & BLOCK_MODE;
169  maxmaxcode = MAXCODE(maxbits);
170 
171  if (maxbits > BITS) {
172  string err = src.c_str();
173  err += ": compressed with ";
174  err += maxbits;
175  err += " bits, can only handle";
176  err += BITS;
177  close(srcFile);
178  throw BESInternalError(err, __FILE__, __LINE__);
179  }
180 
181  maxcode = MAXCODE(n_bits = INIT_BITS) - 1;
182  bitmask = (1 << n_bits) - 1;
183  oldcode = -1;
184  finchar = 0;
185  outpos = 0;
186  posbits = 3 << 3;
187 
188  free_ent = ((block_mode) ? FIRST : 256);
189 
190  BESDEBUG( "bes", "BESUncompress3Z::uncompress - entering loop" << endl);
191 
192  memset(codetab, 0, 256);
193 
194  for (code = 255; code >= 0; --code) {
195  ((unsigned char *) (htab))[code] = (unsigned char) code;
196  }
197 
198  do {
199  resetbuf: ;
200  {
201  int i;
202  // int e;
203  int o;
204 
205  int e = insize - (o = (posbits >> 3));
206 
207  for (i = 0; i < e; ++i)
208  inbuf[i] = inbuf[i + o];
209 
210  insize = e;
211  posbits = 0;
212  }
213 
214  if ((unsigned int)insize < sizeof(inbuf) - BUFSIZ) {
215  if ((rsize = read(srcFile, inbuf + insize, BUFSIZ)) < 0) {
216  string err = "Could not read file ";
217  err += src.c_str();
218  close(srcFile);
219  throw BESInternalError(err, __FILE__, __LINE__);
220  }
221 
222  insize += rsize;
223  }
224 
225  inbits = ((rsize > 0) ? (insize - insize % n_bits) << 3 : (insize << 3) - (n_bits - 1));
226 
227  while (inbits > posbits) {
228  if (free_ent > maxcode) {
229  posbits = ((posbits - 1) + ((n_bits << 3) - (posbits - 1 + (n_bits << 3)) % (n_bits << 3)));
230 
231  ++n_bits;
232  if (n_bits == maxbits)
233  maxcode = maxmaxcode;
234  else
235  maxcode = MAXCODE(n_bits) - 1;
236 
237  bitmask = (1 << n_bits) - 1;
238  goto resetbuf;
239  }
240 
241  unsigned char*p = &inbuf[posbits >> 3];
242 
243  code = ((((long) (p[0])) | ((long) (p[1]) << 8) | ((long) (p[2]) << 16)) >> (posbits & 0x7)) & bitmask;
244 
245  posbits += n_bits;
246 
247  if (oldcode == -1) {
248  if (code >= 256) {
249  string err = "oldcode:-1 code: ";
250  err += code;
251  err += " !!!! uncompress: corrupt input!!!";
252  close(srcFile);
253  throw BESInternalError(err, __FILE__, __LINE__);
254  }
255  outbuf[outpos++] = (unsigned char) (finchar = (int) (oldcode = code));
256  continue;
257  }
258 
259  /* Clear */
260  if (code == CLEAR && block_mode) {
261  memset(codetab, 0, 256);
262  free_ent = FIRST - 1;
263  posbits = ((posbits - 1) + ((n_bits << 3) - (posbits - 1 + (n_bits << 3)) % (n_bits << 3)));
264  maxcode = MAXCODE( n_bits = INIT_BITS ) - 1;
265  bitmask = (1 << n_bits) - 1;
266  goto resetbuf;
267  }
268 
269  incode = code;
270  stackp = de_stack;
271 
272  /* Special case for KwKwK string.*/
273  if (code >= free_ent) {
274  if (code > free_ent) {
275  close(srcFile);
276  throw BESInternalError("uncompress: corrupt input", __FILE__, __LINE__);
277  }
278 
279  *--stackp = (unsigned char) finchar;
280  code = oldcode;
281  }
282 
283  /* Generate output characters in reverse order */
284  while ((unsigned long) code >= (unsigned long) 256) {
285  *--stackp = htab[code];
286  code = codetab[code];
287  }
288 
289  *--stackp = (unsigned char) (finchar = htab[code]);
290 
291  /* And put them out in forward order */
292  {
293  int i;
294  if (outpos + (i = (de_stack - stackp)) >= BUFSIZ) {
295  do {
296 
297  if (i > BUFSIZ - outpos) {
298  i = BUFSIZ - outpos;
299  }
300 
301  if (i > 0) {
302  memcpy(outbuf + outpos, stackp, i);
303  outpos += i;
304  }
305 
306  if (outpos >= BUFSIZ) {
307  if (write(fd, outbuf, outpos) != outpos) {
308  string err = "uncompress: write eror";
309  close(srcFile);
310  throw BESInternalError(err, __FILE__, __LINE__);
311  }
312  outpos = 0;
313  }
314  stackp += i;
315  } while ((i = (de_stack - stackp)) > 0); /* de-stack */
316  }
317  else {
318  memcpy(outbuf + outpos, stackp, i);
319  outpos += i;
320  }
321  }
322  /* Generate the new entry. */
323  if ((code = free_ent) < maxmaxcode) {
324  codetab[code] = (unsigned short) oldcode;
325  htab[code] = (unsigned char) finchar;
326  free_ent = code + 1;
327  }
328 
329  oldcode = incode; /* Remember previous code. */
330  }
331  }
332 
333  while (rsize > 0); /* end of do */
334 
335  if (outpos > 0 && write(fd, outbuf, outpos) != outpos) {
336  string err = "uncompress: write eror";
337  close(srcFile);
338  throw BESInternalError(err, __FILE__, __LINE__);
339  }
340 
341  close(srcFile);
342 
343  BESDEBUG( "bes", "BESUncompress3Z::uncompress - end decompres" << endl);
344 }
345 
exception thrown if internal error encountered
static void uncompress(const std::string &src, int fd)
uncompress a file with the .gz file extension