eccodes/src/grib_buffer.c

274 lines
7.6 KiB
C

/*
* Copyright 2005-2017 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"
void grib_get_buffer_ownership(const grib_context *c, grib_buffer *b)
{
unsigned char* newdata;
if(b->property == GRIB_MY_BUFFER)
return;
newdata = (unsigned char*)grib_context_malloc(c, b->length);
memcpy(newdata, b->data, b->length);
b->data = newdata;
b->property = GRIB_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,"grib_new_buffer: cannot allocate buffer");
return NULL;
}
b->property = GRIB_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,"grib_new_buffer: cannot allocate buffer");
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,"grib_new_buffer: cannot allocate buffer");
return NULL;
}
b->property = GRIB_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 == GRIB_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)
{
unsigned char* newdata;
if(ns>b->length)
{
grib_get_buffer_ownership(c, b);
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)
{
size_t len = ((new_size + 1023)/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_to(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_to(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;
}
}
#if 0
/* new GCC compiler v4.5.0 complains function is defined but not used*/
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 0
if(s->h->context->debug)
printf("SECTION updating length %ld .. %s\n",plen,s->owner->name);
#endif
}
}
}
#endif
#if 0
/* 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);
}
#endif
void 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 */
DebugAssert( buffer->data + offset );
DebugAssert( 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);
grib_section_adjust_sizes(grib_handle_of_accessor(a)->root,1,0);
if(update_paddings)
grib_update_paddings(grib_handle_of_accessor(a)->root);
}
}
}
void grib_update_sections_lengths(grib_handle* h)
{
grib_section_adjust_sizes(h->root,2,0);
grib_update_paddings(h->root);
}