============================================================================================
	アーカイバツールの使い方　by　sogabe　2006.08.28
============================================================================================
○概要
　DSのファイルシステムに大量のファイルをリンクしてしまうと、
　ファイルテーブルを展開するだけで、メインメモリを圧迫してしまうため、
　複数のファイルを１つにまとめる必要があります
　NitroSystemにアーカイバライブラリがありますが、これは、１つにまとめて管理する方に重点がおかれ、
　メインメモリを圧迫することの回避につながりません
（データ取り出し時にメインメモリにアーカイブファイルを展開しなければならないため）
　そこで、書庫ファイルを生成するツールはNitroSystemのものを使用して、
　データ取り出し時にメインメモリを消費しないで済むライブラリ関数を作成することにしました

○具体的な流れ
１：書庫ファイルの生成
　NitroSystemのツール「nnsarc.exe」を使用して生成します（\NitroSystem\tools\win\binの中にあります）
　詳しい使用方法は、\NitroSystem\docs\Foundation\Archiver.pdfを参照すればわかりますが、
　僕が作成するときの記述は、

　nnsarc -c -l -n アーカイバファイル名　アーカイブするファイル名（ワイルドカード使用可）
　または、
　nnsarc -c -l -n -i アーカイバファイル名　アーカイブするファイル名（ワイルドカード使用可）

　になります
　-iオプションをつけることで、インデックスファイルを吐き出すことが出来ます（使用例は後述）

２：作成したアーカイブファイルをソースに登録
　\include\systemフォルダにarc_tool.datというファイルがあるので、そこに作成したアーカイブファイルを登録してください

・arc_tool.datの中身(2005.08.24現在の中身です）
//============================================================================================
/**
 *	file_kindに指定するdefine定義
 */
//============================================================================================

enum{
	ARC_WAZA_SEQ=0,		//技シーケンス
	ARC_SUB_SEQ,		//サーバシーケンス
	ARC_PERSONAL,		//ポケモンパーソナルデータ
	ARC_GROW_TBL,		//ポケモン成長テーブル
	ARC_POKE_GRA,		//ポケモングラフィック
	ARC_POKE_HEIGHT,	//ポケモン高さ情報
	ARC_TR_GRA,		//ポケモングラフィック
	ARC_BATT_GRA,		//戦闘背景グラフィック
	ARC_WAZA_EFF,		//技エフェクト
	ARC_WAZA_TBL,		//技テーブル
	ARC_SCRIPT,		//マップスクリプト
	ARC_SCRIPT_MSG,		//マップメッセージ
};

//============================================================================================
/**
 * アーカイブファイルのテーブル定義
 */
//============================================================================================
static const char	ArchiveFileTable[][80]={
	{"battle/skill/waza_seq.narc"},			//技シーケンス
	{"battle/skill/sub_seq.narc"},			//サーバシーケンス
	{"poketool/personal/personal.narc"},		//ポケモンパーソナルデータ
	{"poketool/personal/growtbl.narc"},		//ポケモン成長テーブル
	{"poketool/pokegra/pokegra.narc"},		//ポケモングラフィック
	{"poketool/pokegra/height.narc"},		//ポケモン高さ情報
	{"poketool/pokegra/trgra.narc"},		//トレーナーグラフィック
	{"battle/graphic/batt_gra.narc"},		//戦闘背景グラフィック
	{"wazaeffect/we.arc"},				//技エフェクト
	{"poketool/waza/waza_tbl.narc"},		//技テーブルデータ
	{"fielddata/script/scr_seq.narc"},		//マップスクリプトデータ
	{"msgdata/scenario/scr_msg.narc"},		//マップスクリプトメッセージデータ
};

　ArchiveFileTableに作成したアーカイブファイルを登録して、enumにはインデックスを定義します

３：データの読み出し方
　\system\arc_tool.hをインクルードしてください
　以下の関数が使用できます

//============================================================================================
/**
 * アーカイブファイルデータロード
 *
 * @param[in]	data		読み込んだデータを格納するワークのポインタ
 * @param[in]	file_kind	読み込むアーカイブファイルの種類インデックスナンバー（\include\system\arc_tool.datに記述）
 * @param[in]	index		読み込むデータのアーカイブファイル上のインデックスナンバー
 */
//============================================================================================
void	ArchiveDataLoad(void *data,int file_kind,int index);

//============================================================================================
/**
 * アーカイブファイルデータロード（読み込んだデータを格納するワークを関数内で確保するバージョン）
 *
 * ※関数内でワークをAllocするので、自前で開放処理をする必要があります(sys_FreeMemory(APP_W_HEAP_AREA,領域ポインタ)で開放）
 *
 * @param[in]	file_kind	読み込むアーカイブファイルの種類インデックスナンバー（\include\system\arc_tool.datに記述）
 * @param[in]	index		読み込むデータのアーカイブファイル上のインデックスナンバー
 *
 * @retval	関数内で確保したデータ格納ワークのアドレス
 */
//============================================================================================
void	*ArchiveDataLoadMalloc(int file_kind,int index);

//============================================================================================
/**
 * アーカイブファイルデータのサイズを取得
 *
 *	ArchiveDataLoadを使用する時、確保するメモリサイズを取得するのに使用します
 *
 * @param[in]	file_kind	読み込むアーカイブファイルの種類インデックスナンバー（\include\system\arc_tool.datに記述）
 * @param[in]	index		読み込むデータのアーカイブファイル上のインデックスナンバー
 */
//============================================================================================
u32		ArchiveDataSizeGet(int file_kind,int index);

　例えば、技ナンバー1番のシーケンスデータを取り出したい場合は、

　ArchiveDataLoad(SeqData,ARC_WAZA_SEQ,1);

　とすれば、SeqDataにシーケンスデータを取り出すことが出来ます


４：書庫ファイルをROMデータに登録する
　Makefileを開いて、MAKEROM_ROMFILES変数に*.narcファイルを登録してROMデータにリンクされるようにします

※MAKEROM_ROMFILES変数の中身（05.08.25現在）
MAKEROM_ROMFILES = $(subst src/,,$(DATABIN)*.* $(SOUNDDIR)sound_data.sdat $(DATAMSG)*.* $(DATASCENARIO)*.narc $(POKEGRADIR)*.narc $(PERSONALDIR)*.narc $(EFFECTDATADIR)*.spa $(BATTLEGRADIR)*.narc $(WAZAEFFDIR)we.arc $(WAZASEQDIR)*.narc $(CATDATADIR)*.* $(WAZATBLDIR)*.narc $(SCRIPTDIR)*.narc)

参考までに各DIR変数の定義は、以下のようになります
POKEGRADIR	= src/poketool/pokegra/
PERSONALDIR	= src/poketool/personal/
EFFECTDATADIR	= src/wazaeffect/effectdata/
BATTLEGRADIR	= src/battle/graphic/
WAZAEFFDIR	= src/wazaeffect/
WAZASEQDIR	= src/battle/skill/
CATDATADIR	= src/wazaeffect/catdata/
WAZATBLDIR	= src/poketool/waza/
SCRIPTDIR	= src/fielddata/script/

○具体的な使用例

ex)オープニングで使用するBGデータをまとめて使用できるようにしたい

