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