src/bytestream.cpp

Wed, 17 Jul 2013 18:59:28 +0300

author
Teemu Piippo <crimsondusk64@gmail.com>
date
Wed, 17 Jul 2013 18:59:28 +0300
changeset 7
fdabb5869e5f
parent 6
67b6ef6917ba
child 10
bc1414343e19
permissions
-rw-r--r--

updated .gitignore

#include "bytestream.h"
#include "misc.h"
#include <string.h>

union {
	uint32 i;
	float f;
} g_floatunion;

Bytestream::Bytestream( ulong len ) {
	m_data = null;
	resize( len );
	clear();
}

Bytestream::Bytestream( const char* data, ulong len ) {
	m_data = null;
	init( data, len );
}

void Bytestream::resize( ulong newsize ) {
	char* olddata = null;
	ulong oldsize;
	
	if( m_data ) {
		oldsize = m_size;
		olddata = new char[oldsize];
		memcpy( olddata, m_data, oldsize );
	}
	
	delete[] m_data;
	m_data = new uint8[newsize];
	m_size = newsize;
	
	if( olddata )
		memcpy( m_data, olddata, min<ulong> ( oldsize, newsize ));
}

void Bytestream::init( const char* data, ulong len ) {
	resize( len );
	memcpy( m_data, data, len );
	m_ptr = &m_data[0];
	m_len = len;
}

size_t Bytestream::len() const {
	return m_len;
}

void Bytestream::clear() {
	m_ptr = &m_data[0];
	m_len = 0;
}

uint8& Bytestream::subscript( ulong idx ) {
	return m_data[idx];
}

const uint8& Bytestream::const_subscript( ulong idx ) const {
	return m_data[idx];
}

void Bytestream::seek( ulong pos ) {
	m_ptr = m_data + pos;
}

// =============================================================================
void Bytestream::rewind() {
	m_ptr = m_data;
}

ulong Bytestream::bytesLeft() const {
	return ( m_len - ( m_ptr - &m_data[0] ));
}

ulong Bytestream::spaceLeft() const {
	return ( m_size - m_len );
}

// =============================================================================
bool Bytestream::readByte( uint8& val ) {
	if( bytesLeft() < 1 )
		return false;
	
	val = *m_ptr++;
	return true;
}

// =============================================================================
bool Bytestream::readShort( uint16& val ) {
	if( bytesLeft() < 2 )
		return false;
	
	val = 0;
	
	for( int i = 0; i < 2; ++i )
		val |= *m_ptr++ << ( i * 8 );

	return true;
}

// =============================================================================
bool Bytestream::readLong( uint32& val ) {
	if( bytesLeft() < 4 )
		return false;
	
	val = 0;
	
	for( int i = 0; i < 4; ++i )
		val |= *m_ptr++ << ( i * 8 );
	
	return true;
}

// =============================================================================
bool Bytestream::readFloat( float& val ) {
	if( !readLong( g_floatunion.i ))
		return false;

	val = g_floatunion.f;
	return true;
}

// =============================================================================
bool Bytestream::readString( str& val ) {
	if( bytesLeft() < 1 ) // need at least the null terminator
		return false;
	
	uint8_t c;
	
	while( readByte( c ) && c != '\0' )
		val += ( char ) c;
	
	return true;
}

// =============================================================================
void Bytestream::doWrite( uint8_t val ) {
	*m_ptr++ = val;
	m_len++;
}

void Bytestream::growToFit( ulong bytes ) {
	if( spaceLeft() < bytes )
		resize( m_size + bytes + 128 );
}

bool Bytestream::readBytes( uint8 numbytes, uint8* val ) {
	while( numbytes-- )
		if( !readByte( *val++ ))
			return false;
	
	return true;
}

void Bytestream::writeBytes( uint8 numbytes, const uint8* val ) {
	growToFit( numbytes );
	
	while( numbytes-- )
		writeByte( *val++ );
}

// =============================================================================
void Bytestream::writeByte( uint8 val ) {
	growToFit( 1 );
	doWrite( val );
}

// =============================================================================
void Bytestream::writeShort( uint16 val ) {
	growToFit( 2 );
	
	for( int i = 0; i < 2; ++i )
		doWrite(( val >> ( i * 8 )) & 0xFF );
}

// =============================================================================
void Bytestream::writeLong( uint32 val ) {
	growToFit( 4 );
	
	for( int i = 0; i < 4; ++i )
		doWrite(( val >> ( i * 8 )) & 0xFF );
}

// =============================================================================
void Bytestream::writeFloat( float val ) {
	g_floatunion.f = val;
	writeLong( g_floatunion.i );
}

// =============================================================================
void Bytestream::writeString( str val ) {
	growToFit( val.length() + 1 );
	
	for( qchar c : val )
		doWrite( c.toAscii() );
	
	doWrite( '\0' );
}

// =============================================================================
bool Bytestream::tryMerge( const Bytestream& other ) {
	if( spaceLeft() < other.len() )
		return false;
	
	for( ulong i = 0; i < other.len(); ++i )
		writeByte( other[i] );
	
	return true;
}

void Bytestream::merge( const Bytestream& other ) {
	growToFit( other.len() );
	
	if( !tryMerge( other )) {
		// Shouldn't happen
		fprint( stderr, "ByteStream: Not enough space for merge (%1 bytes left, need %2)",
				spaceLeft(), other.len() );
		abort();
	}
}

const uint8* Bytestream::data() const {
	return m_data;
}

mercurial