mirror of
https://github.com/Unidata/netcdf-c.git
synced 2024-11-27 07:30:33 +08:00
719 lines
19 KiB
C
719 lines
19 KiB
C
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <assert.h>
|
|
|
|
#include "config.h"
|
|
#include <ast_runtime.h>
|
|
#include <ast_internal.h>
|
|
#include <ast_debug.h>
|
|
|
|
/**
|
|
* Define MAXWIRELEN to be at least big enough
|
|
* to hold instance of any possible primitives
|
|
* except string and byte and as encoded using any
|
|
* of the possible encodings (e.g. int32, int64, varint, etc)
|
|
* => Must hold at least lub(64/7) = 10 */
|
|
#define MAXWIRELEN 16
|
|
|
|
/* max length of a 32 varint Must hold at least lub(32/7) = 5 */
|
|
#define VARINTMAX32 5
|
|
/* max length of a 64 varint Must hold at least lub(64/7) = 10 */
|
|
#define VARINTMAX64 10
|
|
|
|
#define VARINTMAX VARINTMAX64
|
|
|
|
/* Define the maximum c-type size;
|
|
should be max(sizeof(bytes_t),sizeof(uint64_t)
|
|
*/
|
|
#define MAXCTYPESIZE (sizeof(bytes_t)>sizeof(uint64_t)?sizeof(bytes_t):sizeof(uint64_t))
|
|
|
|
|
|
/* Map the primitives (ast_sort) to the associated wiretype */
|
|
static int sort_wiretype_map[] = {
|
|
ast_64bit, /*ast_double*/
|
|
ast_32bit, /*ast_float*/
|
|
ast_varint, /*ast_int32*/
|
|
ast_varint, /*ast_int64*/
|
|
ast_varint, /*ast_uint32*/
|
|
ast_varint, /*ast_uint64*/
|
|
ast_varint, /*ast_sint32*/
|
|
ast_varint, /*ast_sint64*/
|
|
ast_32bit, /*ast_fixed32*/
|
|
ast_64bit, /*ast_fixed64*/
|
|
ast_32bit, /*ast_sfixed32*/
|
|
ast_64bit, /*ast_sfixed64*/
|
|
ast_counted, /*ast_string*/
|
|
ast_counted, /*ast_bytes*/
|
|
ast_varint, /*ast_bool*/
|
|
ast_varint, /*ast_enum*/
|
|
};
|
|
|
|
|
|
enum Sortsize { sizecount=0, size32=32, size64=64 };
|
|
|
|
/* Map sorts to their value sizes; 0=>counted */
|
|
#ifdef IGNORE
|
|
static enum Sortsize sort_size[] = {
|
|
size64, /*ast_double*/
|
|
size32, /*ast_float*/
|
|
size32, /*ast_int32*/
|
|
size64, /*ast_int64*/
|
|
size32, /*ast_uint32*/
|
|
size64, /*ast_uint64*/
|
|
size32, /*ast_sint32*/
|
|
size64, /*ast_sint64*/
|
|
size32, /*ast_fixed32*/
|
|
size64, /*ast_fixed64*/
|
|
size32, /*ast_sfixed32*/
|
|
size32, /*ast_sfixed64*/
|
|
sizecount, /*ast_string*/
|
|
sizecount, /*ast_bytes*/
|
|
size32, /*ast_bool*/
|
|
size32, /*ast_enum*/
|
|
};
|
|
#endif
|
|
|
|
/* Define a null value for bytes_t */
|
|
bytes_t bytes_t_null = {0,NULL};
|
|
|
|
static int ast_readvarint(ast_runtime* rt, uint8_t* buffer, size_t* countp);
|
|
|
|
/* Invoke the ast_runtime operators */
|
|
|
|
static size_t
|
|
ast_write(ast_runtime* rt, size_t count, uint8_t* data)
|
|
{
|
|
return rt->ops->write(rt,count,data);
|
|
}
|
|
|
|
static size_t
|
|
ast_read(ast_runtime* rt, size_t count, uint8_t* buffer)
|
|
{
|
|
return rt->ops->read(rt,count,buffer);
|
|
}
|
|
|
|
ast_err
|
|
ast_mark(ast_runtime* rt, size_t avail)
|
|
{
|
|
return rt->ops->mark(rt,avail);
|
|
}
|
|
|
|
ast_err
|
|
ast_unmark(ast_runtime* rt)
|
|
{
|
|
return rt->ops->unmark(rt);
|
|
}
|
|
|
|
ast_err
|
|
ast_reclaim(ast_runtime* rt)
|
|
{
|
|
return rt->ops->reclaim(rt);
|
|
}
|
|
|
|
void*
|
|
ast_alloc(ast_runtime* rt, size_t len)
|
|
{
|
|
if(len == 0) return NULL;
|
|
return rt->ops->alloc(rt,len);
|
|
}
|
|
|
|
void
|
|
ast_free(ast_runtime* rt, void* mem)
|
|
{
|
|
if(mem == NULL) return;
|
|
return rt->ops->free(rt,mem);
|
|
}
|
|
|
|
/* Define the primitive W/R/F functions */
|
|
|
|
/* Read the tag and return the relevant info */
|
|
ast_err
|
|
ast_read_tag(ast_runtime* rt, uint32_t* wiretypep, uint32_t* fieldnop)
|
|
{
|
|
ast_err status = AST_NOERR;
|
|
uint8_t buffer[MAXWIRELEN];
|
|
size_t count;
|
|
uint32_t key, wiretype, fieldno;
|
|
|
|
/* Extract the wiretype + index */
|
|
status = ast_readvarint(rt,buffer,&count);
|
|
if(status != AST_NOERR) ATHROW(status,done);
|
|
|
|
/* convert from varint */
|
|
key = uint32_decode(count,buffer);
|
|
|
|
/* Extract the wiretype and fieldno */
|
|
wiretype = (key & 0x7);
|
|
fieldno = (key >> 3);
|
|
|
|
/* return the fieldno and wiretype */
|
|
if(fieldnop) *fieldnop = fieldno;
|
|
if(wiretypep) *wiretypep = wiretype;
|
|
|
|
done:
|
|
return ACATCH(status);
|
|
}
|
|
|
|
static ast_err
|
|
ast_read_primitive_data(ast_runtime* rt, const ast_sort sort, void* valuep)
|
|
{
|
|
ast_err status = AST_NOERR;
|
|
uint8_t buffer[MAXWIRELEN];
|
|
size_t count,len;
|
|
uint32_t wiretype;
|
|
|
|
if(valuep == NULL) AERR(status,AST_EFAIL,done);
|
|
|
|
/* compute the wiretype from the sort */
|
|
wiretype = sort_wiretype_map[sort];
|
|
|
|
/* Based on the wiretype, extract the proper number of bytes */
|
|
switch (wiretype) {
|
|
case ast_varint:
|
|
status = ast_readvarint(rt,buffer,&len);
|
|
if(status != AST_NOERR) ATHROW(status,done);
|
|
break;
|
|
case ast_32bit:
|
|
len = 4;
|
|
if(ast_read(rt,len,buffer) != len) AERR(status,AST_EOF,done);
|
|
break;
|
|
case ast_64bit:
|
|
len = 8;
|
|
if(ast_read(rt,len,buffer) != len) AERR(status,AST_EOF,done);
|
|
break;
|
|
case ast_counted: /* get the count */
|
|
status = ast_readvarint(rt,buffer,&len);
|
|
if(status != AST_NOERR) ATHROW(status,done);
|
|
count = (size_t)uint64_decode(len,buffer);
|
|
break;
|
|
default: ATHROW(status,done);
|
|
}
|
|
|
|
/* Now extract the value */
|
|
switch (sort) {
|
|
case ast_enum: /* fall thru */
|
|
case ast_int32:
|
|
*((int32_t*)valuep) = int32_decode(len,buffer);
|
|
break;
|
|
case ast_int64:
|
|
*((int64_t*)valuep) = int64_decode(len,buffer);
|
|
break;
|
|
case ast_uint32:
|
|
*((uint32_t*)valuep) = uint32_decode(len,buffer);
|
|
break;
|
|
case ast_uint64:
|
|
*((uint64_t*)valuep) = uint64_decode(len,buffer);
|
|
break;
|
|
case ast_sint32:
|
|
*((int32_t*)valuep) = unzigzag32(uint32_decode(len,buffer));
|
|
break;
|
|
case ast_sint64:
|
|
*((int64_t*)valuep) = unzigzag64(uint64_decode(len,buffer));
|
|
break;
|
|
case ast_bool:
|
|
*((bool_t*)valuep) = boolen_decode(len,buffer);
|
|
break;
|
|
case ast_fixed32:
|
|
*((uint32_t*)valuep) = fixed32_decode(buffer);
|
|
break;
|
|
case ast_sfixed32:
|
|
*((int32_t*)valuep) = fixed32_decode(buffer);
|
|
break;
|
|
case ast_fixed64:
|
|
*((uint64_t*)valuep) = fixed64_decode(buffer);
|
|
break;
|
|
case ast_sfixed64:
|
|
*((int64_t*)valuep) = fixed64_decode(buffer);
|
|
break;
|
|
case ast_float: {
|
|
uint32_t value = fixed32_decode(buffer);
|
|
memcpy(valuep,&value,sizeof(float));
|
|
} break;
|
|
case ast_double: {
|
|
uint64_t value = fixed64_decode(buffer);
|
|
memcpy(valuep,&value,sizeof(double));
|
|
} break;
|
|
case ast_string: {
|
|
/* Count already holds the length of the string */
|
|
char* stringvalue = ast_alloc(rt,count+1);
|
|
if(stringvalue == NULL) AERR(status,AST_ENOMEM,done);
|
|
if(ast_read(rt,count,(uint8_t*)stringvalue) != count) AERR(status,AST_EOF,done);
|
|
stringvalue[count] = '\0';
|
|
*((char**)valuep) = stringvalue;
|
|
} break;
|
|
case ast_bytes: {
|
|
/* Count already holds the length of the byte string */
|
|
uint8_t* bytestring = ast_alloc(rt,count);
|
|
if(bytestring == NULL) AERR(status,AST_ENOMEM,done);
|
|
if(ast_read(rt,count,bytestring) != count) AERR(status,AST_EOF,done);
|
|
((bytes_t*)valuep)->nbytes = count;
|
|
((bytes_t*)valuep)->bytes = bytestring;
|
|
} break;
|
|
default:
|
|
ATHROW(status,done);
|
|
break;
|
|
}
|
|
|
|
done:
|
|
return ACATCH(status);
|
|
}
|
|
|
|
ast_err
|
|
ast_read_primitive(ast_runtime* rt, const ast_sort sort,
|
|
const int fieldno,void* valuep)
|
|
{
|
|
ast_err status = AST_NOERR;
|
|
uint32_t wiretype;
|
|
|
|
if(valuep == NULL) AERR(status,AST_EFAIL,done);
|
|
|
|
/* compute the wiretype from the sort */
|
|
wiretype = sort_wiretype_map[sort];
|
|
status = ast_read_primitive_data(rt,sort,valuep);
|
|
if(status != AST_NOERR) goto done;
|
|
done:
|
|
return ACATCH(status);
|
|
}
|
|
|
|
static ast_err
|
|
ast_write_primitive_data(ast_runtime* rt, const ast_sort sort,
|
|
const int fieldno,
|
|
const void* valuep)
|
|
{
|
|
ast_err status = AST_NOERR;
|
|
uint8_t buffer[MAXWIRELEN];
|
|
size_t count;
|
|
|
|
/* Write the data in proper wiretype format using the sort */
|
|
switch (sort) {
|
|
case ast_int32:
|
|
count = int32_encode(*(int32_t*)valuep,buffer);
|
|
if(ast_write(rt,count,buffer) != count) {status = AST_EIO; ATHROW(status,done)};
|
|
break;
|
|
case ast_int64:
|
|
count = int64_encode(*(int64_t*)valuep,buffer);
|
|
if(ast_write(rt,count,buffer) != count) {status = AST_EIO; ATHROW(status,done);}
|
|
break;
|
|
case ast_uint32:
|
|
count = uint32_encode(*(uint32_t*)valuep,buffer);
|
|
if(ast_write(rt,count,buffer) != count) {status = AST_EIO; ATHROW(status,done);}
|
|
break;
|
|
case ast_uint64:
|
|
count = uint64_encode(*(uint64_t*)valuep,buffer);
|
|
if(ast_write(rt,count,buffer) != count) {status = AST_EIO; ATHROW(status,done);}
|
|
break;
|
|
case ast_sint32:
|
|
count = sint32_encode(*(int32_t*)valuep,buffer);
|
|
if(ast_write(rt,count,buffer) != count) {status = AST_EIO; ATHROW(status,done);}
|
|
break;
|
|
case ast_sint64:
|
|
count = sint64_encode(*(int64_t*)valuep,buffer);
|
|
if(ast_write(rt,count,buffer) != count) {status = AST_EIO; ATHROW(status,done);}
|
|
break;
|
|
case ast_bool:
|
|
count = boolen_encode(*(bool_t*)valuep,buffer);
|
|
if(ast_write(rt,count,buffer) != count) {status = AST_EIO; ATHROW(status,done);}
|
|
break;
|
|
case ast_enum:
|
|
count = int32_encode(*(int32_t*)valuep,buffer);
|
|
if(ast_write(rt,count,buffer) != count) {status = AST_EIO; ATHROW(status,done);}
|
|
break;
|
|
case ast_fixed32: /* fall thru */
|
|
case ast_sfixed32: /* fall thru */
|
|
case ast_float:
|
|
count = fixed32_encode(*(uint32_t*)valuep,buffer);
|
|
if(ast_write(rt,count,buffer) != count) {status = AST_EIO; ATHROW(status,done);}
|
|
break;
|
|
case ast_fixed64: /* fall thru */
|
|
case ast_sfixed64: /* fall thru */
|
|
case ast_double:
|
|
count = fixed64_encode(*(uint64_t*)valuep,buffer);
|
|
if(ast_write(rt,count,buffer) != count) {status = AST_EIO; ATHROW(status,done);}
|
|
break;
|
|
case ast_string: {
|
|
char* stringvalue = *(char**)valuep;
|
|
size_t len = strlen(stringvalue);
|
|
count = uint32_encode(len,buffer);
|
|
if(ast_write(rt,count,buffer) != count) {status = AST_EIO; ATHROW(status,done);}
|
|
if(ast_write(rt,len,(uint8_t*)stringvalue) != count) {status = AST_EIO; ATHROW(status,done);}
|
|
} break;
|
|
case ast_bytes: {
|
|
bytes_t* bytevalue = (bytes_t*)valuep;
|
|
count = uint32_encode(bytevalue->nbytes,buffer);
|
|
if(ast_write(rt,count,buffer) != count) {status = AST_EIO; ATHROW(status,done);}
|
|
if(ast_write(rt,bytevalue->nbytes,bytevalue->bytes) != bytevalue->nbytes) {status = AST_EIO; ATHROW(status,done);}
|
|
} break;
|
|
default:
|
|
ATHROW(status,done);
|
|
break;
|
|
}
|
|
done:
|
|
return ACATCH(status);
|
|
}
|
|
|
|
static size_t
|
|
ast_encode_tag(ast_runtime* rt,
|
|
const uint32_t wiretype, const uint32_t fieldno,
|
|
uint8_t* buffer/*[MAXWIRELEN]*/)
|
|
{
|
|
int key;
|
|
size_t count;
|
|
|
|
key = (wiretype | (fieldno << 3));
|
|
/* convert key to varint */
|
|
count = uint32_encode(key,(uint8_t*)buffer);
|
|
return count;
|
|
}
|
|
|
|
ast_err
|
|
ast_write_tag(ast_runtime* rt, const uint32_t wiretype, const uint32_t fieldno)
|
|
{
|
|
size_t count;
|
|
uint8_t buffer[MAXWIRELEN];
|
|
|
|
count = ast_encode_tag(rt,wiretype,fieldno,buffer);
|
|
/* Write it out */
|
|
if(ast_write(rt,count,buffer) != count) return AST_EIO;
|
|
return AST_NOERR;
|
|
}
|
|
|
|
/* Procedure to write out count */
|
|
ast_err
|
|
ast_write_size(ast_runtime* rt, const size_t size)
|
|
{
|
|
uint8_t buffer[VARINTMAX64];
|
|
/* write size as varint */
|
|
size_t len = uint64_encode((uint64_t)size,buffer);
|
|
if(ast_write(rt,len,buffer) != len) return AST_EIO;
|
|
return AST_NOERR;
|
|
}
|
|
|
|
ast_err
|
|
ast_write_primitive(ast_runtime* rt, const ast_sort sort, const int fieldno, const void* valuep)
|
|
{
|
|
ast_err status = AST_NOERR;
|
|
ast_wiretype wiretype;
|
|
|
|
wiretype = sort_wiretype_map[sort];
|
|
|
|
status = ast_write_tag(rt,wiretype,fieldno);
|
|
if(status != AST_NOERR) goto done;
|
|
|
|
/* write the data part */
|
|
status = ast_write_primitive_data(rt,sort,fieldno,valuep);
|
|
if(status != AST_NOERR) goto done;
|
|
done:
|
|
return status;
|
|
}
|
|
|
|
ast_err
|
|
ast_read_size(ast_runtime* rt, size_t* sizep)
|
|
{
|
|
uint64_t size = 0;
|
|
uint8_t buffer[VARINTMAX64];
|
|
size_t len;
|
|
ast_err status = ast_readvarint(rt,buffer,&len);
|
|
if(status != AST_NOERR) ATHROW(status,done);
|
|
size = uint64_decode(len,buffer);
|
|
if(sizep) *sizep = (size_t)size;
|
|
done:
|
|
return ACATCH(status);
|
|
}
|
|
|
|
/* Append + extend a REPEAT field */
|
|
ast_err
|
|
ast_repeat_append(ast_runtime* rt, ast_sort sort,void* repeater0, void* value)
|
|
{
|
|
size_t sortsize = ast_ctypesize(rt,sort);
|
|
ast_repeated_field* repeater = (ast_repeated_field*)repeater0;
|
|
char* target;
|
|
|
|
if(repeater->count == 0 || repeater->values == NULL) {
|
|
repeater->count = 0;
|
|
repeater->values = ast_alloc(rt,sortsize);
|
|
if(repeater->values == NULL) return ACATCH(AST_ENOMEM);
|
|
} else {
|
|
void* newmem = ast_alloc(rt,(repeater->count+1)*sortsize);
|
|
if(newmem == NULL) return ACATCH(AST_ENOMEM);
|
|
memcpy(newmem,repeater->values,(repeater->count)*sortsize);
|
|
repeater->values = newmem;
|
|
}
|
|
target = ((char*)repeater->values) + (repeater->count * sortsize);
|
|
memcpy((void*)target,value,sortsize);
|
|
repeater->count++;
|
|
return AST_NOERR;
|
|
}
|
|
|
|
size_t
|
|
ast_ctypesize(ast_runtime* rt, ast_sort sort)
|
|
{
|
|
switch(sort) {
|
|
case ast_double: return sizeof(double);
|
|
case ast_float: return sizeof(float);
|
|
|
|
case ast_enum:
|
|
case ast_bool:
|
|
case ast_int32:
|
|
case ast_sint32:
|
|
case ast_fixed32:
|
|
case ast_sfixed32:
|
|
case ast_uint32: return sizeof(uint32_t);
|
|
|
|
case ast_int64:
|
|
case ast_sint64:
|
|
case ast_fixed64:
|
|
case ast_sfixed64:
|
|
case ast_uint64: return sizeof(uint64_t);
|
|
|
|
case ast_string: return sizeof(char*);
|
|
case ast_bytes: return sizeof(bytes_t);
|
|
|
|
case ast_message:return sizeof(void*);
|
|
|
|
default: assert(0);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
size_t
|
|
ast_get_tagsize(ast_runtime* rt, ast_sort sort, int fieldno)
|
|
{
|
|
size_t count;
|
|
int wiretype;
|
|
uint8_t buffer[MAXWIRELEN];
|
|
|
|
wiretype = sort_wiretype_map[sort];
|
|
count = ast_encode_tag(rt,wiretype,fieldno,buffer);
|
|
return count;
|
|
}
|
|
|
|
|
|
/* Return on the wire # of bytes for this value */
|
|
size_t
|
|
ast_get_size(ast_runtime* rt, ast_sort sort, void* valuep)
|
|
{
|
|
size_t count = 0;
|
|
switch (sort) {
|
|
case ast_enum: /* fall thru */
|
|
case ast_int32:
|
|
count = int32_size(*(int32_t*)valuep);
|
|
break;
|
|
case ast_int64:
|
|
count = int64_size(*(int64_t*)valuep);
|
|
break;
|
|
case ast_uint32:
|
|
count = uint32_size(*(uint32_t*)valuep);
|
|
break;
|
|
case ast_uint64:
|
|
count = uint64_size(*(uint64_t*)valuep);
|
|
break;
|
|
case ast_sint32:
|
|
count = sint32_size(*(int32_t*)valuep);
|
|
break;
|
|
case ast_sint64:
|
|
count = sint64_size(*(int64_t*)valuep);
|
|
break;
|
|
case ast_bool:
|
|
count = 1;
|
|
break;
|
|
case ast_fixed32:
|
|
count = 4;
|
|
break;
|
|
case ast_sfixed32:
|
|
count = 4;
|
|
break;
|
|
case ast_fixed64:
|
|
count = 8;
|
|
break;
|
|
case ast_sfixed64:
|
|
count = 8;
|
|
break;
|
|
case ast_float:
|
|
count = 4;
|
|
break;
|
|
case ast_double:
|
|
count = 8;
|
|
break;
|
|
case ast_string:
|
|
/* string count is size for length counter + strlen(string) */
|
|
count = 0;
|
|
if(valuep != NULL) {
|
|
char* stringvalue = (char*)valuep;
|
|
uint32_t slen = strlen(stringvalue);
|
|
count = uint32_size(slen);
|
|
count += slen;
|
|
}
|
|
break;
|
|
case ast_bytes:
|
|
count = 0;
|
|
if(valuep != NULL) {
|
|
bytes_t* bytedata = (bytes_t*)valuep;
|
|
count = uint32_size(bytedata->nbytes);
|
|
count += bytedata->nbytes;
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
return count;
|
|
}
|
|
|
|
/* Procedure to extract arbitrary varint bytes from input stream */
|
|
static ast_err
|
|
ast_readvarint(ast_runtime* rt, uint8_t* buffer, size_t* countp)
|
|
{
|
|
size_t i=0;
|
|
uint8_t byte[1];
|
|
while(i<VARINTMAX64) {
|
|
size_t count = ast_read(rt,1,byte);
|
|
if(count < 1) return rt->err;
|
|
buffer[i++] = 0x7f & byte[0];
|
|
if((0x80 & byte[0]) == 0) break;
|
|
}
|
|
if(countp) *countp = i;
|
|
return AST_NOERR;
|
|
}
|
|
|
|
/* Given an unknown field, skip past it */
|
|
ast_err
|
|
ast_skip_field(ast_runtime* rt, int wiretype, int fieldno)
|
|
{
|
|
ast_err status = AST_NOERR;
|
|
uint8_t buffer[MAXWIRELEN];
|
|
size_t len;
|
|
switch (wiretype) {
|
|
case ast_varint:
|
|
status = ast_readvarint(rt,buffer,&len);
|
|
if(status != AST_NOERR) ATHROW(status,done);
|
|
break;
|
|
case ast_32bit:
|
|
len = 4;
|
|
status = ast_read(rt,len,buffer);
|
|
if(status != AST_NOERR) ATHROW(status,done);
|
|
break;
|
|
case ast_64bit:
|
|
len = 8;
|
|
status = ast_read(rt,len,buffer);
|
|
if(status != AST_NOERR) ATHROW(status,done);
|
|
break;
|
|
case ast_counted:
|
|
status = ast_readvarint(rt,buffer,&len);
|
|
if(status != AST_NOERR) ATHROW(status,done);
|
|
/* get the count */
|
|
len = (size_t)uint64_decode(len,buffer);
|
|
/* Now skip "count" bytes */
|
|
while(len > 0) {
|
|
size_t n = (len > sizeof(buffer) ? sizeof(buffer) : len);
|
|
size_t actual = ast_read(rt,n,buffer);
|
|
if(actual < n) {status = rt->err; ATHROW(status,done);}
|
|
}
|
|
break;
|
|
default: status = AST_EFAIL; break;
|
|
}
|
|
done:
|
|
return ACATCH(status);
|
|
}
|
|
|
|
ast_err
|
|
ast_write_primitive_packed(ast_runtime* rt, const ast_sort sort,
|
|
const int fieldno, const void* valuep)
|
|
{
|
|
ast_err status = AST_NOERR;
|
|
int i;
|
|
uint8_t buffer[MAXWIRELEN];
|
|
size_t count,size;
|
|
const ast_repeated_field* repeater = (const ast_repeated_field*)valuep;
|
|
char* p;
|
|
int typesize;
|
|
|
|
if(repeater->count == 0) goto done;
|
|
|
|
typesize = ast_ctypesize(rt,sort);
|
|
|
|
/* wiretype is always ast_counted */
|
|
status = ast_write_tag(rt,ast_counted,fieldno);
|
|
if(status != AST_NOERR) goto done;
|
|
|
|
/* Compute the size of what is to be written */
|
|
for(p=repeater->values,size=0,i=0;i<repeater->count;i++,p+=typesize) {
|
|
size += ast_get_size(rt,sort,(void*)p);
|
|
}
|
|
/* convert size to varint and write it out */
|
|
count = uint32_encode(size,buffer);
|
|
if(ast_write(rt,count,buffer) != count) {status = AST_EIO; goto done;}
|
|
/* Now write each value */
|
|
for(p=repeater->values,i=0;i<repeater->count;i++,p+=typesize) {
|
|
status = ast_write_primitive_data(rt,sort,fieldno,(void*)p);
|
|
if(status != AST_NOERR) goto done;
|
|
}
|
|
|
|
done:
|
|
return ACATCH(status);
|
|
}
|
|
|
|
ast_err
|
|
ast_read_primitive_packed(ast_runtime* rt, const ast_sort sort, const int fieldno,
|
|
void* valuep)
|
|
{
|
|
ast_err status = AST_NOERR;
|
|
size_t count,len;
|
|
const ast_repeated_field* repeater = (const ast_repeated_field*)valuep;
|
|
int typesize = ast_ctypesize(rt,sort);
|
|
char* p = NULL;
|
|
uint8_t varintbuf[VARINTMAX64];
|
|
uint8_t cbuffer[MAXCTYPESIZE];
|
|
|
|
if(valuep == NULL) return ACATCH(AST_EFAIL);
|
|
|
|
/* wire type should always be ast_counted */
|
|
status = ast_readvarint(rt,varintbuf,&len);
|
|
if(status != AST_NOERR) ATHROW(status,done);
|
|
/* extract the count */
|
|
count = (size_t)uint64_decode(len,varintbuf);
|
|
|
|
/* mark the runtime */
|
|
status = ast_mark(rt,count);
|
|
if(status != AST_NOERR) ATHROW(status,done);
|
|
|
|
/* Read until we hit the end of the mark */
|
|
for(count=0,p=(char*)valuep;status == AST_NOERR;count++,p+=typesize) {
|
|
status = ast_read_primitive_data(rt,sort,cbuffer);
|
|
if(status != AST_NOERR) break;
|
|
status = ast_repeat_append(rt,sort,(void*)repeater,(void*)cbuffer);
|
|
}
|
|
if(status == AST_EOF) status = AST_NOERR;
|
|
if(status != AST_NOERR) ATHROW(status,done);
|
|
status = ast_unmark(rt);
|
|
|
|
done:
|
|
return ACATCH(status);
|
|
}
|
|
|
|
ast_err
|
|
ast_reclaim_string(ast_runtime* rt, char* value)
|
|
{
|
|
ast_free(rt,value);
|
|
return AST_NOERR;
|
|
}
|
|
|
|
ast_err
|
|
ast_reclaim_bytes(ast_runtime* rt, bytes_t* value)
|
|
{
|
|
ast_free(rt,value->bytes);
|
|
return AST_NOERR;
|
|
}
|
|
|
|
ast_runtime_ops*
|
|
ast_byteio_getopts(ast_runtime* rt)
|
|
{
|
|
return rt->ops;
|
|
}
|
|
|
|
ast_err
|
|
ast_byteio_setopts(ast_runtime* rt, ast_runtime_ops* ops)
|
|
{
|
|
rt->ops = ops;
|
|
return AST_NOERR;
|
|
}
|