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