=================================================================================================
☆手順１の実行
・使用するグラフィックファイルをまとめます
　\src\opening\graphicフォルダ内にある
　opening_bg1.ncgr
　opening_bg2.ncgr
　opening_bg3.ncgr
　opening_bg1.nscr
　opening_bg2.nscr
　opening_bg3.nscr
　opening_bg.nclr

　これらを、
　nnsarc -c -l -n -i opening.narc opening*.n*r
　として、アーカイブファイルを生成すると

fileID:  byte(s) name
----------------------------------------
     0:      512 /opening_bg.nclr
     1:     8192 /opening_bg1.ncgr
     2:     2048 /opening_bg1.nscr
     3:     8192 /opening_bg2.ncgr
     4:     2048 /opening_bg2.nscr
     5:     8192 /opening_bg3.ncgr
     6:     2048 /opening_bg3.nscr

　上記の順で連結されたopening.narcが生成されます
　また、-iオプションを使用しているので、opening.naixファイルが生成されています
　これは、fileIDをenum定義したファイルになります
　
※opening.naixの中身
/*****************************************************************************
	Archive file index definition.
	File: opening.naix

	This file was created by NINTENDO NITRO-System Archiver.

	Update:2005-08-24T16:06:29
 *****************************************************************************/

#ifndef NARC_OPENING_NAIX_
#define NARC_OPENING_NAIX_

enum {
	NARC_opening_opening_bg_nclr = 0,
	NARC_opening_opening_bg1_ncgr = 1,
	NARC_opening_opening_bg1_nscr = 2,
	NARC_opening_opening_bg2_ncgr = 3,
	NARC_opening_opening_bg2_nscr = 4,
	NARC_opening_opening_bg3_ncgr = 5,
	NARC_opening_opening_bg3_nscr = 6
};

/* NARC_OPENING_NAIX_ */
#endif

