blob: 50293001304e00cad80d25413dde9e651adef721 [file] [log] [blame]
/* $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_tagdata.c -- tagged data implementation.
*/
#include "etch_tagged_data.h"
#include "etch_type.h"
#include "etch_arrayval.h"
#include "etch_nativearray.h"
#include "etch_objecttypes.h"
/* the only instance data in the java version is the value factory
* for C, inheritors can implement that, in order that we don't need
* any instance data here and can just implement methods.
*/
/*
* etchtagdata_get_number()
* java.Lang.Number emulation support.
* given an anonymous wrapped primitive, return its value represented as
* a 64-bit integer.
*/
int etchtagdata_get_number(etch_object* valobj,
const double fmin, const double fmax, int64* out)
{
int64 longval = 0;
double dval;
if (!is_etch_primitive_number(valobj)) return -1;
switch(((etch_object*)valobj)->class_id)
{
case CLASSID_PRIMITIVE_INT32:
longval = ((etch_int32*)valobj)->value;
break;
case CLASSID_PRIMITIVE_INT64:
longval = ((etch_int64*)valobj)->value;
break;
case CLASSID_PRIMITIVE_BYTE:
case CLASSID_PRIMITIVE_BOOL:
case CLASSID_PRIMITIVE_INT8:
longval = ((etch_byte*)valobj)->value;
break;
case CLASSID_PRIMITIVE_INT16:
longval = ((etch_int16*)valobj)->value;
break;
case CLASSID_PRIMITIVE_DOUBLE:
case CLASSID_PRIMITIVE_FLOAT:
{
switch(((etch_object*)valobj)->class_id)
{ case CLASSID_PRIMITIVE_DOUBLE:
dval = ((etch_double*)valobj)->value;
break;
case CLASSID_PRIMITIVE_FLOAT:
dval = (double) ((etch_float*)valobj)->value;
break;
}
/* round ieee value if necessary */
if (dval >= 0.0 && dval <= fmax)
dval += 0.5;
else
if (dval < 0.0 && dval >= fmin)
dval -= 0.5;
longval = (int64) dval;
break;
}
}
*out = longval;
return 0;
}
/*
* etchtagdata_get_fnumber()
* java.Lang.Number emulation support.
* given an anonymous wrapped primitive, return its value represented as
* an IEEE number of 64 bits.
*/
int etchtagdata_get_double_number(etch_object* valobj,
const double fmin, const double fmax, double* outd)
{
float fval = 0.0; double dval = 0.0; int64 longval = 0;
if (-1 == etchtagdata_get_number(valobj, fmin, fmax, &longval))
return -1;
switch(((etch_object*)valobj)->class_id)
{
case CLASSID_PRIMITIVE_DOUBLE:
dval = ((etch_double*)valobj)->value;
break;
case CLASSID_PRIMITIVE_FLOAT:
fval = ((etch_float*)valobj)->value;
dval = (double) fval;
break;
default:
dval = (double) longval;
}
*outd = dval;
return 0;
}
/*
* etchtagdata_get_float_number()
* java.Lang.Number emulation support.
* given an anonymous wrapped primitive, return its value represented as
* an IEEE number of 32 bits.
*/
int etchtagdata_get_float_number(etch_object* valobj,
const double fmin, const double fmax, float* outf)
{
float fval = 0.0; double dval = 0.0; int64 longval = 0;
if (-1 == etchtagdata_get_number(valobj, fmin, fmax, &longval))
return -1;
switch(((etch_object*)valobj)->class_id)
{
case CLASSID_PRIMITIVE_DOUBLE:
dval = ((etch_double*)valobj)->value;
fval = (float) dval;
break;
case CLASSID_PRIMITIVE_FLOAT:
fval = ((etch_float*)valobj)->value;
break;
default:
fval = (float) longval;
}
*outf = fval;
return 0;
}
/*
* etchtagdata_byte_value()
* mimic java.Lang.Number.byteValue()
*/
int etchtagdata_byte_value(etch_object* valobj, byte* out)
{
int64 longval = 0;
const int result = etchtagdata_get_number(valobj, 0, 0, &longval);
if (0 == result && out)
(*out) = (byte) longval; /* truncate and return value */
return result;
}
/*
* etchtagdata_bool_value()
* if there was a java.Lang.Number.booleanValue(), this would mimic it
*/
int etchtagdata_bool_value(etch_object* valobj, boolean* out)
{
int64 longval = 0;
const int result = etchtagdata_get_number(valobj, 0, 0, &longval);
if (0 == result && out)
{
if (longval != 1) {
*out = 1;
}
else {
*out = 0;
}
}
return result;
}
/*
* etchtagdata_int16_value()
* mimic java.Lang.Number.shortValue()
*/
int etchtagdata_int16_value(etch_object* valobj, short* out)
{
int64 longval = 0;
const int result = etchtagdata_get_number(valobj, 0, 0, &longval);
if (0 == result && out)
(*out) = (short) longval; /* truncate and return value */
return result;
}
/*
* etchtagdata_int32_value()
* mimic java.Lang.Number.intValue()
*/
int etchtagdata_int32_value(etch_object* valobj, int* out)
{
int64 longval = 0;
const int result = etchtagdata_get_number(valobj, 0, 0, &longval);
if (0 == result && out)
(*out) = (int) longval; /* truncate and return value */
return result;
}
/*
* etchtagdata_int64_value()
* mimic java.Lang.Number.longValue()
*/
int etchtagdata_int64_value(etch_object* valobj, int64* out)
{
int64 longval = 0;
const int result = etchtagdata_get_number(valobj, 0, 0, &longval);
if (0 == result && out)
(*out) = longval;
return result;
}
/*
* etchtagdata_float_value()
* mimic java.Lang.Number.floatValue()
*/
int etchtagdata_float_value(etch_object* valobj, float* out)
{
const static double ETCHTYPE_MAX_FLOATF = ETCHTYPE_MAX_FLOAT + 0.4999;
const static double ETCHTYPE_MIN_FLOATF = ETCHTYPE_MIN_FLOAT - 0.4999;
float floatval = 0.0;
const int result = etchtagdata_get_float_number(valobj,
ETCHTYPE_MIN_FLOATF, ETCHTYPE_MAX_FLOATF, &floatval);
if (0 == result && out)
(*out) = floatval;
return result;
}
/*
* etchtagdata_double_value()
* mimic java.Lang.Number.doubleValue()
*/
int etchtagdata_double_value(etch_object* valobj, double* out)
{
double dval = 0.0;
const int result = etchtagdata_get_double_number(valobj,
ETCHTYPE_MIN_DOUBLE, ETCHTYPE_MAX_DOUBLE, &dval);
if (0 == result && out)
(*out) = dval;
return result;
}
/*
* etchtagdata_adjust_tiny_int()
* if target value is one byte and value is in range of tiny int,
* adjust the type code accordingly, returning it in out parameter
*/
int etchtagdata_adjust_tiny_int(const signed char target_type, etch_object* valobj, signed char* out)
{
signed char type_out = target_type;
signed char byteval = 0;
int result = 0;
if (target_type == ETCH_XTRNL_TYPECODE_BYTE) {
if (0 == (result = etchtagdata_byte_value(valobj, (byte*)&byteval))) {
if (is_inrange_tiny_for_signed_chars(byteval)) {
type_out = byteval;
}
}
}
if (out) {
(*out = type_out);
}
return result;
}
/*
* etchtagdata_validate_value()
* in java binding this is checkValue(object, validator);
* defers to validator to determine type code for the value.
* adjusts the type to tiny integer if applicable and possible.
* returns the type code in the out parameter.
*/
int etchtagdata_validate_value(etch_object* valobj, etch_validator* vtor, signed char* out)
{
signed char xtype = 0;
int result = 0;
if (NULL == valobj) {
xtype = ETCH_XTRNL_TYPECODE_NULL;
} else {
if (etchtagdata_is_eod(valobj)) {
xtype = ETCH_XTRNL_TYPECODE_NONE;
} else {
if (0 == (result = vtor->check_value(vtor, valobj, (byte*)&xtype))) {
result = etchtagdata_adjust_tiny_int(xtype, valobj, &xtype);
}
}
}
if (out) {
(*out = xtype);
}
return result;
}
/**
* etchtagdata_check_value()
* returns a type code for the specified value
* @param valobj an etch value object, caller retains ownership.
*/
signed char etchtagdata_check_value (etch_object* valobj)
{
signed char xtype = 0;
const unsigned int obj_type = valobj? ((etch_object*)valobj)->obj_type: 0;
const unsigned int class_id = valobj? ((etch_object*)valobj)->class_id: 0;
if (NULL == valobj)
xtype = ETCH_XTRNL_TYPECODE_NULL;
else
if (etchtagdata_is_eod(valobj))
xtype = ETCH_XTRNL_TYPECODE_NONE;
else
if (is_etch_primitive(valobj))
{
switch(class_id)
{
case CLASSID_PRIMITIVE_INT32:
xtype = etchtagdata_check_integer(((etch_int32*)valobj)->value);
break;
case CLASSID_PRIMITIVE_INT16:
xtype = etchtagdata_check_short(((etch_int16*)valobj)->value);
break;
case CLASSID_PRIMITIVE_INT64:
xtype = etchtagdata_check_long(((etch_int64*)valobj)->value);
break;
case CLASSID_PRIMITIVE_BYTE:
case CLASSID_PRIMITIVE_INT8:
xtype = etchtagdata_check_byte(((etch_byte*)valobj)->value);
break;
case CLASSID_PRIMITIVE_DOUBLE:
xtype = ETCH_XTRNL_TYPECODE_DOUBLE;
break;
case CLASSID_PRIMITIVE_FLOAT:
xtype = ETCH_XTRNL_TYPECODE_FLOAT;
break;
case CLASSID_PRIMITIVE_BOOL:
xtype = ((etch_boolean*)valobj)->value?
ETCH_XTRNL_TYPECODE_BOOLEAN_TRUE:
ETCH_XTRNL_TYPECODE_BOOLEAN_FALSE;
break;
case CLASSID_STRING:
xtype = ((etch_string*)valobj)->char_count == 0?
ETCH_XTRNL_TYPECODE_EMPTY_STRING:
ETCH_XTRNL_TYPECODE_STRING;
break;
default:
xtype = ETCH_XTRNL_TYPECODE_CUSTOM;
break;
} /* switch(class_id) */
}
else switch(obj_type)
{
case ETCHTYPEB_STRUCTVAL:
xtype = ETCH_XTRNL_TYPECODE_CUSTOM;
break;
case ETCHTYPEB_ARRAYVAL:
xtype = ((etch_arrayvalue*)valobj)->content_obj_type == ETCHTYPEB_BYTE?
ETCH_XTRNL_TYPECODE_BYTES: ETCH_XTRNL_TYPECODE_ARRAY;
break;
case ETCHTYPEB_NATIVEARRAY:
if(((etch_nativearray*)valobj)->numdims > 1) {
xtype = ETCH_XTRNL_TYPECODE_ARRAY;
break;
}
xtype = ((etch_nativearray*)valobj)->content_obj_type == ETCHTYPEB_BYTE?
ETCH_XTRNL_TYPECODE_BYTES: ETCH_XTRNL_TYPECODE_ARRAY;
break;
default:
xtype = ETCH_XTRNL_TYPECODE_CUSTOM;
}
return xtype;
}
/*
* etchtagdata_get_native_typecode()
* returns the external type code corresponding to internal type.
* see etch_binary_tdi.c for implementation
*/
byte etchtagdata_get_native_typecode
(const unsigned short obj_type, const unsigned short class_id)
{
return ETCH_XTRNL_TYPECODE_NONE;
}
/*
* etchtagdata_get_native_type()
* returns the internal type and class ids corresponding to external typecode.
* see etch_binary_tdi.c for implementation
*/
unsigned etchtagdata_get_native_type (const byte typecode)
{
return (CLASSID_NONE << 16) | ETCHTYPEB_NONE;
}
/*
* etchtagdata_get_custom_structtype()
* returns a struct type for the specified class
* see etch_binary_tdi for implementation
*/
etch_type* etchtagdata_get_custom_structtype (etch_object* thisx,
const unsigned short obj_type, const unsigned short class_id)
{
/* we will return a non-disposable (static) type */
etch_type* type = NULL;
return type;
}
/**
* etchtagdata_from_arrayvalue()
* return an etch_nativearray representation of the specified etch_arrayvalue.
* note that an arrayvalue, if created from an etch_nativearray, has retained
* the source nativearray as an instance member. is_force indicates if caller
* wants to build the nativearray regardless of whether one currently exists.
*/
etch_nativearray* etchtagdata_from_arrayvalue(etch_arrayvalue* av, const int is_force)
{
if (av->natarray && !is_force) return av->natarray;
return (-1 == arrayvalue_to_nativearray(av))? NULL: av->natarray;
}
/**
* etchtagdata_alloc_arrayvalue()
* creates and returns an empty arrayvalue object. this method is here for
* for compatibility with the java binding, however it is superfluous.
* we can safely substitute the new_arrayvalue call below and lose this method.
*/
etch_arrayvalue* etchtagdata_alloc_arrayvalue(const byte type_code,
etch_type* custom_struct_type, const int dim, const int initsize)
{
return new_arrayvalue(type_code, custom_struct_type, dim,
initsize, initsize, FALSE, ETCHARRAYLIST_SYNCHRONIZED);
}
/*
* etchtagdata_check_byte()
*/
signed char etchtagdata_check_byte(const signed char val)
{
byte result = ETCH_XTRNL_TYPECODE_BYTE;
if (is_inrange_tiny_for_signed_chars(val))
result = val;
return result;
}
/*
* etchtagdata_check_short()
*/
signed char etchtagdata_check_short(const short val)
{
byte result = ETCH_XTRNL_TYPECODE_SHORT;
if (is_inrange_byte(val))
result = etchtagdata_check_byte((byte)val);
return result;
}
/*
* etchtagdata_check_integer()
*/
signed char etchtagdata_check_integer(const int val)
{
byte result = ETCH_XTRNL_TYPECODE_INT;
if (is_inrange_int16(val))
result = etchtagdata_check_short((short)val);
return result;
}
/*
* etchtagdata_check_long()
*/
signed char etchtagdata_check_long(const int64 val)
{
byte result = ETCH_XTRNL_TYPECODE_LONG;
if (is_inrange_int32(val))
result = etchtagdata_check_integer((int)val);
return result;
}
/**
* etchtagdata_is_null()
* indicate whether this object represents a null value
*/
int etchtagdata_is_null(etch_object* obj)
{
return obj == NULL || obj->is_null;
}
/**
* etchtagdata_is_eod()
* indicate whether this object is the end of stream sentinel
*/
int etchtagdata_is_eod(etch_object* obj)
{
return obj && ((etch_object*)obj)->obj_type == ETCHTYPEB_EODMARK;
}
/**
* etchtagdata_new_nullobj()
* instantiate and return a logically null object
*/
etch_object* etchtagdata_new_nullobj(const int is_static)
{
etch_object* obj = new_nullobj();
if (is_static) set_etchobj_static_all(obj);
return obj;
}
/**
* etchtagdata_new_eodmarker()
* instantiate and return an end of data marker object
*/
etch_object* etchtagdata_new_eodmarker(const int is_static)
{
etch_object* obj = new_object(sizeof(etch_object), ETCHTYPEB_EODMARK, CLASSID_NONE);
if (is_static) set_etchobj_static_all(obj);
return obj;
}
/**
* etchtagdata_new_emptystring()
* instantiate and return an empty string object
*/
etch_string* etchtagdata_new_emptystring(const int is_static)
{
etch_string* obj = new_stringw(L"");
if (is_static) set_etchobj_static_all(obj);
return obj;
}