/************************************************************************ | |
* Id: buffer.c * | |
* * | |
* TR069 Project: A TR069 library in C * | |
* Copyright (C) 2013-2014 netcwmp group * | |
* * | |
* * | |
* Email: netcwmp ( & ) gmail dot com * | |
* * | |
***********************************************************************/ | |
#include "cwmp/buffer.h" | |
#include "cwmp/util.h" | |
#include "cwmp/memory.h" | |
#include "cwmp/log.h" | |
//#include "cwmp_private.h" | |
void cwmp_buffer_clear(void * data) | |
{ | |
cwmp_buffer_t * b; | |
//FUNCTION_TRACE(); | |
if (!data) | |
return; | |
b = (cwmp_buffer_t*)data; | |
b->writed = 0; | |
b->readed = 0; | |
b->offset = b->string; | |
b->size = DEFAULT_BUFFER_SIZE; | |
b->next = 0; | |
b->string[0] = 0; | |
} | |
int cwmp_buffer_create(cwmp_buffer_t **news, pool_t * pool) | |
{ | |
(*news) = PMALLOC(sizeof(cwmp_buffer_t)); | |
if ((*news) == NULL) | |
{ | |
return CWMP_ENOMEM; | |
} | |
(*news)->size = DEFAULT_BUFFER_SIZE; | |
(*news)->writed = 0; | |
(*news)->readed = 0; | |
(*news)->offset = (*news)->string; | |
(*news)->next = 0; | |
(*news)->string[0] = 0; | |
pool_cleanup_add(pool, cwmp_buffer_clear, *news); | |
return CWMP_OK; | |
} | |
int cwmp_buffer_init(cwmp_buffer_t * b) | |
{ | |
b->writed = 0; | |
b->readed = 0; | |
b->size = DEFAULT_BUFFER_SIZE; | |
b->offset = b->string; | |
b->next = 0; | |
b->string[0] = 0; | |
return CWMP_OK; | |
} | |
void cwmp_buffer_free(cwmp_buffer_t * b, pool_t * pool) | |
{ | |
if (b == NULL) | |
return; | |
PFREE(b); | |
} | |
char * cwmp_buffer_current(cwmp_buffer_t * b) | |
{ | |
return b->string + b->writed; | |
} | |
char * cwmp_buffer_string(cwmp_buffer_t * b) | |
{ | |
return b->string; | |
} | |
size_t cwmp_buffer_length(cwmp_buffer_t * b) | |
{ | |
return b == NULL ? 0: (b->writed - b->readed) ; | |
} | |
size_t cwmp_buffer_size(cwmp_buffer_t * b) | |
{ | |
return b == NULL ? 0: b->size; | |
} | |
int cwmp_buffer_remain(cwmp_buffer_t * b) | |
{ | |
return b == NULL ? 0: (b->size - b->writed); | |
} | |
size_t cwmp_chunk_length(cwmp_chunk_t * c) | |
{ | |
return c == NULL? 0 : c->bytes; | |
} | |
void cwmp_buffer_write_position(cwmp_buffer_t * b, size_t pos, const void * val, cwmp_uint32_t len) | |
{ | |
memcpy(b->string + pos, val, len); | |
if (pos + len > b->writed) | |
{ | |
/* b->writed = pos + len; */ | |
} | |
} | |
void cwmp_buffer_write_bytes(cwmp_buffer_t * b, const void * val, size_t len) | |
{ | |
if (len > (b->size - b->writed)) | |
return; | |
memcpy(b->offset, val, len); | |
b->offset += len; | |
b->writed += len; | |
} | |
void cwmp_buffer_write_uint64(cwmp_buffer_t * b, cwmp_uint64_t val) | |
{ | |
cwmp_buffer_write_bytes(b, &val, 8); | |
} | |
void cwmp_buffer_write_uint32(cwmp_buffer_t * b, cwmp_uint32_t val) | |
{ | |
cwmp_buffer_write_bytes(b, &val, 4); | |
} | |
void cwmp_buffer_write_uint16(cwmp_buffer_t * b, cwmp_uint16_t val) | |
{ | |
cwmp_buffer_write_bytes(b, &val, 2); | |
} | |
void cwmp_buffer_write_uint8(cwmp_buffer_t * b, cwmp_byte_t val) | |
{ | |
cwmp_buffer_write_bytes(b, &val, 1); | |
} | |
void cwmp_buffer_write_format_string(cwmp_buffer_t * b, const char * fmt, ...) | |
{ | |
va_list ap = {0}; | |
int len; | |
va_start(ap, fmt); | |
#ifdef WIN32 | |
len = _vsnprintf(cwmp_buffer_current(b), b->size - b->writed, fmt, ap); | |
#else | |
len =vsnprintf(cwmp_buffer_current(b), b->size - b->writed, fmt, ap); | |
#endif | |
b->offset += len; | |
b->writed += len; | |
va_end(ap); | |
} | |
void cwmp_buffer_write_string(cwmp_buffer_t * b, const char * str, size_t len) | |
{ | |
cwmp_buffer_write_bytes(b, str, len); | |
} | |
void cwmp_buffer_clone(cwmp_buffer_t * b, const cwmp_buffer_t * cb) | |
{ | |
size_t len = cb->writed; | |
cwmp_buffer_write_bytes(b, cb->string, len); | |
} | |
int cwmp_buffer_read_bytes(void * val, cwmp_buffer_t * b, const cwmp_uint32_t len) | |
{ | |
if (len > cwmp_buffer_length(b)) | |
{ | |
return CWMP_ERROR; | |
} | |
else | |
{ | |
memcpy(val, b->string + b->readed, len); | |
b->readed += len; | |
return CWMP_OK; | |
} | |
} | |
int cwmp_buffer_read_uint8(cwmp_byte_t * val, cwmp_buffer_t * b) | |
{ | |
return cwmp_buffer_read_bytes((void *)val,b,1); | |
} | |
int cwmp_buffer_read_uint16(cwmp_uint16_t * val, cwmp_buffer_t * b) | |
{ | |
cwmp_uint16_t v; | |
if (cwmp_buffer_read_bytes((void *)&v,b,2) != CWMP_OK) | |
{ | |
return CWMP_ERROR; | |
} | |
else | |
{ | |
(*val) = v; | |
return CWMP_OK; | |
} | |
} | |
int cwmp_buffer_read_uint32(cwmp_uint32_t * val, cwmp_buffer_t * b) | |
{ | |
cwmp_uint32_t v; | |
if (cwmp_buffer_read_bytes((void *)&v,b,4) != CWMP_OK) | |
{ | |
return CWMP_ERROR; | |
} | |
else | |
{ | |
(*val) = v; | |
return CWMP_OK; | |
} | |
} | |
int cwmp_chunk_create(cwmp_chunk_t ** news, pool_t * pool) | |
{ | |
(*news) = PMALLOC(sizeof(cwmp_chunk_t)); | |
if (!(*news)) | |
{ | |
cwmp_log_error("create array buffer out of memory\n"); | |
return CWMP_ENOMEM; | |
} | |
(*news)->buffer = NULL; | |
(*news)->current = NULL; | |
(*news)->bytes = (*news)->count = (*news)->used = 0; | |
/* | |
if (cwmp_buffer_create(&buffer, pool) != CWMP_OK) | |
{ | |
cwmp_log_error("create buffer out of memory\n"); | |
PFREE(*news); | |
return CWMP_ENOMEM; | |
} | |
(*news)->buffer = (*news)->current = buffer; | |
*/ | |
pool_cleanup_add(pool, (pool_cleanup_handler)cwmp_chunk_clear, (*news)); | |
return CWMP_OK; | |
} | |
void cwmp_chunk_print(cwmp_chunk_t * cb) | |
{ | |
cwmp_buffer_t * b = cb->buffer; | |
FUNCTION_TRACE(); | |
while (b) | |
{ | |
//fwrite(cwmp_buffer_string(b), 1, cwmp_buffer_length(b), out); | |
cwmp_log_info("%s", cwmp_buffer_string(b)); | |
b = b->next; | |
} | |
} | |
int cwmp_chunk_write_string(cwmp_chunk_t * cb, const char * str, size_t length, pool_t * pool) | |
{ | |
cwmp_buffer_t *buffer; | |
size_t len, leftbytes, writebytes, writed; | |
//FUNCTION_TRACE(); | |
writed = 0; | |
leftbytes = length; | |
while (leftbytes>0) | |
{ | |
len = cwmp_buffer_remain(cb->current); | |
if (len <= 0) | |
{ | |
if (cb->current && cb->current->next) | |
{ | |
cb->current = cb->current->next; | |
cwmp_buffer_clear(cb->current); | |
} | |
else | |
{ | |
if (cwmp_buffer_create(&buffer, pool) != CWMP_OK) | |
{ | |
cwmp_log_error("create buffer out of memory\n"); | |
return CWMP_ERROR; | |
} | |
if (cb->current != NULL) | |
{ | |
cb->current->next = buffer; | |
} | |
else | |
{ | |
cb->buffer = buffer; | |
} | |
cb->current = buffer; | |
} | |
len=cwmp_buffer_remain(cb->current); | |
} | |
writebytes = leftbytes > len ? len :leftbytes; | |
cwmp_buffer_write_string(cb->current, str + writed, writebytes); | |
writed += writebytes; | |
cb->bytes += writebytes; | |
leftbytes -= writebytes; | |
/*if (leftbytes > 0) | |
{ | |
if (cwmp_buffer_create(&buffer, pool) != CWMP_OK) | |
{ | |
cwmp_log_error("create buffer out of memory\n"); | |
return CWMP_ERROR; | |
} | |
cb->current->next = buffer; | |
cb->current = buffer; | |
} | |
else | |
{ | |
break; | |
} | |
*/ | |
} | |
return writed; | |
} | |
int cwmp_chunk_copy(char * dest, const cwmp_chunk_t * cb, size_t max_length) | |
{ | |
size_t bufleft, destwrited, writebytes; | |
size_t b,d; | |
char * ptr = dest; | |
cwmp_buffer_t * buffer = cb->buffer; | |
bufleft = cb->bytes; | |
destwrited = 0; | |
while ((destwrited <= max_length) && (bufleft > 0) && (buffer!=NULL)) | |
{ | |
b = bufleft > cwmp_buffer_length(buffer) ? cwmp_buffer_length(buffer) : bufleft; | |
d = max_length - destwrited; | |
writebytes = d > b ? b : d; | |
strncpy(ptr, cwmp_buffer_string(buffer), writebytes); | |
ptr += writebytes; | |
destwrited += writebytes; | |
bufleft -= writebytes; | |
buffer = buffer->next; | |
} | |
dest[destwrited] = 0; | |
return destwrited; | |
} | |
void cwmp_chunk_init(cwmp_chunk_t * cb) | |
{ | |
FUNCTION_TRACE(); | |
cb->buffer = NULL; | |
cb->bytes = 0; | |
cb->count = 0; | |
cb->used = 0; | |
cb->current = cb->buffer; | |
} | |
void cwmp_chunk_clear(cwmp_chunk_t * cb) | |
{ | |
//FUNCTION_TRACE(); | |
cb->buffer = NULL; | |
cb->bytes = 0; | |
cb->count = 0; | |
cb->used = 0; | |
cb->current = cb->buffer; | |
} | |
int cwmp_chunk_release(cwmp_chunk_t * cb, int remain, pool_t * pool) | |
{ | |
int i; | |
cwmp_buffer_t * next; | |
cwmp_buffer_t * buffer = cb->buffer; | |
for (i=0; i<remain && buffer; i++) | |
{ | |
buffer = buffer->next; | |
} | |
while (buffer) | |
{ | |
next = buffer->next; | |
cwmp_buffer_free(buffer, pool); | |
buffer = next; | |
} | |
return 0; | |
} |