Coverage Report

Created: 2024-02-28 06:46

/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
/* --------------------------------------------*/