blob: 98070021ad4506f570bd7cf0117653508929ce95 [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_binary_tdo.h"
#include "etch_defvalufact.h"
#include "etch_arrayval.h"
#include "etch_encoding.h"
#include "etch_global.h"
#include "etchlog.h"
char* ETCHBTDO = "BTDO";
byte bintagdata_get_native_typecode(const unsigned short, const unsigned short);
/* - - - - - - - - - - - - - - - - - - - -
* private signatures
* - - - - - - - - - - - - - - - - - - - -
*/
i_binary_tdo* new_binarytdo_vtable();
int destroy_binary_tagged_data_output(binary_tagged_data_output*);
binary_tagged_data_output* clone_binary_tagged_data_output(binary_tagged_data_output*);
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
* - - - - - - - - - - - - - - - - - - - -
*/
/**
* 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);
tdo->destroy = destroy_binary_tagged_data_output;
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 = cache_find(get_vtable_cachehkey(CLASSID_BINARYTDO_VTAB), 0);
if(!vtab)
{ vtab = new_binarytdo_vtable();
cache_insert(vtab->hashkey, vtab, FALSE);
}
tdo->vtab = 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);
}
/**
* destroy_binary_tagged_data_output()
*/
int destroy_binary_tagged_data_output(binary_tagged_data_output* tdo)
{
if (tdo->refcount > 0 && --tdo->refcount > 0) return -1;
if (!is_etchobj_static_content(tdo))
{
if (tdo->impl)
tdo->impl->destroy(tdo->impl);
if (tdo->flexbuf && tdo->is_flexbuf_owned)
tdo->flexbuf->destroy(tdo->flexbuf);
}
/* destroy private instance data */
etch_free(tdo->static_nullobj);
etch_free(tdo->static_eodmarker);
clear_etchobj_static_all(tdo->static_emptystring);
tdo->static_emptystring->destroy(tdo->static_emptystring);
return destroy_objectex((objmask*)tdo);
}
/**
* clone_tagged_data_output()
* tdo copy constructor. if the tdo object implements a separate instance data
* object, that object is cloned as well.
*/
binary_tagged_data_output* clone_binary_tagged_data_output(binary_tagged_data_output* tdo)
{
binary_tagged_data_output* newtdo = (binary_tagged_data_output*) clone_object((objmask*) tdo);
newtdo->impl = tdo->impl? tdo->impl->clone(tdo->impl): NULL;
return newtdo;
}
/**
* 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].obj_type = ETCHTYPEB_TAGDATAOUT;
inheritlist[1].class_id = CLASSID_TAGDATAOUT;
inheritlist[2].obj_type = ETCHTYPEB_TAGDATA;
inheritlist[2].class_id = CLASSID_TAGDATA;
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)
{
binary_tagged_data_output* tdo = (binary_tagged_data_output*) tdox;
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)
{
etch_int32* sizeobj = NULL;
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 (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 = new_arrayvalue_from (na, content_typecode,
NULLTYPE, ETCH_DEFSIZE, ETCH_DEFSIZE, FALSE);
if (NULL == av)
etchlog(ETCHBTDO, ETCHLOG_ERROR, "nativearray conversion failed");
else av->is_array_owned = FALSE; /* 1/20 */
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, (objmask*) intobj);
intobj->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 */
tdo->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)
{
int result = bintdo_write_value_rawint(tdo, (int) bytecount);
size_t nout = etch_flexbuf_put(tdo->flexbuf, 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))
&& (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;
char* bytevector = NULL;
if (NULL == s) return -1;
wire_encoding = get_etch_string_encoding(tdo->vf);
this_encoding = s->encoding;
switch(wire_encoding)
{
case ETCH_ENCODING_UTF16:
switch(this_encoding)
{
case ETCH_ENCODING_UTF16:
bytevector = s->v.valc;
bytes_to_write = s->char_count * sizeof(wchar_t);
break;
case ETCH_ENCODING_UTF8:
case ETCH_ENCODING_ASCII:
result = etch_utf8_to_unicode((wchar_t**)&bytevector, s->v.valc);
if (bytevector) bytes_to_write = (int) wcslen((wchar_t*)bytevector);
is_new_memory = TRUE;
break;
}
break;
case ETCH_ENCODING_UTF8:
case ETCH_ENCODING_ASCII:
switch(this_encoding)
{
case ETCH_ENCODING_UTF16:
result = etch_unicode_to_utf8(&bytevector, s->v.valw);
if (bytevector) bytes_to_write = (int) strlen(bytevector);
is_new_memory = TRUE;
break;
case ETCH_ENCODING_UTF8:
case ETCH_ENCODING_ASCII:
bytevector = s->v.valc;
bytes_to_write = s->char_count;
break;
}
break;
}
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);
}
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;
objmask* 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 = (objmask*) iterator.current_value;
ETCH_ASSERT(thiskey);
thisvtor = (etch_validator*)
etchtype_get_validator_by_name (struct_type, thiskey->name);
if (NULL == thisvtor)
{ etchlog(ETCHBTDO, ETCHLOG_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, objmask* value)
{
int result = 0;
size_t nout = 0;
union_alltypes u;
signed char external_typecode;
if (config.is_validate_on_write)
{ /* 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))
{ etchlog(ETCHBTDO, ETCHLOG_ERROR, "validation failed for type %x class %x\n",
value->obj_type, 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, &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.
*/
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((etch_nativearray*) value);
else u.varrayval = (etch_arrayvalue*) value;
/* fyi a null u.varrayval is handled by both bintdo_write_array()
* and by ETCHOBJ_DESTROY() so we have omitted a null check here */
result = bintdo_write_array ((tagged_data_output*)tdo, u.varrayval, vtor);
/* we want to destroy the array object only if it is a copy we made here;
* otherwise the message owns it as a value, and will destroy it. */
if (is_etch_nativearray(value))
ETCHOBJ_DESTROY(u.varrayval);
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 = tdo->vf->vtab->export_custom_value(tdo->vf, value);
if (NULL == sv) return -1;
result = bintdo_write_struct((tagged_data_output*) tdo, sv);
sv->destroy(sv);
return result;
}
default:
return is_inrange_tiny(external_typecode)? 0: -1;
}
return nout? 0: -1;
}