/src/leptonica/src/zlibmem.c
Line | Count | Source (jump to first uncovered line) |
1 | | /*====================================================================* |
2 | | - Copyright (C) 2001 Leptonica. All rights reserved. |
3 | | - |
4 | | - Redistribution and use in source and binary forms, with or without |
5 | | - modification, are permitted provided that the following conditions |
6 | | - are met: |
7 | | - 1. Redistributions of source code must retain the above copyright |
8 | | - notice, this list of conditions and the following disclaimer. |
9 | | - 2. Redistributions in binary form must reproduce the above |
10 | | - copyright notice, this list of conditions and the following |
11 | | - disclaimer in the documentation and/or other materials |
12 | | - provided with the distribution. |
13 | | - |
14 | | - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
15 | | - ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
16 | | - LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
17 | | - A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ANY |
18 | | - CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
19 | | - EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
20 | | - PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
21 | | - PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY |
22 | | - OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING |
23 | | - NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
24 | | - SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
25 | | *====================================================================*/ |
26 | | |
27 | | |
28 | | /*! |
29 | | * \file zlibmem.c |
30 | | * <pre> |
31 | | * |
32 | | * zlib operations in memory, using bbuffer |
33 | | * l_uint8 *zlibCompress() |
34 | | * l_uint8 *zlibUncompress() |
35 | | * |
36 | | * |
37 | | * This provides an example use of the byte buffer utility |
38 | | * (see bbuffer.c for details of how the bbuffer works internally). |
39 | | * We use zlib to compress and decompress a byte array from |
40 | | * one memory buffer to another. The standard method uses streams, |
41 | | * but here we use the bbuffer as an expandable queue of pixels |
42 | | * for both the reading and writing sides of each operation. |
43 | | * |
44 | | * With memory mapping, one should be able to compress between |
45 | | * memory buffers by using the file system to buffer everything in |
46 | | * the background, but the bbuffer implementation is more portable. |
47 | | * </pre> |
48 | | */ |
49 | | |
50 | | #ifdef HAVE_CONFIG_H |
51 | | #include <config_auto.h> |
52 | | #endif /* HAVE_CONFIG_H */ |
53 | | |
54 | | #include "allheaders.h" |
55 | | |
56 | | /* --------------------------------------------*/ |
57 | | #if HAVE_LIBZ /* defined in environ.h */ |
58 | | /* --------------------------------------------*/ |
59 | | |
60 | | #include "zlib.h" |
61 | | |
62 | | static const l_int32 L_BUF_SIZE = 32768; |
63 | | static const l_int32 ZLIB_COMPRESSION_LEVEL = 6; |
64 | | |
65 | | #ifndef NO_CONSOLE_IO |
66 | | #define DEBUG 0 |
67 | | #endif /* ~NO_CONSOLE_IO */ |
68 | | |
69 | | |
70 | | /*! |
71 | | * \brief zlibCompress() |
72 | | * |
73 | | * \param[in] datain byte buffer with input data |
74 | | * \param[in] nin number of bytes of input data |
75 | | * \param[out] pnout number of bytes of output data |
76 | | * \return dataout compressed data, or NULL on error |
77 | | * |
78 | | * <pre> |
79 | | * Notes: |
80 | | * (1) We repeatedly read in and fill up an input buffer, |
81 | | * compress the data, and read it back out. zlib |
82 | | * uses two byte buffers internally in the z_stream |
83 | | * data structure. We use the bbuffers to feed data |
84 | | * into the fixed bufferin, and feed it out of bufferout, |
85 | | * in the same way that a pair of streams would normally |
86 | | * be used if the data were being read from one file |
87 | | * and written to another. This is done iteratively, |
88 | | * compressing L_BUF_SIZE bytes of input data at a time. |
89 | | * </pre> |
90 | | */ |
91 | | l_uint8 * |
92 | | zlibCompress(const l_uint8 *datain, |
93 | | size_t nin, |
94 | | size_t *pnout) |
95 | 0 | { |
96 | 0 | l_uint8 *dataout; |
97 | 0 | l_int32 status, success; |
98 | 0 | l_int32 flush; |
99 | 0 | size_t nbytes; |
100 | 0 | l_uint8 *bufferin, *bufferout; |
101 | 0 | L_BBUFFER *bbin, *bbout; |
102 | 0 | z_stream z; |
103 | |
|
104 | 0 | if (!datain) |
105 | 0 | return (l_uint8 *)ERROR_PTR("datain not defined", __func__, NULL); |
106 | | |
107 | | /* Set up fixed size buffers used in z_stream */ |
108 | 0 | bufferin = (l_uint8 *)LEPT_CALLOC(L_BUF_SIZE, sizeof(l_uint8)); |
109 | 0 | bufferout = (l_uint8 *)LEPT_CALLOC(L_BUF_SIZE, sizeof(l_uint8)); |
110 | | |
111 | | /* Set up bbuffers and load bbin with the data */ |
112 | 0 | bbin = bbufferCreate(datain, nin); |
113 | 0 | bbout = bbufferCreate(NULL, 0); |
114 | |
|
115 | 0 | success = TRUE; |
116 | 0 | if (!bufferin || !bufferout || !bbin || !bbout) { |
117 | 0 | L_ERROR("calloc fail for buffer\n", __func__); |
118 | 0 | success = FALSE; |
119 | 0 | goto cleanup_arrays; |
120 | 0 | } |
121 | | |
122 | 0 | z.zalloc = (alloc_func)0; |
123 | 0 | z.zfree = (free_func)0; |
124 | 0 | z.opaque = (voidpf)0; |
125 | 0 | z.next_in = bufferin; |
126 | 0 | z.avail_in = 0; |
127 | 0 | z.next_out = bufferout; |
128 | 0 | z.avail_out = L_BUF_SIZE; |
129 | |
|
130 | 0 | status = deflateInit(&z, ZLIB_COMPRESSION_LEVEL); |
131 | 0 | if (status != Z_OK) { |
132 | 0 | L_ERROR("deflateInit failed\n", __func__); |
133 | 0 | success = FALSE; |
134 | 0 | goto cleanup_arrays; |
135 | 0 | } |
136 | | |
137 | 0 | do { |
138 | 0 | if (z.avail_in == 0) { |
139 | 0 | z.next_in = bufferin; |
140 | 0 | bbufferWrite(bbin, bufferin, L_BUF_SIZE, &nbytes); |
141 | | #if DEBUG |
142 | | lept_stderr(" wrote %zu bytes to bufferin\n", nbytes); |
143 | | #endif /* DEBUG */ |
144 | 0 | z.avail_in = nbytes; |
145 | 0 | } |
146 | 0 | flush = (bbin->n) ? Z_SYNC_FLUSH : Z_FINISH; |
147 | 0 | status = deflate(&z, flush); |
148 | | #if DEBUG |
149 | | lept_stderr(" status is %d, bytesleft = %u, totalout = %zu\n", |
150 | | status, z.avail_out, z.total_out); |
151 | | #endif /* DEBUG */ |
152 | 0 | nbytes = L_BUF_SIZE - z.avail_out; |
153 | 0 | if (nbytes) { |
154 | 0 | bbufferRead(bbout, bufferout, nbytes); |
155 | | #if DEBUG |
156 | | lept_stderr(" read %zu bytes from bufferout\n", nbytes); |
157 | | #endif /* DEBUG */ |
158 | 0 | } |
159 | 0 | z.next_out = bufferout; |
160 | 0 | z.avail_out = L_BUF_SIZE; |
161 | 0 | } while (flush != Z_FINISH); |
162 | |
|
163 | 0 | deflateEnd(&z); |
164 | |
|
165 | 0 | cleanup_arrays: |
166 | 0 | if (success) { |
167 | 0 | dataout = bbufferDestroyAndSaveData(&bbout, pnout); |
168 | 0 | } else { |
169 | 0 | dataout = NULL; |
170 | 0 | bbufferDestroy(&bbout); |
171 | 0 | } |
172 | 0 | bbufferDestroy(&bbin); |
173 | 0 | LEPT_FREE(bufferin); |
174 | 0 | LEPT_FREE(bufferout); |
175 | 0 | return dataout; |
176 | 0 | } |
177 | | |
178 | | |
179 | | /*! |
180 | | * \brief zlibUncompress() |
181 | | * |
182 | | * \param[in] datain byte buffer with compressed input data |
183 | | * \param[in] nin number of bytes of input data |
184 | | * \param[out] pnout number of bytes of output data |
185 | | * \return dataout uncompressed data, or NULL on error |
186 | | * |
187 | | * <pre> |
188 | | * Notes: |
189 | | * (1) See zlibCompress(). |
190 | | * </pre> |
191 | | */ |
192 | | l_uint8 * |
193 | | zlibUncompress(const l_uint8 *datain, |
194 | | size_t nin, |
195 | | size_t *pnout) |
196 | 0 | { |
197 | 0 | l_uint8 *dataout; |
198 | 0 | l_uint8 *bufferin, *bufferout; |
199 | 0 | l_int32 status, success; |
200 | 0 | size_t nbytes; |
201 | 0 | L_BBUFFER *bbin, *bbout; |
202 | 0 | z_stream z; |
203 | |
|
204 | 0 | if (!datain) |
205 | 0 | return (l_uint8 *)ERROR_PTR("datain not defined", __func__, NULL); |
206 | | |
207 | | /* Set up fixed size buffers used in z_stream */ |
208 | 0 | bufferin = (l_uint8 *)LEPT_CALLOC(L_BUF_SIZE, sizeof(l_uint8)); |
209 | 0 | bufferout = (l_uint8 *)LEPT_CALLOC(L_BUF_SIZE, sizeof(l_uint8)); |
210 | | |
211 | | /* Set up bbuffers and load bbin with the data */ |
212 | 0 | bbin = bbufferCreate(datain, nin); |
213 | 0 | bbout = bbufferCreate(NULL, 0); |
214 | |
|
215 | 0 | success = TRUE; |
216 | 0 | if (!bufferin || !bufferout || !bbin || !bbout) { |
217 | 0 | L_ERROR("calloc fail for buffer\n", __func__); |
218 | 0 | success = FALSE; |
219 | 0 | goto cleanup_arrays; |
220 | 0 | } |
221 | | |
222 | 0 | z.zalloc = (alloc_func)0; |
223 | 0 | z.zfree = (free_func)0; |
224 | 0 | z.next_in = bufferin; |
225 | 0 | z.avail_in = 0; |
226 | 0 | z.next_out = bufferout; |
227 | 0 | z.avail_out = L_BUF_SIZE; |
228 | |
|
229 | 0 | status = inflateInit(&z); |
230 | 0 | if (status != Z_OK) { |
231 | 0 | L_ERROR("inflateInit fail for buffer\n", __func__); |
232 | 0 | success = FALSE; |
233 | 0 | goto cleanup_arrays; |
234 | 0 | } |
235 | | |
236 | 0 | for ( ; ; ) { |
237 | 0 | if (z.avail_in == 0) { |
238 | 0 | z.next_in = bufferin; |
239 | 0 | bbufferWrite(bbin, bufferin, L_BUF_SIZE, &nbytes); |
240 | | #if DEBUG |
241 | | lept_stderr(" wrote %d bytes to bufferin\n", nbytes); |
242 | | #endif /* DEBUG */ |
243 | 0 | z.avail_in = nbytes; |
244 | 0 | } |
245 | 0 | if (z.avail_in == 0) |
246 | 0 | break; |
247 | 0 | status = inflate(&z, Z_SYNC_FLUSH); |
248 | | #if DEBUG |
249 | | lept_stderr(" status is %d, bytesleft = %d, totalout = %d\n", |
250 | | status, z.avail_out, z.total_out); |
251 | | #endif /* DEBUG */ |
252 | 0 | nbytes = L_BUF_SIZE - z.avail_out; |
253 | 0 | if (nbytes) { |
254 | 0 | bbufferRead(bbout, bufferout, nbytes); |
255 | | #if DEBUG |
256 | | lept_stderr(" read %d bytes from bufferout\n", nbytes); |
257 | | #endif /* DEBUG */ |
258 | 0 | } |
259 | 0 | z.next_out = bufferout; |
260 | 0 | z.avail_out = L_BUF_SIZE; |
261 | 0 | } |
262 | |
|
263 | 0 | inflateEnd(&z); |
264 | |
|
265 | 0 | cleanup_arrays: |
266 | 0 | if (success) { |
267 | 0 | dataout = bbufferDestroyAndSaveData(&bbout, pnout); |
268 | 0 | } else { |
269 | 0 | dataout = NULL; |
270 | 0 | bbufferDestroy(&bbout); |
271 | 0 | } |
272 | 0 | bbufferDestroy(&bbin); |
273 | 0 | LEPT_FREE(bufferin); |
274 | 0 | LEPT_FREE(bufferout); |
275 | 0 | return dataout; |
276 | 0 | } |
277 | | |
278 | | /* --------------------------------------------*/ |
279 | | #endif /* HAVE_LIBZ */ |
280 | | /* --------------------------------------------*/ |