Leptonica 1.68
C Image Processing Library

bbuffer.c

Go to the documentation of this file.
00001 /*====================================================================*
00002  -  Copyright (C) 2001 Leptonica.  All rights reserved.
00003  -  This software is distributed in the hope that it will be
00004  -  useful, but with NO WARRANTY OF ANY KIND.
00005  -  No author or distributor accepts responsibility to anyone for the
00006  -  consequences of using this software, or for whether it serves any
00007  -  particular purpose or works at all, unless he or she says so in
00008  -  writing.  Everyone is granted permission to copy, modify and
00009  -  redistribute this source code, for commercial or non-commercial
00010  -  purposes, with the following restrictions: (1) the origin of this
00011  -  source code must not be misrepresented; (2) modified versions must
00012  -  be plainly marked as such; and (3) this notice may not be removed
00013  -  or altered from any source or modified source distribution.
00014  *====================================================================*/
00015 
00016 /*
00017  *   bbuffer.c
00018  *
00019  *      Create/Destroy BBuffer
00020  *          BBUFFER   *bbufferCreate()
00021  *          void      *bbufferDestroy()
00022  *          l_uint8   *bbufferDestroyAndSaveData()
00023  *
00024  *      Operations to read data TO a BBuffer
00025  *          l_int32    bbufferRead()
00026  *          l_int32    bbufferReadStream()
00027  *          l_int32    bbufferExtendArray()
00028  *
00029  *      Operations to write data FROM a BBuffer
00030  *          l_int32    bbufferWrite()
00031  *          l_int32    bbufferWriteStream()
00032  *
00033  *      Accessors
00034  *          l_int32    bbufferBytesToWrite()
00035  *
00036  *
00037  *    The bbuffer is an implementation of a byte queue.
00038  *    The bbuffer holds a byte array from which bytes are
00039  *    processed in a first-in/first-out fashion.  As with
00040  *    any queue, bbuffer maintains two "pointers," one to the
00041  *    tail of the queue (where you read new bytes onto it)
00042  *    and one to the head of the queue (where you start from
00043  *    when writing bytes out of it. 
00044  *
00045  *    The queue can be visualized:
00046  *
00047  *      
00048  *  byte 0                                           byte (nalloc - 1)
00049  *       |                                                |
00050  *       --------------------------------------------------
00051  *                 H                             T
00052  *       [   aw   ][  bytes currently on queue  ][  anr   ] 
00053  *    
00054  *       ---:  all allocated data in bbuffer
00055  *       H:    queue head (ptr to next byte to be written out)
00056  *       T:    queue tail (ptr to first byte to be written to) 
00057  *       aw:   already written from queue
00058  *       anr:  allocated but not yet read to
00059  *
00060  *    The purpose of bbuffer is to allow you to safely read
00061  *    bytes in, and to sequentially write them out as well.
00062  *    In the process of writing bytes out, you don't actually
00063  *    remove the bytes in the array; you just move the pointer
00064  *    (nwritten) which points to the head of the queue.  In
00065  *    the process of reading bytes in, you sometimes need to
00066  *    expand the array size.  If a read is performed after a
00067  *    write, so that the head of the queue is not at the
00068  *    beginning of the array, the bytes already written are
00069  *    first removed by copying the others over them; then the
00070  *    new bytes are read onto the tail of the queue.
00071  *
00072  *    Note that the meaning of "read into" and "write from"
00073  *    the bbuffer is OPPOSITE to that for a stream, where
00074  *    you read "from" a stream and write "into" a stream.
00075  *    As a mnemonic for remembering the direction:
00076  *        - to read bytes from a stream into the bbuffer,
00077  *          you call fread on the stream
00078  *        - to write bytes from the bbuffer into a stream,
00079  *          you call fwrite on the stream
00080  *
00081  *    See zlibmem.c for an example use of bbuffer, where we
00082  *    compress and decompress an array of bytes in memory.
00083  */
00084 
00085 #include <string.h>
00086 #include "allheaders.h"
00087 
00088 static const l_int32  INITIAL_BUFFER_ARRAYSIZE = 1024;   /* n'importe quoi */
00089 
00090 
00091 /*--------------------------------------------------------------------------*
00092  *                         BBuffer create/destroy                           *
00093  *--------------------------------------------------------------------------*/
00094 /*!
00095  *  bbufferCreate()
00096  *
00097  *      Input:  buffer address in memory (<optional>)
00098  *              size of byte array to be alloc'd (0 for default)
00099  *      Return: bbuffer, or null on error
00100  *
00101  *  Notes:
00102  *      (1) If a buffer address is given, you should read all the data in.
00103  *      (2) Allocates a bbuffer with associated byte array of
00104  *          the given size.  If a buffer address is given,
00105  *          it then reads the number of bytes into the byte array.
00106  */
00107 BBUFFER *
00108 bbufferCreate(l_uint8  *indata,
00109               l_int32   nalloc)
00110 {
00111 BBUFFER  *bb;
00112 
00113     PROCNAME("bbufferCreate");
00114 
00115     if (nalloc <= 0)
00116         nalloc = INITIAL_BUFFER_ARRAYSIZE;
00117 
00118     if ((bb = (BBUFFER *)CALLOC(1, sizeof(BBUFFER))) == NULL)
00119         return (BBUFFER *)ERROR_PTR("bb not made", procName, NULL);
00120     if ((bb->array = (l_uint8 *)CALLOC(nalloc, sizeof(l_uint8))) == NULL)
00121         return (BBUFFER *)ERROR_PTR("byte array not made", procName, NULL);
00122     bb->nalloc = nalloc;
00123     bb->nwritten = 0;
00124 
00125     if (indata) {
00126         memcpy((l_uint8 *)bb->array, indata, nalloc);
00127         bb->n = nalloc;
00128     }
00129     else
00130         bb->n = 0;
00131 
00132     return bb;
00133 }
00134 
00135 
00136 /*!
00137  *  bbufferDestroy()
00138  *
00139  *      Input:  &bbuffer  (<to be nulled>)
00140  *      Return: void
00141  *
00142  *  Notes:
00143  *      (1) Destroys the byte array in the bbuffer and then the bbuffer;
00144  *          then nulls the contents of the input ptr.
00145  */
00146 void
00147 bbufferDestroy(BBUFFER  **pbb)
00148 {
00149 BBUFFER  *bb;
00150 
00151     PROCNAME("bbufferDestroy");
00152 
00153     if (pbb == NULL) {
00154         L_WARNING("ptr address is NULL", procName);
00155         return;
00156     }
00157 
00158     if ((bb = *pbb) == NULL)
00159         return;
00160 
00161     if (bb->array)
00162         FREE(bb->array);
00163     FREE(bb);
00164     *pbb = NULL;
00165 
00166     return;
00167 }
00168 
00169 
00170 /*!
00171  *  bbufferDestroyAndSaveData()
00172  *
00173  *      Input:  &bbuffer (<to be nulled>)
00174  *              &nbytes  (<return> number of bytes saved in array)
00175  *      Return: barray (newly allocated array of data)
00176  *
00177  *  Notes:
00178  *      (1) Copies data to newly allocated array; then destroys the bbuffer.
00179  */
00180 l_uint8 *
00181 bbufferDestroyAndSaveData(BBUFFER  **pbb,
00182                           size_t    *pnbytes)
00183 {
00184 l_uint8  *array;
00185 size_t    nbytes;
00186 BBUFFER  *bb;
00187 
00188     PROCNAME("bbufferDestroyAndSaveData");
00189 
00190     if (pbb == NULL) {
00191         L_WARNING("ptr address is NULL", procName);
00192         return NULL;
00193     }
00194     if (pnbytes == NULL) {
00195         L_WARNING("&nbytes is NULL", procName);
00196         bbufferDestroy(pbb);
00197         return NULL;
00198     }
00199 
00200     if ((bb = *pbb) == NULL)
00201         return NULL;
00202 
00203         /* write all unwritten bytes out to a new array */
00204     nbytes = bb->n - bb->nwritten;
00205     *pnbytes = nbytes;
00206     if ((array = (l_uint8 *)CALLOC(nbytes, sizeof(l_uint8))) == NULL) {
00207         L_WARNING("calloc failure for array", procName);
00208         return NULL;
00209     }
00210     memcpy((void *)array, (void *)(bb->array + bb->nwritten), nbytes);
00211 
00212     bbufferDestroy(pbb);
00213     return array;
00214 }
00215 
00216 
00217         
00218 /*--------------------------------------------------------------------------*
00219  *                   Operations to read data INTO a BBuffer                 *
00220  *--------------------------------------------------------------------------*/
00221 /*!
00222  *  bbufferRead()
00223  *
00224  *      Input:  bbuffer
00225  *              src      (source memory buffer from which bytes are read)
00226  *              nbytes   (bytes to be read)
00227  *      Return: 0 if OK, 1 on error
00228  *
00229  *  Notes:
00230  *      (1) For a read after write, first remove the written
00231  *          bytes by shifting the unwritten bytes in the array,
00232  *          then check if there is enough room to add the new bytes.
00233  *          If not, realloc with bbufferExpandArray(), resulting
00234  *          in a second writing of the unwritten bytes.  While less
00235  *          efficient, this is simpler than making a special case
00236  *          of reallocNew().
00237  */
00238 l_int32
00239 bbufferRead(BBUFFER  *bb,
00240             l_uint8  *src,
00241             l_int32   nbytes)
00242 {
00243 l_int32  navail, nadd, nwritten;
00244 
00245     PROCNAME("bbufferRead");
00246 
00247     if (!bb)
00248         return ERROR_INT("bb not defined", procName, 1);
00249     if (!src)
00250         return ERROR_INT("src not defined", procName, 1);
00251     if (nbytes == 0)
00252         return ERROR_INT("no bytes to read", procName, 1);
00253     
00254     if ((nwritten = bb->nwritten)) {  /* move the unwritten bytes over */
00255         memmove((l_uint8 *)bb->array, (l_uint8 *)(bb->array + nwritten),
00256                  bb->n - nwritten);
00257         bb->nwritten = 0;
00258         bb->n -= nwritten;
00259     }
00260 
00261         /* If necessary, expand the allocated array.  Do so by
00262          * by at least a factor of two. */
00263     navail = bb->nalloc - bb->n;
00264     if (nbytes > navail) {
00265         nadd = L_MAX(bb->nalloc, nbytes);
00266         bbufferExtendArray(bb, nadd);
00267     }
00268 
00269         /* Read in the new bytes */
00270     memcpy((l_uint8 *)(bb->array + bb->n), src, nbytes);
00271     bb->n += nbytes;
00272 
00273     return 0;
00274 }
00275 
00276 
00277 /*!
00278  *  bbufferReadStream()
00279  *
00280  *      Input:  bbuffer
00281  *              fp      (source stream from which bytes are read)
00282  *              nbytes   (bytes to be read)
00283  *      Return: 0 if OK, 1 on error
00284  */
00285 l_int32
00286 bbufferReadStream(BBUFFER  *bb,
00287                   FILE     *fp,
00288                   l_int32   nbytes)
00289 {
00290 l_int32  navail, nadd, nread, nwritten;
00291 
00292     PROCNAME("bbufferReadStream");
00293 
00294     if (!bb)
00295         return ERROR_INT("bb not defined", procName, 1);
00296     if (!fp)
00297         return ERROR_INT("fp not defined", procName, 1);
00298     if (nbytes == 0)
00299         return ERROR_INT("no bytes to read", procName, 1);
00300     
00301     if ((nwritten = bb->nwritten)) {  /* move any unwritten bytes over */
00302         memmove((l_uint8 *)bb->array, (l_uint8 *)(bb->array + nwritten),
00303                  bb->n - nwritten);
00304         bb->nwritten = 0;
00305         bb->n -= nwritten;
00306     }
00307 
00308         /* If necessary, expand the allocated array.  Do so by
00309          * by at least a factor of two. */
00310     navail = bb->nalloc - bb->n;
00311     if (nbytes > navail) {
00312         nadd = L_MAX(bb->nalloc, nbytes);
00313         bbufferExtendArray(bb, nadd);
00314     }
00315 
00316         /* Read in the new bytes */
00317     nread = fread((void *)(bb->array + bb->n), 1, nbytes, fp);
00318     bb->n += nread;
00319 
00320     return 0;
00321 }
00322 
00323 
00324 /*!
00325  *  bbufferExtendArray()
00326  *
00327  *      Input:  bbuffer
00328  *              nbytes  (number of bytes to extend array size)
00329  *      Return: 0 if OK, 1 on error
00330  *
00331  *  Notes:
00332  *      (1) reallocNew() copies all bb->nalloc bytes, even though
00333  *          only bb->n are data.
00334  */
00335 l_int32
00336 bbufferExtendArray(BBUFFER  *bb,
00337                    l_int32   nbytes)
00338 {
00339     PROCNAME("bbufferExtendArray");
00340 
00341     if (!bb)
00342         return ERROR_INT("bb not defined", procName, 1);
00343 
00344     if ((bb->array = (l_uint8 *)reallocNew((void **)&bb->array,
00345                                 bb->nalloc,
00346                                 bb->nalloc + nbytes)) == NULL)
00347             return ERROR_INT("new ptr array not returned", procName, 1);
00348 
00349     bb->nalloc += nbytes;
00350     return 0;
00351 }
00352 
00353 
00354 
00355 /*--------------------------------------------------------------------------*
00356  *                  Operations to write data FROM a BBuffer                 *
00357  *--------------------------------------------------------------------------*/
00358 /*!
00359  *  bbufferWrite()
00360  *
00361  *      Input:  bbuffer
00362  *              dest     (dest memory buffer to which bytes are written)
00363  *              nbytes   (bytes requested to be written)
00364  *              &nout    (<return> bytes actually written)
00365  *      Return: 0 if OK, 1 on error
00366  */
00367 l_int32
00368 bbufferWrite(BBUFFER  *bb,
00369              l_uint8  *dest,
00370              size_t    nbytes,
00371              size_t   *pnout)
00372 {
00373 l_int32  nleft, nout;
00374 
00375     PROCNAME("bbufferWrite");
00376 
00377     if (!bb)
00378         return ERROR_INT("bb not defined", procName, 1);
00379     if (!dest)
00380         return ERROR_INT("dest not defined", procName, 1);
00381     if (nbytes <= 0)
00382         return ERROR_INT("no bytes requested to write", procName, 1);
00383     if (!pnout)
00384         return ERROR_INT("&nout not defined", procName, 1);
00385     
00386     nleft = bb->n - bb->nwritten;
00387     nout = L_MIN(nleft, nbytes);
00388     *pnout = nout;
00389 
00390     if (nleft == 0) {   /* nothing to write; reinitialize the buffer */
00391         bb->n = 0;
00392         bb->nwritten = 0;
00393         return 0;
00394     }
00395 
00396         /* nout > 0; transfer the data out */
00397     memcpy(dest, (l_uint8 *)(bb->array + bb->nwritten), nout);
00398     bb->nwritten += nout;
00399 
00400         /* If all written; "empty" the buffer */
00401     if (nout == nleft) { 
00402         bb->n = 0;
00403         bb->nwritten = 0;
00404     }
00405 
00406     return 0;
00407 }
00408 
00409 
00410 /*!
00411  *  bbufferWriteStream()
00412  *
00413  *      Input:  bbuffer
00414  *              fp       (dest stream to which bytes are written)
00415  *              nbytes   (bytes requested to be written)
00416  *              &nout    (<return> bytes actually written)
00417  *      Return: 0 if OK, 1 on error
00418  */
00419 l_int32
00420 bbufferWriteStream(BBUFFER  *bb,
00421                    FILE     *fp,
00422                    size_t    nbytes,
00423                    size_t   *pnout)
00424 {
00425 l_int32  nleft, nout;
00426 
00427     PROCNAME("bbufferWriteStream");
00428 
00429     if (!bb)
00430         return ERROR_INT("bb not defined", procName, 1);
00431     if (!fp)
00432         return ERROR_INT("output stream not defined", procName, 1);
00433     if (nbytes <= 0)
00434         return ERROR_INT("no bytes requested to write", procName, 1);
00435     if (!pnout)
00436         return ERROR_INT("&nout not defined", procName, 1);
00437     
00438     nleft = bb->n - bb->nwritten;
00439     nout = L_MIN(nleft, nbytes);
00440     *pnout = nout;
00441 
00442     if (nleft == 0) {   /* nothing to write; reinitialize the buffer */
00443         bb->n = 0;
00444         bb->nwritten = 0;
00445         return 0;
00446     }
00447 
00448         /* nout > 0; transfer the data out */
00449     fwrite((void *)(bb->array + bb->nwritten), 1, nout, fp);
00450     bb->nwritten += nout;
00451 
00452         /* If all written; "empty" the buffer */
00453     if (nout == nleft) { 
00454         bb->n = 0;
00455         bb->nwritten = 0;
00456     }
00457 
00458     return 0;
00459 }
00460 
00461 
00462 
00463 /*--------------------------------------------------------------------------*
00464  *                                  Accessors                               *
00465  *--------------------------------------------------------------------------*/
00466 /*!
00467  *  bbufferBytesToWrite()
00468  *
00469  *      Input:  bbuffer
00470  *              &nbytes (<return>)
00471  *      Return: 0 if OK; 1 on error
00472  */
00473 l_int32
00474 bbufferBytesToWrite(BBUFFER  *bb,
00475                     size_t   *pnbytes)
00476 {
00477     PROCNAME("bbufferBytesToWrite");
00478 
00479     if (!bb)
00480         return ERROR_INT("bb not defined", procName, 1);
00481     if (!pnbytes)
00482         return ERROR_INT("&nbytes not defined", procName, 1);
00483 
00484     *pnbytes = bb->n - bb->nwritten;
00485     return 0;
00486 }
00487         
00488 
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Defines