// Buffer.cpp: CBuffer クラスのインプリメンテーション
//
//////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "Buffer.h"

#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif

#define	GROW_SIZE	32768

//////////////////////////////////////////////////////////////////////
//	サイズを指定して初期化
//////////////////////////////////////////////////////////////////////
/*!
	\param size	サイズ
*/
CBuffer::CBuffer(int size)
{
	Init();
	Alloc(size);
}

//////////////////////////////////////////////////////////////////////
//	コピーコンストラクタ
//////////////////////////////////////////////////////////////////////
/*!
	\param other	他のクラス
*/
CBuffer::CBuffer(CBuffer &other)
{
	Init();
	Alloc(other.GetSize());
	memmove(m_buffer,other.GetPtr(),other.GetSize());
}


//////////////////////////////////////////////////////////////////////
//	デストラクタ
//////////////////////////////////////////////////////////////////////
CBuffer::~CBuffer()
{
	delete m_buffer;
	Init();
}

//////////////////////////////////////////////////////////////////////
//	初期化
//////////////////////////////////////////////////////////////////////
void CBuffer::Init()
{
	m_buffer = NULL;
	m_bufferSize = 0;
	m_usingSize = 0;
	SetGrowSize(GROW_SIZE);
}


//////////////////////////////////////////////////////////////////////
// 確保
//////////////////////////////////////////////////////////////////////
/*!
	\param size	確保サイズ
*/
void CBuffer::Alloc(int size)
{
	if(size > m_bufferSize)
	{
		unsigned char *temp = new unsigned char[size + m_growSize];
		int	transSize = m_bufferSize;

		if(m_buffer)
		{
			if(m_bufferSize > size)
				transSize = size;

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

		m_buffer = temp;
		m_bufferSize = size + m_growSize;
		m_usingSize = size;
	}
}


//////////////////////////////////////////////////////////////////////
// 追加
//////////////////////////////////////////////////////////////////////
/*!
	\param data	データ
	\param size サイズ
*/
void CBuffer::Append(const char *data, int size)
{
	int	oldSize = GetSize();
	ReSize(size + oldSize);

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


//////////////////////////////////////////////////////////////////////
// サイズ変更
//////////////////////////////////////////////////////////////////////
/*!
	変更前のデータは保護されるが、変更後が元のサイズより小さい場合、後ろのデータは切り捨てられる<br>

	\param size 変更するサイズ
*/
void CBuffer::ReSize(int size)
{
	if(size > m_bufferSize)
	{
		Alloc(size);
	}
	m_usingSize = size;
}

//////////////////////////////////////////////////////////////////////
// 削除
//////////////////////////////////////////////////////////////////////
/*!
	start から start + size 間でのデータを削除する。<br>
	データは切り詰められる。

	\param start	削除開始点
	\param size		削除するサイズ
*/
void CBuffer::Remove(int start,int size)
{
	if(start < 0 || size < 0 || start + size > m_usingSize)
		return;

	memmove(GetPtr() + start,GetPtr() + size,m_usingSize - (start + size));
	m_usingSize = m_usingSize - size;
}

//////////////////////////////////////////////////////////////////////
// 取得
//////////////////////////////////////////////////////////////////////
char * CBuffer::GetPtr()
{
	return((char *)m_buffer);
}

CBuffer::operator char*()
{
	return((char *)m_buffer);
}

CBuffer::operator CString()
{
	CString ret;
	char * buf = ret.GetBuffer(m_usingSize + 1);
	memcpy(buf,m_buffer,m_usingSize);
	buf[m_usingSize] = 0;
	ret.ReleaseBuffer();

	return(ret);
}

CBuffer::operator unsigned char*()
{
	return(m_buffer);
}

int CBuffer::GetSize()
{
	return(m_usingSize);
}

void CBuffer::operator =(CString &other)
{
	ReSize(other.GetLength());
	memmove(m_buffer,other.GetBuffer(0),m_usingSize);
}

void CBuffer::operator =(CBuffer &other)
{
	ReSize(other.GetSize());
	memmove(m_buffer,other.GetPtr(),m_usingSize);
}

void CBuffer::operator +=(CString &other)
{
	Append(other.GetBuffer(0),other.GetLength());
}

void CBuffer::operator +=(CBuffer &other)
{
	Append(other.GetPtr(),other.GetSize());
}

void CBuffer::operator +=(const char *other)
{
	int	len = (int)strlen(other);
	Append(other,len);
}

void CBuffer::operator +=(char other)
{
	Append(&other,1);
}


//////////////////////////////////////////////////////////////////////
// データコピー
//////////////////////////////////////////////////////////////////////
/*!
	offset から len バイト、data からコピー（上書き）します。

	\param offset	コピー開始地点
	\param data		データ
	\param len		データ長さ
*/
void CBuffer::BlockCopy(int offset, const char *data, int len)
{
	if(offset + len >= m_usingSize)
		ReSize(offset + len);
	memmove(m_buffer + offset,data,len);
}

//////////////////////////////////////////////////////////////////////
// 設定
//////////////////////////////////////////////////////////////////////
/*!
	\param size		増加サイズ
*/
void CBuffer::SetGrowSize(int size)
{
	m_growSize = size;
}


//////////////////////////////////////////////////////////////////////
// UTF8
//////////////////////////////////////////////////////////////////////
/*!
	BSTR文字列をUFT8に変換して設定
	\param bstr		文字列
*/

void CBuffer::SetUTF8(_bstr_t bstr)
{
	//	UTF8へ変換
	int mbLen = WideCharToMultiByte(CP_UTF8,0,bstr.GetBSTR(),bstr.length(),NULL,0,NULL,NULL);

	ReSize(mbLen);
	WideCharToMultiByte(CP_UTF8,0,bstr.GetBSTR(),bstr.length(),GetPtr(),GetSize(),NULL,NULL);
}


/*!
	BSTR文字列に変換
	\return		文字列
*/
_bstr_t CBuffer::GetBSTR()
{
	int mbLen = MultiByteToWideChar(CP_UTF8,0,GetPtr(),GetSize(),NULL,0);

	wchar_t	*wstr = new wchar_t[mbLen + 1];
	MultiByteToWideChar(CP_UTF8,0,GetPtr(),GetSize(),wstr,mbLen);
	wstr[mbLen] = 0;

	_bstr_t	ret(wstr);
	delete wstr;

	return(ret);
}

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

	\param path		パス
*/
int CBuffer::SaveToFile(CString path)
{
	FILE	*out;
	if(fopen_s(&out ,path,"wb") != 0)
		return(-1);

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

int CBuffer::LoadFromFile(CString path)
{
	FILE	*out;
	if(fopen_s(&out ,path,"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);
}

