#include "StdAfx.h"
#include "UTF8StringConvert.h"
#include "BinaryData.h"

//	標準拡張サイズ
#define	DEFAULT_GROW_SIZE	32768

////////////////////////////////////////////////////////////////////////////////////////
//	初期化
////////////////////////////////////////////////////////////////////////////////////////
/*!
	標準初期化
*/
CBinaryData::CBinaryData(int allocSize)
{
	SetCoreInterface(&m_core);
	ReSize(allocSize);
}

/*!
	コピー
*/
CBinaryData::CBinaryData(CBinaryData &other)
{
	SetCoreInterface(&m_core);
	ReSize(other.GetSize());

	memmove(GetPtr(), other.GetPtr(), other.GetSize());
}

/*!
	インタフェース設定
*/
CBinaryData::CBinaryData(IBinaryDataPtr other)
{
	SetCoreInterface(other);
}

/*!
	デストラクタ
*/
CBinaryData::~CBinaryData(void)
{
}


////////////////////////////////////////////////////////////////////////////////////////
//	削除
////////////////////////////////////////////////////////////////////////////////////////
/*!
	削除
*/
int CBinaryData::Remove(int start, int size)
{
	if(start < 0 || size < 0 || start + size > GetSize())
		return(-1);

	memmove(GetPtr() + start,GetPtr() + size, GetSize() - (start + size));
	ReSize(GetSize() - size);
	return(0);
}

////////////////////////////////////////////////////////////////////////////////////////
//	書き込み
////////////////////////////////////////////////////////////////////////////////////////
/*!
	上書き(必要ならば、バッファ追加)
*/
void CBinaryData::OverwriteData(int startOffset, char *data, int len)
{
	if(startOffset + len >= GetSize())
		ReSize(startOffset + len);

	memmove(GetPtr() + startOffset, data, len);
}

/*!
	追加
*/
void CBinaryData::Append(char *data,int size)
{
	int	oldSize = GetSize();
	ReSize(size + oldSize);

	memmove(GetPtr() + oldSize, data, size);
}


////////////////////////////////////////////////////////////////////////////////////////
//	変換
////////////////////////////////////////////////////////////////////////////////////////
/*!
	CUTF8Stringへ
*/
CUTF8String CBinaryData::GetString()
{
	CUTF8String ret;
	ret.SetString((LPCU8STR)GetPtr(), GetSize());

	return(ret);
}


////////////////////////////////////////////////////////////////////////////////////////
//	サーチ
////////////////////////////////////////////////////////////////////////////////////////
/*!
	メモリ領域の検索
*/
int CBinaryData::SerachMemBlock(const char *block, int blockLen)
{
	//	探すまでもない
	if(blockLen <= 0 || GetSize() == 0 || blockLen > GetSize())
		return(-1);

	//	検索
	char	*start = GetPtr(), *find = GetPtr();
	int		left = GetSize();
	while(left >= blockLen)
	{
		//	最初の文字を探す
		find = (char*)memchr(find, block[0], left - blockLen + 1);
		if(find == NULL)
			return(-1);

		//	比較してみる
		if(memcmp(find, block, blockLen) == 0)
			return(find - GetPtr());

		//	次へ
		find++;
		left = GetSize() - (find - start);
	}
	return(-1);
}


//////////////////////////////////////////////////////////////////////
// 保存
//////////////////////////////////////////////////////////////////////
/*!
	ファイルへ保存

	\param path		パス
*/
int CBinaryData::SaveToFile(CUTF8String path)
{
	FILE	*out;
	if(_wfopen_s(&out, _cnvU16(path), _U16("wb")) != 0)
		return(-1);

	fwrite(GetPtr(), GetSize(), 1, out);
	fclose(out);
	return(0);
}

/*!
	ファイルから読み出し

	\param path		パス
*/
int CBinaryData::LoadFromFile(CUTF8String path)
{
	FILE	*out;
	if(_wfopen_s(&out, _cnvU16(path), _U16("rb")) != 0)
		return(-1);
	
	fseek(out,0,SEEK_END);
	long	len = ftell(out);
	fseek(out,0,SEEK_SET);

	ReSize(len);
	fread(GetPtr(), GetSize(), 1, out);
	fclose(out);
	return(0);
}


////////////////////////////////////////////////////////////////////////////////////////
//	CBinaryDataCore
////////////////////////////////////////////////////////////////////////////////////////
CBinaryData::CBinaryDataCore::CBinaryDataCore()
{
	InitInternal();
}

CBinaryData::CBinaryDataCore::~CBinaryDataCore()
{
	if(m_buffer)
		delete m_buffer;
	InitInternal();
}

/*!
	サイズ変更
*/
void CBinaryData::CBinaryDataCore::ReSize(int size)
{
	//	クリア
	if(size == 0)
	{
		if(!m_noFreeEmpty)
		{
			if(m_buffer)
				delete m_buffer;
			m_buffer = NULL;
			m_bufferSize = 0;
		}

		m_usingSize = 0;
		return;
	}

	//	確保
	if(m_buffer == NULL || size > m_bufferSize)
	{
		int allocSize = (size / m_growSize + 1) * m_growSize;
		char *temp = new char[allocSize];
		int	transSize = m_bufferSize;

		//	転送
		if(m_buffer != NULL)
		{
			if(m_bufferSize > size)
				transSize = size;

			memmove(temp, m_buffer, transSize);
			delete m_buffer;
		}

		//	設定
		m_buffer = temp;
		m_bufferSize = allocSize;
	}
	m_usingSize = size;
}

/*!
	サイズ取得
*/
int CBinaryData::CBinaryDataCore::GetSize()
{
	return m_usingSize;
}

/*!
	保持しているデータポインタを取得
*/
char *CBinaryData::CBinaryDataCore::GetPtr()
{
	return m_buffer;
}

/*!
	内部初期化
*/
void CBinaryData::CBinaryDataCore::InitInternal()
{
	m_buffer = NULL;
	m_bufferSize = 0;
	m_usingSize = 0;
	m_noFreeEmpty = 0;
	SetGrowSize(DEFAULT_GROW_SIZE);
}