※任意のファイルを指定する方法
　上記のようなワイルドカードを使用した方法だと、フォルダ内に当てはまるファイルをすべて対象としてしまうため、
　プロジェクトが進む中で不要になったファイルも圧縮してしまいます
　そこでフォルダ内の任意のファイルを指定して圧縮する方法について記述します（森君感謝！）

　nnsarc -c -i -n アーカイブファイルネーム　-S リストファイル

　「-S」のＳは大文字です。
　リストファイルは１つのパスにつき「"」でくくられている必要があります。

　リストファイルの内容は

------------------
"opening_bg1.ncgr"
"opening_bg2.ncgr"
"opening_bg3.ncgr"
"opening_bg1.nscr"
"opening_bg2.nscr"
"opening_bg3.nscr"
"opening_bg.nclr"
-------------------

　このようにすれば、上記のワイルドカード使用の記述と同意になり、
　例えばBG3のファイルが使用されなくなった場合は、上記のリストから削除して、

------------------
"opening_bg1.ncgr"
"opening_bg2.ncgr"
"opening_bg1.nscr"
"opening_bg2.nscr"
"opening_bg.nclr"
-------------------

　このようにすればよいことになります
　また、サブディレクトリのファイルを指定することも出来るので、

------------------
"Character/opening_bg1.ncgr"
"Character/opening_bg2.ncgr"
"Screen/opening_bg1.nscr"
"Screen/opening_bg2.nscr"
"Palette/opening_bg.nclr"
-------------------

　ということも可能です

=================================================================================================
☆手順２の実行
・生成したアーカイバファイルの登録
　arc_tool.datを開き、定義を追加します

//============================================================================================
/**
 *	file_kindに指定するdefine定義
 */
//============================================================================================

enum{
	ARC_WAZA_SEQ=0,		//技シーケンス
	ARC_SUB_SEQ,		//サーバシーケンス
	ARC_PERSONAL,		//ポケモンパーソナルデータ
	ARC_GROW_TBL,		//ポケモン成長テーブル
	ARC_POKE_GRA,		//ポケモングラフィック
	ARC_POKE_HEIGHT,	//ポケモン高さ情報
	ARC_TR_GRA,		//ポケモングラフィック
	ARC_BATT_GRA,		//戦闘背景グラフィック
	ARC_WAZA_EFF,		//技エフェクト
	ARC_WAZA_TBL,		//技テーブル
	ARC_SCRIPT,		//マップスクリプト
	ARC_SCRIPT_MSG,		//マップメッセージ
	ARC_OPENING_GRA,	//オープニンググラフィック
};

//============================================================================================
/**
 * アーカイブファイルのテーブル定義
 */
//============================================================================================
static const char	ArchiveFileTable[][80]={
	{"battle/skill/waza_seq.narc"},			//技シーケンス
	{"battle/skill/sub_seq.narc"},			//サーバシーケンス
	{"poketool/personal/personal.narc"},		//ポケモンパーソナルデータ
	{"poketool/personal/growtbl.narc"},		//ポケモン成長テーブル
	{"poketool/pokegra/pokegra.narc"},		//ポケモングラフィック
	{"poketool/pokegra/height.narc"},		//ポケモン高さ情報
	{"poketool/pokegra/trgra.narc"},		//トレーナーグラフィック
	{"battle/graphic/batt_gra.narc"},		//戦闘背景グラフィック
	{"wazaeffect/we.arc"},				//技エフェクト
	{"poketool/waza/waza_tbl.narc"},		//技テーブルデータ
	{"fielddata/script/scr_seq.narc"},		//マップスクリプトデータ
	{"msgdata/scenario/scr_msg.narc"},		//マップスクリプトメッセージデータ
	{"opening/graphic/opening.narc"},		//オープニンググラフィック
};

=================================================================================================
☆手順３の実行
・データの読み込み
　arc_tool.hとopening.naixをインクルードして

