mirror of
https://github.com/ultimatepp/ultimatepp.git
synced 2026-05-17 14:16:10 -06:00
490 lines
14 KiB
C
490 lines
14 KiB
C
/*====================================================================*
|
|
- Copyright (C) 2001 Leptonica. All rights reserved.
|
|
- This software is distributed in the hope that it will be
|
|
- useful, but with NO WARRANTY OF ANY KIND.
|
|
- No author or distributor accepts responsibility to anyone for the
|
|
- consequences of using this software, or for whether it serves any
|
|
- particular purpose or works at all, unless he or she says so in
|
|
- writing. Everyone is granted permission to copy, modify and
|
|
- redistribute this source code, for commercial or non-commercial
|
|
- purposes, with the following restrictions: (1) the origin of this
|
|
- source code must not be misrepresented; (2) modified versions must
|
|
- be plainly marked as such; and (3) this notice may not be removed
|
|
- or altered from any source or modified source distribution.
|
|
*====================================================================*/
|
|
|
|
/*
|
|
* bbuffer.c
|
|
*
|
|
* Create/Destroy BBuffer
|
|
* BBUFFER *bbufferCreate()
|
|
* void *bbufferDestroy()
|
|
* l_uint8 *bbufferDestroyAndSaveData()
|
|
*
|
|
* Operations to read data TO a BBuffer
|
|
* l_int32 bbufferRead()
|
|
* l_int32 bbufferReadStream()
|
|
* l_int32 bbufferExtendArray()
|
|
*
|
|
* Operations to write data FROM a BBuffer
|
|
* l_int32 bbufferWrite()
|
|
* l_int32 bbufferWriteStream()
|
|
*
|
|
* Accessors
|
|
* l_int32 bbufferBytesToWrite()
|
|
*
|
|
*
|
|
* The bbuffer is an implementation of a byte queue.
|
|
* The bbuffer holds a byte array from which bytes are
|
|
* processed in a first-in/first-out fashion. As with
|
|
* any queue, bbuffer maintains two "pointers," one to the
|
|
* tail of the queue (where you read new bytes onto it)
|
|
* and one to the head of the queue (where you start from
|
|
* when writing bytes out of it.
|
|
*
|
|
* The queue can be visualized:
|
|
*
|
|
*
|
|
* byte 0 byte (nalloc - 1)
|
|
* | |
|
|
* --------------------------------------------------
|
|
* H T
|
|
* [ aw ][ bytes currently on queue ][ anr ]
|
|
*
|
|
* ---: all allocated data in bbuffer
|
|
* H: queue head (ptr to next byte to be written out)
|
|
* T: queue tail (ptr to first byte to be written to)
|
|
* aw: already written from queue
|
|
* anr: allocated but not yet read to
|
|
*
|
|
* The purpose of bbuffer is to allow you to safely read
|
|
* bytes in, and to sequentially write them out as well.
|
|
* In the process of writing bytes out, you don't actually
|
|
* remove the bytes in the array; you just move the pointer
|
|
* (nwritten) which points to the head of the queue. In
|
|
* the process of reading bytes in, you sometimes need to
|
|
* expand the array size. If a read is performed after a
|
|
* write, so that the head of the queue is not at the
|
|
* beginning of the array, the bytes already written are
|
|
* first removed by copying the others over them; then the
|
|
* new bytes are read onto the tail of the queue.
|
|
*
|
|
* Note that the meaning of "read into" and "write from"
|
|
* the bbuffer is OPPOSITE to that for a stream, where
|
|
* you read "from" a stream and write "into" a stream.
|
|
* As a mnemonic for remembering the direction:
|
|
* - to read bytes from a stream into the bbuffer,
|
|
* you call fread on the stream
|
|
* - to write bytes from the bbuffer into a stream,
|
|
* you call fwrite on the stream
|
|
*
|
|
* See zlibmem.c for an example use of bbuffer, where we
|
|
* compress and decompress an array of bytes in memory.
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <stdlib.h>
|
|
#include "allheaders.h"
|
|
|
|
static const l_int32 INITIAL_BUFFER_ARRAYSIZE = 1024; /* n'importe quoi */
|
|
|
|
|
|
/*--------------------------------------------------------------------------*
|
|
* BBuffer create/destroy *
|
|
*--------------------------------------------------------------------------*/
|
|
/*!
|
|
* bbufferCreate()
|
|
*
|
|
* Input: buffer address in memory (<optional>)
|
|
* size of byte array to be alloc'd (0 for default)
|
|
* Return: bbuffer, or null on error
|
|
*
|
|
* Notes:
|
|
* (1) If a buffer address is given, you should read all the data in.
|
|
* (2) Allocates a bbuffer with associated byte array of
|
|
* the given size. If a buffer address is given,
|
|
* it then reads the number of bytes into the byte array.
|
|
*/
|
|
BBUFFER *
|
|
bbufferCreate(l_uint8 *indata,
|
|
l_int32 nalloc)
|
|
{
|
|
BBUFFER *bb;
|
|
|
|
PROCNAME("bbufferCreate");
|
|
|
|
if (nalloc <= 0)
|
|
nalloc = INITIAL_BUFFER_ARRAYSIZE;
|
|
|
|
if ((bb = (BBUFFER *)CALLOC(1, sizeof(BBUFFER))) == NULL)
|
|
return (BBUFFER *)ERROR_PTR("bb not made", procName, NULL);
|
|
if ((bb->array = (l_uint8 *)CALLOC(nalloc, sizeof(l_uint8))) == NULL)
|
|
return (BBUFFER *)ERROR_PTR("byte array not made", procName, NULL);
|
|
bb->nalloc = nalloc;
|
|
bb->nwritten = 0;
|
|
|
|
if (indata) {
|
|
memcpy((l_uint8 *)bb->array, indata, nalloc);
|
|
bb->n = nalloc;
|
|
}
|
|
else
|
|
bb->n = 0;
|
|
|
|
return bb;
|
|
}
|
|
|
|
|
|
/*!
|
|
* bbufferDestroy()
|
|
*
|
|
* Input: &bbuffer (<to be nulled>)
|
|
* Return: void
|
|
*
|
|
* Notes:
|
|
* (1) Destroys the byte array in the bbuffer and then the bbuffer;
|
|
* then nulls the contents of the input ptr.
|
|
*/
|
|
void
|
|
bbufferDestroy(BBUFFER **pbb)
|
|
{
|
|
BBUFFER *bb;
|
|
|
|
PROCNAME("bbufferDestroy");
|
|
|
|
if (pbb == NULL) {
|
|
L_WARNING("ptr address is NULL", procName);
|
|
return;
|
|
}
|
|
|
|
if ((bb = *pbb) == NULL)
|
|
return;
|
|
|
|
if (bb->array)
|
|
FREE(bb->array);
|
|
FREE(bb);
|
|
*pbb = NULL;
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
/*!
|
|
* bbufferDestroyAndSaveData()
|
|
*
|
|
* Input: &bbuffer (<to be nulled>)
|
|
* &nbytes (<return> number of bytes saved in array)
|
|
* Return: barray (newly allocated array of data)
|
|
*
|
|
* Notes:
|
|
* (1) Copies data to newly allocated array; then destroys the bbuffer.
|
|
*/
|
|
l_uint8 *
|
|
bbufferDestroyAndSaveData(BBUFFER **pbb,
|
|
l_int32 *pnbytes)
|
|
{
|
|
l_uint8 *array;
|
|
l_int32 nbytes;
|
|
BBUFFER *bb;
|
|
|
|
PROCNAME("bbufferDestroyAndSaveData");
|
|
|
|
if (pbb == NULL) {
|
|
L_WARNING("ptr address is NULL", procName);
|
|
return NULL;
|
|
}
|
|
if (pnbytes == NULL) {
|
|
L_WARNING("&nbytes is NULL", procName);
|
|
bbufferDestroy(pbb);
|
|
return NULL;
|
|
}
|
|
|
|
if ((bb = *pbb) == NULL)
|
|
return NULL;
|
|
|
|
/* write all unwritten bytes out to a new array */
|
|
nbytes = bb->n - bb->nwritten;
|
|
*pnbytes = nbytes;
|
|
if ((array = (l_uint8 *)CALLOC(nbytes, sizeof(l_uint8))) == NULL) {
|
|
L_WARNING("calloc failure for array", procName);
|
|
return NULL;
|
|
}
|
|
memcpy((void *)array, (void *)(bb->array + bb->nwritten), nbytes);
|
|
|
|
bbufferDestroy(pbb);
|
|
return array;
|
|
}
|
|
|
|
|
|
|
|
/*--------------------------------------------------------------------------*
|
|
* Operations to read data INTO a BBuffer *
|
|
*--------------------------------------------------------------------------*/
|
|
/*!
|
|
* bbufferRead()
|
|
*
|
|
* Input: bbuffer
|
|
* src (source memory buffer from which bytes are read)
|
|
* nbytes (bytes to be read)
|
|
* Return: 0 if OK, 1 on error
|
|
*
|
|
* Notes:
|
|
* (1) For a read after write, first remove the written
|
|
* bytes by shifting the unwritten bytes in the array,
|
|
* then check if there is enough room to add the new bytes.
|
|
* If not, realloc with bbufferExpandArray(), resulting
|
|
* in a second writing of the unwritten bytes. While less
|
|
* efficient, this is simpler than making a special case
|
|
* of reallocNew().
|
|
*/
|
|
l_int32
|
|
bbufferRead(BBUFFER *bb,
|
|
l_uint8 *src,
|
|
l_int32 nbytes)
|
|
{
|
|
l_int32 navail, nadd, nwritten;
|
|
|
|
PROCNAME("bbufferRead");
|
|
|
|
if (!bb)
|
|
return ERROR_INT("bb not defined", procName, 1);
|
|
if (!src)
|
|
return ERROR_INT("src not defined", procName, 1);
|
|
if (nbytes == 0)
|
|
return ERROR_INT("no bytes to read", procName, 1);
|
|
|
|
if ((nwritten = bb->nwritten)) { /* move the unwritten bytes over */
|
|
memmove((l_uint8 *)bb->array, (l_uint8 *)(bb->array + nwritten),
|
|
bb->n - nwritten);
|
|
bb->nwritten = 0;
|
|
bb->n -= nwritten;
|
|
}
|
|
|
|
/* If necessary, expand the allocated array. Do so by
|
|
* by at least a factor of two. */
|
|
navail = bb->nalloc - bb->n;
|
|
if (nbytes > navail) {
|
|
nadd = L_MAX(bb->nalloc, nbytes);
|
|
bbufferExtendArray(bb, nadd);
|
|
}
|
|
|
|
/* Read in the new bytes */
|
|
memcpy((l_uint8 *)(bb->array + bb->n), src, nbytes);
|
|
bb->n += nbytes;
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
/*!
|
|
* bbufferReadStream()
|
|
*
|
|
* Input: bbuffer
|
|
* fp (source stream from which bytes are read)
|
|
* nbytes (bytes to be read)
|
|
* Return: 0 if OK, 1 on error
|
|
*/
|
|
l_int32
|
|
bbufferReadStream(BBUFFER *bb,
|
|
FILE *fp,
|
|
l_int32 nbytes)
|
|
{
|
|
l_int32 navail, nadd, nread, nwritten;
|
|
|
|
PROCNAME("bbufferReadStream");
|
|
|
|
if (!bb)
|
|
return ERROR_INT("bb not defined", procName, 1);
|
|
if (!fp)
|
|
return ERROR_INT("fp not defined", procName, 1);
|
|
if (nbytes == 0)
|
|
return ERROR_INT("no bytes to read", procName, 1);
|
|
|
|
if ((nwritten = bb->nwritten)) { /* move any unwritten bytes over */
|
|
memmove((l_uint8 *)bb->array, (l_uint8 *)(bb->array + nwritten),
|
|
bb->n - nwritten);
|
|
bb->nwritten = 0;
|
|
bb->n -= nwritten;
|
|
}
|
|
|
|
/* If necessary, expand the allocated array. Do so by
|
|
* by at least a factor of two. */
|
|
navail = bb->nalloc - bb->n;
|
|
if (nbytes > navail) {
|
|
nadd = L_MAX(bb->nalloc, nbytes);
|
|
bbufferExtendArray(bb, nadd);
|
|
}
|
|
|
|
/* Read in the new bytes */
|
|
nread = fread((void *)(bb->array + bb->n), 1, nbytes, fp);
|
|
bb->n += nread;
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
/*!
|
|
* bbufferExtendArray()
|
|
*
|
|
* Input: bbuffer
|
|
* nbytes (number of bytes to extend array size)
|
|
* Return: 0 if OK, 1 on error
|
|
*
|
|
* Notes:
|
|
* (1) reallocNew() copies all bb->nalloc bytes, even though
|
|
* only bb->n are data.
|
|
*/
|
|
l_int32
|
|
bbufferExtendArray(BBUFFER *bb,
|
|
l_int32 nbytes)
|
|
{
|
|
PROCNAME("bbufferExtendArray");
|
|
|
|
if (!bb)
|
|
return ERROR_INT("bb not defined", procName, 1);
|
|
|
|
if ((bb->array = (l_uint8 *)reallocNew((void **)&bb->array,
|
|
bb->nalloc,
|
|
bb->nalloc + nbytes)) == NULL)
|
|
return ERROR_INT("new ptr array not returned", procName, 1);
|
|
|
|
bb->nalloc += nbytes;
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
/*--------------------------------------------------------------------------*
|
|
* Operations to write data FROM a BBuffer *
|
|
*--------------------------------------------------------------------------*/
|
|
/*!
|
|
* bbufferWrite()
|
|
*
|
|
* Input: bbuffer
|
|
* dest (dest memory buffer to which bytes are written)
|
|
* nbytes (bytes requested to be written)
|
|
* &nout (<return> bytes actually written)
|
|
* Return: 0 if OK, 1 on error
|
|
*/
|
|
l_int32
|
|
bbufferWrite(BBUFFER *bb,
|
|
l_uint8 *dest,
|
|
l_int32 nbytes,
|
|
l_int32 *pnout)
|
|
{
|
|
l_int32 nleft, nout;
|
|
|
|
PROCNAME("bbufferWrite");
|
|
|
|
if (!bb)
|
|
return ERROR_INT("bb not defined", procName, 1);
|
|
if (!dest)
|
|
return ERROR_INT("dest not defined", procName, 1);
|
|
if (nbytes <= 0)
|
|
return ERROR_INT("no bytes requested to write", procName, 1);
|
|
if (!pnout)
|
|
return ERROR_INT("&nout not defined", procName, 1);
|
|
|
|
nleft = bb->n - bb->nwritten;
|
|
nout = L_MIN(nleft, nbytes);
|
|
*pnout = nout;
|
|
|
|
if (nleft == 0) { /* nothing to write; reinitialize the buffer */
|
|
bb->n = 0;
|
|
bb->nwritten = 0;
|
|
return 0;
|
|
}
|
|
|
|
/* nout > 0; transfer the data out */
|
|
memcpy(dest, (l_uint8 *)(bb->array + bb->nwritten), nout);
|
|
bb->nwritten += nout;
|
|
|
|
/* If all written; "empty" the buffer */
|
|
if (nout == nleft) {
|
|
bb->n = 0;
|
|
bb->nwritten = 0;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
/*!
|
|
* bbufferWriteStream()
|
|
*
|
|
* Input: bbuffer
|
|
* fp (dest stream to which bytes are written)
|
|
* nbytes (bytes requested to be written)
|
|
* &nout (<return> bytes actually written)
|
|
* Return: 0 if OK, 1 on error
|
|
*/
|
|
l_int32
|
|
bbufferWriteStream(BBUFFER *bb,
|
|
FILE *fp,
|
|
l_int32 nbytes,
|
|
l_int32 *pnout)
|
|
{
|
|
l_int32 nleft, nout;
|
|
|
|
PROCNAME("bbufferWriteStream");
|
|
|
|
if (!bb)
|
|
return ERROR_INT("bb not defined", procName, 1);
|
|
if (!fp)
|
|
return ERROR_INT("output stream not defined", procName, 1);
|
|
if (nbytes <= 0)
|
|
return ERROR_INT("no bytes requested to write", procName, 1);
|
|
if (!pnout)
|
|
return ERROR_INT("&nout not defined", procName, 1);
|
|
|
|
nleft = bb->n - bb->nwritten;
|
|
nout = L_MIN(nleft, nbytes);
|
|
*pnout = nout;
|
|
|
|
if (nleft == 0) { /* nothing to write; reinitialize the buffer */
|
|
bb->n = 0;
|
|
bb->nwritten = 0;
|
|
return 0;
|
|
}
|
|
|
|
/* nout > 0; transfer the data out */
|
|
fwrite((void *)(bb->array + bb->nwritten), 1, nout, fp);
|
|
bb->nwritten += nout;
|
|
|
|
/* If all written; "empty" the buffer */
|
|
if (nout == nleft) {
|
|
bb->n = 0;
|
|
bb->nwritten = 0;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
/*--------------------------------------------------------------------------*
|
|
* Accessors *
|
|
*--------------------------------------------------------------------------*/
|
|
/*!
|
|
* bbufferBytesToWrite()
|
|
*
|
|
* Input: bbuffer
|
|
* &nbytes (<return>)
|
|
* Return: 0 if OK; 1 on error
|
|
*/
|
|
l_int32
|
|
bbufferBytesToWrite(BBUFFER *bb,
|
|
l_int32 *pnbytes)
|
|
{
|
|
PROCNAME("bbufferBytesToWrite");
|
|
|
|
if (!bb)
|
|
return ERROR_INT("bb not defined", procName, 1);
|
|
if (!pnbytes)
|
|
return ERROR_INT("&nbytes not defined", procName, 1);
|
|
|
|
*pnbytes = bb->n - bb->nwritten;
|
|
return 0;
|
|
}
|
|
|
|
|