blob: f4532a11d8a845afbe1c097c6e9a0f51029317e3 [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.
*/
#include "serialization/EtchBinaryTaggedDataOutput.h"
#include "support/EtchRuntime.h"
static char* TAG = "EtchBinaryTaggedDataOutput";
const EtchString& EtchBinaryTaggedDataOutput::STRING_TYPE_AND_FIELD() {
static const EtchString name("BinaryTaggedDataOutput.stringTypeAndField");
return name;
}
EtchBinaryTaggedDataOutput::EtchBinaryTaggedDataOutput(EtchRuntime* runtime, EtchValueFactory *vf, EtchURL* uri)
: EtchBinaryTaggedData(vf), mRuntime(runtime), mLevel(vf->getLevel()), mBuffer(NULL) {
EtchString tmp;
if (uri->getTerms().get(STRING_TYPE_AND_FIELD(), &tmp) == ETCH_OK) {
mStringTypeAndField = atoi(tmp.c_str()) > 0;
} else {
mStringTypeAndField = false;
}
EtchValidatorInt::Get(runtime, 0, mIntValidator);
EtchValidatorString::Get(runtime, 0, mStringValidator);
EtchValidatorNone::Get(runtime, mNoneValidator);
}
EtchBinaryTaggedDataOutput::~EtchBinaryTaggedDataOutput() {
}
status_t EtchBinaryTaggedDataOutput::writeMessage(capu::SmartPointer<EtchMessage> msg, capu::SmartPointer<EtchFlexBuffer> buf) {
if ((buf.get() == NULL) || (msg.get() == NULL)) {
return ETCH_EINVAL;
}
status_t ret;
mBuffer = buf;
ret = startMessage(msg);
if (ret != ETCH_OK) {
CAPU_LOG_ERROR(mRuntime->getLogger(), TAG, "Serialization of Message header has failed");
return ETCH_ERROR;
}
ret = writeKeysAndValues(msg);
if (ret != ETCH_OK) {
CAPU_LOG_ERROR(mRuntime->getLogger(), TAG, "Serialization of Message body has failed");
return ETCH_ERROR;
}
ret = endMessage(msg);
if (ret != ETCH_OK) {
CAPU_LOG_ERROR(mRuntime->getLogger(), TAG, "Serialization of Message end has failed");
return ETCH_ERROR;
}
return ETCH_OK;
}
status_t EtchBinaryTaggedDataOutput::writeStruct(capu::SmartPointer<EtchStructValue> sv) {
status_t ret;
ret = startStruct(sv);
if (ret != ETCH_OK) {
CAPU_LOG_ERROR(mRuntime->getLogger(), TAG, "Serialization of struct header has failed");
return ETCH_ERROR;
}
ret = writeKeysAndValues(sv);
if (ret != ETCH_OK) {
CAPU_LOG_ERROR(mRuntime->getLogger(), TAG, "Serialization of struct body has failed");
return ETCH_ERROR;
}
ret = endStruct(sv);
if (ret != ETCH_OK) {
CAPU_LOG_ERROR(mRuntime->getLogger(), TAG, "Serialization of struct end has failed");
return ETCH_ERROR;
}
return ETCH_OK;
}
status_t EtchBinaryTaggedDataOutput::writeArray(EtchArrayValue* av, EtchValidator* v) {
status_t ret;
ret = startArray(av);
if (ret != ETCH_OK) {
CAPU_LOG_ERROR(mRuntime->getLogger(), TAG, "Serialization of array header has failed");
return ETCH_ERROR;
}
ret = writeValues(av, v);
if (ret != ETCH_OK) {
CAPU_LOG_ERROR(mRuntime->getLogger(), TAG, "Serialization of array body has failed");
return ETCH_ERROR;
}
ret = endArray(av);
if (ret != ETCH_OK) {
CAPU_LOG_ERROR(mRuntime->getLogger(), TAG, "Serialization of array end has failed");
return ETCH_ERROR;
}
delete av;
return ETCH_OK;
}
status_t EtchBinaryTaggedDataOutput::writeKeysAndValues(capu::SmartPointer<EtchStructValue> sv) {
if (sv.get() == NULL) {
return ETCH_EINVAL;
}
status_t ret;
EtchType* t = sv->getType();
EtchStructValue::Iterator it = sv->begin();
EtchStructValue::Pair pair;
capu::SmartPointer<EtchValidator> tmp;
while (it.hasNext()) {
if (it.next(&pair) == ETCH_OK) {
EtchField f = pair.first;
ret = writeField(&f);
if (ret != ETCH_OK) {
return ETCH_ERROR;
}
ret = t->getValidator(f, tmp);
if (ret != ETCH_OK) {
return ETCH_ERROR;
}
ret = writeValue(tmp, pair.second);
if (ret != ETCH_OK) {
return ETCH_ERROR;
}
} else {
return ETCH_ERROR;
}
}
return ETCH_OK;
}
status_t EtchBinaryTaggedDataOutput::writeValues(EtchArrayValue* av, EtchValidator* v) {
if ((v == NULL) || (av == NULL))
return ETCH_EINVAL;
capu::SmartPointer<EtchValidator> validatorElement;
if (v->getElementValidator(validatorElement) != ETCH_OK)
return ETCH_ERROR;
capu::int32_t size = av->getIndex();
for (capu::int32_t i = 0; i < size; i++) {
capu::SmartPointer<EtchObject> tmp;
av->get(i, tmp);
if (writeValue(validatorElement, tmp) != ETCH_OK)
return ETCH_ERROR;
}
return ETCH_OK;
}
status_t EtchBinaryTaggedDataOutput::startMessage(capu::SmartPointer<EtchMessage> msg) {
// since message is top-level, no type code is written to
// indicate a message is starting. we do write a version
// number to indicate this version of the binary tagged
// data output format.
mBuffer->putByte(VERSION());
return startStruct(msg);
}
status_t EtchBinaryTaggedDataOutput::endMessage(capu::SmartPointer<EtchMessage> msg) {
return endStruct(msg);
}
status_t EtchBinaryTaggedDataOutput::startStruct(capu::SmartPointer<EtchStructValue> _struct) {
// the caller has already written a type code to indicate a
// struct is starting. this code is shared by startMessage().
if (writeType(_struct->getType()) != ETCH_OK) {
CAPU_LOG_ERROR(mRuntime->getLogger(), TAG, "Serialization of struct type information has failed");
return ETCH_ERROR;
} else if (writeIntValue(_struct->count()) != ETCH_OK) {
CAPU_LOG_ERROR(mRuntime->getLogger(), TAG, "Serialization of field number on struct has failed");
return ETCH_ERROR;
}
return ETCH_OK;
}
status_t EtchBinaryTaggedDataOutput::endStruct(capu::SmartPointer<EtchStructValue> _struct) {
// this code is shared by endMessage.
return writeNoneValue();
}
status_t EtchBinaryTaggedDataOutput::startArray(EtchArrayValue* array) {
// the caller has already written a type code to indicate an
// array is starting.
if (array == NULL) {
return ETCH_ERROR;
}
status_t ret;
capu::int8_t type = array->getTypeCode();
mBuffer->putByte(type);
if (type == EtchTypeCode::CUSTOM) {
ret = writeType(array->getCustomStructType());
if (ret != ETCH_OK) {
CAPU_LOG_ERROR(mRuntime->getLogger(), TAG, "Serialization of array type information has failed");
return ETCH_ERROR;
}
}
ret = writeIntValue(array->getDim());
if (ret != ETCH_OK) {
CAPU_LOG_ERROR(mRuntime->getLogger(), TAG, "Serialization of array dimension information has failed");
return ETCH_ERROR;
}
ret = writeIntValue(array->getSize());
if (ret != ETCH_OK) {
CAPU_LOG_ERROR(mRuntime->getLogger(), TAG, "Serialization of array size information has failed");
return ETCH_ERROR;
}
return ETCH_OK;
}
status_t EtchBinaryTaggedDataOutput::endArray(EtchArrayValue* array) {
return writeNoneValue();
}
status_t EtchBinaryTaggedDataOutput::writeType(EtchType* type) {
if (mStringTypeAndField) {
capu::SmartPointer<EtchString> tmp = new EtchString(type->getName());
return writeStringValue(tmp);
} else
return writeIntValue(type->getId());
}
status_t EtchBinaryTaggedDataOutput::writeIntValue(capu::int32_t value) {
capu::SmartPointer<EtchObject> tmp = new EtchInt32(value);
return writeValue(mIntValidator, tmp);
}
status_t EtchBinaryTaggedDataOutput::writeStringValue(capu::SmartPointer<EtchString> value) {
return writeValue(mStringValidator, capu::smartpointer_cast<EtchObject > (value));
}
status_t EtchBinaryTaggedDataOutput::writeNoneValue() {
return writeValue(mNoneValidator, NONE());
}
status_t EtchBinaryTaggedDataOutput::writeField(EtchField* field) {
if (mStringTypeAndField) {
capu::SmartPointer<EtchString> tmp = new EtchString(field->getName());
return writeStringValue(tmp);
} else {
return writeIntValue(field->getId());
}
}
status_t EtchBinaryTaggedDataOutput::writeValue(capu::SmartPointer<EtchValidator> v, capu::SmartPointer<EtchObject> value) {
capu::int8_t typeCode = checkValue(value);
if (mLevel != LEVEL_NONE && value.get() != NULL) {
if (mLevel == LEVEL_FULL && v.get() == NULL) {
return ETCH_ENOT_EXIST; // missing validator
}
if (v.get() != NULL && !v->validate(value)) {
return ETCH_ERROR; //validation error
}
}
mBuffer->putByte(typeCode);
switch (typeCode) {
case EtchTypeCode::Null:
case EtchTypeCode::NONE:
return ETCH_OK;
case EtchTypeCode::BOOLEAN_FALSE:
CAPU_LOG_TRACE(mRuntime->getLogger(), TAG, "Boolean False has been serialized. (No Data send - encoded via TypeId)");
return ETCH_OK;
case EtchTypeCode::BOOLEAN_TRUE:
CAPU_LOG_TRACE(mRuntime->getLogger(), TAG, "Boolean True has been serialized. (No Data send - encoded via TypeId)");
return ETCH_OK;
case EtchTypeCode::EMPTY_STRING:
CAPU_LOG_TRACE(mRuntime->getLogger(), TAG, "Empty String has been serialized. (No Data send - encoded via TypeId)");
return ETCH_OK;
case EtchTypeCode::BYTE:
CAPU_LOG_TRACE(mRuntime->getLogger(), TAG, "Byte has been serialized");
return mBuffer->putByte(((EtchNumber*) value.get())->getByteValue());
case EtchTypeCode::SHORT:
CAPU_LOG_TRACE(mRuntime->getLogger(), TAG, "Short has been serialized");
return mBuffer->putShort(((EtchNumber*) value.get())->getShortValue());
case EtchTypeCode::INT:
CAPU_LOG_TRACE(mRuntime->getLogger(), TAG, "Int has been serialized");
return mBuffer->putInt(((EtchNumber*) value.get())->getInt32Value());
case EtchTypeCode::LONG:
CAPU_LOG_TRACE(mRuntime->getLogger(), TAG, "Long has been serialized");
return mBuffer->putLong(((EtchNumber*) value.get())->getLongValue());
case EtchTypeCode::FLOAT:
CAPU_LOG_TRACE(mRuntime->getLogger(), TAG, "Float has been serialized");
return mBuffer->putFloat(((EtchFloat*) value.get())->get());
case EtchTypeCode::DOUBLE:
CAPU_LOG_TRACE(mRuntime->getLogger(), TAG, "Double has been serialized");
return mBuffer->putDouble(((EtchDouble*) value.get())->get());
case EtchTypeCode::BYTES:
{
EtchNativeArray<capu::int8_t> *na = (EtchNativeArray<capu::int8_t> *)value.get();
capu::int8_t *data = new capu::int8_t[na->getLength()];
na->get(Pos(0), data, na->getLength(), 0, na->getLength());
status_t ret = writeBytes(data, na->getLength());
delete[] data;
CAPU_LOG_TRACE(mRuntime->getLogger(), TAG, "Byte Array has been serialized");
return ret;
}
// reserved for future use:
// case EtchTypeCode::BOOLS:
// case EtchTypeCode::SHORTS:
// case EtchTypeCode::INTS:
// case EtchTypeCode::LONGS:
// case EtchTypeCode::FLOATS:
// case EtchTypeCode::DOUBLES:
case EtchTypeCode::ARRAY:
{
EtchArrayValue *val = NULL;
if (toArrayValue(value, v.get(), val) != ETCH_OK) {
CAPU_LOG_ERROR(mRuntime->getLogger(), TAG, "Array couldn't be serialized");
return ETCH_ERROR;
}
CAPU_LOG_TRACE(mRuntime->getLogger(), TAG, "Array has been serialized");
return writeArray(val, v.get());
}
case EtchTypeCode::STRING:
{
capu::SmartPointer<EtchString> str = capu::smartpointer_cast<EtchString > (value);
CAPU_LOG_TRACE(mRuntime->getLogger(), TAG, "String has been serialized");
return writeBytes((capu::int8_t*)str->c_str(), str->getNumBytes());
}
case EtchTypeCode::CUSTOM:
{
EtchStructValue* _struct;
if (mVf->exportCustomValue(value, _struct) != ETCH_OK) {
CAPU_LOG_ERROR(mRuntime->getLogger(), TAG, "Custom Data Type couldn't be serialized");
return ETCH_ERROR;
}
CAPU_LOG_TRACE(mRuntime->getLogger(), TAG, "Custom Data Type has been serialized");
return writeStruct(_struct);
}
default:
// type is either "tiny" integer or unused
if (typeCode >= EtchTypeCode::MIN_TINY_INT && typeCode <= EtchTypeCode::MAX_TINY_INT) {
CAPU_LOG_TRACE(mRuntime->getLogger(), TAG, "Tiny Int has been serialized");
return ETCH_OK;
}
//invalid type
CAPU_LOG_ERROR(mRuntime->getLogger(), TAG, "Attempted serialization of an invalid Data Type");
return ETCH_EINVAL;
}
return ETCH_ERROR;
}
status_t EtchBinaryTaggedDataOutput::writeBytes(capu::int8_t* value, capu::int32_t size) {
if (writeIntValue(size) != ETCH_OK) {
return ETCH_ERROR;
}
mBuffer->put(value, size);
return ETCH_OK;
}