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