• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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  *   bbuffer.c
18  *
19  *      Create/Destroy BBuffer
20  *          BBUFFER   *bbufferCreate()
21  *          void      *bbufferDestroy()
22  *          l_uint8   *bbufferDestroyAndSaveData()
23  *
24  *      Operations to read data TO a BBuffer
25  *          l_int32    bbufferRead()
26  *          l_int32    bbufferReadStream()
27  *          l_int32    bbufferExtendArray()
28  *
29  *      Operations to write data FROM a BBuffer
30  *          l_int32    bbufferWrite()
31  *          l_int32    bbufferWriteStream()
32  *
33  *      Accessors
34  *          l_int32    bbufferBytesToWrite()
35  *
36  *
37  *    The bbuffer is an implementation of a byte queue.
38  *    The bbuffer holds a byte array from which bytes are
39  *    processed in a first-in/first-out fashion.  As with
40  *    any queue, bbuffer maintains two "pointers," one to the
41  *    tail of the queue (where you read new bytes onto it)
42  *    and one to the head of the queue (where you start from
43  *    when writing bytes out of it.
44  *
45  *    The queue can be visualized:
46  *
47  *
48  *  byte 0                                           byte (nalloc - 1)
49  *       |                                                |
50  *       --------------------------------------------------
51  *                 H                             T
52  *       [   aw   ][  bytes currently on queue  ][  anr   ]
53  *
54  *       ---:  all allocated data in bbuffer
55  *       H:    queue head (ptr to next byte to be written out)
56  *       T:    queue tail (ptr to first byte to be written to)
57  *       aw:   already written from queue
58  *       anr:  allocated but not yet read to
59  *
60  *    The purpose of bbuffer is to allow you to safely read
61  *    bytes in, and to sequentially write them out as well.
62  *    In the process of writing bytes out, you don't actually
63  *    remove the bytes in the array; you just move the pointer
64  *    (nwritten) which points to the head of the queue.  In
65  *    the process of reading bytes in, you sometimes need to
66  *    expand the array size.  If a read is performed after a
67  *    write, so that the head of the queue is not at the
68  *    beginning of the array, the bytes already written are
69  *    first removed by copying the others over them; then the
70  *    new bytes are read onto the tail of the queue.
71  *
72  *    Note that the meaning of "read into" and "write from"
73  *    the bbuffer is OPPOSITE to that for a stream, where
74  *    you read "from" a stream and write "into" a stream.
75  *    As a mnemonic for remembering the direction:
76  *        - to read bytes from a stream into the bbuffer,
77  *          you call fread on the stream
78  *        - to write bytes from the bbuffer into a stream,
79  *          you call fwrite on the stream
80  *
81  *    See zlibmem.c for an example use of bbuffer, where we
82  *    compress and decompress an array of bytes in memory.
83  */
84 
85 #include <stdio.h>
86 #include <string.h>
87 #include <stdlib.h>
88 #include "allheaders.h"
89 
90 static const l_int32  INITIAL_BUFFER_ARRAYSIZE = 1024;   /* n'importe quoi */
91 
92 
93 /*--------------------------------------------------------------------------*
94  *                         BBuffer create/destroy                           *
95  *--------------------------------------------------------------------------*/
96 /*!
97  *  bbufferCreate()
98  *
99  *      Input:  buffer address in memory (<optional>)
100  *              size of byte array to be alloc'd (0 for default)
101  *      Return: bbuffer, or null on error
102  *
103  *  Notes:
104  *      (1) If a buffer address is given, you should read all the data in.
105  *      (2) Allocates a bbuffer with associated byte array of
106  *          the given size.  If a buffer address is given,
107  *          it then reads the number of bytes into the byte array.
108  */
109 BBUFFER *
bbufferCreate(l_uint8 * indata,l_int32 nalloc)110 bbufferCreate(l_uint8  *indata,
111               l_int32   nalloc)
112 {
113 BBUFFER  *bb;
114 
115     PROCNAME("bbufferCreate");
116 
117     if (nalloc <= 0)
118         nalloc = INITIAL_BUFFER_ARRAYSIZE;
119 
120     if ((bb = (BBUFFER *)CALLOC(1, sizeof(BBUFFER))) == NULL)
121         return (BBUFFER *)ERROR_PTR("bb not made", procName, NULL);
122     if ((bb->array = (l_uint8 *)CALLOC(nalloc, sizeof(l_uint8))) == NULL)
123         return (BBUFFER *)ERROR_PTR("byte array not made", procName, NULL);
124     bb->nalloc = nalloc;
125     bb->nwritten = 0;
126 
127     if (indata) {
128         memcpy((l_uint8 *)bb->array, indata, nalloc);
129         bb->n = nalloc;
130     }
131     else
132         bb->n = 0;
133 
134     return bb;
135 }
136 
137 
138 /*!
139  *  bbufferDestroy()
140  *
141  *      Input:  &bbuffer  (<to be nulled>)
142  *      Return: void
143  *
144  *  Notes:
145  *      (1) Destroys the byte array in the bbuffer and then the bbuffer;
146  *          then nulls the contents of the input ptr.
147  */
148 void
bbufferDestroy(BBUFFER ** pbb)149 bbufferDestroy(BBUFFER  **pbb)
150 {
151 BBUFFER  *bb;
152 
153     PROCNAME("bbufferDestroy");
154 
155     if (pbb == NULL) {
156         L_WARNING("ptr address is NULL", procName);
157         return;
158     }
159 
160     if ((bb = *pbb) == NULL)
161         return;
162 
163     if (bb->array)
164         FREE(bb->array);
165     FREE(bb);
166     *pbb = NULL;
167 
168     return;
169 }
170 
171 
172 /*!
173  *  bbufferDestroyAndSaveData()
174  *
175  *      Input:  &bbuffer (<to be nulled>)
176  *              &nbytes  (<return> number of bytes saved in array)
177  *      Return: barray (newly allocated array of data)
178  *
179  *  Notes:
180  *      (1) Copies data to newly allocated array; then destroys the bbuffer.
181  */
182 l_uint8 *
bbufferDestroyAndSaveData(BBUFFER ** pbb,l_int32 * pnbytes)183 bbufferDestroyAndSaveData(BBUFFER  **pbb,
184                           l_int32   *pnbytes)
185 {
186 l_uint8  *array;
187 l_int32   nbytes;
188 BBUFFER  *bb;
189 
190     PROCNAME("bbufferDestroyAndSaveData");
191 
192     if (pbb == NULL) {
193         L_WARNING("ptr address is NULL", procName);
194         return NULL;
195     }
196     if (pnbytes == NULL) {
197         L_WARNING("&nbytes is NULL", procName);
198         bbufferDestroy(pbb);
199         return NULL;
200     }
201 
202     if ((bb = *pbb) == NULL)
203         return NULL;
204 
205         /* write all unwritten bytes out to a new array */
206     nbytes = bb->n - bb->nwritten;
207     *pnbytes = nbytes;
208     if ((array = (l_uint8 *)CALLOC(nbytes, sizeof(l_uint8))) == NULL) {
209         L_WARNING("calloc failure for array", procName);
210         return NULL;
211     }
212     memcpy((void *)array, (void *)(bb->array + bb->nwritten), nbytes);
213 
214     bbufferDestroy(pbb);
215     return array;
216 }
217 
218 
219 
220 /*--------------------------------------------------------------------------*
221  *                   Operations to read data INTO a BBuffer                 *
222  *--------------------------------------------------------------------------*/
223 /*!
224  *  bbufferRead()
225  *
226  *      Input:  bbuffer
227  *              src      (source memory buffer from which bytes are read)
228  *              nbytes   (bytes to be read)
229  *      Return: 0 if OK, 1 on error
230  *
231  *  Notes:
232  *      (1) For a read after write, first remove the written
233  *          bytes by shifting the unwritten bytes in the array,
234  *          then check if there is enough room to add the new bytes.
235  *          If not, realloc with bbufferExpandArray(), resulting
236  *          in a second writing of the unwritten bytes.  While less
237  *          efficient, this is simpler than making a special case
238  *          of reallocNew().
239  */
240 l_int32
bbufferRead(BBUFFER * bb,l_uint8 * src,l_int32 nbytes)241 bbufferRead(BBUFFER  *bb,
242             l_uint8  *src,
243             l_int32   nbytes)
244 {
245 l_int32  navail, nadd, nwritten;
246 
247     PROCNAME("bbufferRead");
248 
249     if (!bb)
250         return ERROR_INT("bb not defined", procName, 1);
251     if (!src)
252         return ERROR_INT("src not defined", procName, 1);
253     if (nbytes == 0)
254         return ERROR_INT("no bytes to read", procName, 1);
255 
256     if ((nwritten = bb->nwritten)) {  /* move the unwritten bytes over */
257         memmove((l_uint8 *)bb->array, (l_uint8 *)(bb->array + nwritten),
258                  bb->n - nwritten);
259         bb->nwritten = 0;
260         bb->n -= nwritten;
261     }
262 
263         /* If necessary, expand the allocated array.  Do so by
264          * by at least a factor of two. */
265     navail = bb->nalloc - bb->n;
266     if (nbytes > navail) {
267         nadd = L_MAX(bb->nalloc, nbytes);
268         bbufferExtendArray(bb, nadd);
269     }
270 
271         /* Read in the new bytes */
272     memcpy((l_uint8 *)(bb->array + bb->n), src, nbytes);
273     bb->n += nbytes;
274 
275     return 0;
276 }
277 
278 
279 /*!
280  *  bbufferReadStream()
281  *
282  *      Input:  bbuffer
283  *              fp      (source stream from which bytes are read)
284  *              nbytes   (bytes to be read)
285  *      Return: 0 if OK, 1 on error
286  */
287 l_int32
bbufferReadStream(BBUFFER * bb,FILE * fp,l_int32 nbytes)288 bbufferReadStream(BBUFFER  *bb,
289                   FILE     *fp,
290                   l_int32   nbytes)
291 {
292 l_int32  navail, nadd, nread, nwritten;
293 
294     PROCNAME("bbufferReadStream");
295 
296     if (!bb)
297         return ERROR_INT("bb not defined", procName, 1);
298     if (!fp)
299         return ERROR_INT("fp not defined", procName, 1);
300     if (nbytes == 0)
301         return ERROR_INT("no bytes to read", procName, 1);
302 
303     if ((nwritten = bb->nwritten)) {  /* move any unwritten bytes over */
304         memmove((l_uint8 *)bb->array, (l_uint8 *)(bb->array + nwritten),
305                  bb->n - nwritten);
306         bb->nwritten = 0;
307         bb->n -= nwritten;
308     }
309 
310         /* If necessary, expand the allocated array.  Do so by
311          * by at least a factor of two. */
312     navail = bb->nalloc - bb->n;
313     if (nbytes > navail) {
314         nadd = L_MAX(bb->nalloc, nbytes);
315         bbufferExtendArray(bb, nadd);
316     }
317 
318         /* Read in the new bytes */
319     nread = fread((void *)(bb->array + bb->n), 1, nbytes, fp);
320     bb->n += nread;
321 
322     return 0;
323 }
324 
325 
326 /*!
327  *  bbufferExtendArray()
328  *
329  *      Input:  bbuffer
330  *              nbytes  (number of bytes to extend array size)
331  *      Return: 0 if OK, 1 on error
332  *
333  *  Notes:
334  *      (1) reallocNew() copies all bb->nalloc bytes, even though
335  *          only bb->n are data.
336  */
337 l_int32
bbufferExtendArray(BBUFFER * bb,l_int32 nbytes)338 bbufferExtendArray(BBUFFER  *bb,
339                    l_int32   nbytes)
340 {
341     PROCNAME("bbufferExtendArray");
342 
343     if (!bb)
344         return ERROR_INT("bb not defined", procName, 1);
345 
346     if ((bb->array = (l_uint8 *)reallocNew((void **)&bb->array,
347                                 bb->nalloc,
348                                 bb->nalloc + nbytes)) == NULL)
349             return ERROR_INT("new ptr array not returned", procName, 1);
350 
351     bb->nalloc += nbytes;
352     return 0;
353 }
354 
355 
356 
357 /*--------------------------------------------------------------------------*
358  *                  Operations to write data FROM a BBuffer                 *
359  *--------------------------------------------------------------------------*/
360 /*!
361  *  bbufferWrite()
362  *
363  *      Input:  bbuffer
364  *              dest     (dest memory buffer to which bytes are written)
365  *              nbytes   (bytes requested to be written)
366  *              &nout    (<return> bytes actually written)
367  *      Return: 0 if OK, 1 on error
368  */
369 l_int32
bbufferWrite(BBUFFER * bb,l_uint8 * dest,l_int32 nbytes,l_int32 * pnout)370 bbufferWrite(BBUFFER  *bb,
371              l_uint8  *dest,
372              l_int32   nbytes,
373              l_int32  *pnout)
374 {
375 l_int32  nleft, nout;
376 
377     PROCNAME("bbufferWrite");
378 
379     if (!bb)
380         return ERROR_INT("bb not defined", procName, 1);
381     if (!dest)
382         return ERROR_INT("dest not defined", procName, 1);
383     if (nbytes <= 0)
384         return ERROR_INT("no bytes requested to write", procName, 1);
385     if (!pnout)
386         return ERROR_INT("&nout not defined", procName, 1);
387 
388     nleft = bb->n - bb->nwritten;
389     nout = L_MIN(nleft, nbytes);
390     *pnout = nout;
391 
392     if (nleft == 0) {   /* nothing to write; reinitialize the buffer */
393         bb->n = 0;
394         bb->nwritten = 0;
395         return 0;
396     }
397 
398         /* nout > 0; transfer the data out */
399     memcpy(dest, (l_uint8 *)(bb->array + bb->nwritten), nout);
400     bb->nwritten += nout;
401 
402         /* If all written; "empty" the buffer */
403     if (nout == nleft) {
404         bb->n = 0;
405         bb->nwritten = 0;
406     }
407 
408     return 0;
409 }
410 
411 
412 /*!
413  *  bbufferWriteStream()
414  *
415  *      Input:  bbuffer
416  *              fp       (dest stream to which bytes are written)
417  *              nbytes   (bytes requested to be written)
418  *              &nout    (<return> bytes actually written)
419  *      Return: 0 if OK, 1 on error
420  */
421 l_int32
bbufferWriteStream(BBUFFER * bb,FILE * fp,l_int32 nbytes,l_int32 * pnout)422 bbufferWriteStream(BBUFFER  *bb,
423                    FILE     *fp,
424                    l_int32   nbytes,
425                    l_int32  *pnout)
426 {
427 l_int32  nleft, nout;
428 
429     PROCNAME("bbufferWriteStream");
430 
431     if (!bb)
432         return ERROR_INT("bb not defined", procName, 1);
433     if (!fp)
434         return ERROR_INT("output stream not defined", procName, 1);
435     if (nbytes <= 0)
436         return ERROR_INT("no bytes requested to write", procName, 1);
437     if (!pnout)
438         return ERROR_INT("&nout not defined", procName, 1);
439 
440     nleft = bb->n - bb->nwritten;
441     nout = L_MIN(nleft, nbytes);
442     *pnout = nout;
443 
444     if (nleft == 0) {   /* nothing to write; reinitialize the buffer */
445         bb->n = 0;
446         bb->nwritten = 0;
447         return 0;
448     }
449 
450         /* nout > 0; transfer the data out */
451     fwrite((void *)(bb->array + bb->nwritten), 1, nout, fp);
452     bb->nwritten += nout;
453 
454         /* If all written; "empty" the buffer */
455     if (nout == nleft) {
456         bb->n = 0;
457         bb->nwritten = 0;
458     }
459 
460     return 0;
461 }
462 
463 
464 
465 /*--------------------------------------------------------------------------*
466  *                                  Accessors                               *
467  *--------------------------------------------------------------------------*/
468 /*!
469  *  bbufferBytesToWrite()
470  *
471  *      Input:  bbuffer
472  *              &nbytes (<return>)
473  *      Return: 0 if OK; 1 on error
474  */
475 l_int32
bbufferBytesToWrite(BBUFFER * bb,l_int32 * pnbytes)476 bbufferBytesToWrite(BBUFFER  *bb,
477                     l_int32  *pnbytes)
478 {
479     PROCNAME("bbufferBytesToWrite");
480 
481     if (!bb)
482         return ERROR_INT("bb not defined", procName, 1);
483     if (!pnbytes)
484         return ERROR_INT("&nbytes not defined", procName, 1);
485 
486     *pnbytes = bb->n - bb->nwritten;
487     return 0;
488 }
489 
490 
491