1#include "mupdf/fitz.h"
2
3#include <zlib.h>
4
5#include <string.h>
6
7typedef struct fz_inflate_state_s fz_inflate_state;
8
9struct fz_inflate_state_s
10{
11 fz_stream *chain;
12 z_stream z;
13 unsigned char buffer[4096];
14};
15
16void *fz_zlib_alloc(void *ctx, unsigned int items, unsigned int size)
17{
18 return fz_malloc_no_throw(ctx, items * size);
19}
20
21void fz_zlib_free(void *ctx, void *ptr)
22{
23 fz_free(ctx, ptr);
24}
25
26static int
27next_flated(fz_context *ctx, fz_stream *stm, size_t required)
28{
29 fz_inflate_state *state = stm->state;
30 fz_stream *chain = state->chain;
31 z_streamp zp = &state->z;
32 int code;
33 unsigned char *outbuf = state->buffer;
34 int outlen = sizeof(state->buffer);
35
36 if (stm->eof)
37 return EOF;
38
39 zp->next_out = outbuf;
40 zp->avail_out = outlen;
41
42 while (zp->avail_out > 0)
43 {
44 zp->avail_in = (uInt)fz_available(ctx, chain, 1);
45 zp->next_in = chain->rp;
46
47 code = inflate(zp, Z_SYNC_FLUSH);
48
49 chain->rp = chain->wp - zp->avail_in;
50
51 if (code == Z_STREAM_END)
52 {
53 break;
54 }
55 else if (code == Z_BUF_ERROR)
56 {
57 fz_warn(ctx, "premature end of data in flate filter");
58 break;
59 }
60 else if (code == Z_DATA_ERROR && zp->avail_in == 0)
61 {
62 fz_warn(ctx, "ignoring zlib error: %s", zp->msg);
63 break;
64 }
65 else if (code == Z_DATA_ERROR && !strcmp(zp->msg, "incorrect data check"))
66 {
67 fz_warn(ctx, "ignoring zlib error: %s", zp->msg);
68 chain->rp = chain->wp;
69 break;
70 }
71 else if (code != Z_OK)
72 {
73 fz_throw(ctx, FZ_ERROR_GENERIC, "zlib error: %s", zp->msg);
74 }
75 }
76
77 stm->rp = state->buffer;
78 stm->wp = state->buffer + outlen - zp->avail_out;
79 stm->pos += outlen - zp->avail_out;
80 if (stm->rp == stm->wp)
81 {
82 stm->eof = 1;
83 return EOF;
84 }
85 return *stm->rp++;
86}
87
88static void
89close_flated(fz_context *ctx, void *state_)
90{
91 fz_inflate_state *state = (fz_inflate_state *)state_;
92 int code;
93
94 code = inflateEnd(&state->z);
95 if (code != Z_OK)
96 fz_warn(ctx, "zlib error: inflateEnd: %s", state->z.msg);
97
98 fz_drop_stream(ctx, state->chain);
99 fz_free(ctx, state);
100}
101
102fz_stream *
103fz_open_flated(fz_context *ctx, fz_stream *chain, int window_bits)
104{
105 fz_inflate_state *state;
106 int code;
107
108 state = fz_malloc_struct(ctx, fz_inflate_state);
109 state->z.zalloc = fz_zlib_alloc;
110 state->z.zfree = fz_zlib_free;
111 state->z.opaque = ctx;
112 state->z.next_in = NULL;
113 state->z.avail_in = 0;
114
115 code = inflateInit2(&state->z, window_bits);
116 if (code != Z_OK)
117 {
118 fz_free(ctx, state);
119 fz_throw(ctx, FZ_ERROR_GENERIC, "zlib error: inflateInit2 failed");
120 }
121
122 state->chain = fz_keep_stream(ctx, chain);
123
124 return fz_new_stream(ctx, state, next_flated, close_flated);
125}
126