2018-12-07 06:40:43 +08:00
|
|
|
/* Copyright 2018, UCAR/Unidata and OPeNDAP, Inc.
|
2010-06-03 21:24:43 +08:00
|
|
|
See the COPYRIGHT file for more information. */
|
|
|
|
|
2012-08-02 01:18:58 +08:00
|
|
|
#include "config.h"
|
2010-06-03 21:24:43 +08:00
|
|
|
#include <stdlib.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <string.h>
|
|
|
|
|
|
|
|
#include "bytebuffer.h"
|
|
|
|
#include "debug.h"
|
|
|
|
|
|
|
|
#ifndef TRUE
|
|
|
|
#define TRUE 1
|
|
|
|
#endif
|
|
|
|
#ifndef FALSE
|
|
|
|
#define FALSE 0
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#define DEFAULTALLOC 1024
|
|
|
|
#define ALLOCINCR 1024
|
|
|
|
|
|
|
|
int bbdebug = 1;
|
|
|
|
|
|
|
|
/* For debugging purposes*/
|
|
|
|
static long
|
|
|
|
bbFail(void)
|
|
|
|
{
|
|
|
|
fflush(stdout);
|
|
|
|
fprintf(stderr,"bytebuffer failure\n");
|
|
|
|
fflush(stderr);
|
2017-11-01 04:03:57 +08:00
|
|
|
if(bbdebug) abort();
|
2010-06-03 21:24:43 +08:00
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
Bytebuffer*
|
|
|
|
bbNew(void)
|
|
|
|
{
|
2018-11-16 01:00:38 +08:00
|
|
|
Bytebuffer* bb = (Bytebuffer*)emalloc(sizeof(Bytebuffer));
|
2021-12-24 13:18:56 +08:00
|
|
|
if(bb == NULL) {bbFail(); return NULL;}
|
2010-06-03 21:24:43 +08:00
|
|
|
bb->alloc=0;
|
|
|
|
bb->length=0;
|
|
|
|
bb->content=NULL;
|
|
|
|
bb->nonextendible = 0;
|
2014-07-30 01:00:44 +08:00
|
|
|
return bb;
|
2010-06-03 21:24:43 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
bbSetalloc(Bytebuffer* bb, const unsigned int sz0)
|
|
|
|
{
|
|
|
|
unsigned int sz = sz0;
|
|
|
|
char* newcontent;
|
|
|
|
if(bb == NULL) return bbFail();
|
|
|
|
if(sz <= 0) {sz = (bb->alloc?2*bb->alloc:DEFAULTALLOC);}
|
|
|
|
else if(bb->alloc >= sz) return TRUE;
|
|
|
|
else if(bb->nonextendible) return bbFail();
|
2018-11-16 01:00:38 +08:00
|
|
|
newcontent=(char*)ecalloc(sz*sizeof(char));
|
2010-06-03 21:24:43 +08:00
|
|
|
if(bb->alloc > 0 && bb->length > 0 && bb->content != NULL) {
|
|
|
|
memcpy((void*)newcontent,(void*)bb->content,sizeof(char)*bb->length);
|
|
|
|
}
|
|
|
|
if(bb->content != NULL) efree(bb->content);
|
|
|
|
bb->content=newcontent;
|
|
|
|
bb->alloc=sz;
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
bbFree(Bytebuffer* bb)
|
|
|
|
{
|
|
|
|
if(bb == NULL) return;
|
|
|
|
if(bb->content != NULL) efree(bb->content);
|
|
|
|
efree(bb);
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
bbSetlength(Bytebuffer* bb, const unsigned int sz)
|
|
|
|
{
|
|
|
|
if(bb == NULL) return bbFail();
|
2012-08-31 00:43:34 +08:00
|
|
|
if(bb->length < sz) {
|
|
|
|
if(!bbSetalloc(bb,sz)) return bbFail();
|
|
|
|
}
|
2010-06-03 21:24:43 +08:00
|
|
|
bb->length = sz;
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
bbFill(Bytebuffer* bb, const char fill)
|
|
|
|
{
|
|
|
|
unsigned int i;
|
|
|
|
if(bb == NULL) return bbFail();
|
2014-07-30 01:00:44 +08:00
|
|
|
for(i=0;i<bb->length;i++) bb->content[i] = fill;
|
2010-06-03 21:24:43 +08:00
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
bbGet(Bytebuffer* bb, unsigned int index)
|
|
|
|
{
|
|
|
|
if(bb == NULL) return -1;
|
|
|
|
if(index >= bb->length) return -1;
|
|
|
|
return bb->content[index];
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
bbSet(Bytebuffer* bb, unsigned int index, char elem)
|
|
|
|
{
|
|
|
|
if(bb == NULL) return bbFail();
|
|
|
|
if(index >= bb->length) return bbFail();
|
|
|
|
bb->content[index] = elem;
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
bbAppend(Bytebuffer* bb, char elem)
|
|
|
|
{
|
|
|
|
if(bb == NULL) return bbFail();
|
|
|
|
/* We need space for the char + null */
|
2014-09-23 04:31:19 +08:00
|
|
|
while(bb->length+1 >= bb->alloc) {
|
|
|
|
if(!bbSetalloc(bb,0))
|
|
|
|
return bbFail();
|
|
|
|
}
|
2010-06-03 21:24:43 +08:00
|
|
|
bb->content[bb->length] = elem;
|
|
|
|
bb->length++;
|
|
|
|
bb->content[bb->length] = '\0';
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* This assumes s is a null terminated string*/
|
|
|
|
int
|
|
|
|
bbCat(Bytebuffer* bb, const char* s)
|
|
|
|
{
|
|
|
|
bbAppendn(bb,(void*)s,strlen(s)+1); /* include trailing null*/
|
|
|
|
/* back up over the trailing null*/
|
|
|
|
if(bb->length == 0) return bbFail();
|
|
|
|
bb->length--;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
bbCatbuf(Bytebuffer* bb, const Bytebuffer* s)
|
|
|
|
{
|
|
|
|
if(bbLength(s) > 0)
|
|
|
|
bbAppendn(bb,bbContents(s),bbLength(s));
|
|
|
|
bbNull(bb);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
bbAppendn(Bytebuffer* bb, const void* elem, const unsigned int n0)
|
|
|
|
{
|
|
|
|
unsigned int n = n0;
|
|
|
|
if(bb == NULL || elem == NULL) return bbFail();
|
|
|
|
if(n == 0) {n = strlen((char*)elem);}
|
|
|
|
while(!bbNeed(bb,(n+1))) {if(!bbSetalloc(bb,0)) return bbFail();}
|
|
|
|
memcpy((void*)&bb->content[bb->length],(void*)elem,n);
|
|
|
|
bb->length += n;
|
|
|
|
bb->content[bb->length] = '\0';
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
bbInsert(Bytebuffer* bb, const unsigned int index, const char elem)
|
|
|
|
{
|
|
|
|
char tmp[2];
|
|
|
|
tmp[0]=elem;
|
|
|
|
return bbInsertn(bb,index,tmp,1);
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
bbInsertn(Bytebuffer* bb, const unsigned int index, const char* elem, const unsigned int n)
|
|
|
|
{
|
|
|
|
unsigned int i;
|
|
|
|
int j;
|
2014-07-30 01:00:44 +08:00
|
|
|
unsigned int newlen = 0;
|
2010-06-03 21:24:43 +08:00
|
|
|
|
|
|
|
if(bb == NULL) return bbFail();
|
2014-07-30 01:00:44 +08:00
|
|
|
|
|
|
|
newlen = bb->length + n;
|
|
|
|
|
2010-06-03 21:24:43 +08:00
|
|
|
if(newlen >= bb->alloc) {
|
|
|
|
if(!bbExtend(bb,n)) return bbFail();
|
|
|
|
}
|
2014-07-30 01:00:44 +08:00
|
|
|
/*
|
2010-06-03 21:24:43 +08:00
|
|
|
index=0
|
|
|
|
n=3
|
|
|
|
len=3
|
|
|
|
newlen=6
|
|
|
|
a b c
|
|
|
|
x y z a b c
|
|
|
|
-----------
|
|
|
|
0 1 2 3 4 5
|
|
|
|
|
|
|
|
i=0 1 2
|
|
|
|
j=5 4 3
|
|
|
|
2 1 0
|
|
|
|
*/
|
|
|
|
for(j=newlen-1,i=index;i<bb->length;i++) {
|
|
|
|
bb->content[j]=bb->content[j-n];
|
|
|
|
}
|
|
|
|
memcpy((void*)(bb->content+index),(void*)elem,n);
|
|
|
|
bb->length += n;
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
2014-10-04 02:38:32 +08:00
|
|
|
/*! Pop head off of a byte buffer.
|
|
|
|
*
|
|
|
|
* @param Bytebuffer bb Pointer to Bytebuffer.
|
|
|
|
* @param char* pelem pointer to location for head element.
|
|
|
|
*
|
|
|
|
* @return Returns TRUE on success.
|
|
|
|
*/
|
|
|
|
int bbHeadpop(Bytebuffer* bb, char* pelem)
|
2010-06-03 21:24:43 +08:00
|
|
|
{
|
|
|
|
if(bb == NULL) return bbFail();
|
|
|
|
if(bb->length == 0) return bbFail();
|
|
|
|
*pelem = bb->content[0];
|
2014-10-04 02:38:32 +08:00
|
|
|
memmove((void*)&bb->content[0],
|
|
|
|
(void*)&bb->content[1],
|
|
|
|
sizeof(char)*(bb->length - 1));
|
2014-07-30 01:00:44 +08:00
|
|
|
bb->length--;
|
|
|
|
return TRUE;
|
2010-06-03 21:24:43 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
bbTailpop(Bytebuffer* bb, char* pelem)
|
|
|
|
{
|
|
|
|
if(bb == NULL) return bbFail();
|
|
|
|
if(bb->length == 0) return bbFail();
|
|
|
|
*pelem = bb->content[bb->length-1];
|
2014-07-30 01:00:44 +08:00
|
|
|
bb->length--;
|
|
|
|
return TRUE;
|
2010-06-03 21:24:43 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
bbHeadpeek(Bytebuffer* bb, char* pelem)
|
|
|
|
{
|
|
|
|
if(bb == NULL) return bbFail();
|
|
|
|
if(bb->length == 0) return bbFail();
|
|
|
|
*pelem = bb->content[0];
|
2014-07-30 01:00:44 +08:00
|
|
|
return TRUE;
|
2010-06-03 21:24:43 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
bbTailpeek(Bytebuffer* bb, char* pelem)
|
|
|
|
{
|
|
|
|
if(bb == NULL) return bbFail();
|
|
|
|
if(bb->length == 0) return bbFail();
|
|
|
|
*pelem = bb->content[bb->length - 1];
|
2014-07-30 01:00:44 +08:00
|
|
|
return TRUE;
|
2010-06-03 21:24:43 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
char*
|
|
|
|
bbDup(const Bytebuffer* bb)
|
|
|
|
{
|
2018-11-16 01:00:38 +08:00
|
|
|
char* result = (char*)emalloc(bb->length+1);
|
2010-06-03 21:24:43 +08:00
|
|
|
memcpy((void*)result,(const void*)bb->content,bb->length);
|
|
|
|
result[bb->length] = '\0'; /* just in case it is a string*/
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
bbSetcontents(Bytebuffer* bb, char* contents, const unsigned int alloc)
|
|
|
|
{
|
|
|
|
if(bb == NULL) return bbFail();
|
|
|
|
bbClear(bb);
|
|
|
|
if(!bb->nonextendible && bb->content != NULL) efree(bb->content);
|
|
|
|
bb->content = contents;
|
|
|
|
bb->length = 0;
|
|
|
|
bb->alloc = alloc;
|
|
|
|
bb->nonextendible = 1;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Add invisible NULL terminator */
|
|
|
|
int
|
|
|
|
bbNull(Bytebuffer* bb)
|
|
|
|
{
|
|
|
|
bbAppend(bb,'\0');
|
|
|
|
bb->length--;
|
|
|
|
return 1;
|
|
|
|
}
|
2018-11-16 01:00:38 +08:00
|
|
|
|
|
|
|
/* Extract the content and leave content null */
|
|
|
|
char*
|
|
|
|
bbExtract(Bytebuffer* bb)
|
|
|
|
{
|
|
|
|
char* x = NULL;
|
|
|
|
if(bb == NULL || bb->content == NULL)
|
|
|
|
return NULL;
|
|
|
|
x = bb->content;
|
|
|
|
bb->content = NULL;
|
|
|
|
bb->length = 0;
|
|
|
|
bb->alloc = 0;
|
|
|
|
return x;
|
|
|
|
}
|