summaryrefslogtreecommitdiff
path: root/gzlib.c
diff options
context:
space:
mode:
Diffstat (limited to 'gzlib.c')
-rw-r--r--gzlib.c513
1 files changed, 513 insertions, 0 deletions
diff --git a/gzlib.c b/gzlib.c
new file mode 100644
index 0000000..bcef6c2
--- /dev/null
+++ b/gzlib.c
@@ -0,0 +1,513 @@
1/* gzlib.c -- zlib functions common to reading and writing gzip files
2 * Copyright (C) 2004, 2010 Mark Adler
3 * For conditions of distribution and use, see copyright notice in zlib.h
4 */
5
6#ifndef OLD_GZIO
7
8#include "gzguts.h"
9
10#ifdef _LARGEFILE64_SOURCE
11# define LSEEK lseek64
12#else
13# define LSEEK lseek
14#endif
15
16/* Local functions */
17local void gz_reset OF((gz_statep));
18local gzFile gz_open OF((const char *, int, const char *, int));
19
20#if defined UNDER_CE && defined NO_ERRNO_H
21local char *strwinerror OF((DWORD error));
22
23# include <windows.h>
24
25/* Map the Windows error number in ERROR to a locale-dependent error
26 message string and return a pointer to it. Typically, the values
27 for ERROR come from GetLastError.
28
29 The string pointed to shall not be modified by the application,
30 but may be overwritten by a subsequent call to strwinerror
31
32 The strwinerror function does not change the current setting
33 of GetLastError. */
34
35local char *strwinerror (error)
36 DWORD error;
37{
38 static char buf[1024];
39
40 wchar_t *msgbuf;
41 DWORD lasterr = GetLastError();
42 DWORD chars = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM
43 | FORMAT_MESSAGE_ALLOCATE_BUFFER,
44 NULL,
45 error,
46 0, /* Default language */
47 (LPVOID)&msgbuf,
48 0,
49 NULL);
50 if (chars != 0) {
51 /* If there is an \r\n appended, zap it. */
52 if (chars >= 2
53 && msgbuf[chars - 2] == '\r' && msgbuf[chars - 1] == '\n') {
54 chars -= 2;
55 msgbuf[chars] = 0;
56 }
57
58 if (chars > sizeof (buf) - 1) {
59 chars = sizeof (buf) - 1;
60 msgbuf[chars] = 0;
61 }
62
63 wcstombs(buf, msgbuf, chars + 1);
64 LocalFree(msgbuf);
65 }
66 else {
67 sprintf(buf, "unknown win32 error (%ld)", error);
68 }
69
70 SetLastError(lasterr);
71 return buf;
72}
73
74#endif /* UNDER_CE && NO_ERRNO_H */
75
76/* Reset gzip file state */
77local void gz_reset(state)
78 gz_statep state;
79{
80 state->how = 0; /* look for gzip header */
81 if (state->mode == GZ_READ) { /* for reading ... */
82 state->have = 0; /* no output data available */
83 state->eof = 0; /* not at end of file */
84 }
85 state->seek = 0; /* no seek request pending */
86 gz_error(state, Z_OK, NULL); /* clear error */
87 state->pos = 0; /* no uncompressed data yet */
88 state->strm.avail_in = 0; /* no input data yet */
89}
90
91/* Open a gzip file either by name or file descriptor. */
92local gzFile gz_open(path, fd, mode, use64)
93 const char *path;
94 int fd;
95 const char *mode;
96 int use64;
97{
98 gz_statep state;
99
100 /* allocate gzFile structure to return */
101 state = malloc(sizeof(gz_state));
102 if (state == NULL)
103 return NULL;
104 state->size = 0; /* no buffers allocated yet */
105 state->want = GZBUFSIZE; /* requested buffer size */
106 state->msg = NULL; /* no error message yet */
107
108 /* interpret mode */
109 state->mode = GZ_NONE;
110 state->level = Z_DEFAULT_COMPRESSION;
111 state->strategy = Z_DEFAULT_STRATEGY;
112 while (*mode) {
113 if (*mode >= '0' && *mode <= '9')
114 state->level = *mode - '0';
115 else
116 switch (*mode) {
117 case 'r':
118 state->mode = GZ_READ;
119 break;
120#ifndef NO_GZCOMPRESS
121 case 'w':
122 state->mode = GZ_WRITE;
123 break;
124 case 'a':
125 state->mode = GZ_APPEND;
126 break;
127#endif
128 case '+': /* can't read and write at the same time */
129 free(state);
130 return NULL;
131 case 'b': /* ignore -- will request binary anyway */
132 break;
133 case 'f':
134 state->strategy = Z_FILTERED;
135 break;
136 case 'h':
137 state->strategy = Z_HUFFMAN_ONLY;
138 break;
139 case 'R':
140 state->strategy = Z_RLE;
141 break;
142 case 'F':
143 state->strategy = Z_FIXED;
144 default: /* could consider as an error, but just ignore */
145 ;
146 }
147 mode++;
148 }
149
150 /* must provide an "r", "w", or "a" */
151 if (state->mode == GZ_NONE) {
152 free(state);
153 return NULL;
154 }
155
156 /* open the file with the appropriate mode (or just use fd) */
157 state->fd = fd != -1 ? fd :
158 open(path,
159#ifdef O_LARGEFILE
160 (use64 ? O_LARGEFILE : 0) |
161#endif
162#ifdef O_BINARY
163 O_BINARY |
164#endif
165 (state->mode == GZ_READ ?
166 O_RDONLY :
167 (O_WRONLY | O_CREAT | (
168 state->mode == GZ_WRITE ?
169 O_TRUNC :
170 O_APPEND))),
171 0666);
172 if (state->fd == -1) {
173 free(state);
174 return NULL;
175 }
176 if (state->mode == GZ_APPEND)
177 state->mode = GZ_WRITE; /* simplify later checks */
178
179 /* save the path name for error messages */
180 state->path = malloc(strlen(path) + 1);
181 strcpy(state->path, path);
182
183 /* save the current position for rewinding (only if reading) */
184 if (state->mode == GZ_READ) {
185 state->start = LSEEK(state->fd, 0, SEEK_CUR);
186 if (state->start == -1) state->start = 0;
187 }
188
189 /* initialize stream */
190 gz_reset(state);
191
192 /* return stream */
193 return (gzFile)state;
194}
195
196/* -- see zlib.h -- */
197gzFile ZEXPORT gzopen(path, mode)
198 const char *path;
199 const char *mode;
200{
201 return gz_open(path, -1, mode, 0);
202}
203
204/* -- see zlib.h -- */
205gzFile ZEXPORT gzopen64(path, mode)
206 const char *path;
207 const char *mode;
208{
209 return gz_open(path, -1, mode, 1);
210}
211
212/* -- see zlib.h -- */
213gzFile ZEXPORT gzdopen(fd, mode)
214 int fd;
215 const char *mode;
216{
217 char path[46]; /* allow up to 128-bit integers, so don't worry --
218 the sprintf() is safe */
219
220 if (fd < 0)
221 return NULL;
222 sprintf(path, "<fd:%d>", fd); /* for error messages */
223 return gz_open(path, fd, mode, 1);
224}
225
226/* -- see zlib.h -- */
227int ZEXPORT gzbuffer(file, size)
228 gzFile file;
229 unsigned size;
230{
231 gz_statep state;
232
233 /* get internal structure and check integrity */
234 if (file == NULL)
235 return -1;
236 state = (gz_statep)file;
237 if (state->mode != GZ_READ && state->mode != GZ_WRITE)
238 return -1;
239
240 /* make sure we haven't already allocated memory */
241 if (state->size != 0)
242 return -1;
243
244 /* check and set requested size */
245 if (size == 0)
246 return -1;
247 state->want = size;
248 return 0;
249}
250
251/* -- see zlib.h -- */
252int ZEXPORT gzrewind(file)
253 gzFile file;
254{
255 gz_statep state;
256
257 /* get internal structure */
258 if (file == NULL)
259 return -1;
260 state = (gz_statep)file;
261
262 /* check that we're reading and that there's no error */
263 if (state->mode != GZ_READ || state->err != Z_OK)
264 return -1;
265
266 /* back up and start over */
267 if (LSEEK(state->fd, state->start, SEEK_SET) == -1)
268 return -1;
269 gz_reset(state);
270 return 0;
271}
272
273/* -- see zlib.h -- */
274z_off64_t ZEXPORT gzseek64(file, offset, whence)
275 gzFile file;
276 z_off64_t offset;
277 int whence;
278{
279 unsigned n;
280 z_off64_t ret;
281 gz_statep state;
282
283 /* get internal structure and check integrity */
284 if (file == NULL)
285 return -1;
286 state = (gz_statep)file;
287 if (state->mode != GZ_READ && state->mode != GZ_WRITE)
288 return -1;
289
290 /* check that there's no error */
291 if (state->err != Z_OK)
292 return -1;
293
294 /* can only seek from start or relative to current position */
295 if (whence != SEEK_SET && whence != SEEK_CUR)
296 return -1;
297
298 /* normalize offset to a SEEK_CUR specification */
299 if (whence == SEEK_SET)
300 offset -= state->pos;
301
302 /* if within raw area while reading, just go there */
303 if (state->mode == GZ_READ && state->how == 1 &&
304 state->pos + offset >= state->raw) {
305 ret = LSEEK(state->fd, offset, SEEK_CUR);
306 if (ret == -1)
307 return -1;
308 state->have = 0;
309 state->eof = 0;
310 state->seek = 0;
311 gz_error(state, Z_OK, NULL);
312 state->strm.avail_in = 0;
313 state->pos += offset;
314 return state->pos;
315 }
316
317 /* calculate skip amount, rewinding if needed for back seek when reading */
318 if (offset < 0) {
319 if (state->mode != GZ_READ) /* writing -- can't go backwards */
320 return -1;
321 offset += state->pos;
322 if (offset < 0) /* before start of file! */
323 return -1;
324 if (gzrewind(file) == -1) /* rewind, then skip to offset */
325 return -1;
326 }
327
328 /* if reading, skip what's in output buffer (one less gz_getc() check) */
329 if (state->mode == GZ_READ) {
330 n = state->have > offset ? (unsigned)offset : state->have;
331 state->have -= n;
332 state->next += n;
333 state->pos += n;
334 offset -= n;
335 }
336
337 /* request skip (if not zero) */
338 if (offset) {
339 state->seek = 1;
340 state->skip = offset;
341 }
342 return state->pos + offset;
343}
344
345/* -- see zlib.h -- */
346z_off_t ZEXPORT gzseek(file, offset, whence)
347 gzFile file;
348 z_off_t offset;
349 int whence;
350{
351 z_off64_t ret;
352
353 ret = gzseek64(file, (z_off64_t)offset, whence);
354 return ret == (z_off_t)ret ? (z_off_t)ret : -1;
355}
356
357/* -- see zlib.h -- */
358z_off64_t ZEXPORT gztell64(file)
359 gzFile file;
360{
361 gz_statep state;
362
363 /* get internal structure and check integrity */
364 if (file == NULL)
365 return -1;
366 state = (gz_statep)file;
367 if (state->mode != GZ_READ && state->mode != GZ_WRITE)
368 return -1;
369
370 /* return position */
371 return state->pos + (state->seek ? state->skip : 0);
372}
373
374/* -- see zlib.h -- */
375z_off_t ZEXPORT gztell(file)
376 gzFile file;
377{
378 z_off64_t ret;
379
380 ret = gztell64(file);
381 return ret == (z_off_t)ret ? (z_off_t)ret : -1;
382}
383
384/* -- see zlib.h -- */
385z_off64_t ZEXPORT gzoffset64(file)
386 gzFile file;
387{
388 z_off64_t offset;
389 gz_statep state;
390
391 /* get internal structure and check integrity */
392 if (file == NULL)
393 return -1;
394 state = (gz_statep)file;
395 if (state->mode != GZ_READ && state->mode != GZ_WRITE)
396 return -1;
397
398 /* compute and return effective offset in file */
399 offset = LSEEK(state->fd, 0, SEEK_CUR);
400 if (offset == -1)
401 return -1;
402 if (state->mode == GZ_READ) /* reading */
403 offset -= state->strm.avail_in; /* don't count buffered input */
404 return offset;
405}
406
407/* -- see zlib.h -- */
408z_off_t ZEXPORT gzoffset(file)
409 gzFile file;
410{
411 z_off64_t ret;
412
413 ret = gzoffset64(file);
414 return ret == (z_off_t)ret ? (z_off_t)ret : -1;
415}
416
417/* -- see zlib.h -- */
418int ZEXPORT gzeof(file)
419 gzFile file;
420{
421 gz_statep state;
422
423 /* get internal structure and check integrity */
424 if (file == NULL)
425 return -1;
426 state = (gz_statep)file;
427 if (state->mode != GZ_READ && state->mode != GZ_WRITE)
428 return -1;
429
430 /* return end-of-file state */
431 return state->mode == GZ_READ ? (state->eof && state->have == 0) : 0;
432}
433
434/* -- see zlib.h -- */
435const char * ZEXPORT gzerror(file, errnum)
436 gzFile file;
437 int *errnum;
438{
439 gz_statep state;
440
441 /* get internal structure and check integrity */
442 if (file == NULL)
443 return NULL;
444 state = (gz_statep)file;
445 if (state->mode != GZ_READ && state->mode != GZ_WRITE)
446 return NULL;
447
448 /* return error information */
449 *errnum = state->err;
450 return state->msg == NULL ? "" : state->msg;
451}
452
453/* -- see zlib.h -- */
454void ZEXPORT gzclearerr(file)
455 gzFile file;
456{
457 gz_statep state;
458
459 /* get internal structure and check integrity */
460 if (file == NULL)
461 return;
462 state = (gz_statep)file;
463 if (state->mode != GZ_READ && state->mode != GZ_WRITE)
464 return;
465
466 /* clear error and end-of-file */
467 if (state->mode == GZ_READ)
468 state->eof = 0;
469 gz_error(state, Z_OK, NULL);
470}
471
472/* Create an error message in allocated memory and set state->err and
473 state->msg accordingly. Free any previous error message already there. Do
474 not try to free or allocate space if the error is Z_MEM_ERROR (out of
475 memory). Simply save the error message as a static string. If there is
476 an allocation failure constructing the error message, then convert the
477 error to out of memory. */
478void ZEXPORT gz_error(state, err, msg)
479 gz_statep state;
480 int err;
481 char *msg;
482{
483 /* free previously allocated message and clear */
484 if (state->msg != NULL) {
485 if (state->err != Z_MEM_ERROR)
486 free(state->msg);
487 state->msg = NULL;
488 }
489
490 /* set error code, and if no message, then done */
491 state->err = err;
492 if (msg == NULL)
493 return;
494
495 /* for an out of memory error, save as static string */
496 if (err == Z_MEM_ERROR) {
497 state->msg = msg;
498 return;
499 }
500
501 /* construct error message with path */
502 if ((state->msg = malloc(strlen(state->path) + strlen(msg) + 3)) == NULL) {
503 state->err = Z_MEM_ERROR;
504 state->msg = "out of memory";
505 return;
506 }
507 strcpy(state->msg, state->path);
508 strcat(state->msg, ": ");
509 strcat(state->msg, msg);
510 return;
511}
512
513#endif /* !OLD_GZIO */