bes  Updated for version 3.20.6
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  unsigned char *p;
276  posbits -= n_bits;
277  p = &inbuf[posbits >> 3];
278 
279  string err = "uncompress: corrupt input";
280  close(srcFile);
281  throw BESInternalError(err, __FILE__, __LINE__);
282  }
283 
284  *--stackp = (unsigned char) finchar;
285  code = oldcode;
286  }
287 
288  /* Generate output characters in reverse order */
289  while ((unsigned long) code >= (unsigned long) 256) {
290  *--stackp = htab[code];
291  code = codetab[code];
292  }
293 
294  *--stackp = (unsigned char) (finchar = htab[code]);
295 
296  /* And put them out in forward order */
297  {
298  int i;
299  if (outpos + (i = (de_stack - stackp)) >= BUFSIZ) {
300  do {
301 
302  if (i > BUFSIZ - outpos) {
303  i = BUFSIZ - outpos;
304  }
305 
306  if (i > 0) {
307  memcpy(outbuf + outpos, stackp, i);
308  outpos += i;
309  }
310 
311  if (outpos >= BUFSIZ) {
312  if (write(fd, outbuf, outpos) != outpos) {
313  string err = "uncompress: write eror";
314  close(srcFile);
315  throw BESInternalError(err, __FILE__, __LINE__);
316  }
317  outpos = 0;
318  }
319  stackp += i;
320  } while ((i = (de_stack - stackp)) > 0); /* de-stack */
321  }
322  else {
323  memcpy(outbuf + outpos, stackp, i);
324  outpos += i;
325  }
326  }
327  /* Generate the new entry. */
328  if ((code = free_ent) < maxmaxcode) {
329  codetab[code] = (unsigned short) oldcode;
330  htab[code] = (unsigned char) finchar;
331  free_ent = code + 1;
332  }
333 
334  oldcode = incode; /* Remember previous code. */
335  }
336  }
337 
338  while (rsize > 0); /* end of do */
339 
340  if (outpos > 0 && write(fd, outbuf, outpos) != outpos) {
341  string err = "uncompress: write eror";
342  close(srcFile);
343  throw BESInternalError(err, __FILE__, __LINE__);
344  }
345 
346  close(srcFile);
347 
348  BESDEBUG( "bes", "BESUncompress3Z::uncompress - end decompres" << endl);
349 }
350 
BESUncompress3Z::uncompress
static void uncompress(const std::string &src, int fd)
uncompress a file with the .gz file extension
Definition: BESUncompress3Z.cc:57
BESInternalError
exception thrown if internal error encountered
Definition: BESInternalError.h:43