　	{
		void	*mem;
		NNSG2dCharacterData * chr;
		NNSG2dScreenData * scr;
		NNSG2dPaletteData * pal;

		//BG1の読み込み
		mem=ArchiveDataLoadMalloc(ARC_OPENING_GRA,NARC_opening_opening_bg1_ncgr);
		if(NNS_G2dGetUnpackedBGCharacterData(mem,&chr)==TRUE){
			GF_BGL_LoadCharacter(bgl,GF_BGL_FRAME1_M,chr->pRawData,chr->szByte,0);
		}
		sys_FreeMemory(APP_W_HEAP_AREA,mem);
		mem=ArchiveDataLoadMalloc(ARC_OPENING_GRA,NARC_opening_opening_bg1_nscr);
		if(NNS_G2dGetUnpackedScreenData(mem,&scr)==TRUE){
			GF_BGL_ScreenBufSet(bgl,GF_BGL_FRAME1_M,scr->rawData,scr->szByte);
			GF_BGL_LoadScreen(bgl,GF_BGL_FRAME1_M,scr->rawData,scr->szByte,0);
		}
		sys_FreeMemory(APP_W_HEAP_AREA,mem);

		//BG2の読み込み
		mem=ArchiveDataLoadMalloc(ARC_OPENING_GRA,NARC_opening_opening_bg2_ncgr);
		if(NNS_G2dGetUnpackedBGCharacterData(mem,&chr)==TRUE){
			GF_BGL_LoadCharacter(bgl,GF_BGL_FRAME2_M,chr->pRawData,chr->szByte,0);
		}
		sys_FreeMemory(APP_W_HEAP_AREA,mem);
		mem=ArchiveDataLoadMalloc(ARC_OPENING_GRA,NARC_opening_opening_bg2_nscr);
		if(NNS_G2dGetUnpackedScreenData(mem,&scr)==TRUE){
			GF_BGL_ScreenBufSet(bgl,GF_BGL_FRAME2_M,scr->rawData,scr->szByte);
			GF_BGL_LoadScreen(bgl,GF_BGL_FRAME2_M,scr->rawData,scr->szByte,0);
		}
		sys_FreeMemory(APP_W_HEAP_AREA,mem);

		//BG3の読み込み
		mem=ArchiveDataLoadMalloc(ARC_OPENING_GRA,NARC_opening_opening_bg3_ncgr);
		if(NNS_G2dGetUnpackedBGCharacterData(mem,&chr)==TRUE){
			GF_BGL_LoadCharacter(bgl,GF_BGL_FRAME3_M,chr->pRawData,chr->szByte,0);
		}
		sys_FreeMemory(APP_W_HEAP_AREA,mem);
		mem=ArchiveDataLoadMalloc(ARC_OPENING_GRA,NARC_opening_opening_bg3_nscr);
		if(NNS_G2dGetUnpackedScreenData(mem,&scr)==TRUE){
			GF_BGL_ScreenBufSet(bgl,GF_BGL_FRAME3_M,scr->rawData,scr->szByte);
			GF_BGL_LoadScreen(bgl,GF_BGL_FRAME3_M,scr->rawData,scr->szByte,0);
		}
		sys_FreeMemory(APP_W_HEAP_AREA,mem);

		//パレットの読み込み
		mem=ArchiveDataLoadMalloc(ARC_OPENING_GRA,NARC_opening_opening_bg_nclr);
		NNS_G2dGetUnpackedPaletteData(mem,&pal);
		DC_FlushRange( (void *)pal->pRawData, pal->szByte );
		GX_LoadBGPltt( (const void *)pal->pRawData, 0, pal->szByte );
		sys_FreeMemory(APP_W_HEAP_AREA,mem);
	}

　こんな感じで、読み込みます

=================================================================================================
☆手順４の実行
・Makefileへの登録

MAKEROM_ROMFILES = $(subst src/,,$(DATABIN)*.* $(SOUNDDIR)sound_data.sdat $(DATAMSG)*.* $(DATASCENARIO)*.narc $(POKEGRADIR)*.narc $(PERSONALDIR)*.narc $(EFFECTDATADIR)*.spa $(BATTLEGRADIR)*.narc $(WAZAEFFDIR)we.arc $(WAZASEQDIR)*.narc $(CATDATADIR)*.* $(WAZATBLDIR)*.narc $(SCRIPTDIR)*.narc $(OPENINGDIR)*.narc) 

OPENINGDIR		= src/opening/graphic/

=================================================================================================
☆ファイルハンドルの利用
　通常のアーカイブファイルからの読み込み関数を使用すると、

　ファイルポインタ構造体の初期化
　ファイルオープン
　ファイルヘッダ位置へのシーク
　ファイルヘッダサイズの読み込み
　FAT位置へのシーク
　FATサイズの読み込み
　FileCountの読み込み
　FNT位置へのシーク
　FNTサイズの読み込み
　取り出したいFATテーブルに移動
　FATテーブルTopの読み込み
　FATテーブルBottomの読み込み
　取り出したいIMGに移動
　取り出したいデータの読み込み
　ファイルクローズ

