1 | #include "mupdf/fitz.h" |
2 | |
3 | #include <zlib.h> |
4 | |
5 | #include <string.h> |
6 | |
7 | typedef struct fz_inflate_state_s fz_inflate_state; |
8 | |
9 | struct fz_inflate_state_s |
10 | { |
11 | fz_stream *chain; |
12 | z_stream z; |
13 | unsigned char buffer[4096]; |
14 | }; |
15 | |
16 | void *fz_zlib_alloc(void *ctx, unsigned int items, unsigned int size) |
17 | { |
18 | return fz_malloc_no_throw(ctx, items * size); |
19 | } |
20 | |
21 | void fz_zlib_free(void *ctx, void *ptr) |
22 | { |
23 | fz_free(ctx, ptr); |
24 | } |
25 | |
26 | static int |
27 | next_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 | |
88 | static void |
89 | close_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 | |
102 | fz_stream * |
103 | fz_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 | |