mirror of
https://github.com/Unidata/netcdf-c.git
synced 2024-11-21 03:13:42 +08:00
001598ddb6
Fixed issue 323 by properly adding padding when generating the binary data for use with nc_put_var/vara. Also added second testcase.
194 lines
5.3 KiB
C
194 lines
5.3 KiB
C
/*********************************************************************
|
|
* Copyright 2009, UCAR/Unidata
|
|
* See netcdf/COPYRIGHT file for copying and redistribution conditions.
|
|
*********************************************************************/
|
|
|
|
#include "includes.h"
|
|
#include "nc_iter.h"
|
|
|
|
#ifdef ENABLE_BINARY
|
|
|
|
static void alignto(int alignment, Bytebuffer* buf, int base);
|
|
|
|
static int bin_uid = 0;
|
|
|
|
static int
|
|
bin_charconstant(Generator* generator, Symbol* sym, Bytebuffer* buf, ...)
|
|
{
|
|
/* Just transfer charbuf to codebuf */
|
|
Bytebuffer* charbuf;
|
|
va_list ap;
|
|
vastart(ap,buf);
|
|
charbuf = va_arg(ap, Bytebuffer*);
|
|
va_end(ap);
|
|
bbNull(charbuf);
|
|
bbCatbuf(buf,charbuf);
|
|
return 1;
|
|
}
|
|
|
|
static int
|
|
bin_constant(Generator* generator, Symbol* sym, NCConstant* con, Bytebuffer* buf,...)
|
|
{
|
|
if(con->nctype != NC_ECONST) {
|
|
alignbuffer(con,buf);
|
|
}
|
|
switch (con->nctype) {
|
|
case NC_OPAQUE: {
|
|
unsigned char* bytes = NULL;
|
|
size_t len;
|
|
/* Assume the opaque string has been normalized */
|
|
bytes=makebytestring(con->value.opaquev.stringv,&len);
|
|
bbAppendn(buf,(void*)bytes,len);
|
|
free(bytes);
|
|
} break;
|
|
case NC_CHAR:
|
|
bbAppendn(buf,&con->value.charv,sizeof(con->value.charv));
|
|
break;
|
|
case NC_BYTE:
|
|
bbAppendn(buf,(void*)&con->value.int8v,sizeof(con->value.int8v));
|
|
break;
|
|
case NC_SHORT:
|
|
bbAppendn(buf,(void*)&con->value.int16v,sizeof(con->value.int16v));
|
|
break;
|
|
case NC_INT:
|
|
bbAppendn(buf,(void*)&con->value.int32v,sizeof(con->value.int32v));
|
|
break;
|
|
case NC_FLOAT:
|
|
bbAppendn(buf,(void*)&con->value.floatv,sizeof(con->value.floatv));
|
|
break;
|
|
case NC_DOUBLE:
|
|
bbAppendn(buf,(void*)&con->value.doublev,sizeof(con->value.doublev));
|
|
break;
|
|
case NC_UBYTE:
|
|
bbAppendn(buf,(void*)&con->value.uint8v,sizeof(con->value.uint8v));
|
|
break;
|
|
case NC_USHORT:
|
|
bbAppendn(buf,(void*)&con->value.uint16v,sizeof(con->value.uint16v));
|
|
break;
|
|
case NC_UINT:
|
|
bbAppendn(buf,(void*)&con->value.uint32v,sizeof(con->value.uint32v));
|
|
break;
|
|
case NC_INT64: {
|
|
union SI64 { char ch[8]; long long i64;} si64;
|
|
si64.i64 = con->value.int64v;
|
|
bbAppendn(buf,(void*)si64.ch,sizeof(si64.ch));
|
|
} break;
|
|
case NC_UINT64: {
|
|
union SU64 { char ch[8]; unsigned long long i64;} su64;
|
|
su64.i64 = con->value.uint64v;
|
|
bbAppendn(buf,(void*)su64.ch,sizeof(su64.ch));
|
|
} break;
|
|
case NC_NIL:
|
|
case NC_STRING: {
|
|
char* ptr;
|
|
int len = (size_t)con->value.stringv.len;
|
|
if(len == 0 && con->value.stringv.stringv == NULL) {
|
|
char* nil = NULL;
|
|
bbAppendn(buf,(void*)&nil,sizeof(nil));
|
|
} else {
|
|
ptr = (char*)malloc(len+1);
|
|
memcpy(ptr,con->value.stringv.stringv,len);
|
|
ptr[len] = '\0';
|
|
bbAppendn(buf,(void*)&ptr,sizeof(ptr));
|
|
}
|
|
} break;
|
|
|
|
default: PANIC1("bin_constant: unexpected type: %d",con->nctype);
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
static int
|
|
bin_listbegin(Generator* generator, Symbol* tsym, void* liststate, ListClass lc, size_t size, Bytebuffer* buf, int* uidp, ...)
|
|
{
|
|
if(uidp) *uidp = ++bin_uid;
|
|
if(lc == LISTCOMPOUND)
|
|
*((int*)liststate) = bbLength(buf);
|
|
return 1;
|
|
}
|
|
|
|
static int
|
|
bin_list(Generator* generator, Symbol* tsym, void* liststate, ListClass lc, int uid, size_t count, Bytebuffer* buf, ...)
|
|
{
|
|
if(lc == LISTCOMPOUND) {
|
|
int offsetbase = *((int*)liststate);
|
|
/* Pad for the alignment */
|
|
alignto(tsym->typ.alignment,buf,offsetbase);
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
static int
|
|
bin_listend(Generator* generator, Symbol* tsym, void* liststate, ListClass lc, int uid, size_t count, Bytebuffer* buf, ...)
|
|
{
|
|
if(lc == LISTCOMPOUND) {
|
|
int offsetbase = *((int*)liststate);
|
|
/* Pad out the whole instance */
|
|
alignto(tsym->typ.cmpdalign,buf,offsetbase);
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
|
|
static int
|
|
bin_vlendecl(Generator* generator, Symbol* tsym, Bytebuffer* buf, int uid, size_t count,...)
|
|
{
|
|
va_list ap;
|
|
Bytebuffer* vlenmem;
|
|
nc_vlen_t ptr;
|
|
vastart(ap,count);
|
|
vlenmem = va_arg(ap, Bytebuffer*);
|
|
va_end(ap);
|
|
ptr.len = count;
|
|
ptr.p = bbDup(vlenmem);
|
|
bbAppendn(buf,(char*)&ptr,sizeof(ptr));
|
|
return 1;
|
|
}
|
|
|
|
static int
|
|
bin_vlenstring(Generator* generator, Symbol* sym, Bytebuffer* codebuf, int* uidp, size_t* sizep,...)
|
|
{
|
|
Bytebuffer* vlenmem;
|
|
nc_vlen_t ptr;
|
|
va_list ap;
|
|
if(uidp) *uidp = ++bin_uid;
|
|
vastart(ap,sizep);
|
|
vlenmem = va_arg(ap, Bytebuffer*);
|
|
va_end(ap);
|
|
ptr.len = bbLength(vlenmem);
|
|
ptr.p = bbDup(vlenmem);
|
|
bbAppendn(codebuf,(char*)&ptr,sizeof(ptr));
|
|
return 1;
|
|
}
|
|
|
|
static const char zeros[] =
|
|
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
|
|
|
|
static void
|
|
alignto(int alignment, Bytebuffer* buf, int base)
|
|
{
|
|
int pad = 0;
|
|
int offset = bbLength(buf);
|
|
offset -= base; /* Need to actually align wrt to the base */
|
|
pad = getpadding(offset,alignment);
|
|
if(pad > 0) {
|
|
bbAppendn(buf,(void*)zeros,pad);
|
|
}
|
|
}
|
|
|
|
/* Define the single static bin data generator */
|
|
static Generator bin_generator_singleton = {
|
|
NULL,
|
|
bin_charconstant,
|
|
bin_constant,
|
|
bin_listbegin,
|
|
bin_list,
|
|
bin_listend,
|
|
bin_vlendecl,
|
|
bin_vlenstring
|
|
};
|
|
Generator* bin_generator = &bin_generator_singleton;
|
|
|
|
#endif /*ENABLE_BINARY*/
|
|
|