/*
* Copyright (c) 2020 Red Hat, Inc.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* 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. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*
* $Id: //eng/uds-releases/jasper/src/uds/buffer.c#3 $
*/
#include "buffer.h"
#include "bufferPrivate.h"
#include "logger.h"
#include "memoryAlloc.h"
#include "numeric.h"
#include "permassert.h"
#include "typeDefs.h"
/**********************************************************************/
int wrapBuffer(byte *bytes,
size_t length,
size_t contentLength,
Buffer **bufferPtr)
{
int result = ASSERT((contentLength <= length),
"content length, %zu, fits in buffer size, %zu",
length, contentLength);
Buffer *buffer;
result = ALLOCATE(1, Buffer, "buffer", &buffer);
if (result != UDS_SUCCESS) {
return result;
}
buffer->data = bytes;
buffer->start = 0;
buffer->end = contentLength;
buffer->length = length;
buffer->wrapped = true;
*bufferPtr = buffer;
return UDS_SUCCESS;
}
/***********************************************************************/
int makeBuffer(size_t size, Buffer **newBuffer)
{
byte *data;
int result = ALLOCATE(size, byte, "buffer data", &data);
if (result != UDS_SUCCESS) {
return result;
}
Buffer *buffer;
result = wrapBuffer(data, size, 0, &buffer);
if (result != UDS_SUCCESS) {
FREE(data);
return result;
}
buffer->wrapped = false;
*newBuffer = buffer;
return UDS_SUCCESS;
}
/***********************************************************************/
void freeBuffer(Buffer **pBuffer)
{
Buffer *buffer = *pBuffer;
*pBuffer = NULL;
if (buffer == NULL) {
return;
}
if (!buffer->wrapped) {
FREE(buffer->data);
}
FREE(buffer);
}
/**********************************************************************/
size_t bufferLength(Buffer *buffer)
{
return buffer->length;
}
/**********************************************************************/
size_t contentLength(Buffer *buffer)
{
return buffer->end - buffer->start;
}
/**********************************************************************/
size_t uncompactedAmount(Buffer *buffer)
{
return buffer->start;
}
/**********************************************************************/
size_t availableSpace(Buffer *buffer)
{
return buffer->length - buffer->end;
}
/**********************************************************************/
size_t bufferUsed(Buffer *buffer)
{
return buffer->end;
}
/***********************************************************************/
int growBuffer(Buffer *buffer, size_t length)
{
if (buffer == NULL) {
return logWarningWithStringError(UDS_INVALID_ARGUMENT,
"cannot resize NULL buffer");
}
if (buffer->wrapped) {
return logWarningWithStringError(UDS_INVALID_ARGUMENT,
"cannot resize wrapped buffer");
}
if (buffer->end > length) {
return logWarningWithStringError(UDS_INVALID_ARGUMENT,
"cannot shrink buffer");
}
byte *data;
int result = reallocateMemory(buffer->data, buffer->length, length,
"buffer data", &data);
if (result != UDS_SUCCESS) {
return result;
}
buffer->data = data;
buffer->length = length;
return UDS_SUCCESS;
}
/***********************************************************************/
bool ensureAvailableSpace(Buffer *buffer, size_t bytes)
{
if (availableSpace(buffer) >= bytes) {
return true;
}
compactBuffer(buffer);
return (availableSpace(buffer) >= bytes);
}
/***********************************************************************/
void clearBuffer(Buffer *buffer)
{
buffer->start = 0;
buffer->end = buffer->length;
}
/***********************************************************************/
void compactBuffer(Buffer *buffer)
{
if ((buffer->start == 0) || (buffer->end == 0)) {
return;
}
size_t bytesToMove = buffer->end - buffer->start;
memmove(buffer->data, buffer->data + buffer->start, bytesToMove);
buffer->start = 0;
buffer->end = bytesToMove;
}
/**********************************************************************/
int resetBufferEnd(Buffer *buffer, size_t end)
{
if (end > buffer->length) {
return UDS_BUFFER_ERROR;
}
buffer->end = end;
if (buffer->start > buffer->end) {
buffer->start = buffer->end;
}
return UDS_SUCCESS;
}
/**********************************************************************/
int skipForward(Buffer *buffer, size_t bytesToSkip)
{
if (contentLength(buffer) < bytesToSkip) {
return UDS_BUFFER_ERROR;
}
buffer->start += bytesToSkip;
return UDS_SUCCESS;
}
/**********************************************************************/
int rewindBuffer(Buffer *buffer, size_t bytesToRewind)
{
if (buffer->start < bytesToRewind) {
return UDS_BUFFER_ERROR;
}
buffer->start -= bytesToRewind;
return UDS_SUCCESS;
}
/**********************************************************************/
bool hasSameBytes(Buffer *buffer, const byte *data, size_t length)
{
return ((contentLength(buffer) >= length)
&& (memcmp(buffer->data + buffer->start, data, length) == 0));
}
/**********************************************************************/
bool equalBuffers(Buffer *buffer1, Buffer *buffer2)
{
return hasSameBytes(buffer1, buffer2->data + buffer2->start,
contentLength(buffer2));
}
/**********************************************************************/
int getByte(Buffer *buffer, byte *bytePtr)
{
if (contentLength(buffer) < sizeof(byte)) {
return UDS_BUFFER_ERROR;
}
*bytePtr = buffer->data[buffer->start++];
return UDS_SUCCESS;
}
/**********************************************************************/
int peekByte(Buffer *buffer, size_t offset, byte *bytePtr)
{
if (contentLength(buffer) < (offset + sizeof(byte))) {
return UDS_BUFFER_ERROR;
}
*bytePtr = buffer->data[buffer->start + offset];
return UDS_SUCCESS;
}
/**********************************************************************/
int putByte(Buffer *buffer, byte b)
{
if (!ensureAvailableSpace(buffer, sizeof(byte))) {
return UDS_BUFFER_ERROR;
}
buffer->data[buffer->end++] = b;
return UDS_SUCCESS;
}
/**********************************************************************/
int getBytesFromBuffer(Buffer *buffer, size_t length, void *destination)
{
if (contentLength(buffer) < length) {
return UDS_BUFFER_ERROR;
}
memcpy(destination, buffer->data + buffer->start, length);
buffer->start += length;
return UDS_SUCCESS;
}
/**********************************************************************/
byte *getBufferContents(Buffer *buffer)
{
return buffer->data + buffer->start;
}
/**********************************************************************/
int copyBytes(Buffer *buffer, size_t length, byte **destinationPtr)
{
byte *destination;
int result = ALLOCATE(length, byte, "copyBytes() buffer",
&destination);
if (result != UDS_SUCCESS) {
return result;
}
result = getBytesFromBuffer(buffer, length, destination);
if (result != UDS_SUCCESS) {
FREE(destination);
} else {
*destinationPtr = destination;
}
return result;
}
/**********************************************************************/
int putBytes(Buffer *buffer, size_t length, const void *source)
{
if (!ensureAvailableSpace(buffer, length)) {
return UDS_BUFFER_ERROR;
}
memcpy(buffer->data + buffer->end, source, length);
buffer->end += length;
return UDS_SUCCESS;
}
/**********************************************************************/
int putBuffer(Buffer *target, Buffer *source, size_t length)
{
if (contentLength(source) < length) {
return UDS_BUFFER_ERROR;
}
int result = putBytes(target, length, getBufferContents(source));
if (result != UDS_SUCCESS) {
return result;
}
source->start += length;
return UDS_SUCCESS;
}
/**********************************************************************/
int zeroBytes(Buffer *buffer, size_t length)
{
if (!ensureAvailableSpace(buffer, length)) {
return UDS_BUFFER_ERROR;
}
memset(buffer->data + buffer->end, 0, length);
buffer->end += length;
return UDS_SUCCESS;
}
/**********************************************************************/
int getBoolean(Buffer *buffer, bool *b)
{
byte by;
int result = getByte(buffer, &by);
if (result == UDS_SUCCESS) {
*b = (by == 1);
}
return result;
}
/**********************************************************************/
int putBoolean(Buffer *buffer, bool b)
{
return putByte(buffer, (byte) (b ? 1 : 0));
}
/**********************************************************************/
int getUInt16BEFromBuffer(Buffer *buffer, uint16_t *ui)
{
if (contentLength(buffer) < sizeof(uint16_t)) {
return UDS_BUFFER_ERROR;
}
decodeUInt16BE(buffer->data, &buffer->start, ui);
return UDS_SUCCESS;
}
/**********************************************************************/
int putUInt16BEIntoBuffer(Buffer *buffer, uint16_t ui)
{
if (!ensureAvailableSpace(buffer, sizeof(uint16_t))) {
return UDS_BUFFER_ERROR;
}
encodeUInt16BE(buffer->data, &buffer->end, ui);
return UDS_SUCCESS;
}
/**********************************************************************/
int getUInt32BEFromBuffer(Buffer *buffer, uint32_t *ui)
{
if (contentLength(buffer) < sizeof(uint32_t)) {
return UDS_BUFFER_ERROR;
}
decodeUInt32BE(buffer->data, &buffer->start, ui);
return UDS_SUCCESS;
}
/**********************************************************************/
int putUInt32BEIntoBuffer(Buffer *buffer, uint32_t ui)
{
if (!ensureAvailableSpace(buffer, sizeof(uint32_t))) {
return UDS_BUFFER_ERROR;
}
encodeUInt32BE(buffer->data, &buffer->end, ui);
return UDS_SUCCESS;
}
/**********************************************************************/
int getUInt32BEsFromBuffer(Buffer *buffer, size_t count, uint32_t *ui)
{
if (contentLength(buffer) < (sizeof(uint32_t) * count)) {
return UDS_BUFFER_ERROR;
}
unsigned int i;
for (i = 0; i < count; i++) {
decodeUInt32BE(buffer->data, &buffer->start, ui + i);
}
return UDS_SUCCESS;
}
/**********************************************************************/
int putUInt32BEsIntoBuffer(Buffer *buffer, size_t count, const uint32_t *ui)
{
if (!ensureAvailableSpace(buffer, sizeof(uint32_t) * count)) {
return UDS_BUFFER_ERROR;
}
unsigned int i;
for (i = 0; i < count; i++) {
encodeUInt32BE(buffer->data, &buffer->end, ui[i]);
}
return UDS_SUCCESS;
}
/**********************************************************************/
int getUInt64BEsFromBuffer(Buffer *buffer, size_t count, uint64_t *ui)
{
if (contentLength(buffer) < (sizeof(uint64_t) * count)) {
return UDS_BUFFER_ERROR;
}
unsigned int i;
for (i = 0; i < count; i++) {
decodeUInt64BE(buffer->data, &buffer->start, ui + i);
}
return UDS_SUCCESS;
}
/**********************************************************************/
int putUInt64BEsIntoBuffer(Buffer *buffer, size_t count, const uint64_t *ui)
{
if (!ensureAvailableSpace(buffer, sizeof(uint64_t) * count)) {
return UDS_BUFFER_ERROR;
}
unsigned int i;
for (i = 0; i < count; i++) {
encodeUInt64BE(buffer->data, &buffer->end, ui[i]);
}
return UDS_SUCCESS;
}
/**********************************************************************/
int getUInt16LEFromBuffer(Buffer *buffer, uint16_t *ui)
{
if (contentLength(buffer) < sizeof(uint16_t)) {
return UDS_BUFFER_ERROR;
}
decodeUInt16LE(buffer->data, &buffer->start, ui);
return UDS_SUCCESS;
}
/**********************************************************************/
int putUInt16LEIntoBuffer(Buffer *buffer, uint16_t ui)
{
if (!ensureAvailableSpace(buffer, sizeof(uint16_t))) {
return UDS_BUFFER_ERROR;
}
encodeUInt16LE(buffer->data, &buffer->end, ui);
return UDS_SUCCESS;
}
/**********************************************************************/
int getUInt16LEsFromBuffer(Buffer *buffer, size_t count, uint16_t *ui)
{
if (contentLength(buffer) < (sizeof(uint16_t) * count)) {
return UDS_BUFFER_ERROR;
}
unsigned int i;
for (i = 0; i < count; i++) {
decodeUInt16LE(buffer->data, &buffer->start, ui + i);
}
return UDS_SUCCESS;
}
/**********************************************************************/
int putUInt16LEsIntoBuffer(Buffer *buffer, size_t count, const uint16_t *ui)
{
if (!ensureAvailableSpace(buffer, sizeof(uint16_t) * count)) {
return UDS_BUFFER_ERROR;
}
unsigned int i;
for (i = 0; i < count; i++) {
encodeUInt16LE(buffer->data, &buffer->end, ui[i]);
}
return UDS_SUCCESS;
}
/**********************************************************************/
int getInt32LEFromBuffer(Buffer *buffer, int32_t *i)
{
if (contentLength(buffer) < sizeof(int32_t)) {
return UDS_BUFFER_ERROR;
}
decodeInt32LE(buffer->data, &buffer->start, i);
return UDS_SUCCESS;
}
/**********************************************************************/
int getUInt32LEFromBuffer(Buffer *buffer, uint32_t *ui)
{
if (contentLength(buffer) < sizeof(uint32_t)) {
return UDS_BUFFER_ERROR;
}
decodeUInt32LE(buffer->data, &buffer->start, ui);
return UDS_SUCCESS;
}
/**********************************************************************/
int putUInt32LEIntoBuffer(Buffer *buffer, uint32_t ui)
{
if (!ensureAvailableSpace(buffer, sizeof(uint32_t))) {
return UDS_BUFFER_ERROR;
}
encodeUInt32LE(buffer->data, &buffer->end, ui);
return UDS_SUCCESS;
}
/**********************************************************************/
int putInt64LEIntoBuffer(Buffer *buffer, int64_t i)
{
if (!ensureAvailableSpace(buffer, sizeof(int64_t))) {
return UDS_BUFFER_ERROR;
}
encodeInt64LE(buffer->data, &buffer->end, i);
return UDS_SUCCESS;
}
/**********************************************************************/
int getUInt64LEFromBuffer(Buffer *buffer, uint64_t *ui)
{
if (contentLength(buffer) < sizeof(uint64_t)) {
return UDS_BUFFER_ERROR;
}
decodeUInt64LE(buffer->data, &buffer->start, ui);
return UDS_SUCCESS;
}
/**********************************************************************/
int putUInt64LEIntoBuffer(Buffer *buffer, uint64_t ui)
{
if (!ensureAvailableSpace(buffer, sizeof(uint64_t))) {
return UDS_BUFFER_ERROR;
}
encodeUInt64LE(buffer->data, &buffer->end, ui);
return UDS_SUCCESS;
}
/**********************************************************************/
int getUInt64LEsFromBuffer(Buffer *buffer, size_t count, uint64_t *ui)
{
if (contentLength(buffer) < (sizeof(uint64_t) * count)) {
return UDS_BUFFER_ERROR;
}
unsigned int i;
for (i = 0; i < count; i++) {
decodeUInt64LE(buffer->data, &buffer->start, ui + i);
}
return UDS_SUCCESS;
}
/**********************************************************************/
int putUInt64LEsIntoBuffer(Buffer *buffer, size_t count, const uint64_t *ui)
{
if (!ensureAvailableSpace(buffer, sizeof(uint64_t) * count)) {
return UDS_BUFFER_ERROR;
}
unsigned int i;
for (i = 0; i < count; i++) {
encodeUInt64LE(buffer->data, &buffer->end, ui[i]);
}
return UDS_SUCCESS;
}