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