　のようにファイルオープンからデータの読み込み、ファイルクローズまでが、
　いくつかのデータのシークや読み込みを経て、行われています
　これらは、すべてROMアクセスのため負荷がかかり、
　連続で大量のデータを読み込む場合にロックがかかってしまいます
　そこで、同一アーカイバからデータを連続で読み込む場合に、
　ファイルハンドルを作成して、上記の動作の

　取り出したいIMGに移動
　取り出したいデータの読み込み

　のみを行うような関数群を用意して高速化をはかりました（田谷君感謝！）
　以下がその関数群です

//------------------------------------------------------------------
/**
 * アーカイブデータのファイルハンドルオープン
 *
 * @param   arcId		アーカイブデータインデックス
 * @param   heapId		管理用ヒープＩＤ
 *
 * @retval  ARCHANDLE	オープンされたハンドルのポインタ（失敗ならNULL）
 */
//------------------------------------------------------------------
ARCHANDLE* ArchiveDataHandleOpen( u32 arcId, u32 heapId );

//------------------------------------------------------------------
/**
 * アーカイブデータのハンドルクローズ
 *
 * @param   handle			ハンドルポインタ
 *
 */
//------------------------------------------------------------------
void ArchiveDataHandleClose( ARCHANDLE* handle );

//------------------------------------------------------------------
/**
 * アーカイブデータハンドルを使ってデータ取得（内部でアロケートしたメモリに）
 *
 * @param   handle			ハンドルポインタ
 * @param   datID			アーカイブ内のデータインデックス
 * @param   heapID			メモリアロケート用のヒープＩＤ
 *
 * @retval  u32				データサイズ（バイト）
 */
//------------------------------------------------------------------
void* ArchiveDataLoadAllocByHandle( ARCHANDLE* handle, u32 datId, u32 heapID );

//------------------------------------------------------------------
/**
 * アーカイブデータハンドルを使ってデータ取得
 *
 * @param   handle		ハンドルポインタ
 * @param   datId		アーカイブ内のデータインデックス
 * @param   buffer		データ読み込み先バッファ
 *
 */
//------------------------------------------------------------------
void ArchiveDataLoadByHandle( ARCHANDLE* handle, u32 datId, void* buffer );

//------------------------------------------------------------------
/**
 * アーカイブデータハンドルを使ってデータサイズ取得
 *
 * @param   handle		ハンドルポインタ
 * @param   datId		アーカイブ内のデータインデックス
 * @retval	u32			インデックスのデータサイズ
 *
 */
//------------------------------------------------------------------
u32 ArchiveDataSizeGetByHandle( ARCHANDLE* handle, u32 datId );

//------------------------------------------------------------------
/**
 * アーカイブデータハンドルを使ってデータ取得（読み込み開始オフセット＆サイズ指定）
 *
 * @param   handle		ハンドルポインタ
 * @param   datId		アーカイブ内のデータインデックス
 * @param   ofs			読み込み開始オフセット
 * @param   size		読み込みサイズ
 * @param   buffer		データ読み込み先バッファ
 *
 */
//------------------------------------------------------------------
void ArchiveDataLoadOfsByHandle( ARCHANDLE* handle, u32 datId, u32 ofs, u32 size, void* buffer );

//------------------------------------------------------------------
/**
 * アーカイブデータハンドルを使ってイメージデータオフセット取得
 *
 * @param   handle		ハンドルポインタ
 * @param   datId		アーカイブ内のデータインデックス
 * @param   offset		オフセット読み込み先バッファ
 *
 */
//------------------------------------------------------------------
void ArchiveDataLoadImgofsByHandle( ARCHANDLE* handle, u32 datId, u32* offset );

//------------------------------------------------------------------
/**
 * アーカイブデータハンドルを使ってデータ取得（ファイルハンドル内情報の続きから読み込み）
 *
 * @param   handle		ハンドルポインタ
 * @param   size		読み込みサイズ
 * @param   buffer		データ読み込み先バッファ
 *
 */
//------------------------------------------------------------------
void ArchiveDataLoadByHandleContinue( ARCHANDLE* handle, u32 size, void* buffer );

//------------------------------------------------------------------
/**
 * アーカイブデータハンドルを介してファイルシーク
 *
 * @param   handle		ハンドルポインタ
 * @param   size		ファイルの先頭から移動するサイズ
 *
 */
//------------------------------------------------------------------
void ArchiveDataSeekByHandle( ARCHANDLE* handle, u32 size );

//============================================================================================
/**
 * アーカイブファイルデータのファイル数を取得(ハンドル使用)
 *
 * @param	handle			ハンドルポインタ
 * @retval	u16				ファイル数	
 */
//============================================================================================
u16		ArchiveDataFileCntGetByHandle(ARCHANDLE* handle);

