/* * This is the source code of tgnet library v. 1.1 * It is licensed under GNU GPL v. 2 or later. * You should have received a copy of the license in this archive (see LICENSE). * * Copyright Nikolai Kudashov, 2015-2018. */ #include #include #include "NativeByteBuffer.h" #include "FileLog.h" #include "ByteArray.h" #include "ConnectionsManager.h" #include "BuffersStorage.h" static int buffersCount = 0; NativeByteBuffer::NativeByteBuffer(uint32_t size) { #ifdef ANDROID if (jclass_ByteBuffer != nullptr) { JNIEnv *env = 0; if (javaVm->GetEnv((void **) &env, JNI_VERSION_1_6) != JNI_OK) { if (LOGS_ENABLED) DEBUG_E("can't get jnienv"); exit(1); } javaByteBuffer = env->CallStaticObjectMethod(jclass_ByteBuffer, jclass_ByteBuffer_allocateDirect, size); if (javaByteBuffer == nullptr) { if (LOGS_ENABLED) DEBUG_E("can't create javaByteBuffer"); exit(1); } DEBUG_REF("nativebytebuffer"); jobject globalRef = env->NewGlobalRef(javaByteBuffer); env->DeleteLocalRef(javaByteBuffer); javaByteBuffer = globalRef; buffer = (uint8_t *) env->GetDirectBufferAddress(javaByteBuffer); bufferOwner = false; } else { #endif buffer = new uint8_t[size]; bufferOwner = true; #ifdef ANDROID } #endif if (buffer == nullptr) { if (LOGS_ENABLED) DEBUG_E("can't allocate NativeByteBuffer buffer"); exit(1); } _limit = _capacity = size; } NativeByteBuffer::NativeByteBuffer(bool calculate) { calculateSizeOnly = calculate; } NativeByteBuffer::NativeByteBuffer(uint8_t *buff, uint32_t length) { buffer = buff; sliced = true; _limit = _capacity = length; } NativeByteBuffer::~NativeByteBuffer() { #ifdef ANDROID if (javaByteBuffer != nullptr) { JNIEnv *env = 0; if (javaVm->GetEnv((void **) &env, JNI_VERSION_1_6) != JNI_OK) { if (LOGS_ENABLED) DEBUG_E("can't get jnienv"); exit(1); } DEBUG_DELREF("nativebytebuffer"); env->DeleteGlobalRef(javaByteBuffer); javaByteBuffer = nullptr; } #endif if (bufferOwner && !sliced && buffer != nullptr) { delete[] buffer; buffer = nullptr; } } uint32_t NativeByteBuffer::position() { return _position; } void NativeByteBuffer::position(uint32_t position) { if (position > _limit) { return; } _position = position; } uint32_t NativeByteBuffer::capacity() { return _capacity; } uint32_t NativeByteBuffer::limit() { return _limit; } uint32_t NativeByteBuffer::remaining() { return _limit - _position; } void NativeByteBuffer::clearCapacity() { if (!calculateSizeOnly) { return; } _capacity = 0; } void NativeByteBuffer::limit(uint32_t limit) { if (limit > _capacity) { return; } if (_position > limit) { _position = limit; } _limit = limit; } void NativeByteBuffer::flip() { _limit = _position; _position = 0; } void NativeByteBuffer::clear() { _position = 0; _limit = _capacity; } uint8_t *NativeByteBuffer::bytes() { return buffer; } void NativeByteBuffer::rewind() { _position = 0; } void NativeByteBuffer::compact() { if (_position == _limit) { return; } memmove(buffer, buffer + _position, sizeof(uint8_t) * (_limit - _position)); _position = (_limit - _position); _limit = _capacity; } bool NativeByteBuffer::hasRemaining() { return _position < _limit; } void NativeByteBuffer::skip(uint32_t length) { if (!calculateSizeOnly) { if (_position + length > _limit) { return; } _position += length; } else { _capacity += length; } } void NativeByteBuffer::writeInt32(int32_t x, bool *error) { if (!calculateSizeOnly) { if (_position + 4 > _limit) { if (error != nullptr) { *error = true; } if (LOGS_ENABLED) DEBUG_E("write int32 error"); return; } buffer[_position++] = (uint8_t) x; buffer[_position++] = (uint8_t) (x >> 8); buffer[_position++] = (uint8_t) (x >> 16); buffer[_position++] = (uint8_t) (x >> 24); } else { _capacity += 4; } } void NativeByteBuffer::writeInt64(int64_t x, bool *error) { if (!calculateSizeOnly) { if (_position + 8 > _limit) { if (error != nullptr) { *error = true; } if (LOGS_ENABLED) DEBUG_E("write int64 error"); return; } buffer[_position++] = (uint8_t) x; buffer[_position++] = (uint8_t) (x >> 8); buffer[_position++] = (uint8_t) (x >> 16); buffer[_position++] = (uint8_t) (x >> 24); buffer[_position++] = (uint8_t) (x >> 32); buffer[_position++] = (uint8_t) (x >> 40); buffer[_position++] = (uint8_t) (x >> 48); buffer[_position++] = (uint8_t) (x >> 56); } else { _capacity += 8; } } void NativeByteBuffer::writeBool(bool value, bool *error) { if (!calculateSizeOnly) { if (value) { writeInt32(0x997275b5, error); } else { writeInt32(0xbc799737, error); } } else { _capacity += 4; } } void NativeByteBuffer::writeBytes(uint8_t *b, uint32_t length, bool *error) { if (!calculateSizeOnly) { if (_position + length > _limit) { if (error != nullptr) { *error = true; } if (LOGS_ENABLED) DEBUG_E("write bytes error"); return; } writeBytesInternal(b, 0, length); } else { _capacity += length; } } void NativeByteBuffer::writeBytes(uint8_t *b, uint32_t offset, uint32_t length, bool *error) { if (!calculateSizeOnly) { if (_position + length > _limit) { if (error != nullptr) { *error = true; } if (LOGS_ENABLED) DEBUG_E("write bytes error"); return; } writeBytesInternal(b, offset, length); } else { _capacity += length; } } void NativeByteBuffer::writeBytes(NativeByteBuffer *b, bool *error) { uint32_t length = b->_limit - b->_position; if (length == 0) { return; } if (!calculateSizeOnly) { if (_position + length > _limit) { if (error != nullptr) { *error = true; } if (LOGS_ENABLED) DEBUG_E("write bytes error"); return; } writeBytesInternal(b->buffer + b->_position, 0, length); b->position(b->limit()); } else { _capacity += length; } } void NativeByteBuffer::writeBytes(ByteArray *b, bool *error) { if (!calculateSizeOnly) { if (_position + b->length > _limit) { if (error != nullptr) { *error = true; } if (LOGS_ENABLED) DEBUG_E("write bytes error"); return; } writeBytesInternal(b->bytes, 0, b->length); } else { _capacity += b->length; } } void NativeByteBuffer::writeBytesInternal(uint8_t *b, uint32_t offset, uint32_t length) { memcpy(buffer + _position, b + offset, sizeof(uint8_t) * length); _position += length; } void NativeByteBuffer::writeByte(uint8_t i, bool *error) { if (!calculateSizeOnly) { if (_position + 1 > _limit) { if (error != nullptr) { *error = true; } if (LOGS_ENABLED) DEBUG_E("write byte error"); return; } buffer[_position++] = i; } else { _capacity += 1; } } void NativeByteBuffer::writeString(std::string s, bool *error) { writeByteArray((uint8_t *) s.c_str(), (uint32_t) s.length(), error); } void NativeByteBuffer::writeByteArray(uint8_t *b, uint32_t offset, uint32_t length, bool *error) { if (length <= 253) { if (!calculateSizeOnly) { if (_position + 1 > _limit) { if (error != nullptr) { *error = true; } if (LOGS_ENABLED) DEBUG_E("write byte array error"); return; } buffer[_position++] = (uint8_t) length; } else { _capacity += 1; } } else { if (!calculateSizeOnly) { if (_position + 4 > _limit) { if (error != nullptr) { *error = true; } if (LOGS_ENABLED) DEBUG_E("write byte array error"); return; } buffer[_position++] = (uint8_t) 254; buffer[_position++] = (uint8_t) length; buffer[_position++] = (uint8_t) (length >> 8); buffer[_position++] = (uint8_t) (length >> 16); } else { _capacity += 4; } } if (!calculateSizeOnly) { if (_position + length > _limit) { if (error != nullptr) { *error = true; } if (LOGS_ENABLED) DEBUG_E("write byte array error"); return; } writeBytesInternal(b, offset, length); } else { _capacity += length; } uint32_t addition = (length + (length <= 253 ? 1 : 4)) % 4; if (addition != 0) { addition = 4 - addition; } if (!calculateSizeOnly && _position + addition > _limit) { if (error != nullptr) { *error = true; } if (LOGS_ENABLED) DEBUG_E("write byte array error"); return; } for (uint32_t a = 0; a < addition; a++) { if (!calculateSizeOnly) { buffer[_position++] = (uint8_t) 0; } else { _capacity += 1; } } } void NativeByteBuffer::writeByteArray(uint8_t *b, uint32_t length, bool *error) { writeByteArray(b, 0, length, error); } void NativeByteBuffer::writeByteArray(NativeByteBuffer *b, bool *error) { b->rewind(); writeByteArray(b->buffer, 0, b->limit(), error); } void NativeByteBuffer::writeByteArray(ByteArray *b, bool *error) { writeByteArray(b->bytes, 0, b->length, error); } void NativeByteBuffer::writeDouble(double d, bool *error) { int64_t value; memcpy(&value, &d, sizeof(int64_t)); writeInt64(value, error); } void NativeByteBuffer::writeInt32(int32_t x) { writeInt32(x, nullptr); } void NativeByteBuffer::writeInt64(int64_t x) { writeInt64(x, nullptr); } void NativeByteBuffer::writeBool(bool value) { writeBool(value, nullptr); } void NativeByteBuffer::writeBytes(uint8_t *b, uint32_t length) { writeBytes(b, length, nullptr); } void NativeByteBuffer::writeBytes(uint8_t *b, uint32_t offset, uint32_t length) { writeBytes(b, offset, length, nullptr); } void NativeByteBuffer::writeBytes(ByteArray *b) { writeBytes(b, nullptr); } void NativeByteBuffer::writeBytes(NativeByteBuffer *b) { writeBytes(b, nullptr); } void NativeByteBuffer::writeByte(uint8_t i) { writeByte(i, nullptr); } void NativeByteBuffer::writeString(std::string s) { writeString(s, nullptr); } void NativeByteBuffer::writeByteArray(uint8_t *b, uint32_t offset, uint32_t length) { writeByteArray(b, offset, length, nullptr); } void NativeByteBuffer::writeByteArray(uint8_t *b, uint32_t length) { writeByteArray(b, length, nullptr); } void NativeByteBuffer::writeByteArray(NativeByteBuffer *b) { writeByteArray(b, nullptr); } void NativeByteBuffer::writeByteArray(ByteArray *b) { writeByteArray(b->bytes, b->length, nullptr); } void NativeByteBuffer::writeDouble(double d) { writeDouble(d, nullptr); } int32_t NativeByteBuffer::readInt32(bool *error) { if (_position + 4 > _limit) { if (error != nullptr) { *error = true; } if (LOGS_ENABLED) DEBUG_E("read int32 error"); return 0; } int32_t result = ((buffer[_position] & 0xff)) | ((buffer[_position + 1] & 0xff) << 8) | ((buffer[_position + 2] & 0xff) << 16) | ((buffer[_position + 3] & 0xff) << 24); _position += 4; return result; } uint32_t NativeByteBuffer::readUint32(bool *error) { return (uint32_t) readInt32(error); } uint64_t NativeByteBuffer::readUint64(bool *error) { return (uint64_t) readInt64(error); } int32_t NativeByteBuffer::readBigInt32(bool *error) { if (_position + 4 > _limit) { if (error != nullptr) { *error = true; } if (LOGS_ENABLED) DEBUG_E("read big int32 error"); return 0; } int32_t result = ((buffer[_position] & 0xff) << 24) | ((buffer[_position + 1] & 0xff) << 16) | ((buffer[_position + 2] & 0xff) << 8) | ((buffer[_position + 3] & 0xff)); _position += 4; return result; } int64_t NativeByteBuffer::readInt64(bool *error) { if (_position + 8 > _limit) { if (error != nullptr) { *error = true; } if (LOGS_ENABLED) DEBUG_E("read int64 error"); return 0; } int64_t result = ((int64_t) (buffer[_position] & 0xff)) | ((int64_t) (buffer[_position + 1] & 0xff) << 8) | ((int64_t) (buffer[_position + 2] & 0xff) << 16) | ((int64_t) (buffer[_position + 3] & 0xff) << 24) | ((int64_t) (buffer[_position + 4] & 0xff) << 32) | ((int64_t) (buffer[_position + 5] & 0xff) << 40) | ((int64_t) (buffer[_position + 6] & 0xff) << 48) | ((int64_t) (buffer[_position + 7] & 0xff) << 56); _position += 8; return result; } uint8_t NativeByteBuffer::readByte(bool *error) { if (_position + 1 > _limit) { if (error != nullptr) { *error = true; } if (LOGS_ENABLED) DEBUG_E("read byte error"); return 0; } return buffer[_position++]; } bool NativeByteBuffer::readBool(bool *error) { uint32_t consructor = readUint32(error); if (consructor == 0x997275b5) { return true; } else if (consructor == 0xbc799737) { return false; } if (error != nullptr) { *error = true; if (LOGS_ENABLED) DEBUG_E("read bool error"); } return false; } void NativeByteBuffer::readBytes(uint8_t *b, uint32_t length, bool *error) { if (length > _limit - _position) { if (error != nullptr) { *error = true; } if (LOGS_ENABLED) DEBUG_E("read bytes error"); return; } memcpy(b, buffer + _position, length); _position += length; } ByteArray *NativeByteBuffer::readBytes(uint32_t length, bool *error) { if (length > _limit - _position) { if (error != nullptr) { *error = true; } if (LOGS_ENABLED) DEBUG_E("read bytes error"); return nullptr; } ByteArray *byteArray = new ByteArray(length); memcpy(byteArray->bytes, buffer + _position, sizeof(uint8_t) * length); _position += length; return byteArray; } std::string NativeByteBuffer::readString(bool *error) { uint32_t sl = 1; if (_position + 1 > _limit) { if (error != nullptr) { *error = true; } if (LOGS_ENABLED) DEBUG_E("read string error"); return std::string(""); } uint32_t l = buffer[_position++]; if (l >= 254) { if (_position + 3 > _limit) { if (error != nullptr) { *error = true; } if (LOGS_ENABLED) DEBUG_E("read string error"); return std::string(""); } l = buffer[_position] | (buffer[_position + 1] << 8) | (buffer[_position + 2] << 16); _position += 3; sl = 4; } uint32_t addition = (l + sl) % 4; if (addition != 0) { addition = 4 - addition; } if (_position + l + addition > _limit) { if (error != nullptr) { *error = true; } if (LOGS_ENABLED) DEBUG_E("read string error"); return std::string(""); } std::string result = std::string((const char *) (buffer + _position), l); _position += l + addition; return result; } ByteArray *NativeByteBuffer::readByteArray(bool *error) { uint32_t sl = 1; if (_position + 1 > _limit) { if (error != nullptr) { *error = true; } if (LOGS_ENABLED) DEBUG_E("read byte array error"); return nullptr; } uint32_t l = buffer[_position++]; if (l >= 254) { if (_position + 3 > _limit) { if (error != nullptr) { *error = true; } if (LOGS_ENABLED) DEBUG_E("read byte array error"); return nullptr; } l = buffer[_position] | (buffer[_position + 1] << 8) | (buffer[_position + 2] << 16); _position += 3; sl = 4; } uint32_t addition = (l + sl) % 4; if (addition != 0) { addition = 4 - addition; } if (_position + l + addition > _limit) { if (error != nullptr) { *error = true; } if (LOGS_ENABLED) DEBUG_E("read byte array error"); return nullptr; } ByteArray *result = new ByteArray(l); memcpy(result->bytes, buffer + _position, sizeof(uint8_t) * l); _position += l + addition; return result; } NativeByteBuffer *NativeByteBuffer::readByteBuffer(bool copy, bool *error) { uint32_t sl = 1; if (_position + 1 > _limit) { if (error != nullptr) { *error = true; } if (LOGS_ENABLED) DEBUG_E("read byte buffer error"); return nullptr; } uint32_t l = buffer[_position++]; if (l >= 254) { if (_position + 3 > _limit) { if (error != nullptr) { *error = true; } if (LOGS_ENABLED) DEBUG_E("read byte buffer error"); return nullptr; } l = buffer[_position] | (buffer[_position + 1] << 8) | (buffer[_position + 2] << 16); _position += 3; sl = 4; } uint32_t addition = (l + sl) % 4; if (addition != 0) { addition = 4 - addition; } if (_position + l + addition > _limit) { if (error != nullptr) { *error = true; } if (LOGS_ENABLED) DEBUG_E("read byte buffer error"); return nullptr; } NativeByteBuffer *result = nullptr; if (copy) { result = BuffersStorage::getInstance().getFreeBuffer(l); memcpy(result->buffer, buffer + _position, sizeof(uint8_t) * l); } else { result = new NativeByteBuffer(buffer + _position, l); } _position += l + addition; return result; } double NativeByteBuffer::readDouble(bool *error) { double value; int64_t value2 = readInt64(error); memcpy(&value, &value2, sizeof(double)); return value; } void NativeByteBuffer::reuse() { if (sliced) { return; } BuffersStorage::getInstance().reuseFreeBuffer(this); } #ifdef ANDROID jobject NativeByteBuffer::getJavaByteBuffer() { if (javaByteBuffer == nullptr && javaVm != nullptr) { JNIEnv *env = 0; if (javaVm->GetEnv((void **) &env, JNI_VERSION_1_6) != JNI_OK) { if (LOGS_ENABLED) DEBUG_E("can't get jnienv"); exit(1); } javaByteBuffer = env->NewDirectByteBuffer(buffer, _capacity); if (javaByteBuffer == nullptr) { if (LOGS_ENABLED) DEBUG_E("can't allocate NativeByteBuffer buffer"); exit(1); } DEBUG_REF("nativebytebuffer"); jobject globalRef = env->NewGlobalRef(javaByteBuffer); env->DeleteLocalRef(javaByteBuffer); javaByteBuffer = globalRef; } return javaByteBuffer; } #endif