eccodes/src/grib_buffer.cc

249 lines
7.8 KiB
C++

/*
* (C) Copyright 2005- ECMWF.
*
* This software is licensed under the terms of the Apache Licence Version 2.0
* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
*
* In applying this licence, ECMWF does not waive the privileges and immunities granted to it by
* virtue of its status as an intergovernmental organisation nor does it submit to any jurisdiction.
*/
/***************************************************************************
* Jean Baptiste Filippi - 01.11.2005 *
***************************************************************************/
#include "grib_api_internal.h"
static void grib_get_buffer_ownership(const grib_context* c, grib_buffer* b)
{
unsigned char* newdata = NULL;
if (b->property == CODES_MY_BUFFER)
return;
newdata = (unsigned char*)grib_context_malloc(c, b->length);
memcpy(newdata, b->data, b->length);
b->data = newdata;
b->property = CODES_MY_BUFFER;
}
grib_buffer* grib_create_growable_buffer(const grib_context* c)
{
grib_buffer* b = (grib_buffer*)grib_context_malloc_clear(c, sizeof(grib_buffer));
if (b == NULL) {
grib_context_log(c, GRIB_LOG_ERROR, "%s: cannot allocate buffer", __func__);
return NULL;
}
b->property = CODES_MY_BUFFER;
b->length = 10240;
b->ulength = 0;
b->data = (unsigned char*)grib_context_malloc_clear(c, b->length);
b->growable = 1;
if (!b->data) {
grib_context_log(c, GRIB_LOG_ERROR, "%s: cannot allocate buffer", __func__);
grib_context_free(c, b);
return NULL;
}
return b;
}
grib_buffer* grib_new_buffer(const grib_context* c, const unsigned char* data, size_t buflen)
{
grib_buffer* b = (grib_buffer*)grib_context_malloc_clear(c, sizeof(grib_buffer));
if (b == NULL) {
grib_context_log(c, GRIB_LOG_ERROR, "%s: cannot allocate buffer", __func__);
return NULL;
}
b->property = CODES_USER_BUFFER;
b->length = buflen;
b->ulength = buflen;
b->ulength_bits = buflen * 8;
b->data = (unsigned char*)data;
return b;
}
void grib_buffer_delete(const grib_context* c, grib_buffer* b)
{
if (b->property == CODES_MY_BUFFER)
grib_context_free(c, b->data);
b->length = 0;
b->ulength = 0;
grib_context_free(c, b);
}
static void grib_grow_buffer_to(const grib_context* c, grib_buffer* b, size_t ns)
{
if (ns > b->length) {
grib_get_buffer_ownership(c, b);
unsigned char* newdata = (unsigned char*)grib_context_malloc_clear(c, ns);
memcpy(newdata, b->data, b->length);
grib_context_free(c, b->data);
b->data = newdata;
b->length = ns;
}
}
void grib_grow_buffer(const grib_context* c, grib_buffer* b, size_t new_size)
{
if (new_size > b->length) {
size_t len = 0;
size_t inc = b->length > 2048 ? b->length : 2048;
len = ((new_size + 2 * inc) / 1024) * 1024;
grib_grow_buffer_to(c, b, len);
}
}
void grib_buffer_set_ulength_bits(const grib_context* c, grib_buffer* b, size_t length_bits)
{
size_t length = length_bits / 8;
if (length_bits % 8)
length++;
grib_grow_buffer(c, b, length);
b->ulength_bits = length_bits;
b->ulength = length;
}
void grib_buffer_set_ulength(const grib_context* c, grib_buffer* b, size_t length)
{
grib_grow_buffer(c, b, length);
b->ulength = length;
b->ulength_bits = length * 8;
}
static void update_offsets(grib_accessor* a, long len)
{
while (a) {
grib_section* s = a->sub_section;
a->offset += len;
grib_context_log(a->context, GRIB_LOG_DEBUG, "::::: grib_buffer : accessor %s is moving by %d bytes to %ld", a->name, len, a->offset);
if (s)
update_offsets(s->block->first, len);
a = a->next;
}
}
static void update_offsets_after(grib_accessor* a, long len)
{
while (a) {
update_offsets(a->next, len);
a = a->parent->owner;
}
}
// void grib_recompute_sections_lengths(grib_section* s)
// {
// if(s)
// {
// long plen = 0;
// size_t len = 1;
// grib_accessor* a = s->block->first;
// while(a)
// {
// /* grib_recompute_sections_lengths(grib_get_sub_section(a)); */
// grib_recompute_sections_lengths(a->sub_section);
// a = a->next;
// }
// if(s->aclength)
// {
// int ret;
// if(s->owner)
// plen = grib_get_next_position_offset(s->block->last) - s->owner->offset;
// else
// plen = grib_get_next_position_offset(s->block->last);
// if((ret = grib_pack_long(s->aclength, &plen, &len)) != GRIB_SUCCESS)
// ;
//
// if(s->h->context->debug)
// printf("SECTION updating length %ld .. %s\n",plen,s->owner->name);
// }
// }
// }
// /* new GCC compiler v4.5.0 complains function is defined but not used*/
// static void update_sections_lengths(grib_section* s)
// {
// long plen = 0;
// size_t len = 1;
// if(!s) return;
// if(s->aclength)
// {
// int ret;
// if(s->owner)
// plen = grib_get_next_position_offset(s->block->last) - s->owner->offset;
// else
// plen = grib_get_next_position_offset(s->block->last);
// /* if(s->owner) */
// /* s->owner->length = plen; */
// /* if(s->aclength) */
// if((ret = grib_pack_long(s->aclength, &plen, &len)) != GRIB_SUCCESS)
// ;
// if(s->h->context->debug)
// {
// printf("SECTION updating length %ld .. %s\n",plen,s->owner->name);
// printf("NEXT_POS = %ld, owner offset= %ld %s %s\n",
// grib_get_next_position_offset(s->block->last),
// s->owner ? s->owner->offset : 0L, s->owner->name,
// s->block->last->name);
// }
// }
// if(s->owner)
// update_sections_lengths(s->owner->parent);
// }
int grib_buffer_replace(grib_accessor* a, const unsigned char* data,
size_t newsize, int update_lengths, int update_paddings)
{
size_t offset = a->offset;
long oldsize = grib_get_next_position_offset(a) - offset;
long increase = (long)newsize - (long)oldsize;
grib_buffer* buffer = grib_handle_of_accessor(a)->buffer;
size_t message_length = buffer->ulength;
grib_context_log(a->context, GRIB_LOG_DEBUG,
"grib_buffer_replace %s offset=%ld oldsize=%ld newsize=%ld message_length=%ld update_paddings=%d",
a->name, (long)offset, oldsize, (long)newsize, (long)message_length, update_paddings);
grib_buffer_set_ulength(a->context,
buffer,
buffer->ulength + increase);
/* move the end */
if (increase)
memmove(
buffer->data + offset + newsize,
buffer->data + offset + oldsize,
message_length - offset - oldsize);
/* copy new data */
DEBUG_ASSERT(buffer->data + offset);
DEBUG_ASSERT(data || (newsize == 0)); /* if data==NULL then newsize must be 0 */
if (data) {
/* Note: memcpy behaviour is undefined if either dest or src is NULL */
memcpy(buffer->data + offset, data, newsize);
}
if (increase) {
update_offsets_after(a, increase);
if (update_lengths) {
grib_update_size(a, newsize);
int err = grib_section_adjust_sizes(grib_handle_of_accessor(a)->root, 1, 0);
if (err) return err;
if (update_paddings)
grib_update_paddings(grib_handle_of_accessor(a)->root);
}
}
return GRIB_SUCCESS;
}
void grib_update_sections_lengths(grib_handle* h)
{
grib_section_adjust_sizes(h->root, 2, 0);
grib_update_paddings(h->root);
}