blob: f3ca824fdad94cdb01ee45724087dd53cec21168 [file]
/* $Id$
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to you under the Apache License, Version
* 2.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
* etch_binary_tdo.c -- binary tagged data output implementation.
*/
#include "etch_runtime.h"
#include "etch_binary_tdo.h"
#include "etch_default_value_factory.h"
#include "etch_cache.h"
#include "etch_arrayval.h"
#include "etch_encoding.h"
#include "etch_nativearray.h"
#include "etch_objecttypes.h"
#include "etch_log.h"
#include "etch_mem.h"
static const char* LOG_CATEGORY = "etch_binary_tdo";
byte bintagdata_get_native_typecode(const unsigned short, const unsigned short);
/* - - - - - - - - - - - - - - - - - - - -
* private signatures
* - - - - - - - - - - - - - - - - - - - -
*/
i_binary_tdo* new_binarytdo_vtable();
int bintdo_start_message(tagged_data_output*, etch_message*);
int bintdo_write_message(tagged_data_output*, etch_message*, etch_flexbuffer*);
int bintdo_end_message (tagged_data_output*, etch_message*);
int bintdo_start_struct (tagged_data_output*, etch_structvalue*);
int bintdo_write_struct (tagged_data_output*, etch_structvalue*);
int bintdo_end_struct (tagged_data_output*, etch_structvalue*);
int bintdo_start_array (tagged_data_output*, etch_arrayvalue*);
int bintdo_write_array (tagged_data_output*, etch_arrayvalue*, etch_validator*);
int bintdo_end_array (tagged_data_output*, etch_arrayvalue*);
int bintdo_write_type (binary_tagged_data_output*, etch_type*);
int bintdo_write_values(binary_tagged_data_output*, etch_arrayvalue*, etch_validator*);
int bintdo_write_keys_values(binary_tagged_data_output*, etch_structvalue*);
int bintdo_write_bytes_from (binary_tagged_data_output*, etch_nativearray*);
int bintdo_write_value_rawint(binary_tagged_data_output*, const int);
int bintdo_write_intvalue (binary_tagged_data_output*, const int);
int bintdo_write_nonevalue(binary_tagged_data_output*);
/* - - - - - - - - - - - - - - - - - - - -
* constructors/destructors
* - - - - - - - - - - - - - - - - - - - -
*/
/**
* destroy_binary_tagged_data_output()
*/
int destroy_binary_tagged_data_output(void* data)
{
binary_tagged_data_output* tdo = (binary_tagged_data_output*)data;
if (!is_etchobj_static_content(tdo))
{
etch_object_destroy(tdo->impl);
if (tdo->flexbuf && tdo->is_flexbuf_owned)
etch_object_destroy(tdo->flexbuf);
}
/* destroy private instance data */
etch_free(tdo->static_nullobj);
etch_free(tdo->static_eodmarker);
clear_etchobj_static_all(tdo->static_emptystring);
etch_object_destroy(tdo->static_emptystring);
return destroy_objectex((etch_object*)tdo);
}
/**
* clone_tagged_data_output()
* tdo copy constructor. if the tdo object implements a separate instance data
* object, that object is cloned as well.
*/
void* clone_binary_tagged_data_output(void* data)
{
binary_tagged_data_output* tdo = (binary_tagged_data_output*)data;
binary_tagged_data_output* newtdo = (binary_tagged_data_output*) clone_object((etch_object*) tdo);
newtdo->impl = tdo->impl? tdo->impl->clone(tdo->impl): NULL;
return newtdo;
}
/**
* new_binary_tdo()
* binary_tagged_data_output constructor
* @param vf a value factory. can be null. caller retains ownership.
* @param fbuf the buffer to write to. can be null. caller retains ownership.
*/
binary_tagged_data_output* new_binary_tagdata_output(etch_value_factory* vf, etch_flexbuffer* fbuf)
{
i_binary_tdo* vtab = NULL;
binary_tagged_data_output* tdo = (binary_tagged_data_output*) new_object
(sizeof(binary_tagged_data_output), ETCHTYPEB_TAGDATAOUT, CLASSID_TAGDATAOUT);
((etch_object*)tdo)->destroy = destroy_binary_tagged_data_output;
((etch_object*)tdo)->clone = clone_binary_tagged_data_output;
tdo->flexbuf = fbuf; /* if caller passes buffer, caller owns it */
if (fbuf) tdo->is_flexbuf_owned = FALSE;
tdo->vf = vf;
vtab = etch_cache_find(get_vtable_cachehkey(CLASSID_BINARYTDO_VTAB), 0);
if(!vtab)
{ vtab = new_binarytdo_vtable();
etch_cache_insert(((etch_object*)vtab)->get_hashkey(vtab), vtab, FALSE);
}
((etch_object*)tdo)->vtab = (vtabmask*)vtab;
tdo->vtor_eod = etchvtor_eod_get();
tdo->vtor_int = etchvtor_int32_get(0);
tdo->static_nullobj = etchtagdata_new_nullobj(TRUE);
tdo->static_eodmarker = etchtagdata_new_eodmarker(TRUE);
tdo->static_emptystring = etchtagdata_new_emptystring(TRUE);
return tdo;
}
/**
* new_binary_tdo()
* casts result to generic tdo for use by interfaces
*/
tagged_data_output* new_binary_tdo(etch_value_factory* vf)
{
return (tagged_data_output*) new_binary_tagdata_output(vf, NULL);
}
/**
* new_new_binarytdo_vtable()
* constructor for binary tdo virtual function table
*/
i_binary_tdo* new_binarytdo_vtable()
{
etchparentinfo* inheritlist = new_etch_inheritance_list(3, 2, NULL);
i_binary_tdo* vtab
= new_vtable(NULL, sizeof(i_binary_tdo), CLASSID_BINARYTDO_VTAB);
/* i_tagged_data_input */
vtab->start_message = bintdo_start_message;
vtab->write_message = bintdo_write_message;
vtab->end_message = bintdo_end_message;
vtab->start_struct = bintdo_start_struct;
vtab->write_struct = bintdo_write_struct;
vtab->end_struct = bintdo_end_struct;
vtab->start_array = bintdo_start_array;
vtab->write_array = bintdo_write_array;
vtab->end_array = bintdo_end_array;
/* i_tagdata */
#if(0)
vtab->check_value = etchtagdata_check_value;
vtab->get_native_type = bintdo_get_native_type;
vtab->get_native_type_code = bintdo_get_native_typecode;
vtab->get_custom_structtype = bintdo_get_custom_structtype;
#endif
/* inheritance */
inheritlist[1].o.obj_type = ETCHTYPEB_TAGDATAOUT;
inheritlist[1].c.class_id = CLASSID_TAGDATAOUT;
inheritlist[2].o.obj_type = ETCHTYPEB_TAGDATA;
inheritlist[2].c.class_id = CLASSID_TAGDATA;
vtab->inherits_from = inheritlist;
return vtab;
}
/* - - - - - - - - - - - - - - - - - - - -
* write message
* - - - - - - - - - - - - - - - - - - - -
*/
/**
* bintdo_start_message()
* message is unique among serialized objects in that since message is at the
* top level, no type byte is written to mark the start of a message. a version
* number is written to identify the btd implementation version used to write
* the message.
*/
int bintdo_start_message(tagged_data_output* tdox, etch_message* msg)
{
binary_tagged_data_output* tdo = (binary_tagged_data_output*) tdox;
ETCH_ASSERT(tdo && msg);
etch_flexbuf_put_byte(tdo->flexbuf, ETCH_BINTAGDATA_CURRENT_VERSION);
return bintdo_start_struct(tdox, msg->sv);
}
/**
* bintdo_write_message()
* message is unique among serialized objects in that since message is at the
* top level, no type byte is written to mark the start of a message. a version
* number is written to identify the btd implementation version used to write
* the message.
*/
int bintdo_write_message(tagged_data_output* tdox, etch_message* msg, etch_flexbuffer* fbuf)
{
binary_tagged_data_output* tdo = (binary_tagged_data_output*) tdox;
ETCH_ASSERT(tdo && msg && fbuf);
tdo->flexbuf = fbuf;
if (-1 == bintdo_start_message(tdox, msg)) return -1;
if (-1 == bintdo_write_keys_values(tdo, msg->sv)) return -1;
return bintdo_end_message(tdox, msg);
}
/**
* tdo_end_message()
* marks the end of the message in process.
*/
int bintdo_end_message(tagged_data_output* tdox, etch_message* msg)
{
return bintdo_end_struct(tdox, msg->sv);
}
/* - - - - - - - - - - - - - - - - - - - -
* write struct
* - - - - - - - - - - - - - - - - - - - -
*/
/**
* bintdo_start_struct()
* write the beginning of struct data.
*/
int bintdo_start_struct(tagged_data_output* tdox, etch_structvalue* sv)
{
binary_tagged_data_output* tdo = (binary_tagged_data_output*) tdox;
ETCH_ASSERT(tdo && sv);
/* caller has already written a bytecode to the buffer indicating struct follows */
if (-1 == bintdo_write_type(tdo, sv->struct_type)) return -1;
return bintdo_write_value_rawint(tdo, structvalue_count(sv));
}
/**
* bintdo_write_struct()
*/
int bintdo_write_struct(tagged_data_output* tdox, etch_structvalue* sv)
{
ETCH_ASSERT(tdox && sv);
if (-1 == bintdo_start_struct(tdox, sv)) return -1;
if (-1 == bintdo_write_keys_values((binary_tagged_data_output*)tdox, sv)) return -1;
return bintdo_end_struct(tdox, sv);
}
/**
* bintdo_end_struct()
* mark end of specified struct
*/
int bintdo_end_struct(tagged_data_output* tdox, etch_structvalue* sv)
{
return bintdo_write_nonevalue((binary_tagged_data_output*) tdox);
}
/* - - - - - - - - - - - - - - - - - - - -
* write array
* - - - - - - - - - - - - - - - - - - - -
*/
/**
* bintdo_start_array()
* starts writing of an array
*/
int bintdo_start_array (tagged_data_output* tdox, etch_arrayvalue* av)
{
int errs = 0;
binary_tagged_data_output* tdo = (binary_tagged_data_output*) tdox;
ETCH_ASSERT(tdo && av);
etch_flexbuf_put_byte (tdo->flexbuf, av->type_code);
if (ETCH_XTRNL_TYPECODE_CUSTOM == av->type_code)
errs += bintdo_write_type (tdo, av->custom_struct_type);
errs += bintdo_write_value_rawint (tdo, av->dim);
errs += bintdo_write_value_rawint (tdo, arrayvalue_count(av));
return errs? -1: 0;
}
/**
* bintdo_write_array()
*/
int bintdo_write_array (tagged_data_output* tdox, etch_arrayvalue* av, etch_validator* vtor)
{
ETCH_ASSERT(tdox && vtor);
if (!is_etch_arrayvalue(av)) return -1;
if (-1 == bintdo_start_array (tdox, av)) return -1;
if (-1 == bintdo_write_values ((binary_tagged_data_output*) tdox, av, vtor))
return -1;
return bintdo_end_array(tdox, av);
}
/**
* bintdo_end_array()
* writes end of the array being read.
*/
int bintdo_end_array (tagged_data_output* tdo, etch_arrayvalue* av)
{
return bintdo_write_nonevalue ((binary_tagged_data_output*) tdo);
}
/**
* bintdo_to_arrayvalue()
* convert supplied native array to an etch_arrayvalue.
* @param na the native array. caller retains.
* @return an etch_arrayvalue. caller owns it.
*/
etch_arrayvalue* bintdo_to_arrayvalue (binary_tagged_data_output* tdo, etch_nativearray* na)
{
etch_type* NULLTYPE = NULL;
signed char content_typecode = arrayvalue_get_external_typecode(na->content_obj_type, na->content_class_id);
/* todo we should calculate array size from native array
* metadata rather than creating it using a default size */
etch_arrayvalue* av = NULL;
if(((etch_object*)na)->class_id != CLASSID_ARRAY_OBJECT && content_typecode == ETCH_XTRNL_TYPECODE_CUSTOM) {
etch_type* theType = NULL;
//theType = class_to_type_map_get(tdo->vf)->class_to_type, na->content_class_id);
theType = ((struct i_value_factory*)((etch_object*)tdo->vf)->vtab)->get_custom_struct_type(tdo->vf, ETCHMAKECLASS(na->content_obj_type, na->content_class_id));
av = new_arrayvalue_from (na, content_typecode, theType, ETCH_DEFSIZE, ETCH_DEFSIZE, TRUE);
av->content_class_id = na->content_class_id;
av->custom_struct_type = theType;
}
else
if(((etch_object*)na)->class_id == CLASSID_ARRAY_OBJECT && content_typecode == ETCH_XTRNL_TYPECODE_CUSTOM) {
av = new_arrayvalue_from (na, ETCH_XTRNL_TYPECODE_ANY, NULLTYPE, ETCH_DEFSIZE, ETCH_DEFSIZE, TRUE);
av->content_class_id = na->content_class_id;
}
else {
av = new_arrayvalue_from (na, content_typecode, NULLTYPE, ETCH_DEFSIZE, ETCH_DEFSIZE, TRUE);
av->content_class_id = na->content_class_id;
}
if(NULL == av) {
ETCH_LOG(LOG_CATEGORY, ETCH_LOG_ERROR, "nativearray conversion failed");
}
return av;
}
///**
// * normalize_etch_array()
// * validate parameter as an array type with dimension <= that specified,
// * and convert to arrayvalue if necessary.
// * @param a an arrayvalue or nativearray. caller retains.
// * @param maxdim maximum number of dimensions, zero means don't validate dimensions.
// * @return the passed array expressed as an to arrayvalue, or NULL if error.
// */
//etch_arrayvalue* normalize_etch_array(void* a, const int maxdim)
//{
// etch_arrayvalue* av = NULL;
//
// if (is_etch_nativearray(a))
// { etch_nativearray* na = (etch_nativearray*) a;
// if (0 == maxdim || na->numdims <= maxdim)
// av = bintdo_to_arrayvalue(na);
// }
// else
// if (is_etch_arrayvalue(a))
// { etch_arrayvalue* xav = (etch_arrayvalue*) a;
// if (0 == maxdim || xav->dim <= maxdim)
// av = xav;
// }
//
// return av;
//}
/* - - - - - - - - - - - - - - - - - - - -
* disassemble objects and write bytes
* - - - - - - - - - - - - - - - - - - - -
*/
/**
* bintdo_write_nonevalue()
* convenience method to write eod marker
*/
int bintdo_write_nonevalue(binary_tagged_data_output* tdo)
{
return bintdo_write_value(tdo, tdo->vtor_eod, tdo->static_eodmarker);
}
/**
* bintdo_write_intvalue()
* convenience method used when an encoded integer is expected next in
* the buffer, to write such a value to the buffer.
*
* this method is no longer used, we now use bintdo_write_value_rawint()
*/
int bintdo_write_intvalue(binary_tagged_data_output* tdo, const int value)
{
etch_int32* intobj = new_int32(value);
int result = bintdo_write_value(tdo, tdo->vtor_int, (etch_object*) intobj);
etch_object_destroy(intobj);
return result;
}
/**
* bintdo_write_value_rawint()
* write specified 32-bit integer value to the buffer
*/
int bintdo_write_value_rawint(binary_tagged_data_output* tdo, const int value)
{
size_t nout = 0;
if (is_inrange_tiny(value))
nout = etch_flexbuf_put_byte(tdo->flexbuf, (signed char) value);
else
if (is_inrange_byte(value))
if (sizeof(byte) == etch_flexbuf_put_byte(tdo->flexbuf, ETCH_XTRNL_TYPECODE_BYTE))
nout = etch_flexbuf_put_byte(tdo->flexbuf, (signed char) value);
else;
else
if (is_inrange_int16(value))
if (sizeof(byte) == etch_flexbuf_put_byte(tdo->flexbuf, ETCH_XTRNL_TYPECODE_SHORT))
nout = etch_flexbuf_put_short(tdo->flexbuf, (short) value);
else;
else
if (sizeof(byte) == etch_flexbuf_put_byte(tdo->flexbuf, ETCH_XTRNL_TYPECODE_INT))
nout = etch_flexbuf_put_int(tdo->flexbuf, value);
return nout? 0: -1;
}
/**
* bintdo_write_type()
* convenience method used when an etch_type is to be written to the buffer,
* to write such a value to the buffer. caller owns the supplied type.
* only the type's id is written.
*/
int bintdo_write_type(binary_tagged_data_output* tdo, etch_type* type)
{
return type? bintdo_write_value_rawint(tdo, type->id): -1;
}
/**
* bintdo_get_bytes()
* gets serialized bytes of the specified message. caller owns returned byte vector.
* not sure what this is used for.
* "static" method, no tdo is passed.
* @return count of bytes
*/
int bintdo_get_bytes(etch_message* msg, etch_value_factory* vf, byte** out)
{
size_t bytecount = 0;
etch_flexbuffer* fbuf = new_flexbuffer(0); /* tdo will own this */
binary_tagged_data_output* tdo = new_binary_tagdata_output(vf, fbuf);
bintdo_write_message((tagged_data_output*)tdo, msg, fbuf);
*out = etch_flexbuf_get_all(fbuf, &bytecount); /* new allocation */
etch_object_destroy(tdo);
return (int) bytecount;
}
/**
* bintdo_write_bytes()
* writes a byte vector to the buffer.
*/
int bintdo_write_bytes(binary_tagged_data_output* tdo, char* bytes, const int bytecount)
{
size_t nout = 0;
/* TODO handle return value */
bintdo_write_value_rawint(tdo, (int) bytecount);
nout = etch_flexbuf_put(tdo->flexbuf, (unsigned char*)bytes, 0, bytecount);
return nout == bytecount? 0: -1;
}
/**
* bintdo_write_bytes_from()
* writes a byte vector from a native array to the buffer.
* @param bytearray an etch_nativearray of single dimension and of content type byte.
*/
int bintdo_write_bytes_from(binary_tagged_data_output* tdo, etch_nativearray* bytearray)
{
/* we're assuming we always get a nativearray object and not a char*,
* however i'm not sure yet exactly where the tdo input is created,
* so i'm not positive this is the way is should be. update: perhaps this
* method should be passed an arrayvalue, keep an eye on this.
*/
size_t bytecount = 0, nout = 0;
int result = 0;
//if ((is_etch_nativearray(bytearray))
//&& (((etch_object*)bytearray)->class_id = CLASSID_ARRAY_BYTE)
//&& (bytearray->numdims == 1));
//else return -1;
bytecount = bytearray->bytecount; /* or bytearray->dimsize[0], same thing */
result = bintdo_write_value_rawint(tdo, (int) bytecount);
nout = etch_flexbuf_put(tdo->flexbuf, bytearray->values, 0, bytecount);
return nout == bytecount? 0: -1;
}
/**
* bintdo_write_string()
* writes a string value to the buffer.
*/
int bintdo_write_string(binary_tagged_data_output* tdo, etch_string* s)
{
int result = 0, wire_encoding = 0, this_encoding = 0, is_new_memory = 0;
int bytes_to_write = 0, bytes_written = 0;
unsigned char* bytevector = NULL;
unsigned int terminator = 0;
if (NULL == s) return -1;
wire_encoding = get_etch_string_encoding(tdo->vf);
this_encoding = s->encoding;
if (wire_encoding == this_encoding) {
bytevector = s->v.value;
bytes_to_write = s->byte_count;
} else {
// TODO: pool
result = etch_encoding_transcode((char**)&bytevector, wire_encoding, s->v.value, this_encoding, s->byte_count, &bytes_to_write, NULL);
ETCH_ASSERT(result != -1);
is_new_memory = TRUE;
}
terminator = etch_encoding_get_sizeof_terminator(wire_encoding);
if ((unsigned int)bytes_to_write > terminator) {
bytes_to_write -= terminator;
}
if (NULL == bytevector) return -1;
result = bintdo_write_value_rawint(tdo, bytes_to_write);
bytes_written = (int) etch_flexbuf_put(tdo->flexbuf, bytevector, 0, bytes_to_write);
result = bytes_written == bytes_to_write? 0: -1;
if (is_new_memory)
etch_free(bytevector);
return result;
}
/**
* bintdo_write_values()
* write all values from the specified array
*/
int bintdo_write_values(binary_tagged_data_output* tdo, etch_arrayvalue* av,
etch_validator* vtor)
{
int errs = 0;
etch_validator* ev = vtor? vtor->element_validator(vtor): NULL;
etch_iterator iterator;
set_iterator(&iterator, av->list, &av->list->iterable);
while(iterator.has_next(&iterator))
{
errs += (0 != bintdo_write_value(tdo, ev, iterator.current_value));
iterator.next(&iterator);
}
etch_object_destroy(ev);
return errs? -1: 0;
}
/**
* bintdo_write_keys_values()
* write key/value pairs from the struct to the buffer
*/
int bintdo_write_keys_values (binary_tagged_data_output* tdo, etch_structvalue* sv)
{
etch_type* struct_type = sv->struct_type;
etch_validator* thisvtor = NULL;
etch_field* thiskey = NULL;
etch_object* thisval = NULL;
int result = 0;
etch_iterator iterator;
set_iterator(&iterator, sv->items, &sv->items->iterable);
while(iterator.has_next(&iterator))
{
thiskey = (etch_field*) iterator.current_key;
thisval = (etch_object*) iterator.current_value;
ETCH_ASSERT(thiskey);
thisvtor = (etch_validator*)
etchtype_get_validator_by_name (struct_type, thiskey->name);
if (NULL == thisvtor)
{
ETCH_LOG(LOG_CATEGORY, ETCH_LOG_ERROR, "type '%s' missing validator '%s'\n", struct_type->aname, thiskey->aname);
result = -1;
break;
}
result = bintdo_write_value_rawint (tdo, thiskey->id);
result = bintdo_write_value (tdo, thisvtor, thisval);
if (-1 == result) break;
iterator.next(&iterator);
}
return result;
}
/**
* bintdo_write_value()
* write specified value to the buffer
* @param vtor validator for specified value, or null if none
* @param value the value to be encoded and written, as a *non-disposable* object,
* i.e. caller owns memory for the value object.
*/
int bintdo_write_value (binary_tagged_data_output* tdo, etch_validator* vtor, etch_object* value)
{
etch_config_t* config = NULL;
int32 propvalue = 0;
int result = 0;
size_t nout = 0;
union_alltypes u;
signed char external_typecode;
etch_runtime_get_config(&config);
ETCH_ASSERT(config);
etch_config_get_property_int(config, "etch.validate.write", &propvalue);
if (propvalue == 1)
{ /* we should disable validate on write in production */
if (NULL == value); /* don't recall why null value is not validated */
else
if (!vtor || -1 == vtor->validate (vtor, (etch_object*) value))
{
ETCH_LOG(LOG_CATEGORY, ETCH_LOG_ERROR, "validation failed for type %x class %x\n", ((etch_object*)value)->obj_type, ((etch_object*)value)->class_id);
return -1;
}
}
/* determine tag (fyi signed only because using the java byte constants) */
external_typecode = etchtagdata_check_value((etch_object*) value);
/* write tag */
if (sizeof(byte) != etch_flexbuf_put_byte(tdo->flexbuf, external_typecode))
return -1;
switch(external_typecode)
{
case ETCH_XTRNL_TYPECODE_NULL:
case ETCH_XTRNL_TYPECODE_NONE:
case ETCH_XTRNL_TYPECODE_EMPTY_STRING:
case ETCH_XTRNL_TYPECODE_BOOLEAN_FALSE:
case ETCH_XTRNL_TYPECODE_BOOLEAN_TRUE:
return 0; /* nothing to do, tag says it all */
case ETCH_XTRNL_TYPECODE_BYTE:
if (0 == etchtagdata_byte_value((etch_object*) value, (byte*)&u.vbyte))
nout = etch_flexbuf_put_byte(tdo->flexbuf, u.vbyte);
break;
case ETCH_XTRNL_TYPECODE_INT:
if (0 == etchtagdata_int32_value((etch_object*) value, &u.vint32))
nout = etch_flexbuf_put_int(tdo->flexbuf, u.vint32);
break;
case ETCH_XTRNL_TYPECODE_LONG:
if (0 == etchtagdata_int64_value((etch_object*) value, &u.vint64))
nout = etch_flexbuf_put_long(tdo->flexbuf, u.vint64);
break;
case ETCH_XTRNL_TYPECODE_SHORT:
if (0 == etchtagdata_int16_value((etch_object*) value, &u.vint16))
nout = etch_flexbuf_put_short(tdo->flexbuf, u.vint16);
break;
case ETCH_XTRNL_TYPECODE_DOUBLE:
if (0 == etchtagdata_double_value((etch_object*) value, &u.vdouble))
nout = etch_flexbuf_put_double(tdo->flexbuf, u.vdouble);
break;
case ETCH_XTRNL_TYPECODE_FLOAT:
if (0 == etchtagdata_float_value((etch_object*) value, &u.vfloat))
nout = etch_flexbuf_put_float(tdo->flexbuf, u.vfloat);
break;
case ETCH_XTRNL_TYPECODE_BYTES:
/* we get an arrayvalue here. to do differently would be problematic
* without rewriting higher levels to not work with arrayvalue.
* perhaps we should simply pass arrayvalue to bintdo_write_bytes_from().
* TODO either accept a native array here, or change
* bintdo_write_bytes_from() to accept an arrayvalue, or both.
*/
if(is_etch_nativearray(value)){
u.vnatarray = (etch_nativearray*)value;
result = bintdo_write_bytes_from(tdo,u.vnatarray);
return result;
}
else{
u.vnatarray = ((etch_arrayvalue*)value)->natarray;
result = bintdo_write_bytes_from(tdo, u.vnatarray);
return result;
}
case ETCH_XTRNL_TYPECODE_ARRAY:
/* if arriving here from client app we may get an etch_nativearray,
* which we must convert to an arrayvalue now.
* TODO write a version of bintdo_write_array which accepts a
* nativearray, so we can avoid this to_arrayvalue() conversion.
*/
if (is_etch_nativearray(value)) {
u.varrayval = bintdo_to_arrayvalue(tdo, (etch_nativearray*) value);
result = bintdo_write_array((tagged_data_output*)tdo, u.varrayval, vtor);
etch_object_destroy(u.varrayval);
}
else {
u.varrayval = (etch_arrayvalue*) value;
result = bintdo_write_array((tagged_data_output*)tdo, u.varrayval, vtor);
}
return result;
case ETCH_XTRNL_TYPECODE_STRING:
{ etch_string* s = (etch_string*) value;
result = bintdo_write_string(tdo, s);
return result;
}
case ETCH_XTRNL_TYPECODE_CUSTOM:
{
etch_structvalue* sv = ((struct i_value_factory*)((etch_object*)tdo->vf)->vtab)->export_custom_value(tdo->vf, value);
if (NULL == sv) return -1;
result = bintdo_write_struct((tagged_data_output*) tdo, sv);
etch_object_destroy(sv);
return result;
}
default:
return is_inrange_tiny_for_signed_chars(external_typecode)? 0: -1;
}
return nout? 0: -1;
}