blob: 6dfc0de6d2bf65ed64005bb3f87ed5e9c44d532e [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 "transport/EtchFlexBuffer.h"
EtchFlexBuffer::EtchFlexBuffer() :
INIT_BUFFER_LEN(32), MAX_BUFFER_LEN(4 * 1024 * 1024),
TRIM_BUFFER_LEN(16 * 1024), mBuffer(NULL),
mSize(INIT_BUFFER_LEN), mIndex(0),
mLength(0), mByteRepresentation(ETCH_BIG_ENDIAN) {
mBuffer = new capu::int8_t[INIT_BUFFER_LEN];
}
EtchFlexBuffer::EtchFlexBuffer(capu::int8_t *buf, capu::uint32_t size) :
INIT_BUFFER_LEN(32),
MAX_BUFFER_LEN(4 * 1024 * 1024),
TRIM_BUFFER_LEN(16 * 1024),
mBuffer(buf), mSize(size), mIndex(0),
mLength(size), mByteRepresentation(ETCH_BIG_ENDIAN) {
}
EtchFlexBuffer::~EtchFlexBuffer() {
delete [] mBuffer;
}
capu::int8_t * EtchFlexBuffer::getBuffer() {
return mBuffer;
}
capu::uint32_t EtchFlexBuffer::getLength() {
return mLength;
}
capu::uint32_t EtchFlexBuffer::getSize() {
return mSize;
}
capu::uint32_t EtchFlexBuffer::getIndex() {
return mIndex;
}
status_t EtchFlexBuffer::getInteger(capu::uint32_t & value) {
if (sizeof (capu::uint32_t) > getAvailableBytes())
return ETCH_ERANGE;
if (mByteRepresentation == ETCH_LITTLE_ENDIAN) {
// little-endian
capu::uint32_t result = (mBuffer[mIndex++] & 255);
result += (mBuffer[mIndex++] & 255) << 8;
result += (mBuffer[mIndex++] & 255) << 16;
value = result + ((mBuffer[mIndex++] & 255) << 24);
} else if (mByteRepresentation == ETCH_BIG_ENDIAN) {
// big-endian
capu::uint32_t result = mBuffer[mIndex++] & 255;
result = (result << 8) + (mBuffer[mIndex++] & 255);
result = (result << 8) + (mBuffer[mIndex++] & 255);
value = (result << 8) + (mBuffer[mIndex++] & 255);
} else {
return ETCH_EINVAL;
}
return ETCH_OK;
}
status_t EtchFlexBuffer::getByte(capu::int8_t & value) {
if (1 > getAvailableBytes())
return ETCH_ERANGE;
value = mBuffer[mIndex++];
return ETCH_OK;
}
status_t EtchFlexBuffer::getShort(capu::int16_t & value) {
if (2 > getAvailableBytes())
return ETCH_ERANGE;
if (mByteRepresentation == ETCH_LITTLE_ENDIAN) {
// little-endian
capu::int32_t _value = mBuffer[mIndex++] & 255;
value = (capu::int16_t) (_value + ((mBuffer[mIndex++] & 255) << 8));
} else if (mByteRepresentation == ETCH_BIG_ENDIAN) {
// big-endian
capu::int32_t _value = mBuffer[mIndex++];
value = (capu::int16_t) ((_value << 8) + (mBuffer[mIndex++] & 255));
} else {
return ETCH_EINVAL;
}
return ETCH_OK;
}
status_t EtchFlexBuffer::getLong(capu::int64_t & value) {
if (8 > getAvailableBytes())
return ETCH_ERANGE;
if (mByteRepresentation == ETCH_LITTLE_ENDIAN) {
// little-endian
capu::int64_t _value = mBuffer[mIndex++] & 255;
_value += (capu::int64_t) (mBuffer[mIndex++] & 255) << 8;
_value += (capu::int64_t) (mBuffer[mIndex++] & 255) << 16;
_value += (capu::int64_t) (mBuffer[mIndex++] & 255) << 24;
_value += (capu::int64_t) (mBuffer[mIndex++] & 255) << 32;
_value += (capu::int64_t) (mBuffer[mIndex++] & 255) << 40;
_value += (capu::int64_t) (mBuffer[mIndex++] & 255) << 48;
value = _value + ((capu::int64_t) (mBuffer[mIndex++] & 255) << 56);
} else if (mByteRepresentation == ETCH_BIG_ENDIAN) {
// big-endian
capu::int64_t _value = mBuffer[mIndex++];
_value = (_value << 8) + (mBuffer[mIndex++] & 255);
_value = (_value << 8) + (mBuffer[mIndex++] & 255);
_value = (_value << 8) + (mBuffer[mIndex++] & 255);
_value = (_value << 8) + (mBuffer[mIndex++] & 255);
_value = (_value << 8) + (mBuffer[mIndex++] & 255);
_value = (_value << 8) + (mBuffer[mIndex++] & 255);
value = (_value << 8) + (mBuffer[mIndex++] & 255);
} else {
return ETCH_EINVAL;
}
return ETCH_OK;
}
status_t EtchFlexBuffer::getFloat(capu::float_t & value) {
capu::uint32_t tmp;
status_t err = getInteger(tmp);
if (err != ETCH_OK)
return err;
memcpy(&value, &tmp, sizeof (capu::float_t));
return ETCH_OK;
}
status_t EtchFlexBuffer::getDouble(capu::double_t & value) {
capu::int64_t tmp;
status_t err = getLong(tmp);
if (err != ETCH_OK)
return err;
memcpy(&value, &tmp, sizeof (capu::double_t));
return ETCH_OK;
}
status_t EtchFlexBuffer::get(capu::int8_t *buf, capu::uint32_t off, capu::uint32_t len, capu::uint32_t& numBytes) {
if (buf == NULL) {
numBytes = 0;
return ETCH_EINVAL;
}
if (len == 0) {
numBytes = 0;
return ETCH_EINVAL;
}
capu::int32_t n = 0;
if ((signed)(len - off) < static_cast<capu::int32_t>(getAvailableBytes())) {
if ((signed)(len - off) < 0) {
return ETCH_EINVAL;
}
n = len - off;
} else {
n = getAvailableBytes();
}
numBytes = n;
memcpy(buf, &mBuffer[mIndex], n);
mIndex += n;
return ETCH_OK;
}
capu::uint32_t EtchFlexBuffer::getAvailableBytes() {
return mLength - mIndex;
}
status_t EtchFlexBuffer::setIndex(capu::uint32_t index) {
if (index > mLength)
return ETCH_EINVAL;
mIndex = index;
return ETCH_OK;
}
status_t EtchFlexBuffer::setLength(capu::uint32_t length) {
if (length > mSize) {
if (expandBuffer(length) == ETCH_ENO_MEMORY)
return ETCH_ENO_MEMORY;
}
mLength = length;
if (mIndex > mLength)
mIndex = mLength;
return ETCH_OK;
}
void EtchFlexBuffer::reset() {
mLength = 0;
mIndex = 0;
if (mSize > TRIM_BUFFER_LEN) {
//if buffer is too big trim it
delete [] mBuffer;
mBuffer = new capu::int8_t[TRIM_BUFFER_LEN];
mSize = TRIM_BUFFER_LEN;
}
}
status_t EtchFlexBuffer::put(EtchFlexBuffer & buffer) {
status_t result = checkBuffer(buffer, buffer.getAvailableBytes());
if (result != ETCH_OK)
return result;
copy(&buffer.mBuffer[buffer.mIndex], buffer.getAvailableBytes());
return ETCH_OK;
}
status_t EtchFlexBuffer::put(EtchFlexBuffer & buffer, capu::uint32_t numBytes) {
status_t result = checkBuffer(buffer, numBytes);
if (result != ETCH_OK)
return result;
copy(&buffer.mBuffer[buffer.mIndex], numBytes);
return ETCH_OK;
}
status_t EtchFlexBuffer::put(capu::int8_t * buffer, capu::uint32_t numBytes) {
if (buffer == NULL)
return ETCH_EINVAL;
if (numBytes == 0)
return ETCH_ERANGE;
if (numBytes > (mSize - mIndex)) {
if (expandBuffer(mIndex + numBytes) == ETCH_ENO_MEMORY)
return ETCH_ENO_MEMORY;
}
copy(buffer, numBytes);
return ETCH_OK;
}
void EtchFlexBuffer::setByteRepresentation(EtchByteRepresentation value) {
mByteRepresentation = value;
}
status_t EtchFlexBuffer::putByte(capu::int8_t value) {
if (1 > (mSize - mIndex)) {
if (expandBuffer(mIndex + 1) == ETCH_ENO_MEMORY)
return ETCH_ENO_MEMORY;
}
mBuffer[mIndex++] = (capu::int8_t) value;
if (mIndex > mLength)
mLength = mIndex;
return ETCH_OK;
}
status_t EtchFlexBuffer::putShort(capu::int16_t value) {
if (2 > (mSize - mIndex)) {
if (expandBuffer(mIndex + 1) == ETCH_ENO_MEMORY)
return ETCH_ENO_MEMORY;
}
if (mByteRepresentation == ETCH_LITTLE_ENDIAN) {
mBuffer[mIndex++] = (capu::int8_t) value;
mBuffer[mIndex++] = (capu::int8_t) (value >> 8);
} else if (mByteRepresentation == ETCH_BIG_ENDIAN) {
mBuffer[mIndex++] = (capu::int8_t) (value >> 8);
mBuffer[mIndex++] = (capu::int8_t) value;
} else {
return ETCH_EINVAL;
}
if (mIndex > mLength)
mLength = mIndex;
return ETCH_OK;
}
status_t EtchFlexBuffer::putInt(capu::int32_t value) {
if (4 > (mSize - mIndex)) {
if (expandBuffer(mIndex + 1) == ETCH_ENO_MEMORY)
return ETCH_ENO_MEMORY;
}
if (mByteRepresentation == ETCH_LITTLE_ENDIAN) {
mBuffer[mIndex++] = (capu::int8_t) value;
mBuffer[mIndex++] = (capu::int8_t) (value >> 8);
mBuffer[mIndex++] = (capu::int8_t) (value >> 16);
mBuffer[mIndex++] = (capu::int8_t) (value >> 24);
} else if (mByteRepresentation == ETCH_BIG_ENDIAN) {
mBuffer[mIndex++] = (capu::int8_t) (value >> 24);
mBuffer[mIndex++] = (capu::int8_t) (value >> 16);
mBuffer[mIndex++] = (capu::int8_t) (value >> 8);
mBuffer[mIndex++] = (capu::int8_t) value;
} else {
return ETCH_EINVAL;
}
if (mIndex > mLength)
mLength = mIndex;
return ETCH_OK;
}
status_t EtchFlexBuffer::putLong(capu::int64_t value) {
if (8 > (mSize - mIndex)) {
if (expandBuffer(mIndex + 1) == ETCH_ENO_MEMORY)
return ETCH_ENO_MEMORY;
}
if (mByteRepresentation == ETCH_LITTLE_ENDIAN) {
mBuffer[mIndex++] = (capu::int8_t) value;
mBuffer[mIndex++] = (capu::int8_t) (value >> 8);
mBuffer[mIndex++] = (capu::int8_t) (value >> 16);
mBuffer[mIndex++] = (capu::int8_t) (value >> 24);
mBuffer[mIndex++] = (capu::int8_t) (value >> 32);
mBuffer[mIndex++] = (capu::int8_t) (value >> 40);
mBuffer[mIndex++] = (capu::int8_t) (value >> 48);
mBuffer[mIndex++] = (capu::int8_t) (value >> 56);
} else if (mByteRepresentation == ETCH_BIG_ENDIAN) {
mBuffer[mIndex++] = (capu::int8_t) (value >> 56);
mBuffer[mIndex++] = (capu::int8_t) (value >> 48);
mBuffer[mIndex++] = (capu::int8_t) (value >> 40);
mBuffer[mIndex++] = (capu::int8_t) (value >> 32);
mBuffer[mIndex++] = (capu::int8_t) (value >> 24);
mBuffer[mIndex++] = (capu::int8_t) (value >> 16);
mBuffer[mIndex++] = (capu::int8_t) (value >> 8);
mBuffer[mIndex++] = (capu::int8_t) value;
} else {
return ETCH_EINVAL;
}
if (mIndex > mLength)
mLength = mIndex;
return ETCH_OK;
}
status_t EtchFlexBuffer::putFloat(capu::float_t value) {
capu::int32_t tmp;
memcpy(&tmp, &value, sizeof (capu::float_t));
return putInt(tmp);
}
status_t EtchFlexBuffer::putDouble(capu::double_t value) {
capu::int64_t tmp;
memcpy(&tmp, &value, sizeof (capu::double_t));
return putLong(tmp);
}
EtchByteRepresentation EtchFlexBuffer::getByteRepresentation() {
return mByteRepresentation;
}
status_t EtchFlexBuffer::expandBuffer(capu::uint32_t numBytes) {
capu::uint32_t _size = mSize;
if (_size < INIT_BUFFER_LEN)
_size = INIT_BUFFER_LEN;
while ((mIndex + numBytes > _size) && (_size < MAX_BUFFER_LEN))
_size = _size << 1;
//BUFFER OVERFLOW
if (mIndex + numBytes > _size)
return ETCH_ENO_MEMORY;
capu::int8_t * b = new capu::int8_t[_size];
memcpy(b, mBuffer, mSize);
delete [] mBuffer;
mBuffer = b;
mSize = _size;
return ETCH_OK;
}
status_t EtchFlexBuffer::checkBuffer(EtchFlexBuffer & buffer, capu::uint32_t numBytes) {
if ((buffer.mBuffer == NULL)
|| (buffer.mIndex + numBytes > buffer.mSize)
|| (buffer.mIndex > buffer.mSize)
|| (numBytes <= 0)
|| (numBytes > buffer.getAvailableBytes())) {
return ETCH_EINVAL;
}
if (numBytes > (mSize - mIndex)) {
if (expandBuffer(mIndex + numBytes) == ETCH_ENO_MEMORY)
return ETCH_ENO_MEMORY;
}
return ETCH_OK;
}
void EtchFlexBuffer::copy(capu::int8_t *buffer, capu::uint32_t numBytes) {
memcpy(&mBuffer[mIndex], (const void *) buffer, numBytes);
mIndex += numBytes;
if (mIndex > mLength)
mLength = mIndex;
}