bes Updated for version 3.21.1
The Backend Server (BES) is the lower two tiers of the Hyrax data server
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
49using std::endl;
50using std::string;
51
57void 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