1 /*====================================================================*
2 - Copyright (C) 2001 Leptonica. All rights reserved.
3 - This software is distributed in the hope that it will be
4 - useful, but with NO WARRANTY OF ANY KIND.
5 - No author or distributor accepts responsibility to anyone for the
6 - consequences of using this software, or for whether it serves any
7 - particular purpose or works at all, unless he or she says so in
8 - writing. Everyone is granted permission to copy, modify and
9 - redistribute this source code, for commercial or non-commercial
10 - purposes, with the following restrictions: (1) the origin of this
11 - source code must not be misrepresented; (2) modified versions must
12 - be plainly marked as such; and (3) this notice may not be removed
13 - or altered from any source or modified source distribution.
14 *====================================================================*/
15
16
17 /*
18 * zlibmem.c
19 *
20 * zlib operations in memory, using bbuffer
21 * l_uint8 *zlibCompress()
22 * l_uint8 *zlibUncompress()
23 *
24 *
25 * This provides an example use of the byte buffer utility
26 * (see bbuffer.c for details of how the bbuffer works internally).
27 * We use zlib to compress and decompress a byte array from
28 * one memory buffer to another. The standard method uses streams,
29 * but here we use the bbuffer as an expandable queue of pixels
30 * for both the reading and writing sides of each operation.
31 *
32 * With memory mapping, one should be able to compress between
33 * memory buffers by using the file system to buffer everything in
34 * the background, but the bbuffer implementation is more portable.
35 */
36
37 #include <stdio.h>
38 #include <stdlib.h>
39 #include "allheaders.h"
40
41 #ifdef HAVE_CONFIG_H
42 #include "config_auto.h"
43 #endif /* HAVE_CONFIG_H */
44
45 /* --------------------------------------------*/
46 #if HAVE_LIBZ /* defined in environ.h */
47 /* --------------------------------------------*/
48
49 #include "zlib.h"
50
51 static const l_int32 L_BUF_SIZE = 32768;
52 static const l_int32 ZLIB_COMPRESSION_LEVEL = 6;
53
54
55 /*!
56 * zlibCompress()
57 *
58 * Input: datain (byte buffer with input data)
59 * nin (number of bytes of input data)
60 * &nout (<return> number of bytes of output data)
61 * Return: dataout (compressed data), or null on error
62 *
63 * Notes:
64 * (1) We repeatedly read in and fill up an input buffer,
65 * compress the data, and read it back out. zlib
66 * uses two byte buffers internally in the z_stream
67 * data structure. We use the bbuffers to feed data
68 * into the fixed bufferin, and feed it out of bufferout,
69 * in the same way that a pair of streams would normally
70 * be used if the data were being read from one file
71 * and written to another. This is done iteratively,
72 * compressing L_BUF_SIZE bytes of input data at a time.
73 */
74 l_uint8 *
zlibCompress(l_uint8 * datain,l_int32 nin,l_int32 * pnout)75 zlibCompress(l_uint8 *datain,
76 l_int32 nin,
77 l_int32 *pnout)
78 {
79 l_uint8 *dataout;
80 l_int32 status, nbytes;
81 l_uint8 *bufferin, *bufferout;
82 BBUFFER *bbin, *bbout;
83 z_stream z;
84
85 PROCNAME("zlibCompress");
86
87 if (!datain)
88 return (l_uint8 *)ERROR_PTR("datain not defined", procName, NULL);
89
90 /* Set up fixed size buffers used in z_stream */
91 if ((bufferin = (l_uint8 *)CALLOC(L_BUF_SIZE, sizeof(l_uint8))) == NULL)
92 return (l_uint8 *)ERROR_PTR("bufferin not made", procName, NULL);
93 if ((bufferout = (l_uint8 *)CALLOC(L_BUF_SIZE, sizeof(l_uint8))) == NULL)
94 return (l_uint8 *)ERROR_PTR("bufferout not made", procName, NULL);
95
96 /* Set up bbuffers and load bbin with the data */
97 if ((bbin = bbufferCreate(datain, nin)) == NULL)
98 return (l_uint8 *)ERROR_PTR("bbin not made", procName, NULL);
99 if ((bbout = bbufferCreate(NULL, 0)) == NULL)
100 return (l_uint8 *)ERROR_PTR("bbout not made", procName, NULL);
101
102 z.zalloc = (alloc_func)0;
103 z.zfree = (free_func)0;
104 z.opaque = (voidpf)0;
105
106 z.next_in = bufferin;
107 z.avail_in = 0;
108 z.next_out = bufferout;
109 z.avail_out = L_BUF_SIZE;
110
111 deflateInit(&z, ZLIB_COMPRESSION_LEVEL);
112
113 for ( ; ; ) {
114 if (z.avail_in == 0) {
115 z.next_in = bufferin;
116 bbufferWrite(bbin, bufferin, L_BUF_SIZE, &nbytes);
117 /* fprintf(stderr, " wrote %d bytes to bufferin\n", nbytes); */
118 z.avail_in = nbytes;
119 }
120 if (z.avail_in == 0)
121 break;
122 status = deflate(&z, Z_SYNC_FLUSH);
123 /* fprintf(stderr, " status is %d, bytesleft = %d, totalout = %d\n",
124 status, z.avail_out, z.total_out); */
125 nbytes = L_BUF_SIZE - z.avail_out;
126 if (nbytes) {
127 bbufferRead(bbout, bufferout, nbytes);
128 /* fprintf(stderr, " read %d bytes from bufferout\n", nbytes); */
129 }
130 z.next_out = bufferout;
131 z.avail_out = L_BUF_SIZE;
132 }
133
134 deflateEnd(&z);
135
136 bbufferDestroy(&bbin);
137 dataout = bbufferDestroyAndSaveData(&bbout, pnout);
138
139 FREE(bufferin);
140 FREE(bufferout);
141 return dataout;
142 }
143
144
145 /*!
146 * zlibUncompress()
147 *
148 * Input: datain (byte buffer with compressed input data)
149 * nin (number of bytes of input data)
150 * &nout (<return> number of bytes of output data)
151 * Return: dataout (uncompressed data), or null on error
152 *
153 * Notes:
154 * (1) See zlibCompress().
155 */
156 l_uint8 *
zlibUncompress(l_uint8 * datain,l_int32 nin,l_int32 * pnout)157 zlibUncompress(l_uint8 *datain,
158 l_int32 nin,
159 l_int32 *pnout)
160 {
161 l_uint8 *dataout;
162 l_int32 status, nbytes;
163 l_uint8 *bufferin, *bufferout;
164 BBUFFER *bbin, *bbout;
165 z_stream z;
166
167 PROCNAME("zlibUncompress");
168
169 if (!datain)
170 return (l_uint8 *)ERROR_PTR("datain not defined", procName, NULL);
171
172 if ((bufferin = (l_uint8 *)CALLOC(L_BUF_SIZE, sizeof(l_uint8))) == NULL)
173 return (l_uint8 *)ERROR_PTR("bufferin not made", procName, NULL);
174 if ((bufferout = (l_uint8 *)CALLOC(L_BUF_SIZE, sizeof(l_uint8))) == NULL)
175 return (l_uint8 *)ERROR_PTR("bufferout not made", procName, NULL);
176
177 if ((bbin = bbufferCreate(datain, nin)) == NULL)
178 return (l_uint8 *)ERROR_PTR("bbin not made", procName, NULL);
179 if ((bbout = bbufferCreate(NULL, 0)) == NULL)
180 return (l_uint8 *)ERROR_PTR("bbout not made", procName, NULL);
181
182 z.zalloc = (alloc_func)0;
183 z.zfree = (free_func)0;
184
185 z.next_in = bufferin;
186 z.avail_in = 0;
187 z.next_out = bufferout;
188 z.avail_out = L_BUF_SIZE;
189
190 inflateInit(&z);
191
192 for ( ; ; ) {
193 if (z.avail_in == 0) {
194 z.next_in = bufferin;
195 bbufferWrite(bbin, bufferin, L_BUF_SIZE, &nbytes);
196 /* fprintf(stderr, " wrote %d bytes to bufferin\n", nbytes); */
197 z.avail_in = nbytes;
198 }
199 if (z.avail_in == 0)
200 break;
201 status = inflate(&z, Z_SYNC_FLUSH);
202 /* fprintf(stderr, " status is %d, bytesleft = %d, totalout = %d\n",
203 status, z.avail_out, z.total_out); */
204 nbytes = L_BUF_SIZE - z.avail_out;
205 if (nbytes) {
206 bbufferRead(bbout, bufferout, nbytes);
207 /* fprintf(stderr, " read %d bytes from bufferout\n", nbytes); */
208 }
209 z.next_out = bufferout;
210 z.avail_out = L_BUF_SIZE;
211 }
212
213 inflateEnd(&z);
214
215 bbufferDestroy(&bbin);
216 dataout = bbufferDestroyAndSaveData(&bbout, pnout);
217
218 FREE(bufferin);
219 FREE(bufferout);
220 return dataout;
221 }
222
223 /* --------------------------------------------*/
224 #endif /* HAVE_LIBZ */
225 /* --------------------------------------------*/
226
227