File:  [RetroPC.NET] / xmil / nds / tools / StoreRom.cpp
Revision 1.1: download - view: text, annotated - select for diffs
Thu Mar 26 06:36:12 2009 JST (16 years, 7 months ago) by yui
Branches: MAIN
CVS tags: HEAD
added nds core

#include <windows.h>
#include <tchar.h>
#include <stdio.h>


typedef unsigned char		UINT8;
typedef unsigned int		UINT32;

struct tagRomImg
{
	UINT8	bios1[0x1000];
	UINT8	bios2[0x8000];
	UINT8	ank[0x0800];
	UINT8	txt[0x1000];
	UINT8	knjx1[0x20000];
	UINT8	knjx1t[0x40000];

	UINT32 uDisk1Size;
	UINT32 uDisk2Size;
	UINT8 sDisk1[512*1024];
	UINT8 sDisk2[512*1024];
};

static const unsigned char s_cExtRom[] = {'R','O','M','A','R','E','A'};


static void lstrcatn(LPTSTR lpszDst, LPCTSTR lpcszSrc, int nCount)
{
	const int nPos = ::lstrlen(lpszDst);
	::lstrcpyn(lpszDst + nPos, lpcszSrc, nCount - nPos);
}

static unsigned char *readFile(LPCTSTR lpcszPath, UINT *puSize)
{
	unsigned char *pBuffer = 0;
	DWORD dwReadSize = 0;

	HANDLE hFile = INVALID_HANDLE_VALUE;
	if (lpcszPath)
	{
		hFile = CreateFile(lpcszPath, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
	}
	if (hFile != INVALID_HANDLE_VALUE)
	{
		const DWORD dwSize = GetFileSize(hFile, NULL);
		if (dwSize)
		{
			pBuffer = new unsigned char [dwSize];
		}
		if (pBuffer)
		{
			if (!ReadFile(hFile, pBuffer, dwSize, &dwReadSize, NULL))
			{
				delete[] pBuffer;
				pBuffer = 0;
			}
		}
		CloseHandle(hFile);
	}
	if (puSize)
	{
		*puSize = dwReadSize;
	}
	return pBuffer;
}

static bool writeFile(LPCTSTR lpcszPath, const unsigned char *pcBuffer, UINT uSize)
{
	bool bResult = false;

	HANDLE hFile = INVALID_HANDLE_VALUE;
	if (lpcszPath)
	{
		hFile = CreateFile(lpcszPath, GENERIC_WRITE, 0, 0, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
	}
	if (hFile != INVALID_HANDLE_VALUE)
	{
		DWORD dwWrittenSize = 0;
		bResult = (WriteFile(hFile, pcBuffer, uSize, &dwWrittenSize, NULL)) && (dwWrittenSize == uSize);
		CloseHandle(hFile);
	}
	return bResult;
}

static UINT loadFile(LPCTSTR lpcszDir, LPCTSTR lpcszFile, LPVOID lpvBuffer, UINT uSize)
{
	TCHAR szPath[MAX_PATH];
	if (lpcszDir)
	{
		lstrcpyn(szPath, lpcszDir, MAX_PATH);
		lstrcatn(szPath, _T("\\"), MAX_PATH);
		lstrcatn(szPath, lpcszFile, MAX_PATH);
	}
	else
	{
		lstrcpyn(szPath, lpcszFile, MAX_PATH);
	}

	DWORD dwReadSize = 0;
	HANDLE hFile = CreateFile(szPath, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
	if (hFile != INVALID_HANDLE_VALUE)
	{
		ReadFile(hFile, lpvBuffer, uSize, &dwReadSize, NULL);
		CloseHandle(hFile);
	}
	else
	{
		_tprintf(_T("warning: not found %s\n"), lpcszDir);
	}
	return dwReadSize;
}

static int searchBinary(const unsigned char *pcBuffer, int nBufferSize, const unsigned char *pcKey, int nKeySize)
{
	if ((!pcBuffer) || (!pcKey) || (!nKeySize))
	{
		return -1;
	}

	const int nSearchLength = nBufferSize - nKeySize;
	for (int i=0; i<=nSearchLength; i++)
	{
		if (!memcmp(pcBuffer + i, pcKey, nKeySize))
		{
			return i;
		}
	}

	return -1;
}


// ----

#define	FONTX1_LR	0x10000
#define	FONTX1T_LR	0x20000

static const UINT8 s_jis2x1t[64] =
{
		0xff, 0xff, 0xff, 0xff,		/* 0x00 */
		0xff, 0xff, 0xff, 0xff,		/* 0x08 */
		0xff, 0xff, 0xff, 0xff,		/* 0x10 */
		0xff, 0xff, 0xff, 0xff,		/* 0x18 */
		0xff, 0x00, 0x02, 0x01,		/* 0x20 */
		0xff, 0xff, 0xff, 0xff,		/* 0x28 */
		0xff, 0x04, 0x06, 0x08,		/* 0x30 */
		0xff, 0x05, 0x07, 0x09,		/* 0x38 */

		0xff, 0x0a, 0x0c, 0x0e,		/* 0x40 */
		0xff, 0x0b, 0x0d, 0x0f,		/* 0x48 */
		0xff, 0x10, 0x12, 0x14,		/* 0x50 */
		0xff, 0x11, 0x13, 0x15,		/* 0x58 */
		0xff, 0x16, 0x18, 0x1a,		/* 0x60 */
		0xff, 0x17, 0x19, 0x1b,		/* 0x68 */
		0xff, 0x1c, 0x1e, 0x1d,		/* 0x70 */
		0xff, 0xff, 0xff, 0xff,		/* 0x78 */
};

__declspec(naked) static UINT __fastcall jis2sjis(UINT uJis)
{
	__asm
	{
				mov		eax, ecx
				and		eax, 7f7fh
				add		ah, 21h
				shr		ah, 1
				jnc		short jis2sjis1a
				add		al, 5eh
jis2sjis1a:		cmp		al, 60h
				sbb		al, 0e0h
				xor		ah, 0a0h
				ret
	}
}

static UINT8 *getFontAddrTurbo(tagRomImg *pImg, UINT uJis)
{
	const UINT uAddr = s_jis2x1t[((uJis >> 9) & 0x3c) + ((uJis >> 5) & 3)];
	if (uAddr & 0xc0)
	{
		return 0;
	}
	UINT8 *pRet = pImg->knjx1t;
	pRet += (uAddr << 12);
	pRet += ((uJis & 0x700) << 1);
	pRet += ((uJis & 0x01f) << 4);
	return pRet;
}

static void storeKnjTurbo(tagRomImg *pImg, const UINT8 *pcSrc, UINT uFrom, UINT uTo)
{
	for (UINT i=uFrom; i<uTo; i++)
	{
		const UINT h = i << 8;
		for (UINT l=0x21; l<0x7f; l++)
		{
			/* 漢字のポインタを求める */
			const UINT8 *p = 0;
			const UINT uSjis = jis2sjis(h + l);
			if ((uSjis >= 0x8140) && (uSjis < 0x84c0))
			{
				p = pcSrc + 0x00000 + ((uSjis - 0x8140) << 5);
			}
			else if ((uSjis >= 0x8890) && (uSjis < 0xa000))
			{
				p = pcSrc + 0x07000 + ((uSjis - 0x8890) << 5);
			}
			else if ((uSjis >= 0xe040) && (uSjis < 0xeab0))
			{
				p = pcSrc + 0x35e00 + ((uSjis - 0xe040) << 5);
			}
			if (p)								/* 規格内コードならば */
			{
				UINT8 *q = getFontAddrTurbo(pImg, h + l);
				/* コピーする */
				if (q)
				{
					for (UINT j=0; j<16; j++)
					{
						q[0] = p[0];
						q[FONTX1T_LR] = p[1];
						p += 2;
						q += 1;
					}
				}
			}
		}
	}
}

static void setMirrorTurbo(tagRomImg *pImg)
{
	CopyMemory(pImg->knjx1t + 0x03000, pImg->knjx1t + 0x02000, 0x1000);
	CopyMemory(pImg->knjx1t + 0x23000, pImg->knjx1t + 0x22000, 0x1000);
	CopyMemory(pImg->knjx1t + 0x1f000, pImg->knjx1t + 0x1e000, 0x1000);
	CopyMemory(pImg->knjx1t + 0x3f000, pImg->knjx1t + 0x3e000, 0x1000);
}

static void convertTurbo2Normal(tagRomImg *pImg)
{
	UINT8 *pDst = pImg->knjx1 + 0x0100;
	UINT i;
	for (i=0x2100; i<0x2800; i+=0x100)
	{
		for (UINT j=0x20; j<0x80; j+=0x20)
		{
			const UINT8 *pcSrc = getFontAddrTurbo(pImg, i + j);
			if (pcSrc)
			{
				CopyMemory(pDst, pcSrc, 0x200);
				CopyMemory(pDst + FONTX1_LR, pcSrc + FONTX1T_LR, 0x200);
			}
			pDst += 0x200;
		}
	}

	pDst = pImg->knjx1 + 0x4000;
	for (i=0x3000; i<0x5000; i+=0x100)
	{
		for (UINT j=0x20; j<0x80; j+=0x20)
		{
			const UINT8 *pcSrc = getFontAddrTurbo(pImg, i + j);
			if (pcSrc)
			{
				CopyMemory(pDst, pcSrc, 0x200);
				CopyMemory(pDst + FONTX1_LR, pcSrc + FONTX1T_LR, 0x200);
			}
			pDst += 0x200;
		}
	}
}

static void loadFont(tagRomImg *pImg, LPCTSTR lpcszDir, LPCTSTR lpcszFile)
{
	UINT8 sFont[306176];
	ZeroMemory(sFont, sizeof(sFont));
	loadFile(lpcszDir, lpcszFile, sFont, sizeof(sFont));

	storeKnjTurbo(pImg, sFont, 0x21, 0x50);
	storeKnjTurbo(pImg, sFont, 0x50, 0x78);
}


// ----

static bool storeRom(LPCTSTR lpcszSrc, LPCTSTR lpcszDst, LPCTSTR lpcszRomDir, LPCTSTR lpcszDisk1, LPCTSTR lpcszDisk2)
{
	unsigned char *pBuffer = 0;
	bool bRet = false;

	do
	{
		if (!lpcszDst)
		{
			lpcszDst = lpcszSrc;
		}

		UINT uSize = 0;
		pBuffer = readFile(lpcszSrc, &uSize);
		if (!pBuffer)
		{
			_tprintf(_T("error: couldn't open [%s]\n"), lpcszSrc);
			break;
		}

		// ストア位置をチェックする
		const int nPos = searchBinary(pBuffer, uSize, s_cExtRom, sizeof(s_cExtRom));
		if (nPos < 0)
		{
			_tprintf(_T("error: not found Rom Area\n"));
			break;
		}
		if ((static_cast<UINT>(nPos) + sizeof(tagRomImg)) > uSize)
		{
			_tprintf(_T("error: not found Rom Area (no left space)\n"));
			break;
		}


		// イメージを読む
		tagRomImg *pImg = reinterpret_cast<tagRomImg *>(pBuffer + nPos);
		loadFile(lpcszRomDir, _T("IPLROM.X1"), pImg->bios1, sizeof(pImg->bios1));
		loadFile(lpcszRomDir, _T("IPLROM.X1T"), pImg->bios2, sizeof(pImg->bios2));
		loadFile(lpcszRomDir, _T("FNT0808.X1"), pImg->ank, sizeof(pImg->ank));
		loadFile(lpcszRomDir, _T("FNT0816.X1"), pImg->txt, sizeof(pImg->txt));
		loadFont(pImg, lpcszRomDir, _T("FNT1616.X1"));

		setMirrorTurbo(pImg);
		convertTurbo2Normal(pImg);

		if (!lpcszDisk1)
		{
			lpcszDisk1 = _T("DISK1.D88");
		}
		if (!lpcszDisk2)
		{
			lpcszDisk2 = _T("DISK2.D88");
		}

		pImg->uDisk1Size = loadFile(lpcszRomDir, lpcszDisk1, pImg->sDisk1, sizeof(pImg->sDisk1));
		pImg->uDisk2Size = loadFile(lpcszRomDir, lpcszDisk2, pImg->sDisk2, sizeof(pImg->sDisk2));

		// 保存する
		bRet = writeFile(lpcszDst, pBuffer, uSize);
	} while(0 /*CONSTCOND*/);

	if (pBuffer)
	{
		delete[] pBuffer;
	}
	return bRet;
}



// ----

int _tmain(int argc, TCHAR **argv)
{
	if (argc < 2)
	{
		_tprintf(_T("usage: StoreRom [ELF-binary] -D [Rom-Dir]\n"));
		return 0;
	}

	LPCTSTR lpcszSrc = 0;
	LPCTSTR lpcszDst = 0;
	LPCTSTR lpcszDir = 0;
	LPCTSTR lpcszDisk1 = 0;
	LPCTSTR lpcszDisk2 = 0;
	LPCTSTR *lppcszStore = 0;

	for (int i=1; i<argc; i++)
	{
		LPCTSTR lpcsz = argv[i];
		if (lppcszStore)
		{
			*lppcszStore = lpcsz;
			lppcszStore = 0;
		}
		else if ((lpcsz[0] == '/') || (lpcsz[0] == '-'))
		{
			TCHAR cOpt = lpcsz[1];
			if ((cOpt >= 'A') && (cOpt <= 'Z'))
			{
				cOpt += 0x20;
			}
			switch(cOpt)
			{
				case 'd':
					lppcszStore = &lpcszDir;
					break;

				case '1':
					lppcszStore = &lpcszDisk1;
					break;

				case '2':
					lppcszStore = &lpcszDisk2;
					break;
			}
		}
		else if (!lpcszSrc)
		{
			lpcszSrc = lpcsz;
		}
		else if (!lpcszDst)
		{
			lpcszDst = lpcsz;
		}
	}

	storeRom(lpcszSrc, lpcszDst, lpcszDir, lpcszDisk1, lpcszDisk2);

	return 0;
}


RetroPC.NET-CVS <cvs@retropc.net>