⛏️ index : haiku.git

/*
 * Copyright 2012 Haiku, Inc. All rights reserved.
 * Distributed under the terms of the MIT License.
 *
 * Authors:
 *		Paweł Dziepak, pdziepak@quarnos.org
 */


#include "XDR.h"

#include <stdlib.h>
#include <string.h>

#include <ByteOrder.h>


using namespace XDR;

Stream::Stream(void* buffer, uint32 size)
	:
	fBuffer(reinterpret_cast<uint32*>(buffer)),
	fSize(size),
	fPosition(0)
{
}


Stream::~Stream()
{
}


uint32
Stream::_PositionToSize() const
{
	return fPosition * sizeof(uint32);
}


uint32
Stream::_RealSize(uint32 size) const
{
	uint32 real_size = size;
	if (real_size % 4 != 0)
		real_size = ((real_size >> 2) + 1) << 2;
	return real_size;
}


ReadStream::ReadStream(void* buffer, uint32 size)
	:
	Stream(buffer, size),
	fEOF(false)
{
}


ReadStream::~ReadStream()
{
}


int32
ReadStream::GetInt()
{
	if (_PositionToSize() >= fSize) {
		fEOF = true;
		return 0;
	}

	return B_BENDIAN_TO_HOST_INT32(fBuffer[fPosition++]);
}


uint32
ReadStream::GetUInt()
{
	if (_PositionToSize() >= fSize) {
		fEOF = true;
		return 0;
	}

	return B_BENDIAN_TO_HOST_INT32(fBuffer[fPosition++]);
}


int64
ReadStream::GetHyper()
{
	if (_PositionToSize() + sizeof(int64) > fSize) {
		fEOF = true;
		return 0;
	}

	int64* ptr = reinterpret_cast<int64*>(fBuffer + fPosition);
	fPosition += 2;

	return B_BENDIAN_TO_HOST_INT64(*ptr);
}


uint64
ReadStream::GetUHyper()
{
	if (_PositionToSize() + sizeof(uint64) > fSize) {
		fEOF = true;
		return 0;
	}

	uint64* ptr = reinterpret_cast<uint64*>(fBuffer + fPosition);
	fPosition += 2;

	return B_BENDIAN_TO_HOST_INT64(*ptr);
}


char*
ReadStream::GetString()
{
	if (_PositionToSize() >= fSize) {
		fEOF = true;
		return NULL;
	}

	uint32 size;
	const void* ptr = GetOpaque(&size);
	if (ptr == NULL)
		return NULL;

	char* str = reinterpret_cast<char*>(malloc(size + 1));
	if (str == NULL)
		return NULL;

	memcpy(str, ptr, size);
	str[size] = 0;

	return str;
}


const void*
ReadStream::GetOpaque(uint32* size)
{
	if (_PositionToSize() >= fSize) {
		fEOF = true;
		return NULL;
	}

	void* ptr = NULL;
	uint32 s = GetUInt();
	if (s != 0) {
		ptr = fBuffer + fPosition;
		if (_PositionToSize() + s <= fSize)
			fPosition += _RealSize(s) / sizeof(uint32);
		else {
			s = fSize - _PositionToSize();
			fPosition = fSize;
		}
	}

	if (size != NULL)
		*size = s;

	return ptr;
}


WriteStream::WriteStream()
	:
	Stream(malloc(kInitialSize), kInitialSize),
	fError(B_OK)
{
}


WriteStream::WriteStream(const WriteStream& x)
	:
	Stream(malloc(x.fSize), x.fSize),
	fError(x.fError)
{
	fPosition = x.fPosition;
	memcpy(fBuffer, x.fBuffer, fSize);
}


WriteStream::~WriteStream()
{
	free(fBuffer);
}


void
WriteStream::Clear()
{
	free(fBuffer);
	fSize = kInitialSize;
	fBuffer = reinterpret_cast<uint32*>(malloc(fSize));
	fError = B_OK;
	fPosition = 0;
}


status_t
WriteStream::InsertUInt(Stream::Position pos, uint32 x)
{
	if (pos * sizeof(uint32) >= fSize) {
		fError = B_BAD_VALUE;
		return B_BAD_VALUE;
	}

	fBuffer[pos] = B_HOST_TO_BENDIAN_INT32(x);
	return B_OK;
}


status_t
WriteStream::AddInt(int32 x)
{
	status_t err = _CheckResize(sizeof(int32));
	if (err != B_OK)
		return err;

	fBuffer[fPosition++] = B_HOST_TO_BENDIAN_INT32(x);
	return B_OK;
}


status_t
WriteStream::AddUInt(uint32 x)
{
	status_t err = _CheckResize(sizeof(uint32));
	if (err != B_OK)
		return err;

	fBuffer[fPosition++] = B_HOST_TO_BENDIAN_INT32(x);
	return B_OK;
}


status_t
WriteStream::AddHyper(int64 x)
{
	status_t err = _CheckResize(sizeof(int64));
	if (err != B_OK)
		return err;

	int64* ptr = reinterpret_cast<int64*>(fBuffer + fPosition);
	*ptr = B_HOST_TO_BENDIAN_INT64(x);
	fPosition += 2;
	return B_OK;
}


status_t
WriteStream::AddUHyper(uint64 x)
{
	status_t err = _CheckResize(sizeof(uint64));
	if (err != B_OK)
		return err;

	uint64* ptr = reinterpret_cast<uint64*>(fBuffer + fPosition);
	*ptr = B_HOST_TO_BENDIAN_INT64(x);
	fPosition += 2;
	return B_OK;
}


status_t
WriteStream::AddString(const char* str, uint32 maxlen)
{
	uint32 len = strlen(str);
	uint32 size = maxlen == 0 ? len : min_c(maxlen, len);

	return AddOpaque(str, size);
}


status_t
WriteStream::AddOpaque(const void* ptr, uint32 size)
{
	uint32 real_size = _RealSize(size);
	status_t err = _CheckResize(real_size + sizeof(uint32));
	if (err != B_OK)
		return err;

	AddUInt(size);
	memset(fBuffer + fPosition, 0, real_size);
	memcpy(fBuffer + fPosition, ptr, size);
	fPosition += real_size / sizeof(int32);

	return B_OK;
}


status_t
WriteStream::AddOpaque(const WriteStream& stream)
{
	return AddOpaque(stream.Buffer(), stream.Size());
}


status_t
WriteStream::Append(const WriteStream& stream)
{
	uint32 size = stream.Size();
	status_t err = _CheckResize(size);
	if (err != B_OK)
		return err;

	memcpy(fBuffer + fPosition, stream.Buffer(), size);
	fPosition += size / sizeof(int32);

	return B_OK;
}


status_t
WriteStream::_CheckResize(uint32 size)
{
	if (_PositionToSize() + size <= fSize)
		return B_OK;

	uint32 new_size = max_c(fSize * 2, fPosition * sizeof(uint32) + size);

	void* ptr = realloc(fBuffer, new_size);
	if (ptr == NULL) {
		fError = B_NO_MEMORY;
		return B_NO_MEMORY;
	}

	fBuffer = reinterpret_cast<uint32*>(ptr);
	fSize = new_size;

	return B_OK;
}