/* * Copyright (c) 2020 TAOS Data, Inc. * * This program is free software: you can use, redistribute, and/or modify * it under the terms of the GNU Affero General Public License, version 3 * or later ("AGPL"), as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ #include "os.h" #include "tbuffer.h" #include "exception.h" #include "taoserror.h" typedef union Un4B { uint32_t ui; float f; } Un4B; #if __STDC_VERSION__ >= 201112L static_assert(sizeof(Un4B) == sizeof(uint32_t), "sizeof(Un4B) must equal to sizeof(uint32_t)"); static_assert(sizeof(Un4B) == sizeof(float), "sizeof(Un4B) must equal to sizeof(float)"); #endif typedef union Un8B { uint64_t ull; double d; } Un8B; #if __STDC_VERSION__ >= 201112L static_assert(sizeof(Un8B) == sizeof(uint64_t), "sizeof(Un8B) must equal to sizeof(uint64_t)"); static_assert(sizeof(Un8B) == sizeof(double), "sizeof(Un8B) must equal to sizeof(double)"); #endif //////////////////////////////////////////////////////////////////////////////// // reader functions size_t tbufSkip(SBufferReader* buf, size_t size) { if( (buf->pos + size) > buf->size ) { THROW( TSDB_CODE_COM_MEMORY_CORRUPTED ); } size_t old = buf->pos; buf->pos += size; return old; } const char* tbufRead( SBufferReader* buf, size_t size ) { const char* ret = buf->data + buf->pos; tbufSkip( buf, size ); return ret; } void tbufReadToBuffer( SBufferReader* buf, void* dst, size_t size ) { assert( dst != NULL ); // always using memcpy, leave optimization to compiler memcpy( dst, tbufRead(buf, size), size ); } static size_t tbufReadLength( SBufferReader* buf ) { // maximum length is 65535, if larger length is required // this function and the corresponding write function need to be // revised. uint16_t l = tbufReadUint16( buf ); return l; } const char* tbufReadString( SBufferReader* buf, size_t* len ) { size_t l = tbufReadLength( buf ); const char* ret = buf->data + buf->pos; tbufSkip( buf, l + 1 ); if( ret[l] != 0 ) { THROW( TSDB_CODE_COM_MEMORY_CORRUPTED ); } if( len != NULL ) { *len = l; } return ret; } size_t tbufReadToString( SBufferReader* buf, char* dst, size_t size ) { assert( dst != NULL ); size_t len; const char* str = tbufReadString( buf, &len ); if (len >= size) { len = size - 1; } memcpy( dst, str, len ); dst[len] = 0; return len; } const char* tbufReadBinary( SBufferReader* buf, size_t *len ) { size_t l = tbufReadLength( buf ); const char* ret = buf->data + buf->pos; tbufSkip( buf, l ); if( len != NULL ) { *len = l; } return ret; } size_t tbufReadToBinary( SBufferReader* buf, void* dst, size_t size ) { assert( dst != NULL ); size_t len; const char* data = tbufReadBinary( buf, &len ); if( len >= size ) { len = size; } memcpy( dst, data, len ); return len; } bool tbufReadBool( SBufferReader* buf ) { bool ret; tbufReadToBuffer( buf, &ret, sizeof(ret) ); return ret; } char tbufReadChar( SBufferReader* buf ) { char ret; tbufReadToBuffer( buf, &ret, sizeof(ret) ); return ret; } int8_t tbufReadInt8( SBufferReader* buf ) { int8_t ret; tbufReadToBuffer( buf, &ret, sizeof(ret) ); return ret; } uint8_t tbufReadUint8( SBufferReader* buf ) { uint8_t ret; tbufReadToBuffer( buf, &ret, sizeof(ret) ); return ret; } int16_t tbufReadInt16( SBufferReader* buf ) { int16_t ret; tbufReadToBuffer( buf, &ret, sizeof(ret) ); if( buf->endian ) { return (int16_t)ntohs( ret ); } return ret; } uint16_t tbufReadUint16( SBufferReader* buf ) { uint16_t ret; tbufReadToBuffer( buf, &ret, sizeof(ret) ); if( buf->endian ) { return ntohs( ret ); } return ret; } int32_t tbufReadInt32( SBufferReader* buf ) { int32_t ret; tbufReadToBuffer( buf, &ret, sizeof(ret) ); if( buf->endian ) { return (int32_t)ntohl( ret ); } return ret; } uint32_t tbufReadUint32( SBufferReader* buf ) { uint32_t ret; tbufReadToBuffer( buf, &ret, sizeof(ret) ); if( buf->endian ) { return ntohl( ret ); } return ret; } int64_t tbufReadInt64( SBufferReader* buf ) { int64_t ret; tbufReadToBuffer( buf, &ret, sizeof(ret) ); if( buf->endian ) { return (int64_t)htobe64( ret ); // TODO: ntohll } return ret; } uint64_t tbufReadUint64( SBufferReader* buf ) { uint64_t ret; tbufReadToBuffer( buf, &ret, sizeof(ret) ); if( buf->endian ) { return htobe64( ret ); // TODO: ntohll } return ret; } float tbufReadFloat( SBufferReader* buf ) { Un4B _un; tbufReadToBuffer( buf, &_un, sizeof(_un) ); if( buf->endian ) { _un.ui = ntohl( _un.ui ); } return _un.f; } double tbufReadDouble(SBufferReader* buf) { Un8B _un; tbufReadToBuffer( buf, &_un, sizeof(_un) ); if( buf->endian ) { _un.ull = htobe64( _un.ull ); } return _un.d; } //////////////////////////////////////////////////////////////////////////////// // writer functions void tbufCloseWriter( SBufferWriter* buf ) { tfree(buf->data); // (*buf->allocator)( buf->data, 0 ); // potential memory leak. buf->data = NULL; buf->pos = 0; buf->size = 0; } void tbufEnsureCapacity( SBufferWriter* buf, size_t size ) { size += buf->pos; if( size > buf->size ) { size_t nsize = size + buf->size; char* data = (*buf->allocator)( buf->data, nsize ); // TODO: the exception should be thrown by the allocator function if( data == NULL ) { THROW( TSDB_CODE_COM_OUT_OF_MEMORY ); } buf->data = data; buf->size = nsize; } } size_t tbufReserve( SBufferWriter* buf, size_t size ) { tbufEnsureCapacity( buf, size ); size_t old = buf->pos; buf->pos += size; return old; } char* tbufGetData( SBufferWriter* buf, bool takeOver ) { char* ret = buf->data; if( takeOver ) { buf->pos = 0; buf->size = 0; buf->data = NULL; } return ret; } void tbufWrite( SBufferWriter* buf, const void* data, size_t size ) { assert( data != NULL ); tbufEnsureCapacity( buf, size ); memcpy( buf->data + buf->pos, data, size ); buf->pos += size; } void tbufWriteAt( SBufferWriter* buf, size_t pos, const void* data, size_t size ) { assert( data != NULL ); // this function can only be called to fill the gap on previous writes, // so 'pos + size <= buf->pos' must be true assert( pos + size <= buf->pos ); memcpy( buf->data + pos, data, size ); } static void tbufWriteLength( SBufferWriter* buf, size_t len ) { // maximum length is 65535, if larger length is required // this function and the corresponding read function need to be // revised. assert( len <= 0xffff ); tbufWriteUint16( buf, (uint16_t)len ); } void tbufWriteStringLen( SBufferWriter* buf, const char* str, size_t len ) { tbufWriteLength( buf, len ); tbufWrite( buf, str, len ); tbufWriteChar( buf, '\0' ); } void tbufWriteString( SBufferWriter* buf, const char* str ) { tbufWriteStringLen( buf, str, strlen(str) ); } void tbufWriteBinary( SBufferWriter* buf, const void* data, size_t len ) { tbufWriteLength( buf, len ); tbufWrite( buf, data, len ); } void tbufWriteBool( SBufferWriter* buf, bool data ) { tbufWrite( buf, &data, sizeof(data) ); } void tbufWriteBoolAt( SBufferWriter* buf, size_t pos, bool data ) { tbufWriteAt( buf, pos, &data, sizeof(data) ); } void tbufWriteChar( SBufferWriter* buf, char data ) { tbufWrite( buf, &data, sizeof(data) ); } void tbufWriteCharAt( SBufferWriter* buf, size_t pos, char data ) { tbufWriteAt( buf, pos, &data, sizeof(data) ); } void tbufWriteInt8( SBufferWriter* buf, int8_t data ) { tbufWrite( buf, &data, sizeof(data) ); } void tbufWriteInt8At( SBufferWriter* buf, size_t pos, int8_t data ) { tbufWriteAt( buf, pos, &data, sizeof(data) ); } void tbufWriteUint8( SBufferWriter* buf, uint8_t data ) { tbufWrite( buf, &data, sizeof(data) ); } void tbufWriteUint8At( SBufferWriter* buf, size_t pos, uint8_t data ) { tbufWriteAt( buf, pos, &data, sizeof(data) ); } void tbufWriteInt16( SBufferWriter* buf, int16_t data ) { if( buf->endian ) { data = (int16_t)htons( data ); } tbufWrite( buf, &data, sizeof(data) ); } void tbufWriteInt16At( SBufferWriter* buf, size_t pos, int16_t data ) { if( buf->endian ) { data = (int16_t)htons( data ); } tbufWriteAt( buf, pos, &data, sizeof(data) ); } void tbufWriteUint16( SBufferWriter* buf, uint16_t data ) { if( buf->endian ) { data = htons( data ); } tbufWrite( buf, &data, sizeof(data) ); } void tbufWriteUint16At( SBufferWriter* buf, size_t pos, uint16_t data ) { if( buf->endian ) { data = htons( data ); } tbufWriteAt( buf, pos, &data, sizeof(data) ); } void tbufWriteInt32( SBufferWriter* buf, int32_t data ) { if( buf->endian ) { data = (int32_t)htonl( data ); } tbufWrite( buf, &data, sizeof(data) ); } void tbufWriteInt32At( SBufferWriter* buf, size_t pos, int32_t data ) { if( buf->endian ) { data = (int32_t)htonl( data ); } tbufWriteAt( buf, pos, &data, sizeof(data) ); } void tbufWriteUint32( SBufferWriter* buf, uint32_t data ) { if( buf->endian ) { data = htonl( data ); } tbufWrite( buf, &data, sizeof(data) ); } void tbufWriteUint32At( SBufferWriter* buf, size_t pos, uint32_t data ) { if( buf->endian ) { data = htonl( data ); } tbufWriteAt( buf, pos, &data, sizeof(data) ); } void tbufWriteInt64( SBufferWriter* buf, int64_t data ) { if( buf->endian ) { data = (int64_t)htobe64( data ); } tbufWrite( buf, &data, sizeof(data) ); } void tbufWriteInt64At( SBufferWriter* buf, size_t pos, int64_t data ) { if( buf->endian ) { data = (int64_t)htobe64( data ); } tbufWriteAt( buf, pos, &data, sizeof(data) ); } void tbufWriteUint64( SBufferWriter* buf, uint64_t data ) { if( buf->endian ) { data = htobe64( data ); } tbufWrite( buf, &data, sizeof(data) ); } void tbufWriteUint64At( SBufferWriter* buf, size_t pos, uint64_t data ) { if( buf->endian ) { data = htobe64( data ); } tbufWriteAt( buf, pos, &data, sizeof(data) ); } void tbufWriteFloat( SBufferWriter* buf, float data ) { Un4B _un; _un.f = data; if( buf->endian ) { _un.ui = htonl( _un.ui ); } tbufWrite( buf, &_un, sizeof(_un) ); } void tbufWriteFloatAt( SBufferWriter* buf, size_t pos, float data ) { Un4B _un; _un.f = data; if( buf->endian ) { _un.ui = htonl( _un.ui ); } tbufWriteAt( buf, pos, &_un, sizeof(_un) ); } void tbufWriteDouble( SBufferWriter* buf, double data ) { Un8B _un; _un.d = data; if( buf->endian ) { _un.ull = htobe64( _un.ull ); } tbufWrite( buf, &_un, sizeof(_un) ); } void tbufWriteDoubleAt( SBufferWriter* buf, size_t pos, double data ) { Un8B _un; _un.d = data; if( buf->endian ) { _un.ull = htobe64( _un.ull ); } tbufWriteAt( buf, pos, &_un, sizeof(_un) ); }