/*
 * Copyright 2022, ttcoder
 * All rights reserved. Distributed under the terms of the MIT license.
 */

// this
#include "BufIO.h"



PickStr::PickStr( const char * str, unsigned numchars )
:	_buf()
{
	Genode::copy_cstring(
		_buf,
		str,
		Genode::min( sizeof(_buf), numchars +sizeof('\0') )
		);
	
	_buf[ sizeof(_buf) -1 ] = '\0';  // extra nul ending
}


const char * PickStr::string() const
{
	return _buf;
}

unsigned PickStr::length() const
{
	return Genode::strlen( _buf );
}



//#pragma mark -


BufIO::BufIO( Genode::Allocator & alloc )
:	bufData( nullptr )
	,bufSize( 0 )
	,heapAlloc( alloc )
{
}

BufIO::~BufIO()
{
	Clear();
}


void BufIO::Dump()
{
	Genode::log( "------------ dumping BufIO's ", bufSize, " bytes ------------" );
	
	//unlimited length, but goes off the deep end beyond the (often missing) trailing nul byte...:
	//Genode::log( (const char*)bufData );
	
	PickStr small( (const char*)bufData, bufSize );
	Genode::log( small.string() );
	
	Genode::log( "------------------" );
}

const void * BufIO::Buffer() const
{
	return bufData;
}

unsigned BufIO::BufferLength() const
{
	return bufSize;
}

void BufIO::Clear()
{
	if( bufData )
		heapAlloc.free( bufData, bufSize );
	
	bufData = nullptr;
	bufSize = 0;
}

void BufIO::AppendStr( const char * string )
{
	Append( string, Genode::strlen(string) );
}

void BufIO::Append( const void * buf, unsigned size )
{
	//Genode::log( "Append ", buf, ", ", size, " bytes" );
	
	if( nullptr == buf || size <= 0 )
	{
		//Genode::log( "buf.Append(): nothing to do" );
		
		return;  // dodge doing an alloc(0), which errors out
	}
	
	char * newbuf = static_cast<char*>( heapAlloc.alloc(bufSize + size) );
	
	// T-
	if( bufData && bufSize )
	{
		Genode::memcpy( newbuf, bufData, bufSize );
		
		heapAlloc.free( bufData, bufSize );
		bufData = nullptr;
	}
	// T0
	Genode::memcpy( newbuf+bufSize, buf, size );
	
	// T+
	bufData = newbuf;
	bufSize += size;
}

void BufIO::Erase( unsigned where, unsigned delta )
{
	if( where +delta > bufSize )
	{
		Genode::error( "idx: BufIO.erase(", where, ", ", delta, ") but buffer is only ", bufSize, " bytes long" );
		
		return;
	}
	
	// <bufData> must be non-NULL from here on:
	
	char * newbuf = nullptr;
	
	if( delta < bufSize )
	{
		// the resulting buffer will not be empty
		newbuf = static_cast<char*>( heapAlloc.alloc(bufSize - delta) );
		
		// T-
		Genode::memcpy( newbuf, bufData, where );
		Genode::memcpy(
			newbuf  +where,
			static_cast<const char*>( bufData ) +where +delta,
			bufSize -where -delta
			);
	}
	// else:
	// do NOT call alloc() on a zero-sized buffer, otherwise we get "Error: attempt to allocate zero-size block from heap"
	
	// T0
	heapAlloc.free( bufData, bufSize );
	bufData = nullptr;
	
	// T+
	bufData = newbuf;
	bufSize -= delta;
}

