From ffb5d834a53259c6e028f50790572e948b26bce3 Mon Sep 17 00:00:00 2001 From: nishikawa_takeshi Date: Tue, 6 Jan 2009 11:40:02 +0000 Subject: [PATCH] =?UTF-8?q?=E3=83=9E=E3=82=B9=E3=82=BF=E3=82=A8=E3=83=87?= =?UTF-8?q?=E3=82=A3=E3=82=BF=EF=BC=9A=20=E3=83=BBShared2=E3=83=95?= =?UTF-8?q?=E3=82=A1=E3=82=A4=E3=83=AB=E3=81=A8=E3=83=8E=E3=83=BC=E3=83=9E?= =?UTF-8?q?=E3=83=AB=E3=82=B8=E3=83=A3=E3=83=B3=E3=83=97=E3=81=AE=E3=82=A2?= =?UTF-8?q?=E3=82=AF=E3=82=BB=E3=82=B9=E8=A8=B1=E5=8F=AF=E3=82=92=E8=A8=AD?= =?UTF-8?q?=E5=AE=9A=E3=83=95=E3=82=A1=E3=82=A4=E3=83=AB=E3=81=A7=E8=A8=AD?= =?UTF-8?q?=E5=AE=9A=E3=81=95=E3=81=9B=E3=82=8B=E4=BB=95=E6=A7=98=E3=81=AB?= =?UTF-8?q?=E5=A4=89=E6=9B=B4=E3=80=82=20=E3=83=BBShared2=E3=83=95?= =?UTF-8?q?=E3=82=A1=E3=82=A4=E3=83=AB=E3=81=AE=E3=82=A2=E3=82=AF=E3=82=BB?= =?UTF-8?q?=E3=82=B9=E3=83=81=E3=82=A7=E3=83=83=E3=82=AF=E3=81=A8=E3=82=B5?= =?UTF-8?q?=E3=82=A4=E3=82=BA=E3=83=81=E3=82=A7=E3=83=83=E3=82=AF=E3=82=92?= =?UTF-8?q?=E3=83=95=E3=82=A1=E3=82=A4=E3=83=AB=E3=81=94=E3=81=A8=E3=81=AB?= =?UTF-8?q?=E5=A4=89=E6=9B=B4=E3=80=82=20=E3=83=BBShared2=E3=83=95?= =?UTF-8?q?=E3=82=A1=E3=82=A4=E3=83=AB=E3=82=B5=E3=82=A4=E3=82=BA=E3=81=AE?= =?UTF-8?q?=E6=8C=87=E5=AE=9A=E3=82=92=E8=BF=BD=E5=8A=A0=E8=A8=AD=E5=AE=9A?= =?UTF-8?q?=E3=83=95=E3=82=A1=E3=82=A4=E3=83=AB=E3=81=8B=E3=82=89=E8=A8=AD?= =?UTF-8?q?=E5=AE=9A=E3=83=95=E3=82=A1=E3=82=A4=E3=83=AB=E3=81=AB=E5=A4=89?= =?UTF-8?q?=E6=9B=B4=E3=80=82=20=E3=83=BBresource=E4=BB=A5=E4=B8=8B?= =?UTF-8?q?=E3=81=AE=E3=83=95=E3=82=A1=E3=82=A4=E3=83=AB=E3=81=AE=E5=8F=82?= =?UTF-8?q?=E7=85=A7=E3=82=92=E3=82=AB=E3=83=AC=E3=83=B3=E3=83=88=E7=9B=B8?= =?UTF-8?q?=E5=AF=BE=E3=81=8B=E3=82=89=E3=83=90=E3=82=A4=E3=83=8A=E3=83=AA?= =?UTF-8?q?=E3=82=92=E6=A0=BC=E7=B4=8D=E3=81=99=E3=82=8B=E3=83=95=E3=82=A9?= =?UTF-8?q?=E3=83=AB=E3=83=80=E7=9B=B8=E5=AF=BE=E3=81=AB=E5=A4=89=E6=9B=B4?= =?UTF-8?q?=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit git-svn-id: file:///Users/lillianskinner/Downloads/platinum/twl/TwlToolsRED@102 7061adef-622a-194b-ae81-725974e89856 --- .../MasterEditorTWL/MasterEditorTWL.ncb | Bin 11365376 -> 11373568 bytes .../MasterEditorTWL/MasterEditorTWL.suo | Bin 66560 -> 68096 bytes .../MasterEditorTWL/AssemblyInfo.cpp | 2 +- .../MasterEditorTWL/Debug/BuildLog.htm | Bin 12768 -> 20412 bytes .../MasterEditorTWL/MasterEditorTWL/Form1.h | 98 +- .../MasterEditorTWL/Form_file.cpp | 6 +- .../MasterEditorTWL/Form_init.cpp | 129 +- .../MasterEditorTWL/Form_mwlist.cpp | 6 +- .../MasterEditorTWL/MasterEditorTWL.vcproj | 4 + .../MasterEditorTWL/deliverable.cpp | 5 +- .../MasterEditorTWL/deliverable.h | 6 +- .../MasterEditorTWL/MasterEditorTWL/srl.cpp | 1035 +--------------- .../MasterEditorTWL/MasterEditorTWL/srl.h | 70 +- .../MasterEditorTWL/srl_mrc.cpp | 1037 +++++++++++++++++ .../MasterEditorTWL/resource/ini.xml | 7 + 15 files changed, 1336 insertions(+), 1069 deletions(-) create mode 100644 build/tools/MasterEditor/MasterEditorTWL/MasterEditorTWL/srl_mrc.cpp diff --git a/build/tools/MasterEditor/MasterEditorTWL/MasterEditorTWL.ncb b/build/tools/MasterEditor/MasterEditorTWL/MasterEditorTWL.ncb index eb509d3559004842c8f195d26e2bbfd2ea1d83dc..a0f49fb4c4230d776a5ac3240a6ea686a346c666 100644 GIT binary patch delta 90269 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 delta 59951 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 azSiK)OP9zN?9we&N{@^8{=Xx>p8PilS?X>8 diff --git a/build/tools/MasterEditor/MasterEditorTWL/MasterEditorTWL.suo b/build/tools/MasterEditor/MasterEditorTWL/MasterEditorTWL.suo index fff0604e79235da11f80bfce1428429ad8498761..46959e4e7a380b4c7584703ea9d1441bc06b839d 100644 GIT binary patch delta 7198 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 delta 5327 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 delta 319 zcmdlppYcKR1`{?>0|r9|CkA5%3m`NBLIVaf29wS6MK&^R{>5R#GI$|0Oiow+&)HhO*6x o4(3dgA2G>IauM5nz?qG4vX-j^>nnrL2J0usyNYf$^6p{*0Fv`W1poj5 diff --git a/build/tools/MasterEditor/MasterEditorTWL/MasterEditorTWL/Form1.h b/build/tools/MasterEditor/MasterEditorTWL/MasterEditorTWL/Form1.h index b133bf5..53e0078 100644 --- a/build/tools/MasterEditor/MasterEditorTWL/MasterEditorTWL/Form1.h +++ b/build/tools/MasterEditor/MasterEditorTWL/MasterEditorTWL/Form1.h @@ -723,12 +723,12 @@ private: System::Windows::Forms::CheckBox^ cboxIsUnnecessaryRating; this->labAssemblyVersion->Text = "ver." + this->getVersion(); // TAD読み込みの際に作成される一時ファイルと同名ファイルがあった場合には削除してよいか確認 - System::Diagnostics::Debug::WriteLine( this->getSplitTadTmpFilename() ); - if( System::IO::File::Exists( this->getSplitTadTmpFilename() ) ) + System::Diagnostics::Debug::WriteLine( this->getSplitTadTmpFile() ); + if( System::IO::File::Exists( this->getSplitTadTmpFile() ) ) { this->sucMsg( "本プログラムで作成する一時ファイルと同名のファイルが存在します。このファイルを削除します。", "There is the file which has same name as temporary file made by this program. That file is deleted." ); - System::IO::File::Delete( this->getSplitTadTmpFilename() ); + System::IO::File::Delete( this->getSplitTadTmpFile() ); } // デフォルト値 @@ -787,7 +787,7 @@ private: System::Windows::Forms::CheckBox^ cboxIsUnnecessaryRating; ~Form1() { // TAD読み出しの際に作成される一時SRLファイルを削除(書き出しをせずに終了したときに起こりうる) - System::String ^srlfile = this->getSplitTadTmpFilename(); + System::String ^srlfile = this->getSplitTadTmpFile(); if( System::IO::File::Exists( srlfile ) ) { System::IO::File::Delete( srlfile ); // すでに存在する場合は削除 @@ -2857,18 +2857,6 @@ private: System::Windows::Forms::CheckBox^ cboxIsUnnecessaryRating; // tadの読み込み System::Boolean loadTad( System::String ^tadfile ); - // tadの読み込みで生成する一時SRLファイル名を返す - System::String ^getSplitTadTmpFilename(void) - { - System::String ^dir = System::IO::Path::GetDirectoryName( System::Reflection::Assembly::GetEntryAssembly()->Location ); - if( !dir->EndsWith("\\") ) - { - dir = dir + "\\"; - } - System::String ^tmpfile = dir + METWL_TAD_TMP_FILENAME; - return tmpfile; - } - // 提出ファイル名をゲームコードなどから決定 System::String^ getSubmitFilePrefix(void) { @@ -2929,7 +2917,21 @@ private: System::Windows::Forms::CheckBox^ cboxIsUnnecessaryRating; void changeVisibleForms( System::Boolean visible ) { this->gboxShared2Size->Visible = visible; + this->cboxIsShared2->Visible = visible; + this->tboxShared2Size0->Visible = visible; + this->labShared2Size0->Visible = visible; + this->tboxShared2Size1->Visible = visible; + this->labShared2Size1->Visible = visible; + this->tboxShared2Size2->Visible = visible; + this->labShared2Size2->Visible = visible; + this->tboxShared2Size3->Visible = visible; + this->labShared2Size3->Visible = visible; + this->tboxShared2Size4->Visible = visible; + this->labShared2Size4->Visible = visible; + this->tboxShared2Size5->Visible = visible; + this->labShared2Size5->Visible = visible; this->cboxIsNormalJump->Visible = visible; + this->tboxIsGameCardOn->Visible = visible; this->labIsGameCardOn->Visible = visible; this->labIsGameCardOn2->Visible = visible; @@ -2960,7 +2962,7 @@ private: System::Windows::Forms::CheckBox^ cboxIsUnnecessaryRating; { System::Reflection::Assembly ^ass = System::Reflection::Assembly::GetEntryAssembly(); System::Version ^ver = ass->GetName()->Version; - return ( ver->Major.ToString() + "." + ver->Minor.ToString() + "a" ); + return ( ver->Major.ToString() + "." + ver->Minor.ToString() ); } // SRLに登録されないROM仕様のフォーム入力を @@ -2998,6 +3000,66 @@ private: System::Windows::Forms::CheckBox^ cboxIsUnnecessaryRating; } } + private: + // ---------------------------------------------- + // 固定ファイル名の取得 + // ---------------------------------------------- + + // バイナリがあるディレクトリ + System::String^ getBinDir(void) + { + System::String ^dir = System::IO::Path::GetDirectoryName( System::Reflection::Assembly::GetEntryAssembly()->Location ); + if( !dir->EndsWith("\\") ) + { + dir = dir + "\\"; + } + return dir; + } + // リソースファイルがあるディレクトリ + System::String^ getResDir(void) + { + System::String ^dir = System::IO::Directory::GetParent( this->getBinDir() )->Parent->FullName; + if( !dir->EndsWith("\\") ) + { + dir = dir + "\\"; + } + dir = dir + "resource\\"; + return dir; + } + // 設定ファイル + System::String^ getIniFile(void) + { + return (this->getResDir() + "ini.xml"); + } + System::String^ getAppendIniFile(void) + { + return (this->getResDir() + "append_ini.xml"); + } + // 提出確認書テンプレート + System::String^ getSheetTemplateFile(void) + { + return (this->getResDir() + "sheet_templete.xml"); + } + // ミドルウェアリスト作成用のXSL + System::String^ getMiddlewareListStyleFile(void) + { + return (this->getResDir() + "middleware.xsl"); + } + System::String^ getMiddlewareListStyleFileEmbedded(void) + { + return (this->getResDir() + "middleware_e.xsl"); + } + // ミドルウェアリスト作成時の一時ファイル + System::String^ getMiddlewareListTmpFile(void) + { + return (this->getBinDir() + "middleware-tmp.xml"); + } + // tadの読み込みで生成する一時SRLファイル + System::String^ getSplitTadTmpFile(void) + { + return (this->getBinDir() + "tmp.srl"); + } + private: // ---------------------------------------------- // フォームとSRL内情報を矛盾なく一致させる @@ -3442,7 +3504,7 @@ private: System::Windows::Forms::CheckBox^ cboxIsUnnecessaryRating; // 書類作成 srlfile = System::IO::Path::GetFileName( srlfile ); //result = this->hDeliv->write( delivfile, this->hSrl, hcrc, srlfile, !this->isJapanese() ); - result = this->hDeliv->writeSpreadsheet( delivfile, this->hSrl, crc, srlfile, !this->isJapanese() ); + result = this->hDeliv->writeSpreadsheet( delivfile, this->getSheetTemplateFile(), this->hSrl, crc, srlfile, !this->isJapanese() ); if( result != ECDeliverableResult::NOERROR ) { switch( result ) diff --git a/build/tools/MasterEditor/MasterEditorTWL/MasterEditorTWL/Form_file.cpp b/build/tools/MasterEditor/MasterEditorTWL/MasterEditorTWL/Form_file.cpp index 03b660e..1fd41fd 100644 --- a/build/tools/MasterEditor/MasterEditorTWL/MasterEditorTWL/Form_file.cpp +++ b/build/tools/MasterEditor/MasterEditorTWL/MasterEditorTWL/Form_file.cpp @@ -44,7 +44,7 @@ System::Boolean Form1::loadRom( System::String ^infile ) if( result ) { this->IsLoadTad = false; - System::String ^tmpsrl = this->getSplitTadTmpFilename(); + System::String ^tmpsrl = this->getSplitTadTmpFile(); if( System::IO::File::Exists( tmpsrl ) ) { System::IO::File::Delete( tmpsrl ); // SRLの読み込みが成功したら以前のTAD読み込みで使用した一時ファイルは不要 @@ -63,7 +63,7 @@ System::Boolean Form1::saveRom( System::String ^outfile ) if( this->IsLoadTad ) { // 一時ファイルにSRLを書き出しているのでその一時ファイルから出力ファイルを作成 - System::String ^tmpsrl = this->getSplitTadTmpFilename(); + System::String ^tmpsrl = this->getSplitTadTmpFile(); result = this->saveSrl( tmpsrl, outfile ); if( result ) { @@ -84,7 +84,7 @@ System::Boolean Form1::saveRom( System::String ^outfile ) System::Boolean Form1::loadTad( System::String ^tadfile ) { // tadファイルを変換したSRLを一時ファイルに保存 - System::String ^srlfile = this->getSplitTadTmpFilename(); + System::String ^srlfile = this->getSplitTadTmpFile(); if( splitTad( tadfile, srlfile ) != 0 ) // 上書きで保存 { this->errMsg( "TADファイルの読み込みに失敗しました。", "Reading TAD file failed." ); diff --git a/build/tools/MasterEditor/MasterEditorTWL/MasterEditorTWL/Form_init.cpp b/build/tools/MasterEditor/MasterEditorTWL/MasterEditorTWL/Form_init.cpp index d3cbcd5..22609d0 100644 --- a/build/tools/MasterEditor/MasterEditorTWL/MasterEditorTWL/Form_init.cpp +++ b/build/tools/MasterEditor/MasterEditorTWL/MasterEditorTWL/Form_init.cpp @@ -34,7 +34,7 @@ void Form1::loadInit(void) // xmlファイルの読み込み try { - doc->Load( "../resource/ini.xml" ); + doc->Load( this->getIniFile() ); } catch( System::IO::FileNotFoundException ^s ) { @@ -59,6 +59,104 @@ void Form1::loadInit(void) { this->readOnly(); } + + // タグ + { + // Shared2ファイルのアクセス許可(ファイルごとに指定) + System::String ^shared2 = MasterEditorTWL::getXPathText( root, "/init/access/shared2" ); + if( shared2 ) + { + cli::array ^list = shared2->Split( ',' ); + if( list ) + { + for each( System::String ^item in list ) + { + //System::Diagnostics::Debug::WriteLine( "access permit shared2 file: " + item ); + System::Int32 number = System::Int32::Parse( item ); + this->hSrl->hMrcExternalCheckItems->hIsPermitShared2Array[ number ] = true; // 設定ファイルで指定されている番号のみ許可 + } + } + } + + // ノーマルジャンプのアクセス許可 + System::String ^isNJ = MasterEditorTWL::getXPathText( root, "/init/access/normalJump" ); + if( isNJ && isNJ->Equals( "Permit" ) ) + { + this->hSrl->hMrcExternalCheckItems->IsPermitNormalJump = true; + } + } + // タグに付随して非表示項目を表示するかどうかを決める + { + // Shared2ファイル + System::Boolean bVisible; + for each( System::Boolean permit in this->hSrl->hMrcExternalCheckItems->hIsPermitShared2Array ) + { + if( permit && !this->gboxShared2Size->Visible ) + { + bVisible = true; // どれかひとつでもtrueならグループボックス全体を表示する + } + } + this->gboxShared2Size->Visible = bVisible; + this->cboxIsShared2->Visible = bVisible; + if( bVisible ) + { + int i; + for( i=0; i < METWL_NUMOF_SHARED2FILES; i++ ) + { + // グループボックス全体が表示されていたら全ファイルの項目が表示されるので + // アクセス許可されていないファイルのみ非表示にする + if( this->hSrl->hMrcExternalCheckItems->hIsPermitShared2Array[i] ) + { + switch(i) + { + case 0: this->tboxShared2Size0->Visible = true; this->labShared2Size0->Visible = true; break; + case 1: this->tboxShared2Size1->Visible = true; this->labShared2Size1->Visible = true; break; + case 2: this->tboxShared2Size2->Visible = true; this->labShared2Size2->Visible = true; break; + case 3: this->tboxShared2Size3->Visible = true; this->labShared2Size3->Visible = true; break; + case 4: this->tboxShared2Size4->Visible = true; this->labShared2Size4->Visible = true; break; + case 5: this->tboxShared2Size5->Visible = true; this->labShared2Size5->Visible = true; break; + default: break; + } + } + } + } + + // ノーマルジャンプ + this->cboxIsNormalJump->Visible = this->hSrl->hMrcExternalCheckItems->IsPermitNormalJump; + } + + // タグ : Shared2ファイルサイズの真値(アクセス許可されているファイルのみ記載) + System::Int32 i; + for( i=0; i < METWL_NUMOF_SHARED2FILES; i++ ) + { + System::String ^str = MasterEditorTWL::getXPathText( root, "/init/shared2/size" + i.ToString() ); + if( str ) + { + this->hSrl->hMrcExternalCheckItems->hShared2SizeArray[i] = System::UInt32::Parse( str ); + } + else // アクセス許可されていないファイルは非公開なのでサイズが設定ファイルに記載されない + { + this->hSrl->hMrcExternalCheckItems->hShared2SizeArray[i] = 0; + } + } + + // タグ : 予約領域の範囲を記載 + System::Xml::XmlNodeList ^list = root->SelectNodes( "/init/reserved-list/reserved" ); + System::Collections::IEnumerator^ iter = list->GetEnumerator(); + while( iter->MoveNext() ) + { + System::Xml::XmlNode ^area = safe_cast(iter->Current); + System::Xml::XmlNode ^begin = area->SelectSingleNode( "begin" ); // 相対パス + System::Xml::XmlNode ^end = area->SelectSingleNode( "end" ); + if( begin && begin->FirstChild && begin->FirstChild->Value && + end && end->FirstChild && end->FirstChild->Value ) + { + System::UInt32 ibeg = System::UInt32::Parse( begin->FirstChild->Value, System::Globalization::NumberStyles::AllowHexSpecifier ); + System::UInt32 iend = System::UInt32::Parse( end->FirstChild->Value, System::Globalization::NumberStyles::AllowHexSpecifier ); + MasterEditorTWL::VCReservedArea iarea(ibeg, iend); + this->hSrl->hMrcExternalCheckItems->hReservedAreaList->Add( iarea ); + } + } } // loadInit() @@ -68,7 +166,7 @@ void Form1::loadInit(void) void Form1::loadAppendInit(void) { - System::String ^initfile = "../resource/append_ini.xml"; + System::String ^initfile = this->getAppendIniFile(); // 通常は存在しない if( !System::IO::File::Exists( initfile ) ) @@ -105,7 +203,7 @@ void Form1::loadAppendInit(void) if( bCheck ) // チェックするときのみ追加チェック項目を設定 { // チェックするかどうか - this->hSrl->hMrcSpecialList->IsCheck = true; + this->hSrl->hMrcExternalCheckItems->IsAppendCheck = true; // SDK try @@ -114,37 +212,16 @@ void Form1::loadAppendInit(void) u32 minor = System::UInt32::Parse( MasterEditorTWL::getXPathText( root, "/init/sdk/minor" ) ); u32 relstep = System::UInt32::Parse( MasterEditorTWL::getXPathText( root, "/init/sdk/relstep" ) ); u32 sdkver = (major << 24) | (minor << 16) | (relstep & 0xFFFF); - this->hSrl->hMrcSpecialList->SDKVer = sdkver; + this->hSrl->hMrcExternalCheckItems->SDKVer = sdkver; } catch ( System::Exception ^ex ) { (void)ex; this->errMsg( "設定ファイル中のSDKバージョンが読み込めませんでした。バージョンは0とみなされます。", "SDK ver. can't be read from setting file. Therefore it is set by 0." ); - this->hSrl->hMrcSpecialList->SDKVer = 0; + this->hSrl->hMrcExternalCheckItems->SDKVer = 0; } - // Shared2File - try - { - System::Int32 i; - for( i=0; i < METWL_NUMOF_SHARED2FILES; i++ ) - { - u32 size = System::UInt32::Parse( MasterEditorTWL::getXPathText( root, "/init/shared2/size" + i.ToString() ) ); - this->hSrl->hMrcSpecialList->hShared2SizeArray[i] = size; - } - } - catch ( System::Exception ^ex ) - { - (void)ex; - this->errMsg( "設定ファイル中のShared2ファイルサイズが読み込めませんでした。サイズはすべて0とみなされます。", - "One of shared2 file sizes can't be read from setting file. Therefore they are set by 0." ); - System::Int32 i; - for( i=0; i < METWL_NUMOF_SHARED2FILES; i++ ) - { - this->hSrl->hMrcSpecialList->hShared2SizeArray[i] = 0; - } - } } //if( bCheck ) } // loadAppendInit() \ No newline at end of file diff --git a/build/tools/MasterEditor/MasterEditorTWL/MasterEditorTWL/Form_mwlist.cpp b/build/tools/MasterEditor/MasterEditorTWL/MasterEditorTWL/Form_mwlist.cpp index aec5d8c..9ca6fab 100644 --- a/build/tools/MasterEditor/MasterEditorTWL/MasterEditorTWL/Form_mwlist.cpp +++ b/build/tools/MasterEditor/MasterEditorTWL/MasterEditorTWL/Form_mwlist.cpp @@ -106,7 +106,7 @@ System::Boolean Form1::saveMiddlewareListXmlEmbeddedXsl( System::String ^filenam System::Xml::XmlElement ^root = doc->DocumentElement; try { - xsl->Load("../resource/middleware_e.xsl"); + xsl->Load( this->getMiddlewareListStyleFileEmbedded() ); root->AppendChild( doc->ImportNode(xsl->DocumentElement, true) ); } catch ( System::Exception ^ex ) @@ -133,7 +133,7 @@ System::Boolean Form1::saveMiddlewareListXmlEmbeddedXsl( System::String ^filenam System::Boolean Form1::saveMiddlewareListHtml( System::String ^filename ) { System::Xml::Xsl::XslCompiledTransform ^xslt = gcnew System::Xml::Xsl::XslCompiledTransform; - System::String ^tmpxml = gcnew System::String( "middleware-tmp.xml" ); + System::String ^tmpxml = gcnew System::String( this->getMiddlewareListTmpFile() ); if( !saveMiddlewareListXml(tmpxml) ) { @@ -142,7 +142,7 @@ System::Boolean Form1::saveMiddlewareListHtml( System::String ^filename ) try { - xslt->Load("../resource/middleware.xsl"); + xslt->Load( this->getMiddlewareListStyleFile() ); xslt->Transform( tmpxml, filename ); } catch (System::Exception ^s) diff --git a/build/tools/MasterEditor/MasterEditorTWL/MasterEditorTWL/MasterEditorTWL.vcproj b/build/tools/MasterEditor/MasterEditorTWL/MasterEditorTWL/MasterEditorTWL.vcproj index 4e1c03f..f030682 100644 --- a/build/tools/MasterEditor/MasterEditorTWL/MasterEditorTWL/MasterEditorTWL.vcproj +++ b/build/tools/MasterEditor/MasterEditorTWL/MasterEditorTWL/MasterEditorTWL.vcproj @@ -267,6 +267,10 @@ RelativePath=".\srl.cpp" > + + diff --git a/build/tools/MasterEditor/MasterEditorTWL/MasterEditorTWL/deliverable.cpp b/build/tools/MasterEditor/MasterEditorTWL/MasterEditorTWL/deliverable.cpp index 0bde4b5..049b99d 100644 --- a/build/tools/MasterEditor/MasterEditorTWL/MasterEditorTWL/deliverable.cpp +++ b/build/tools/MasterEditor/MasterEditorTWL/MasterEditorTWL/deliverable.cpp @@ -25,13 +25,14 @@ using namespace MasterEditorTWL; // @arg [in] 英語フラグ // ECDeliverableResult RCDeliverable::writeSpreadsheet( - System::String ^hFilename, MasterEditorTWL::RCSrl ^hSrl, System::UInt16 CRC, System::String ^hSrlFilename, System::Boolean english ) + System::String ^hFilename, System::String ^hSheetTemplateFilename, + MasterEditorTWL::RCSrl ^hSrl, System::UInt16 CRC, System::String ^hSrlFilename, System::Boolean english ) { // テンプレートを読み込む System::Xml::XmlDocument ^doc = gcnew System::Xml::XmlDocument(); try { - doc->Load( "../resource/sheet_templete.xml" ); + doc->Load( hSheetTemplateFilename ); } catch ( System::Exception ^ex ) { diff --git a/build/tools/MasterEditor/MasterEditorTWL/MasterEditorTWL/deliverable.h b/build/tools/MasterEditor/MasterEditorTWL/MasterEditorTWL/deliverable.h index 193b8a9..21c5a31 100644 --- a/build/tools/MasterEditor/MasterEditorTWL/MasterEditorTWL/deliverable.h +++ b/build/tools/MasterEditor/MasterEditorTWL/MasterEditorTWL/deliverable.h @@ -108,16 +108,18 @@ namespace MasterEditorTWL public: // - // 書類出力 + // 提出確認書出力 // // @arg [out] 出力ファイル名 + // @arg [in] 提出確認書のテンプレート // @arg [in] ROMバイナリ(SRL)固有情報 // @arg [in] ファイル全体のCRC // @arg [in] SRLのファイル名(書類に記述するために使用) // @arg [in] 英語フラグ // ECDeliverableResult writeSpreadsheet( - System::String ^hFilename, RCSrl ^hSrl, System::UInt16 CRC, System::String ^hSrlFilename, System::Boolean english ); + System::String ^hFilename, System::String ^hSheetTemplateFilename, + RCSrl ^hSrl, System::UInt16 CRC, System::String ^hSrlFilename, System::Boolean english ); }; // end of ref class RCDeliverable diff --git a/build/tools/MasterEditor/MasterEditorTWL/MasterEditorTWL/srl.cpp b/build/tools/MasterEditor/MasterEditorTWL/MasterEditorTWL/srl.cpp index 0d32f6e..4d55074 100644 --- a/build/tools/MasterEditor/MasterEditorTWL/MasterEditorTWL/srl.cpp +++ b/build/tools/MasterEditor/MasterEditorTWL/MasterEditorTWL/srl.cpp @@ -14,11 +14,9 @@ using namespace MasterEditorTWL; -extern const u8 gBannerFont[]; - -// +// **************************************************************** // RCSrl クラス -// +// **************************************************************** // constructor RCSrl::RCSrl() @@ -26,7 +24,7 @@ RCSrl::RCSrl() this->pRomHeader = new (ROM_Header); std::memset( pRomHeader, 0, sizeof(ROM_Header) ); - this->hMrcSpecialList = gcnew RCMrcSpecialList(); + this->hMrcExternalCheckItems = gcnew RCMrcExternalCheckItems(); } // destructor @@ -45,11 +43,11 @@ RCSrl::!RCSrl() delete (this->pRomHeader); } -// +// ------------------------------------------------------------------- // ROMヘッダをファイルからリード // // @arg [in] 入力ファイル名 -// +// ------------------------------------------------------------------- ECSrlResult RCSrl::readFromFile( System::String ^filename ) { FILE *fp = NULL; @@ -127,11 +125,11 @@ ECSrlResult RCSrl::readFromFile( System::String ^filename ) return (ECSrlResult::NOERROR); } -// +// ------------------------------------------------------------------- // ROMヘッダをファイルにライト // // @arg [in] 出力ファイル名 -// +// ------------------------------------------------------------------- ECSrlResult RCSrl::writeToFile( System::String ^filename ) { FILE *fp = NULL; @@ -162,9 +160,9 @@ ECSrlResult RCSrl::writeToFile( System::String ^filename ) return (ECSrlResult::NOERROR); } -// +// ------------------------------------------------------------------- // ROMヘッダから取得したROM固有情報をフィールドに反映させる -// +// ------------------------------------------------------------------- ECSrlResult RCSrl::setRomInfo(void) { System::Int32 i; @@ -351,7 +349,9 @@ ECSrlResult RCSrl::setRomInfo(void) return ECSrlResult::NOERROR; } // ECSrlResult RCSrl::setRomInfo(void) +// ------------------------------------------------------------------- // ROMヘッダ内のリージョン情報をフィールドに反映させる +// ------------------------------------------------------------------- bool RCSrl::setRegionInfo( u32 region ) { this->IsRegionJapan = ((region & METWL_MASK_REGION_JAPAN) != 0)?true:false; @@ -363,14 +363,16 @@ bool RCSrl::setRegionInfo( u32 region ) if( MasterEditorTWL::getOgnListInRegion( region ) == nullptr ) { this->hParentalErrorList->Add( gcnew RCMrcError( - "カードリージョン", 0x1b0, 0x1b3, "仕向地の組み合わせが不正です。ペアレンタルコントロール情報は無視して読み込まれました。", - "Card Region", "Illigal Region. Parental Control Information is ignored in reading.", true, true ) ); + "リージョン", 0x1b0, 0x1b3, "仕向地の組み合わせが不正です。ペアレンタルコントロール情報は無視して読み込まれました。", + "Region", "Illigal Region. Parental Control Information is ignored in reading.", true, true ) ); return false; } return true; } +// ---------------------------------------------------------------------- // ROMヘッダ内のレーティング表示不要フラグを調べてフィールドに反映させる +// ---------------------------------------------------------------------- void RCSrl::setUnnecessaryRatingInfo( u32 region ) { System::Collections::Generic::List ^ognlist = MasterEditorTWL::getOgnListInRegion( region ); @@ -406,7 +408,9 @@ void RCSrl::setUnnecessaryRatingInfo( u32 region ) } } +// ------------------------------------------------------------------- // ROMヘッダ内のペアレンタルコントロール情報をフィールドに反映させる +// ------------------------------------------------------------------- void RCSrl::setRatingInfo( u32 region ) { // リージョンに含まれている団体をリストアップ @@ -424,7 +428,9 @@ void RCSrl::setRatingInfo( u32 region ) } } +// ------------------------------------------------------------------- // 団体のレーティング情報からコンボボックスのインデックスを決定する +// ------------------------------------------------------------------- void RCSrl::setOneRatingOrgInfo( int ogn ) { System::Boolean enable = ((this->pRomHeader->s.parental_control_rating_info[ ogn ] & OS_TWL_PCTL_OGNINFO_ENABLE_MASK) != 0)?true:false; @@ -486,9 +492,9 @@ void RCSrl::setOneRatingOrgInfo( int ogn ) this->hArrayParentalIndex[ ogn ] = index; } -// +// ------------------------------------------------------------------- // ROMヘッダにROM固有情報フィールドの値を反映させる -// +// ------------------------------------------------------------------- ECSrlResult RCSrl::setRomHeader(void) { ECSrlResult result; @@ -576,10 +582,10 @@ void RCSrl::setRatingRomHeader( u32 region ) } } -// +// ------------------------------------------------------------------- // ヘッダのCRCを算出 -// -static u16 calcCRC( const u16 start, const u8 *data, const int allsize ) +// ------------------------------------------------------------------- +u16 calcCRC( const u16 start, const u8 *data, const int allsize ) { u16 r1; u16 total = start; @@ -620,9 +626,9 @@ ECSrlResult RCSrl::calcRomHeaderCRC(void) return (ECSrlResult::NOERROR); } // ECSrlResult RCSrl::calcRomHeaderCRC(void) -// +// ------------------------------------------------------------------- // ROMヘッダを再署名 -// +// ------------------------------------------------------------------- ECSrlResult RCSrl::signRomHeader(void) { SignatureData signSrc; // 署名のもととなるダイジェスト値 @@ -698,9 +704,9 @@ ECSrlResult RCSrl::signRomHeader(void) return (ECSrlResult::NOERROR); } // ECSrlResult RCSrl::signRomHeader(void) -// +// ------------------------------------------------------------------- // ROMヘッダの署名を外す -// +// ------------------------------------------------------------------- ECSrlResult RCSrl::decryptRomHeader( ROM_Header *prh ) { u8 original[ RSA_KEY_LENGTH ]; // 署名外した後のデータ格納先 @@ -767,9 +773,9 @@ ECSrlResult RCSrl::decryptRomHeader( ROM_Header *prh ) return (ECSrlResult::NOERROR); } -// +// ------------------------------------------------------------------- // アプリ種別の判定 -// +// ------------------------------------------------------------------- ECAppType RCSrl::selectAppType(void) { ECAppType type = ECAppType::ILLEGAL; @@ -796,9 +802,9 @@ ECAppType RCSrl::selectAppType(void) return type; } -// +// ------------------------------------------------------------------- // DSダウンロード署名がSRLに格納されているか調べる -// +// ------------------------------------------------------------------- ECSrlResult RCSrl::hasDSDLPlaySign( FILE *fp ) { const s32 DSDLPLAY_SIZE = 0x88; @@ -830,9 +836,9 @@ ECSrlResult RCSrl::hasDSDLPlaySign( FILE *fp ) return (ECSrlResult::NOERROR); } -// +// ------------------------------------------------------------------- // SDKバージョンを取得する -// +// ------------------------------------------------------------------- ECSrlResult RCSrl::searchSDKVersion( FILE *fp ) { // SDKバージョンはSRLバイナリ中に以下のマジックナンバとともに埋められている @@ -908,9 +914,9 @@ ECSrlResult RCSrl::searchSDKVersion( FILE *fp ) return ECSrlResult::NOERROR; } -// +// ------------------------------------------------------------------- // 使用ライセンスを取得する -// +// ------------------------------------------------------------------- #define LICENSE_LEN_MAX 1024 // これよりもライセンスの文字列が長いとき正しく取得できない ECSrlResult RCSrl::searchLicenses(FILE *fp) { @@ -961,972 +967,3 @@ ECSrlResult RCSrl::searchLicenses(FILE *fp) return ECSrlResult::NOERROR; } //RCSrl::searchLicenses -// -// MRC -// -ECSrlResult RCSrl::mrc( FILE *fp ) -{ -#ifdef METWL_WHETHER_MRC - ECSrlResult result; - result = this->mrcNTR( fp ); - if( result != ECSrlResult::NOERROR ) - { - return result; - } - result = this->mrcTWL( fp ); - if( result != ECSrlResult::NOERROR ) - { - return result; - } - this->hErrorList->AddRange( this->hParentalErrorList ); // ペアレンタルコントロールのリストは別につくっているので追加 -#endif - return ECSrlResult::NOERROR; -} - -// NTR互換MRC -ECSrlResult RCSrl::mrcNTR( FILE *fp ) -{ - System::Int32 i; - System::Boolean result; - - // ROMヘッダのチェック - - // 文字コードチェック - result = true; - for( i=0; i < TITLE_NAME_MAX; i++ ) - { - char c = this->pRomHeader->s.title_name[i]; - if( ((c < 0x20) || (0x5f < c)) && (c != 0x00) ) - { - result = false; - } - } - if( !result ) - { - this->hErrorList->Add( gcnew RCMrcError( - "ソフトタイトル", 0x0, 0xb, "使用不可のASCIIコードが使用されています。", - "Game Title", "Unusable ASCII code is used.", false, true ) ); - } - - result = true; - for( i=0; i < TITLE_NAME_MAX; i++ ) - { - char c = this->pRomHeader->s.title_name[TITLE_NAME_MAX - i - 1]; // 末尾から探索 - if( ((0x21 <= c ) && (c <= 0x5f)) || (c == 0x00) ) // 00hと20h以外の使用可能な文字が出てくるまでにスペースが存在したらダメ - { - break; - } - else if( c == 0x20 ) - { - result = false; - } - } - if( !result ) - { - this->hErrorList->Add( gcnew RCMrcError( - "ソフトタイトル", 0x0, 0xb, "末尾の未使用部分には00hを登録してください。", - "Game Title", "Please use 00h for an unused part.", false, true ) ); - } - - result = true; - for( i=1; i < TITLE_NAME_MAX; i++ ) - { - char prev = this->pRomHeader->s.title_name[i-1]; - char curr = this->pRomHeader->s.title_name[i]; - if( (prev == 0x00) && (0x21 <= curr) && (curr <= 0x5f) ) // 途中に00hがあるとダメ - { - result = false; - break; - } - } - if( !result ) - { - this->hErrorList->Add( gcnew RCMrcError( - "ソフトタイトル", 0x0, 0xb, "スペース部分には20hを登録してください。", - "Game Title", "Please use 20h for an space part.", false, true ) ); - } - - result = true; - for( i=0; i < GAME_CODE_MAX; i++ ) - { - char c = this->pRomHeader->s.game_code[i]; - if( (c < 0x20) || (0x5f < c) ) // 00hを許さない - { - result = false; - } - } - if( !result ) - { - this->hErrorList->Add( gcnew RCMrcError( - "イニシャルコード", 0xc, 0xf, "使用不可のASCIIコードが使用されています。", - "Game Code", "Unusable ASCII code is used.", false, true ) ); - } - if( memcmp( this->pRomHeader->s.game_code, "NTRJ", GAME_CODE_MAX ) == 0 ) - { - this->hErrorList->Add( gcnew RCMrcError( - "イニシャルコード", 0xc, 0xf, "SDKデフォルトのコード(NTRJ)が使用されています。", - "Game Code", "SDK default code(NTRJ) is used.", false, true ) ); - } - - result = true; - for( i=0; i < MAKER_CODE_MAX; i++ ) - { - char c = this->pRomHeader->s.maker_code[i]; - if( (c < 0x20) || (0x5f < c) ) - { - result = false; - } - } - if( !result ) - { - this->hErrorList->Add( gcnew RCMrcError( - "メーカーコード", 0x10, 0x11, "使用不可のASCIIコードが使用されています。", - "Maker Code", "Unusable ASCII code is used.", false, true ) ); - } - - // 値チェック - - if( this->pRomHeader->s.rom_type != 0x00 ) - { - this->hErrorList->Add( gcnew RCMrcError( - "デバイスタイプ", 0x13, 0x13, "不正な値です。00hを設定してください。", - "Device Type", "Invalid data. Please set 00h.", false, true ) ); - } - - u8 romver = this->pRomHeader->s.rom_version; - if( ((romver < 0x00) || (0x0f < romver)) && (romver != 0xE0) ) - { - this->hErrorList->Add( gcnew RCMrcError( - "リマスターバージョン", 0x1e, 0x1e, "不正な値です。正式版では01h-0Fhのいずれかの値、事前版ではE0hを設定してください。", - "Release Ver.", "Invalid data. Please set either one of 01h-0Fh(Regular ver.), or E0h(Preliminary ver.)", false, true ) ); - } - if( this->pRomHeader->s.banner_offset == 0 ) - { - this->hErrorList->Add( gcnew RCMrcError( - "バナーオフセット", 0x68, 0x6b, "バナーデータが設定されていません。", - "Banner Offset.", "Banner data is not set.", false, true ) ); - } - if( this->pRomHeader->s.rom_valid_size == 0 ) - { - this->hErrorList->Add( gcnew RCMrcError( - "ROM実効サイズ", 0x80, 0x83, "値が設定されていません。", - "ROM Valid Size.", "Data is not set.", false, true ) ); - } - - // CRC - u16 crc; - // セキュア領域 - if( !this->IsMediaNand ) // カードアプリのときのみ - { - // セキュア領域はROMヘッダ外 - u8 *secures; - s32 secure_size = SECURE_AREA_END - this->pRomHeader->s.main_rom_offset; - if (secure_size > SECURE_AREA_SIZE) - { - secure_size = SECURE_AREA_SIZE; - } - if (secure_size <= 0) - { - this->hErrorList->Add( gcnew RCMrcError( - "セキュア領域CRC", 0x15e, 0x15f, "セキュア領域のアドレス指定が不正です。", - "Secure Area CRC.", "Illegal address of secure area.", false, true ) ); - } - secures = new u8[secure_size]; // never return if not allocated - fseek( fp, (u32)this->pRomHeader->s.main_rom_offset, SEEK_SET ); - if( secure_size != fread( secures, 1, secure_size, fp ) ) - { - delete []secures; - return ECSrlResult::ERROR_FILE_READ; - } - crc = calcCRC(CRC16_INIT_VALUE, (u8 *)secures, secure_size); - delete []secures; - if( crc != this->pRomHeader->s.secure_area_crc16 ) - { - this->hErrorList->Add( gcnew RCMrcError( - "セキュア領域CRC", 0x07c, 0x07d, "計算結果と一致しません。セキュア領域が改ざんされた可能性があります。", - "Secure Area CRC.", "Calclated CRC is different from Registered one.", false, true ) ); - } - } - - // ロゴ領域 - crc = 0xcf56; - if( crc != this->pRomHeader->s.nintendo_logo_crc16 ) - { - this->hErrorList->Add( gcnew RCMrcError( - "キャラクターデータCRC", 0x15c, 0x15d, "計算結果と一致しません。キャラクターデータが改ざんされた可能性があります。", - "Charactor Data CRC.", "Calclated CRC is different from Registered one.", false, true ) ); - } - - // ヘッダCRC - crc = calcCRC( CRC16_INIT_VALUE, (u8*)this->pRomHeader, CALC_CRC16_SIZE ); - if( crc != this->pRomHeader->s.header_crc16 ) - { - this->hErrorList->Add( gcnew RCMrcError( - "ROMヘッダCRC", 0x15e, 0x15f, "計算結果と一致しません。ROMヘッダが改ざんされた可能性があります。", - "ROM Header CRC.", "Calclated CRC is different from Registered one.", false, true ) ); - } - - // ROMヘッダ以外の領域のチェック (ファイルから適宜リードする) - - // システムコールライブラリ - u8 syscall[32]; - u32 offset = this->pRomHeader->s.main_rom_offset; - fseek( fp, offset, SEEK_SET ); - if( 32 != fread( syscall, 1, 32, fp ) ) - { - return ECSrlResult::ERROR_FILE_READ; - } - for( i=0; i < 32; i++ ) - { - if( syscall[i] != 0x00 ) - break; - } - if( i == 32 ) // 全部0 - { - this->hErrorList->Add( gcnew RCMrcError( - "システムコールライブラリ", METWL_ERRLIST_NORANGE, METWL_ERRLIST_NORANGE, "SDKデフォルトです。", - "System-Call Library", "This Library is SDK default one.", false, true ) ); - } - return ECSrlResult::NOERROR; -} // mrcNTR() - -// TWL専用 -ECSrlResult RCSrl::mrcTWL( FILE *fp ) -{ - System::Int32 i; - - // ROMヘッダのチェック (NTR互換領域) - -#ifdef METWL_WHETHER_PLATFORM_CHECK - // プラットフォームのチェック - if( (this->pRomHeader->s.platform_code != PLATFORM_CODE_TWL_HYBLID) && - (this->pRomHeader->s.platform_code != PLATFORM_CODE_TWL_LIMITED) && - (this->pRomHeader->s.enable_signature == 0) ) - { - return ECSrlResult::ERROR_PLATFORM; - } -#endif - - if( this->IsOldDevEncrypt && this->HasDSDLPlaySign ) - { - this->hErrorList->Add( gcnew RCMrcError( - "旧開発用暗号フラグ", 0x1c, 0x1c, - "このROMはクローンブート対応アプリですが、製品用本体ではクローンブートができなくなります。", - "Old Development Flag", - "This ROM supports Clone-Boot, and the flag is old type. Therefore, Clone-Boot can't be done.", - false, true ) ); - } - - // 値チェック - - fseek( fp, 0, SEEK_END ); - u32 filesize = ftell(fp); // 実ファイルサイズ - u32 romsize = 1 << (this->pRomHeader->s.rom_size); // ROM容量(単位Mbit) - if( !this->IsMediaNand ) // カードアプリのときのみのチェック - { - u32 filesizeMb = (filesize / (1024*1024)) * 8; // 単位をMbitに直す - if( romsize < filesizeMb ) - { - this->hErrorList->Add( gcnew RCMrcError( - "デバイス容量", 0x14, 0x14, "実ファイルサイズよりも小さい値が指定されています。", - "Device Capacity", "Setting data is less than the actual file size.", false, true ) ); - } - else if( filesizeMb < romsize ) - { - this->hWarnList->Add( gcnew RCMrcError( // 警告 - "デバイス容量", 0x14, 0x14, "実ファイルサイズに比べて無駄のある値が設定されています。", - "Device Capacity", "Setting data is larger than the actual file size.", false, true ) ); - } - if( (romsize < METWL_ROMSIZE_MIN) || (METWL_ROMSIZE_MAX < romsize) ) - { - this->hErrorList->Add( gcnew RCMrcError( - "デバイス容量", 0x14, 0x14, "指定可能な容量ではありません。", - "Device Capacity", "Invalid capacity.", false, true ) ); - } - if( (filesizeMb < 1) || (MasterEditorTWL::countBits(filesizeMb) != 1) ) - { - this->hWarnList->Add( gcnew RCMrcError( - "実ファイルサイズ", METWL_ERRLIST_NORANGE, METWL_ERRLIST_NORANGE, "中途半端な値です。通常では2のべき乗[Mbit]の値です。", - "Actual File Size", "Invalid size. This size is usually power of 2.", false, true ) ); - } - // 1Gbit以上のときの最終領域が固定値かどうか - this->mrcPadding( fp ); - - // セグメント3のCRC - u16 crcseg3; - BOOL crcret = getSeg3CRCInFp( fp, &crcseg3 ); - if( !crcret || (crcseg3 != METWL_SEG3_CRC) ) - { - this->hErrorList->Add( gcnew RCMrcError( - "セグメント3 CRC", METWL_ERRLIST_NORANGE, METWL_ERRLIST_NORANGE, - "セグメント3領域に誤りがあります。", - "Segment-3 CRC", "Invalid data exist in Segment-3 area.", false, true ) ); - } - - u16 NA = this->pRomHeader->s.twl_card_normal_area_rom_offset & 0x7fffUL; - u16 KA = this->pRomHeader->s.twl_card_keytable_area_rom_offset; - if( (NA == 0) || (KA == 0) || (NA > KA) ) - { - this->hErrorList->Add( gcnew RCMrcError( - "TWL ROMオフセット", 0x90, 0x93, - "TWLノーマル領域ROMオフセット(NA)およびTWL専用領域ROMオフセット(KA)はともに1以上で、かつNAはKAを超えてはいけません。", - "TWL ROM Offset", - "Both TWL Normal Area ROM Offset(NA) and TWL Limited Area ROM Offset(KA) are bigger than 0. And NA must be smaller than KA, or equals to KA.", - false, true ) ); - } - } //if( *(this->hIsNAND) == false ) - else // NANDアプリのときのみのチェック - { - if( (romsize < METWL_ROMSIZE_MIN_NAND) || (METWL_ROMSIZE_MAX_NAND < romsize) ) - { - this->hErrorList->Add( gcnew RCMrcError( - "デバイス容量", 0x14, 0x14, "NANDアプリに対して指定可能な容量ではありません。", - "Device Capacity", "Invalid capacity.", false, true ) ); - } - u32 allsize = filesize + this->pRomHeader->s.public_save_data_size + this->pRomHeader->s.private_save_data_size; - if( allsize > METWL_ALLSIZE_MAX_NAND ) - { - this->hErrorList->Add( gcnew RCMrcError( - "実ファイルサイズ", METWL_ERRLIST_NORANGE, METWL_ERRLIST_NORANGE, - "ROMデータの実ファイルサイズとPublicセーブデータおよびPrivateセーブデータのサイズの総和が32MByteを超えています。", - "Actual File Size", - "The sum of this size, the public save data size and private save data size exceed 32MByte.", false, true ) ); - } - } - - if( this->IsAppLauncher || this->IsAppSecure || this->IsAppSystem ) - { - if( this->pRomHeader->s.disable_debug == 0 ) - { - this->hWarnList->Add( gcnew RCMrcError( - "デバッガ動作禁止フラグ", 0x1f, 0x1f, - "デバッガ上で解析可能な設定になっています。デバッガ向けソフトとしてROMをリリースする場合にはセキュリティ上の問題がないかご確認ください。", - "Disable Launch on Debugger Flag", - "This ROM can be analyzed on the debugger. If the ROM is released for the debugger, please check the security settings.", - false, true ) ); - } - } - else // ユーザのときのみ - { - if( this->pRomHeader->s.disable_debug != 0 ) - { - this->hErrorList->Add( gcnew RCMrcError( - "デバッガ動作禁止フラグ", 0x1f, 0x1f, - "デバッガ上で解析不可な設定になっています。この設定は許可されていません。", - "Disable Launch on Debugger Flag", - "This ROM can't be analyzed on the debugger. This setting is unavailable.", - false, true ) ); - } - - u8 okbits = 0x02 | 0x40 | 0x80; - u8 *p = (u8*)&(this->pRomHeader->s); - if( p[0x1d] & ~okbits ) - { - this->hErrorList->Add( gcnew RCMrcError( - "特定仕向地", 0x1d, 0x1d, - "不正なビットが立っています。この設定は許可されていません。", - "Extra Region Code", - "Illegal bit is setting. This setting is unavailable.", - false, true ) ); - } - } - - if( this->pRomHeader->s.warning_no_spec_rom_speed != 0 ) - { - this->hWarnList->Add( gcnew RCMrcError( - "諸フラグ", 0x1f, 0x1f, "rsfファイルでROMSpeedTypeが設定されていません。", - "Setting Flags", "In a RSF file, the item \"ROMSpeedType\" is not set.", false, true ) ); - } - if( (this->pRomHeader->s.game_cmd_param & CARD_LATENCY_MASK) != CARD_1TROM_GAME_LATENCY ) - { - this->hErrorList->Add( gcnew RCMrcError( - "ROMコントロール情報", 0x60, 0x67, "TWLではマスクROMは用意されていません。ワンタイムPROM設定にしてください。", - "ROM Control Info.", "Mask ROM can be set. Please set One-time PROM.", false, true ) ); - } - - if( !this->IsMediaNand ) - { - if( (this->pRomHeader->s.enable_aes == 0) || (this->pRomHeader->s.aes_target_size == 0) ) - { - this->hErrorList->Add( gcnew RCMrcError( - "AES暗号", 0x60, 0x67, "AES暗号が無効になっています。セキュリティ上の問題があります。", - "AES Encryption", "AES Encryption is disable. It is a security problem.", false, true ) ); - } - } - else // NANDアプリ - { - if( (this->pRomHeader->s.enable_aes == 0) || (this->pRomHeader->s.aes_target_size == 0) || (this->pRomHeader->s.aes_target2_size == 0) ) - { - this->hErrorList->Add( gcnew RCMrcError( - "AES暗号", 0x60, 0x67, "AES暗号が無効になっています。セキュリティ上の問題があります。", - "AES Encryption", "AES Encryption is disable. It is a security problem.", false, true ) ); - } - } - - // ROMヘッダのチェック (TWL専用領域) - - // 値チェック - { - u32 idH; - u8 idL[4]; - int apptype; - const int appUser = 0; - const int appSystem = 1; - const int appSecure = 2; - const int appLauncher = 3; - System::String ^appstrJ = gcnew System::String(""); - System::String ^appstrE = gcnew System::String(""); - - idH = this->pRomHeader->s.titleID_Hi; - memcpy( idL, &(this->pRomHeader->s.titleID_Lo[0]), 4 ); - - if( (idL[3]=='H') && (idL[2]=='N') && (idL[1]=='A') ) // ランチャアプリかどうかはTitleID_Loの値で決定 - { - apptype = appLauncher; - appstrJ = "ランチャーアプリ"; - appstrE = "Launcher-App."; - } - else if( idH & TITLE_ID_HI_SECURE_FLAG_MASK ) // 立ってたらセキュアアプリ - { - apptype = appSecure; - appstrJ = "セキュアアプリ"; - appstrE = "Secure-App."; - } - else if( (idH & TITLE_ID_HI_APP_TYPE_MASK) == 1 ) // 立ってたらシステムアプリ - { - apptype = appSystem; - appstrJ = "システムアプリ"; - appstrE = "System-App."; - } - else if( (idH & TITLE_ID_HI_APP_TYPE_MASK) == 0 ) // 残るはユーザアプリ - { - apptype = appUser; - appstrJ = "ユーザアプリ"; - appstrE = "User-App."; - } - else - { - apptype = -1; - } - - if( apptype < 0 ) - { - this->hWarnList->Add( gcnew RCMrcError( - "アプリ種別", 0x230, 0x237, "不正な値です。", - "Application Type", "Illigal type.", false, true ) ); - } - - System::Boolean bApp = false; -#ifdef METWL_VER_APPTYPE_LAUNCHER - if( apptype == appLauncher ) - { - bApp = true; - } - else -#endif //#ifdef METWL_VER_APPTYPE_LAUNCHER -#ifdef METWL_VER_APPTYPE_SECURE - if( apptype == appSecure ) - { - bApp = true; - } - else -#endif //#ifdef METWL_VER_APPTYPE_SECURE -#ifdef METWL_VER_APPTYPE_SYSTEM - if( apptype == appSystem ) - { - bApp = true; - } - else -#endif //#ifdef METWL_VER_APPTYPE_SYSTEM -#ifdef METWL_VER_APPTYPE_USER - if( apptype == appUser ) - { - bApp = true; - } -#endif //#ifdef METWL_VER_APPTYPE_USER - - if( !bApp ) - { - this->hWarnList->Add( gcnew RCMrcError( - "アプリ種別", 0x230, 0x237, "このROMデータは" + appstrJ + "です。本プログラムでは非対応です。", - "Application Type", "This ROM is " + appstrE + " which is unsurpported by this editor.", false, true ) ); - } - - } // アプリ種別のチェック - - if( this->IsAppLauncher || this->IsAppSecure || this->IsAppSystem ) - { - if( this->pRomHeader->s.access_control.shared2_file == 0 ) - { - if( (this->pRomHeader->s.shared2_file0_size != 0) || (this->pRomHeader->s.shared2_file1_size != 0) || - (this->pRomHeader->s.shared2_file2_size != 0) || (this->pRomHeader->s.shared2_file3_size != 0) || - (this->pRomHeader->s.shared2_file4_size != 0) || (this->pRomHeader->s.shared2_file5_size != 0) ) - { - this->hErrorList->Add( gcnew RCMrcError( - "アクセスコントロール情報", 0x1b4, 0x1b7, "Shared2ファイルのサイズが設定されているにもかかわらず不使用設定になっています。", - "Access Control Info.", "Sizes of shared2 files is setting, but using them is not enabled.", false, true ) ); - } - } - if( (this->pRomHeader->s.access_control.game_card_on != 0) && - (this->pRomHeader->s.access_control.game_card_nitro_mode != 0) ) - { - this->hErrorList->Add( gcnew RCMrcError( - "アクセスコントロール情報", 0x1b4, 0x1b7, "ゲームカードアクセス設定にノーマルモードとNTRモードの両方を設定することはできません。", - "Access Control Info.", "Game card access setting is either normal mode or NTR mode.", false, true ) ); - } - } - else - { - if( this->pRomHeader->s.access_control.sd_card_access != 0 ) - { - this->hErrorList->Add( gcnew RCMrcError( - "アクセスコントロール情報", 0x1b4, 0x1b7, - "SDカードへのアクセスは許可されていません。", - "Access Control Info.", - "Application for Game Card doesn't access to NAND frash memory.", - false, true ) ); - } - if( !this->IsMediaNand ) // カードアプリのときのみ - { - if( this->pRomHeader->s.access_control.nand_access != 0 ) - { - this->hErrorList->Add( gcnew RCMrcError( - "アクセスコントロール情報", 0x1b4, 0x1b7, - "ゲームカード用ソフトは、NANDフラッシュメモリへのアクセスを許可されていません。", - "Access Control Info.", - "Application for Game Card doesn't access to NAND frash memory.", - false, true ) ); - } - } - u32 okbits; - if( !this->IsMediaNand ) - { - okbits = 0x00000008 | 0x00000010; - } - else - { - okbits = 0x00000008 | 0x00000010 | 0x00000400; // NANDアプリのときはJpegSignフラグは許される - } - u32 *p = (u32*)&(this->pRomHeader->s); - if( p[ 0x1b4 / 4 ] & ~okbits ) - { - this->hErrorList->Add( gcnew RCMrcError( - "アクセスコントロール情報", 0x1b4, 0x1b7, - "許可されていないアクセスが設定されています。この設定は許可されていません。", - "Access Control Info.", - "Illegal Access is setting. This setting is unavailable.", - false, true ) ); - } - } - - if( this->IsWL ) - { - this->hErrorList->Add( gcnew RCMrcError( - "TWL拡張諸フラグ", 0x1bf, 0x1bf, - "本来、立つはずのないフラグが立てられています。ビルド時の設定をご確認ください。", - "TWL Extended Flag", - "Unavailable flag is set. Please check building option.", - false, true ) ); - } - - if( this->IsWiFiIcon && this->IsWirelessIcon ) - { - this->hErrorList->Add( gcnew RCMrcError( - "アイコン表示フラグ", 0x1bf, 0x1bf, - "ワイヤレス通信アイコンとWi-Fi通信アイコンは同時に表示できません。", - "Icon Displaying Flag", - "Icon displayed on menu is either Wireless Icon or Wi-Fi Connection Icon.", - false, true ) ); - } - - if( !this->IsMediaNand ) // カードアプリのときのみ - { - u32 ideal = (this->pRomHeader->s.twl_card_keytable_area_rom_offset * 0x80000) + 0x3000; // TWL KeyTable領域の開始 + KeyTableサイズ - u32 actual = this->pRomHeader->s.main_ltd_rom_offset; - if( ideal > actual ) - { - this->hErrorList->Add( gcnew RCMrcError( - "拡張常駐モジュール", 0x1c0, 0x1c3, - "TWL拡張常駐モジュールの配置に問題があります。弊社窓口にご連絡ください。", - "Extended Static Module", - "Alignment of TWL Extended Static Module is illegal. Please contact us, sorry.", - false, true ) ); - } - } - - if( !this->IsAppLauncher && this->IsSCFGAccess ) - { - this->hWarnList->Add( gcnew RCMrcError( - "SCFG設定", 0x1b8, 0x1bb, "SCFGレジスタへアクセス可能になっています。", - "SCFG Setting", "In this setting, SCFG register is accessible.", false, true ) ); - } - - if( (this->pRomHeader->s.titleID_Lo[0] != this->pRomHeader->s.game_code[3]) || - (this->pRomHeader->s.titleID_Lo[1] != this->pRomHeader->s.game_code[2]) || - (this->pRomHeader->s.titleID_Lo[2] != this->pRomHeader->s.game_code[1]) || - (this->pRomHeader->s.titleID_Lo[3] != this->pRomHeader->s.game_code[0]) ) - { - this->hWarnList->Add( gcnew RCMrcError( - "タイトルID", 0x230, 0x233, "下位4バイトがイニシャルコードと一致しません。", - "Title ID", "Lower 4 bytes don't match ones of Game Code.", false, true ) ); - } - - // ROMヘッダ以外の領域のチェック - - this->mrcBanner( fp ); - this->mrcReservedArea(fp); - - for each( RCLicense ^lic in this->hLicenseList ) - { - if( lic->Publisher->Equals( "NINTENDO" ) && lic->Name->Equals( "DEBUG" ) ) - { - this->hErrorList->Add( gcnew RCMrcError( - "Debug/Releaseビルド", METWL_ERRLIST_NORANGE, METWL_ERRLIST_NORANGE, - "FINALROMビルドのROMではありません。必ずFINALROMビルドのROMを作成してご提出ください。", - "Debug/Release Build", - "This ROM isn't FINALROM-build. Please submit a FINALROM-build ROM.", false, true ) ); - } - } - - // 追加チェック - if( this->hMrcSpecialList->IsCheck ) - { - // SDKバージョン - System::Boolean isOld = false; - System::Boolean isPR = false; - System::Boolean isRC = false; - for each( RCSDKVersion ^sdk in this->hSDKList ) - { - if( sdk->IsStatic ) - { - isPR = MasterEditorTWL::IsSDKVersionPR( sdk->Code ); - isRC = MasterEditorTWL::IsSDKVersionRC( sdk->Code ); - isOld = MasterEditorTWL::IsOldSDKVersion( sdk->Code, this->hMrcSpecialList->SDKVer ); - } - } - if( isOld ) - { - this->hWarnList->Add( gcnew RCMrcError( - "SDKバージョン", METWL_ERRLIST_NORANGE, METWL_ERRLIST_NORANGE, "設定ファイルに登録されているバージョンよりも古いバージョンです。", - "SDK Version", "Older version (comparing with a setting file)", false, true ) ); - } - if( isPR ) - { - this->hWarnList->Add( gcnew RCMrcError( - "SDKバージョン", METWL_ERRLIST_NORANGE, METWL_ERRLIST_NORANGE, "ご使用のSDKバージョンはPR版です。", - "SDK Version", "Used version is PR.", false, true ) ); - } - if( isRC ) - { - this->hWarnList->Add( gcnew RCMrcError( - "SDKバージョン", METWL_ERRLIST_NORANGE, METWL_ERRLIST_NORANGE, "ご使用のSDKバージョンはRC版です。", - "SDK Version", "Used version is RC.", false, true ) ); - } - - // Shared2ファイルサイズ - for( i=0; i < METWL_NUMOF_SHARED2FILES; i++ ) - { - if( this->hShared2SizeArray[i] > 0 ) // 0は未使用を表すのでチェックしない - { - if( this->hShared2SizeArray[i] != this->hMrcSpecialList->hShared2SizeArray[i] ) - { - this->hWarnList->Add( gcnew RCMrcError( - "Shared2ファイル" + i.ToString(), METWL_ERRLIST_NORANGE, METWL_ERRLIST_NORANGE, - "本プログラムに登録されているファイルサイズ情報と一致しません。", - "Shared2 file" + i.ToString(), "The size doesn't match one registered in this program.", false, true ) ); - } - } - } - } //if( *(this->hMrcSpecialList->hIsCheck) ) - - return ECSrlResult::NOERROR; -} // mrcTWL() - -// パディングのチェック -void RCSrl::mrcPadding(FILE *fp) -{ - u32 romsize = 1 << (this->pRomHeader->s.rom_size); // ROM容量 - u32 padsize = 0; // 単位はByte - System::String ^padstrJ = gcnew System::String(""); - System::String ^padstrE = gcnew System::String(""); - System::String ^romstr = gcnew System::String(""); - - switch( romsize ) - { - case 1024: - padsize = 0x00280000; // 20Mbit = 2.5MB - padstrJ = "最終20Mbit"; - padstrE = "Last 20Mbit"; - romstr = "1Gbit"; - break; - case 2048: - padsize = 0x00500000; // 40Mbit = 5MB - padstrJ = "最終40Mbit"; - padstrE = "Last 40Mbit"; - romstr = "2Gbit"; - break; - case 4096: - padsize = 0x00A60000; // 83Mbit = 10.375MB - padstrJ = "最終83Mbit"; - padstrE = "Last 83Mbit"; - romstr = "4Gbit"; - break; - default: - padsize = 0; - break; - } - if( padsize == 0 ) - { - return; - } - - fseek( fp, 0, SEEK_END ); - u32 filesize = ftell(fp); // 実ファイルサイズ(単位Mbit) - u32 offset = ((romsize / 8) * 1024 * 1024) - padsize; - if( (offset + padsize) > filesize ) - { - this->hErrorList->Add( gcnew RCMrcError( - padstrJ, METWL_ERRLIST_NORANGE, METWL_ERRLIST_NORANGE, - "読み出すことができませんでした。", - padstrE, "This area couldn't be read", false, true ) ); - return; - } - - u8 *buf = new u8[ padsize ]; - fseek( fp, offset, SEEK_SET ); - if( padsize != fread( buf, 1, padsize, fp ) ) - { - this->hErrorList->Add( gcnew RCMrcError( - padstrJ, METWL_ERRLIST_NORANGE, METWL_ERRLIST_NORANGE, - "読み出すことができませんでした。", - padstrE, "This area couldn't be read", false, true ) ); - delete []buf; - return; - } - - System::Boolean bResult = true; - u32 i; - for( i=0; i < padsize; i++ ) - { - if( buf[i] != 0xff ) - { - bResult = false; - } - } - if( !bResult ) - { - this->hErrorList->Add( gcnew RCMrcError( - padstrJ, METWL_ERRLIST_NORANGE, METWL_ERRLIST_NORANGE, - "FFh以外の値が格納されています。 " + romstr + " ROMの容量制限が守られていません。", - padstrE, - "This area includes illegai data. " + romstr + " Volume constraint is violated.", - false, true ) ); - } - delete []buf; -} - -// 予約領域 -void RCSrl::mrcReservedArea(FILE *fp) -{ - System::Xml::XmlDocument ^doc = gcnew System::Xml::XmlDocument(); - try - { - doc->Load( "../resource/ini.xml" ); - } - catch( System::Exception ^ex ) - { - (void)ex; - this->hErrorList->Add( gcnew RCMrcError( - "予約領域", METWL_ERRLIST_NORANGE, METWL_ERRLIST_NORANGE, - "設定ファイルから予約領域のリストを読み出すことができませんでした。", - "Reserved Area", - "The list of reserved areas is not found in the setting file.", - false, true ) ); - return; - } - - // 設定ファイルから予約領域の情報を読み出す - System::Xml::XmlNodeList ^list = doc->SelectNodes( "/init/reserved-list/reserved" ); - System::Collections::IEnumerator^ iter = list->GetEnumerator(); - while( iter->MoveNext() ) - { - System::Xml::XmlNode ^area = safe_cast(iter->Current); - System::Xml::XmlNode ^begin = area->SelectSingleNode( "begin" ); // 相対パス - System::Xml::XmlNode ^end = area->SelectSingleNode( "end" ); // 相対パス - if( begin && begin->FirstChild && begin->FirstChild->Value && - end && end->FirstChild && end->FirstChild->Value ) - { - System::UInt32 ibeg = System::UInt32::Parse( begin->FirstChild->Value, System::Globalization::NumberStyles::AllowHexSpecifier ); - System::UInt32 iend = System::UInt32::Parse( end->FirstChild->Value, System::Globalization::NumberStyles::AllowHexSpecifier ); - System::UInt32 size = iend - ibeg + 1; - System::UInt32 i; - System::Boolean bReserved = true; - for( i=0; i < size; i++ ) - { - u8 *p = (u8*)this->pRomHeader; - if( p[ ibeg + i ] != 0 ) - { - bReserved = false; - break; - } - } - if( !bReserved ) - { - this->hErrorList->Add( gcnew RCMrcError( - "予約領域", ibeg, iend, "不正な値が含まれています。この領域をすべて0で埋めてください。", - "Reserved Area", "Invalid data is included. Please set 0 into this area.", false, true ) ); - } - - } - } -} - -// バナー -void RCSrl::mrcBanner(FILE *fp) -{ - u8 map[ 0x10000 ]; - u32 i; - - // 本体設定だけはガイドライン無視 - if( memcmp( this->pRomHeader->s.game_code, "HNB", 3 ) == 0 ) - { - //this->hWarnList->Add( gcnew RCMrcError( - // "バナーファイル", METWL_ERRLIST_NORANGE, METWL_ERRLIST_NORANGE, - // "本体設定アプリに限ってはバナーの文字コードチェックをスキップします。", - // "Banner File", - // "Only a machine setting app., a charactor code check of the banner file is skip.", - // false, true ) ); - return; - } - - // バナーオフセットにエラーがあるときには調べない - if( this->pRomHeader->s.banner_offset == 0 ) - { - return; - } - - // 使用可能な文字のマップをつくる - // 文字コードをインデックスとして使用可能なら 1 が入る - // そうでないなら 0 が入る - for( i=0; i < 0x10000; i++ ) - { - map[i] = 0; - } - for( i=2; ; i+=2 ) // 0個目の要素はマジックコードなので含めない - { - u16 index = (u16)gBannerFont[i+1]; - index = (index << 8) + gBannerFont[i]; - if( index == 0xFEFF ) - { - break; - } - map[ index ] = 1; - } - map[ 0x0000 ] = 1; // 0x0000は許される - - // バナーを読み込む - u32 size = this->pRomHeader->s.banner_size; - u8 *banner = new u8[size]; - fseek( fp, this->pRomHeader->s.banner_offset, SEEK_SET ); - if( size != fread( banner, 1, size, fp ) ) - { - this->hErrorList->Add( gcnew RCMrcError( - "バナーファイル", METWL_ERRLIST_NORANGE, METWL_ERRLIST_NORANGE, - "読み出すことができませんでした。", - "Banner File", - "The file can't be read.", - false, true ) ); - } - - // バナーの各文字がマップに登録されているかチェック - System::Boolean bResult = true; - u32 start = 0x240; - u32 end = (size < 0x1240)?(size):(0x1240); // NTR互換領域までのときはTWL拡張領域をサーチしない - for( i=0x240; i < end; i+=2 ) - { - if( (0x840 <= i) && (i < 0xA40) ) // 中韓のフォント箇所はチェックしない - { - continue; - } - u16 index = banner[i+1]; - u16 indexbak = index; - index = (index << 8) + banner[i]; - if( map[ index ] == 0 ) - { - //System::Diagnostics::Debug::WriteLine( i.ToString("X") + ":" + index.ToString("X") + ":" + indexbak.ToString("X") ); - bResult = false; - break; - } - } - if( !bResult ) - { - this->hErrorList->Add( gcnew RCMrcError( - "バナーファイル", METWL_ERRLIST_NORANGE, METWL_ERRLIST_NORANGE, - "使用不可能な文字セットが使用されています。", - "Banner File", - "A set of illegal charactor code is used.", - false, true ) ); - } - delete []banner; -} - -// バナーとして使用可能なフォントリスト(u16リトルエンディアン) -const u8 gBannerFont[] = -{ - 0xff, 0xfe, 0x20, 0x00, 0x21, 0x00, 0x22, 0x00, 0x23, 0x00, 0x24, 0x00, 0x25, 0x00, 0x26, 0x00, - 0x27, 0x00, 0x28, 0x00, 0x29, 0x00, 0x2a, 0x00, 0x2b, 0x00, 0x2c, 0x00, 0x2d, 0x00, 0x2e, 0x00, - 0x2f, 0x00, 0x30, 0x00, 0x31, 0x00, 0x32, 0x00, 0x33, 0x00, 0x34, 0x00, 0x35, 0x00, 0x36, 0x00, - 0x37, 0x00, 0x38, 0x00, 0x39, 0x00, 0x3a, 0x00, 0x3b, 0x00, 0x3c, 0x00, 0x3d, 0x00, 0x3e, 0x00, - 0x3f, 0x00, 0x40, 0x00, 0x41, 0x00, 0x42, 0x00, 0x43, 0x00, 0x44, 0x00, 0x45, 0x00, 0x46, 0x00, - 0x47, 0x00, 0x48, 0x00, 0x49, 0x00, 0x4a, 0x00, 0x4b, 0x00, 0x4c, 0x00, 0x4d, 0x00, 0x4e, 0x00, - 0x4f, 0x00, 0x50, 0x00, 0x51, 0x00, 0x52, 0x00, 0x53, 0x00, 0x54, 0x00, 0x55, 0x00, 0x56, 0x00, - 0x57, 0x00, 0x58, 0x00, 0x59, 0x00, 0x5a, 0x00, 0x5b, 0x00, 0x5c, 0x00, 0x5d, 0x00, 0x5e, 0x00, - 0x5f, 0x00, 0x60, 0x00, 0x61, 0x00, 0x62, 0x00, 0x63, 0x00, 0x64, 0x00, 0x65, 0x00, 0x66, 0x00, - 0x67, 0x00, 0x68, 0x00, 0x69, 0x00, 0x6a, 0x00, 0x6b, 0x00, 0x6c, 0x00, 0x6d, 0x00, 0x6e, 0x00, - 0x6f, 0x00, 0x70, 0x00, 0x71, 0x00, 0x72, 0x00, 0x73, 0x00, 0x74, 0x00, 0x75, 0x00, 0x76, 0x00, - 0x77, 0x00, 0x78, 0x00, 0x79, 0x00, 0x7a, 0x00, 0x7b, 0x00, 0x7c, 0x00, 0x7d, 0x00, 0x7e, 0x00, - 0x7f, 0x00, 0xac, 0x20, 0x1a, 0x20, 0x1e, 0x20, 0x26, 0x20, 0xc6, 0x02, 0x52, 0x01, 0x18, 0x20, - 0x19, 0x20, 0x1c, 0x20, 0x1d, 0x20, 0x22, 0x20, 0xdc, 0x02, 0x22, 0x21, 0x3a, 0x20, 0x53, 0x01, - 0xa1, 0x00, 0xa2, 0x00, 0xa3, 0x00, 0xa8, 0x00, 0xa9, 0x00, 0xae, 0x00, 0xb7, 0x00, 0xbf, 0x00, - 0xc0, 0x00, 0xc1, 0x00, 0xc2, 0x00, 0xc3, 0x00, 0xc4, 0x00, 0xc5, 0x00, 0xc6, 0x00, 0xc7, 0x00, - 0xc8, 0x00, 0xc9, 0x00, 0xca, 0x00, 0xcb, 0x00, 0xcc, 0x00, 0xcd, 0x00, 0xce, 0x00, 0xcf, 0x00, - 0xd0, 0x00, 0xd1, 0x00, 0xd2, 0x00, 0xd3, 0x00, 0xd4, 0x00, 0xd5, 0x00, 0xd6, 0x00, 0xd8, 0x00, - 0xd9, 0x00, 0xda, 0x00, 0xdb, 0x00, 0xdc, 0x00, 0xdd, 0x00, 0xdf, 0x00, 0xe0, 0x00, 0xe1, 0x00, - 0xe2, 0x00, 0xe3, 0x00, 0xe4, 0x00, 0xe5, 0x00, 0xe6, 0x00, 0xe7, 0x00, 0xe8, 0x00, 0xe9, 0x00, - 0xea, 0x00, 0xeb, 0x00, 0xec, 0x00, 0xed, 0x00, 0xee, 0x00, 0xef, 0x00, 0xf0, 0x00, 0xf1, 0x00, - 0xf2, 0x00, 0xf3, 0x00, 0xf4, 0x00, 0xf5, 0x00, 0xf6, 0x00, 0xf7, 0x00, 0xf8, 0x00, 0xf9, 0x00, - 0xfa, 0x00, 0xfb, 0x00, 0xfc, 0x00, 0xfd, 0x00, 0x00, 0x30, 0x01, 0x30, 0x02, 0x30, 0x0c, 0xff, - 0x0e, 0xff, 0xfb, 0x30, 0x3a, 0x00, 0x3b, 0x00, 0x1f, 0xff, 0x01, 0xff, 0xfc, 0x30, 0x41, 0x30, - 0x42, 0x30, 0x43, 0x30, 0x44, 0x30, 0x45, 0x30, 0x46, 0x30, 0x47, 0x30, 0x48, 0x30, 0x49, 0x30, - 0x4a, 0x30, 0x4b, 0x30, 0x4c, 0x30, 0x4d, 0x30, 0x4e, 0x30, 0x4f, 0x30, 0x50, 0x30, 0x51, 0x30, - 0x52, 0x30, 0x53, 0x30, 0x54, 0x30, 0x55, 0x30, 0x56, 0x30, 0x57, 0x30, 0x58, 0x30, 0x59, 0x30, - 0x5a, 0x30, 0x5b, 0x30, 0x5c, 0x30, 0x5d, 0x30, 0x5e, 0x30, 0x5f, 0x30, 0x60, 0x30, 0x61, 0x30, - 0x62, 0x30, 0x63, 0x30, 0x64, 0x30, 0x65, 0x30, 0x66, 0x30, 0x67, 0x30, 0x68, 0x30, 0x69, 0x30, - 0x6a, 0x30, 0x6b, 0x30, 0x6c, 0x30, 0x6d, 0x30, 0x6e, 0x30, 0x6f, 0x30, 0x70, 0x30, 0x71, 0x30, - 0x72, 0x30, 0x73, 0x30, 0x74, 0x30, 0x75, 0x30, 0x76, 0x30, 0x77, 0x30, 0x78, 0x30, 0x79, 0x30, - 0x7a, 0x30, 0x7b, 0x30, 0x7c, 0x30, 0x7d, 0x30, 0x7e, 0x30, 0x7f, 0x30, 0x80, 0x30, 0x81, 0x30, - 0x82, 0x30, 0x83, 0x30, 0x84, 0x30, 0x85, 0x30, 0x86, 0x30, 0x87, 0x30, 0x88, 0x30, 0x89, 0x30, - 0x8a, 0x30, 0x8b, 0x30, 0x8c, 0x30, 0x8d, 0x30, 0x8e, 0x30, 0x8f, 0x30, 0x90, 0x30, 0x91, 0x30, - 0x92, 0x30, 0x93, 0x30, 0x9b, 0x30, 0x9c, 0x30, 0x9d, 0x30, 0x9e, 0x30, 0xa1, 0x30, 0xa2, 0x30, - 0xa3, 0x30, 0xa4, 0x30, 0xa5, 0x30, 0xa6, 0x30, 0xa7, 0x30, 0xa8, 0x30, 0xa9, 0x30, 0xaa, 0x30, - 0xab, 0x30, 0xac, 0x30, 0xad, 0x30, 0xae, 0x30, 0xaf, 0x30, 0xb0, 0x30, 0xb1, 0x30, 0xb2, 0x30, - 0xb3, 0x30, 0xb4, 0x30, 0xb5, 0x30, 0xb6, 0x30, 0xb7, 0x30, 0xb8, 0x30, 0xb9, 0x30, 0xba, 0x30, - 0xbb, 0x30, 0xbc, 0x30, 0xbd, 0x30, 0xbe, 0x30, 0xbf, 0x30, 0xc0, 0x30, 0xc1, 0x30, 0xc2, 0x30, - 0xc3, 0x30, 0xc4, 0x30, 0xc5, 0x30, 0xc6, 0x30, 0xc7, 0x30, 0xc8, 0x30, 0xc9, 0x30, 0xca, 0x30, - 0xcb, 0x30, 0xcc, 0x30, 0xcd, 0x30, 0xce, 0x30, 0xcf, 0x30, 0xd0, 0x30, 0xd1, 0x30, 0xd2, 0x30, - 0xd3, 0x30, 0xd4, 0x30, 0xd5, 0x30, 0xd6, 0x30, 0xd7, 0x30, 0xd8, 0x30, 0xd9, 0x30, 0xda, 0x30, - 0xdb, 0x30, 0xdc, 0x30, 0xdd, 0x30, 0xde, 0x30, 0xdf, 0x30, 0xe0, 0x30, 0xe1, 0x30, 0xe2, 0x30, - 0xe3, 0x30, 0xe4, 0x30, 0xe5, 0x30, 0xe6, 0x30, 0xe7, 0x30, 0xe8, 0x30, 0xe9, 0x30, 0xea, 0x30, - 0xeb, 0x30, 0xec, 0x30, 0xed, 0x30, 0xee, 0x30, 0xef, 0x30, 0xf0, 0x30, 0xf1, 0x30, 0xf2, 0x30, - 0xf3, 0x30, 0xf4, 0x30, 0xf5, 0x30, 0xf6, 0x30, 0x01, 0x30, 0x02, 0x30, 0x0c, 0xff, 0x0e, 0xff, - 0xfb, 0x30, 0x1a, 0xff, 0x1b, 0xff, 0x1f, 0xff, 0x01, 0xff, 0x9b, 0x30, 0x9c, 0x30, 0xb4, 0x00, - 0x40, 0xff, 0x3e, 0xff, 0xe3, 0xff, 0x3f, 0xff, 0x05, 0x30, 0xfc, 0x30, 0x15, 0x20, 0x10, 0x20, - 0x0f, 0xff, 0x3c, 0xff, 0x5e, 0xff, 0x5c, 0xff, 0x26, 0x20, 0x18, 0x20, 0x19, 0x20, 0x1c, 0x20, - 0x1d, 0x20, 0x08, 0xff, 0x09, 0xff, 0x14, 0x30, 0x15, 0x30, 0x3b, 0xff, 0x3d, 0xff, 0x5b, 0xff, - 0x5d, 0xff, 0x08, 0x30, 0x09, 0x30, 0x0c, 0x30, 0x0d, 0x30, 0x0b, 0xff, 0x0d, 0xff, 0xb1, 0x00, - 0xd7, 0x00, 0xf7, 0x00, 0x1d, 0xff, 0x1e, 0x22, 0x34, 0x22, 0xb0, 0x00, 0x32, 0x20, 0x33, 0x20, - 0x06, 0xff, 0x06, 0x26, 0x05, 0x26, 0xcb, 0x25, 0xcf, 0x25, 0xce, 0x25, 0xc7, 0x25, 0xc6, 0x25, - 0xa1, 0x25, 0xa0, 0x25, 0xb3, 0x25, 0xb2, 0x25, 0xbd, 0x25, 0xbc, 0x25, 0x3b, 0x20, 0x12, 0x30, - 0x92, 0x21, 0x90, 0x21, 0x91, 0x21, 0x93, 0x21, 0x6f, 0x26, 0x6d, 0x26, 0x6a, 0x26, 0x0a, 0x00, - 0xff, 0xfe, // 終わりを表す意味で0xFEFFを最後につける -}; diff --git a/build/tools/MasterEditor/MasterEditorTWL/MasterEditorTWL/srl.h b/build/tools/MasterEditor/MasterEditorTWL/MasterEditorTWL/srl.h index 4af116f..831c804 100644 --- a/build/tools/MasterEditor/MasterEditorTWL/MasterEditorTWL/srl.h +++ b/build/tools/MasterEditor/MasterEditorTWL/MasterEditorTWL/srl.h @@ -217,32 +217,68 @@ namespace MasterEditorTWL }; // ------------------------------------------------------------------- - // Type : ref class - // Name : RCMrcSpecialList + // Type : value class + // Name : VCReservedArea // - // Description : MRCの追加エラー項目クラス + // Description : 予約領域の範囲クラス // // Role : 構造体としてデータをまとめておく // ------------------------------------------------------------------- - ref class RCMrcSpecialList + value class VCReservedArea + { + private: + System::UInt32 begin; + System::UInt32 end; + public: + VCReservedArea( System::UInt32 begin, System::UInt32 end ) + { + this->begin = begin; + this->end = end; + } + public: + property System::UInt32 Begin // read only + { + System::UInt32 get(){ return this->begin; } + } + property System::UInt32 End + { + System::UInt32 get(){ return this->end; } + } + }; + + // ------------------------------------------------------------------- + // Type : ref class + // Name : RCMrcExternalCheckItems + // + // Description : MRCチェック項目の外部パラメータクラス + // + // Role : 構造体としてデータをまとめておく + // ------------------------------------------------------------------- + ref class RCMrcExternalCheckItems { public: - property System::Boolean IsCheck; - property System::UInt32 SDKVer; - property System::Byte EULAVer; - property cli::array ^hShared2SizeArray; + property System::Boolean IsAppendCheck; // 追加チェックをするかどうか(すべての項目が追加チェックとは限らない) + property System::UInt32 SDKVer; // SDKのバージョン + property System::Boolean IsPermitNormalJump; // ノーマルジャンプがアクセス許可されているか + property cli::array ^hIsPermitShared2Array; // Shared2ファイルアクセスが許可されているか + property cli::array ^hShared2SizeArray; // Shared2ファイルサイズ + property System::Collections::Generic::List ^hReservedAreaList; // 予約領域の範囲 public: - RCMrcSpecialList() + RCMrcExternalCheckItems() { - this->IsCheck = false; - this->SDKVer = 0; - this->EULAVer = 0; - this->hShared2SizeArray = gcnew cli::array(METWL_NUMOF_SHARED2FILES); // ファイルサイズの数に合わせる + this->IsAppendCheck = false; + this->SDKVer = 0; + this->IsPermitNormalJump = false; + this->hIsPermitShared2Array = gcnew cli::array(METWL_NUMOF_SHARED2FILES); + this->hShared2SizeArray = gcnew cli::array(METWL_NUMOF_SHARED2FILES); System::Int32 i; for( i=0; i < METWL_NUMOF_SHARED2FILES; i++ ) { - this->hShared2SizeArray[i] = 0; + this->hIsPermitShared2Array[i] = false; + this->hShared2SizeArray[i] = 0; } + this->hReservedAreaList = gcnew System::Collections::Generic::List; + this->hReservedAreaList->Clear(); } }; @@ -340,7 +376,7 @@ namespace MasterEditorTWL property System::Collections::Generic::List ^hParentalErrorList; // ペアレンタルコントロールのチェックはsetと同時に行なう // MRC追加項目 - property RCMrcSpecialList ^hMrcSpecialList; + property RCMrcExternalCheckItems ^hMrcExternalCheckItems; // constructor / destructor / finalizer public: @@ -389,9 +425,13 @@ namespace MasterEditorTWL ECSrlResult mrc( FILE *fp ); ECSrlResult mrcNTR( FILE *fp ); ECSrlResult mrcTWL( FILE *fp ); + void mrcAppType( FILE *fp ); + void mrcAccessControl( FILE *fp ); void mrcPadding( FILE *fp ); void mrcBanner( FILE *fp ); void mrcReservedArea( FILE *fp ); + void mrcShared2( FILE *fp ); + void mrcSDKVersion( FILE *fp ); }; // end of ref class RCSrl diff --git a/build/tools/MasterEditor/MasterEditorTWL/MasterEditorTWL/srl_mrc.cpp b/build/tools/MasterEditor/MasterEditorTWL/MasterEditorTWL/srl_mrc.cpp new file mode 100644 index 0000000..64fbd25 --- /dev/null +++ b/build/tools/MasterEditor/MasterEditorTWL/MasterEditorTWL/srl_mrc.cpp @@ -0,0 +1,1037 @@ +// srl.h のクラス実装 + +#include "stdafx.h" +#include +#include "common.h" +#include "srl.h" +#include "utility.h" +#include "keys.h" +#include "crc_whole.h" +#include +#include +#include +#include + +using namespace MasterEditorTWL; + +extern const u8 gBannerFont[]; +extern u16 calcCRC( const u16 start, const u8 *data, const int allsize ); + +// **************************************************************** +// RCSrl クラスの MRC 機能を別ファイルに独立させた +// **************************************************************** + +// ------------------------------------------------------------------- +// MRC本体 +// ------------------------------------------------------------------- +ECSrlResult RCSrl::mrc( FILE *fp ) +{ +#ifdef METWL_WHETHER_MRC + ECSrlResult result; + result = this->mrcNTR( fp ); + if( result != ECSrlResult::NOERROR ) + { + return result; + } + result = this->mrcTWL( fp ); + if( result != ECSrlResult::NOERROR ) + { + return result; + } + this->hErrorList->AddRange( this->hParentalErrorList ); // ペアレンタルコントロールのリストは別につくっているので追加 +#endif + return ECSrlResult::NOERROR; +} + +// ------------------------------------------------------------------- +// NTR互換MRC +// ------------------------------------------------------------------- +ECSrlResult RCSrl::mrcNTR( FILE *fp ) +{ + System::Int32 i; + System::Boolean result; + + // ROMヘッダのチェック + + // 文字コードチェック + result = true; + for( i=0; i < TITLE_NAME_MAX; i++ ) + { + char c = this->pRomHeader->s.title_name[i]; + if( ((c < 0x20) || (0x5f < c)) && (c != 0x00) ) + { + result = false; + } + } + if( !result ) + { + this->hErrorList->Add( gcnew RCMrcError( + "ソフトタイトル", 0x0, 0xb, "使用不可のASCIIコードが使用されています。", + "Game Title", "Unusable ASCII code is used.", false, true ) ); + } + + result = true; + for( i=0; i < TITLE_NAME_MAX; i++ ) + { + char c = this->pRomHeader->s.title_name[TITLE_NAME_MAX - i - 1]; // 末尾から探索 + if( ((0x21 <= c ) && (c <= 0x5f)) || (c == 0x00) ) // 00hと20h以外の使用可能な文字が出てくるまでにスペースが存在したらダメ + { + break; + } + else if( c == 0x20 ) + { + result = false; + } + } + if( !result ) + { + this->hErrorList->Add( gcnew RCMrcError( + "ソフトタイトル", 0x0, 0xb, "末尾の未使用部分には00hを登録してください。", + "Game Title", "Please use 00h for an unused part.", false, true ) ); + } + + result = true; + for( i=1; i < TITLE_NAME_MAX; i++ ) + { + char prev = this->pRomHeader->s.title_name[i-1]; + char curr = this->pRomHeader->s.title_name[i]; + if( (prev == 0x00) && (0x21 <= curr) && (curr <= 0x5f) ) // 途中に00hがあるとダメ + { + result = false; + break; + } + } + if( !result ) + { + this->hErrorList->Add( gcnew RCMrcError( + "ソフトタイトル", 0x0, 0xb, "スペース部分には20hを登録してください。", + "Game Title", "Please use 20h for an space part.", false, true ) ); + } + + result = true; + for( i=0; i < GAME_CODE_MAX; i++ ) + { + char c = this->pRomHeader->s.game_code[i]; + if( (c < 0x20) || (0x5f < c) ) // 00hを許さない + { + result = false; + } + } + if( !result ) + { + this->hErrorList->Add( gcnew RCMrcError( + "イニシャルコード", 0xc, 0xf, "使用不可のASCIIコードが使用されています。", + "Game Code", "Unusable ASCII code is used.", false, true ) ); + } + if( memcmp( this->pRomHeader->s.game_code, "NTRJ", GAME_CODE_MAX ) == 0 ) + { + this->hErrorList->Add( gcnew RCMrcError( + "イニシャルコード", 0xc, 0xf, "SDKデフォルトのコード(NTRJ)が使用されています。", + "Game Code", "SDK default code(NTRJ) is used.", false, true ) ); + } + + result = true; + for( i=0; i < MAKER_CODE_MAX; i++ ) + { + char c = this->pRomHeader->s.maker_code[i]; + if( (c < 0x20) || (0x5f < c) ) + { + result = false; + } + } + if( !result ) + { + this->hErrorList->Add( gcnew RCMrcError( + "メーカーコード", 0x10, 0x11, "使用不可のASCIIコードが使用されています。", + "Maker Code", "Unusable ASCII code is used.", false, true ) ); + } + + // 値チェック + + if( this->pRomHeader->s.rom_type != 0x00 ) + { + this->hErrorList->Add( gcnew RCMrcError( + "デバイスタイプ", 0x13, 0x13, "不正な値です。00hを設定してください。", + "Device Type", "Invalid data. Please set 00h.", false, true ) ); + } + + u8 romver = this->pRomHeader->s.rom_version; + if( ((romver < 0x00) || (0x0f < romver)) && (romver != 0xE0) ) + { + this->hErrorList->Add( gcnew RCMrcError( + "リマスターバージョン", 0x1e, 0x1e, "不正な値です。正式版では01h-0Fhのいずれかの値、事前版ではE0hを設定してください。", + "Release Ver.", "Invalid data. Please set either one of 01h-0Fh(Regular ver.), or E0h(Preliminary ver.)", false, true ) ); + } + if( this->pRomHeader->s.banner_offset == 0 ) + { + this->hErrorList->Add( gcnew RCMrcError( + "バナーオフセット", 0x68, 0x6b, "バナーデータが設定されていません。", + "Banner Offset.", "Banner data is not set.", false, true ) ); + } + if( this->pRomHeader->s.rom_valid_size == 0 ) + { + this->hErrorList->Add( gcnew RCMrcError( + "ROM実効サイズ", 0x80, 0x83, "値が設定されていません。", + "ROM Valid Size.", "Data is not set.", false, true ) ); + } + + // CRC + u16 crc; + // セキュア領域 + if( !this->IsMediaNand ) // カードアプリのときのみ + { + // セキュア領域はROMヘッダ外 + u8 *secures; + s32 secure_size = SECURE_AREA_END - this->pRomHeader->s.main_rom_offset; + if (secure_size > SECURE_AREA_SIZE) + { + secure_size = SECURE_AREA_SIZE; + } + if (secure_size <= 0) + { + this->hErrorList->Add( gcnew RCMrcError( + "セキュア領域CRC", 0x15e, 0x15f, "セキュア領域のアドレス指定が不正です。", + "Secure Area CRC.", "Illegal address of secure area.", false, true ) ); + } + secures = new u8[secure_size]; // never return if not allocated + fseek( fp, (u32)this->pRomHeader->s.main_rom_offset, SEEK_SET ); + if( secure_size != fread( secures, 1, secure_size, fp ) ) + { + delete []secures; + return ECSrlResult::ERROR_FILE_READ; + } + crc = calcCRC(CRC16_INIT_VALUE, (u8 *)secures, secure_size); + delete []secures; + if( crc != this->pRomHeader->s.secure_area_crc16 ) + { + this->hErrorList->Add( gcnew RCMrcError( + "セキュア領域CRC", 0x07c, 0x07d, "計算結果と一致しません。セキュア領域が改ざんされた可能性があります。", + "Secure Area CRC.", "Calclated CRC is different from Registered one.", false, true ) ); + } + } + + // ロゴ領域 + crc = 0xcf56; + if( crc != this->pRomHeader->s.nintendo_logo_crc16 ) + { + this->hErrorList->Add( gcnew RCMrcError( + "キャラクターデータCRC", 0x15c, 0x15d, "計算結果と一致しません。キャラクターデータが改ざんされた可能性があります。", + "Charactor Data CRC.", "Calclated CRC is different from Registered one.", false, true ) ); + } + + // ヘッダCRC + crc = calcCRC( CRC16_INIT_VALUE, (u8*)this->pRomHeader, CALC_CRC16_SIZE ); + if( crc != this->pRomHeader->s.header_crc16 ) + { + this->hErrorList->Add( gcnew RCMrcError( + "ROMヘッダCRC", 0x15e, 0x15f, "計算結果と一致しません。ROMヘッダが改ざんされた可能性があります。", + "ROM Header CRC.", "Calclated CRC is different from Registered one.", false, true ) ); + } + + // ROMヘッダ以外の領域のチェック (ファイルから適宜リードする) + + // システムコールライブラリ + u8 syscall[32]; + u32 offset = this->pRomHeader->s.main_rom_offset; + fseek( fp, offset, SEEK_SET ); + if( 32 != fread( syscall, 1, 32, fp ) ) + { + return ECSrlResult::ERROR_FILE_READ; + } + for( i=0; i < 32; i++ ) + { + if( syscall[i] != 0x00 ) + break; + } + if( i == 32 ) // 全部0 + { + this->hErrorList->Add( gcnew RCMrcError( + "システムコールライブラリ", METWL_ERRLIST_NORANGE, METWL_ERRLIST_NORANGE, "SDKデフォルトです。", + "System-Call Library", "This Library is SDK default one.", false, true ) ); + } + return ECSrlResult::NOERROR; +} // mrcNTR() + +// ------------------------------------------------------------------- +// TWL専用MRC +// ------------------------------------------------------------------- +ECSrlResult RCSrl::mrcTWL( FILE *fp ) +{ + // ROMヘッダのチェック (NTR互換領域) + +#ifdef METWL_WHETHER_PLATFORM_CHECK + // プラットフォームのチェック + if( (this->pRomHeader->s.platform_code != PLATFORM_CODE_TWL_HYBLID) && + (this->pRomHeader->s.platform_code != PLATFORM_CODE_TWL_LIMITED) && + (this->pRomHeader->s.enable_signature == 0) ) + { + return ECSrlResult::ERROR_PLATFORM; + } +#endif + + if( this->IsOldDevEncrypt && this->HasDSDLPlaySign ) + { + this->hErrorList->Add( gcnew RCMrcError( + "旧開発用暗号フラグ", 0x1c, 0x1c, + "このROMはクローンブート対応アプリですが、製品用本体ではクローンブートができなくなります。", + "Old Development Flag", + "This ROM supports Clone-Boot, and the flag is old type. Therefore, Clone-Boot can't be done.", + false, true ) ); + } + + // 値チェック + + fseek( fp, 0, SEEK_END ); + u32 filesize = ftell(fp); // 実ファイルサイズ + u32 romsize = 1 << (this->pRomHeader->s.rom_size); // ROM容量(単位Mbit) + if( !this->IsMediaNand ) // カードアプリのときのみのチェック + { + u32 filesizeMb = (filesize / (1024*1024)) * 8; // 単位をMbitに直す + if( romsize < filesizeMb ) + { + this->hErrorList->Add( gcnew RCMrcError( + "デバイス容量", 0x14, 0x14, "実ファイルサイズよりも小さい値が指定されています。", + "Device Capacity", "Setting data is less than the actual file size.", false, true ) ); + } + else if( filesizeMb < romsize ) + { + this->hWarnList->Add( gcnew RCMrcError( // 警告 + "デバイス容量", 0x14, 0x14, "実ファイルサイズに比べて無駄のある値が設定されています。", + "Device Capacity", "Setting data is larger than the actual file size.", false, true ) ); + } + if( (romsize < METWL_ROMSIZE_MIN) || (METWL_ROMSIZE_MAX < romsize) ) + { + this->hErrorList->Add( gcnew RCMrcError( + "デバイス容量", 0x14, 0x14, "指定可能な容量ではありません。", + "Device Capacity", "Invalid capacity.", false, true ) ); + } + if( (filesizeMb < 1) || (MasterEditorTWL::countBits(filesizeMb) != 1) ) + { + this->hWarnList->Add( gcnew RCMrcError( + "実ファイルサイズ", METWL_ERRLIST_NORANGE, METWL_ERRLIST_NORANGE, "中途半端な値です。通常では2のべき乗[Mbit]の値です。", + "Actual File Size", "Invalid size. This size is usually power of 2.", false, true ) ); + } + // 1Gbit以上のときの最終領域が固定値かどうか + this->mrcPadding( fp ); + + // セグメント3のCRC + u16 crcseg3; + BOOL crcret = getSeg3CRCInFp( fp, &crcseg3 ); + if( !crcret || (crcseg3 != METWL_SEG3_CRC) ) + { + this->hErrorList->Add( gcnew RCMrcError( + "セグメント3 CRC", METWL_ERRLIST_NORANGE, METWL_ERRLIST_NORANGE, + "セグメント3領域に誤りがあります。", + "Segment-3 CRC", "Invalid data exist in Segment-3 area.", false, true ) ); + } + + u16 NA = this->pRomHeader->s.twl_card_normal_area_rom_offset & 0x7fffUL; + u16 KA = this->pRomHeader->s.twl_card_keytable_area_rom_offset; + if( (NA == 0) || (KA == 0) || (NA > KA) ) + { + this->hErrorList->Add( gcnew RCMrcError( + "TWL ROMオフセット", 0x90, 0x93, + "TWLノーマル領域ROMオフセット(NA)およびTWL専用領域ROMオフセット(KA)はともに1以上で、かつNAはKAを超えてはいけません。", + "TWL ROM Offset", + "Both TWL Normal Area ROM Offset(NA) and TWL Limited Area ROM Offset(KA) are bigger than 0. And NA must be smaller than KA, or equals to KA.", + false, true ) ); + } + } //if( *(this->hIsNAND) == false ) + else // NANDアプリのときのみのチェック + { + if( (romsize < METWL_ROMSIZE_MIN_NAND) || (METWL_ROMSIZE_MAX_NAND < romsize) ) + { + this->hErrorList->Add( gcnew RCMrcError( + "デバイス容量", 0x14, 0x14, "NANDアプリに対して指定可能な容量ではありません。", + "Device Capacity", "Invalid capacity.", false, true ) ); + } + u32 allsize = filesize + this->pRomHeader->s.public_save_data_size + this->pRomHeader->s.private_save_data_size; + if( allsize > METWL_ALLSIZE_MAX_NAND ) + { + this->hErrorList->Add( gcnew RCMrcError( + "実ファイルサイズ", METWL_ERRLIST_NORANGE, METWL_ERRLIST_NORANGE, + "ROMデータの実ファイルサイズとPublicセーブデータおよびPrivateセーブデータのサイズの総和が32MByteを超えています。", + "Actual File Size", + "The sum of this size, the public save data size and private save data size exceed 32MByte.", false, true ) ); + } + } + + if( this->IsAppLauncher || this->IsAppSecure || this->IsAppSystem ) + { + if( this->pRomHeader->s.disable_debug == 0 ) + { + this->hWarnList->Add( gcnew RCMrcError( + "デバッガ動作禁止フラグ", 0x1f, 0x1f, + "デバッガ上で解析可能な設定になっています。デバッガ向けソフトとしてROMをリリースする場合にはセキュリティ上の問題がないかご確認ください。", + "Disable Launch on Debugger Flag", + "This ROM can be analyzed on the debugger. If the ROM is released for the debugger, please check the security settings.", + false, true ) ); + } + } + else // ユーザのときのみ + { + if( this->pRomHeader->s.disable_debug != 0 ) + { + this->hErrorList->Add( gcnew RCMrcError( + "デバッガ動作禁止フラグ", 0x1f, 0x1f, + "デバッガ上で解析不可な設定になっています。この設定は許可されていません。", + "Disable Launch on Debugger Flag", + "This ROM can't be analyzed on the debugger. This setting is unavailable.", + false, true ) ); + } + + u8 okbits = 0x02 | 0x40 | 0x80; + u8 *p = (u8*)&(this->pRomHeader->s); + if( p[0x1d] & ~okbits ) + { + this->hErrorList->Add( gcnew RCMrcError( + "特定仕向地", 0x1d, 0x1d, + "不正なビットが立っています。この設定は許可されていません。", + "Extra Region Code", + "Illegal bit is setting. This setting is unavailable.", + false, true ) ); + } + } + + if( this->pRomHeader->s.warning_no_spec_rom_speed != 0 ) + { + this->hWarnList->Add( gcnew RCMrcError( + "諸フラグ", 0x1f, 0x1f, "rsfファイルでROMSpeedTypeが設定されていません。", + "Setting Flags", "In a RSF file, the item \"ROMSpeedType\" is not set.", false, true ) ); + } + if( (this->pRomHeader->s.game_cmd_param & CARD_LATENCY_MASK) != CARD_1TROM_GAME_LATENCY ) + { + this->hErrorList->Add( gcnew RCMrcError( + "ROMコントロール情報", 0x60, 0x67, "TWLではマスクROMは用意されていません。ワンタイムPROM設定にしてください。", + "ROM Control Info.", "Mask ROM can be set. Please set One-time PROM.", false, true ) ); + } + + if( !this->IsMediaNand ) + { + if( (this->pRomHeader->s.enable_aes == 0) || (this->pRomHeader->s.aes_target_size == 0) ) + { + this->hErrorList->Add( gcnew RCMrcError( + "AES暗号", 0x60, 0x67, "AES暗号が無効になっています。セキュリティ上の問題があります。", + "AES Encryption", "AES Encryption is disable. It is a security problem.", false, true ) ); + } + } + else // NANDアプリ + { + if( (this->pRomHeader->s.enable_aes == 0) || (this->pRomHeader->s.aes_target_size == 0) || (this->pRomHeader->s.aes_target2_size == 0) ) + { + this->hErrorList->Add( gcnew RCMrcError( + "AES暗号", 0x60, 0x67, "AES暗号が無効になっています。セキュリティ上の問題があります。", + "AES Encryption", "AES Encryption is disable. It is a security problem.", false, true ) ); + } + } + + // ROMヘッダのチェック (TWL専用領域) + + // アプリ種別のチェック + this->mrcAppType(fp); + + // 各種デバイスへのアクセスフラグのチェック + this->mrcAccessControl(fp); + this->mrcShared2(fp); + + if( this->IsWL ) + { + this->hErrorList->Add( gcnew RCMrcError( + "TWL拡張諸フラグ", 0x1bf, 0x1bf, + "本来、立つはずのないフラグが立てられています。ビルド時の設定をご確認ください。", + "TWL Extended Flag", + "Unavailable flag is set. Please check building option.", + false, true ) ); + } + + if( this->IsWiFiIcon && this->IsWirelessIcon ) + { + this->hErrorList->Add( gcnew RCMrcError( + "アイコン表示フラグ", 0x1bf, 0x1bf, + "ワイヤレス通信アイコンとWi-Fi通信アイコンは同時に表示できません。", + "Icon Displaying Flag", + "Icon displayed on menu is either Wireless Icon or Wi-Fi Connection Icon.", + false, true ) ); + } + + if( !this->IsMediaNand ) // カードアプリのときのみ + { + u32 ideal = (this->pRomHeader->s.twl_card_keytable_area_rom_offset * 0x80000) + 0x3000; // TWL KeyTable領域の開始 + KeyTableサイズ + u32 actual = this->pRomHeader->s.main_ltd_rom_offset; + if( ideal > actual ) + { + this->hErrorList->Add( gcnew RCMrcError( + "拡張常駐モジュール", 0x1c0, 0x1c3, + "TWL拡張常駐モジュールの配置に問題があります。弊社窓口にご連絡ください。", + "Extended Static Module", + "Alignment of TWL Extended Static Module is illegal. Please contact us, sorry.", + false, true ) ); + } + } + + if( !this->IsAppLauncher && this->IsSCFGAccess ) + { + this->hWarnList->Add( gcnew RCMrcError( + "SCFG設定", 0x1b8, 0x1bb, "SCFGレジスタへアクセス可能になっています。", + "SCFG Setting", "In this setting, SCFG register is accessible.", false, true ) ); + } + + if( (this->pRomHeader->s.titleID_Lo[0] != this->pRomHeader->s.game_code[3]) || + (this->pRomHeader->s.titleID_Lo[1] != this->pRomHeader->s.game_code[2]) || + (this->pRomHeader->s.titleID_Lo[2] != this->pRomHeader->s.game_code[1]) || + (this->pRomHeader->s.titleID_Lo[3] != this->pRomHeader->s.game_code[0]) ) + { + this->hWarnList->Add( gcnew RCMrcError( + "タイトルID", 0x230, 0x233, "下位4バイトがイニシャルコードと一致しません。", + "Title ID", "Lower 4 bytes don't match ones of Game Code.", false, true ) ); + } + + // ROMヘッダ以外の領域のチェック + + this->mrcBanner( fp ); + this->mrcReservedArea(fp); + + for each( RCLicense ^lic in this->hLicenseList ) + { + if( lic->Publisher->Equals( "NINTENDO" ) && lic->Name->Equals( "DEBUG" ) ) + { + this->hErrorList->Add( gcnew RCMrcError( + "Debug/Releaseビルド", METWL_ERRLIST_NORANGE, METWL_ERRLIST_NORANGE, + "FINALROMビルドのROMではありません。必ずFINALROMビルドのROMを作成してご提出ください。", + "Debug/Release Build", + "This ROM isn't FINALROM-build. Please submit a FINALROM-build ROM.", false, true ) ); + } + } + + // 追加チェック + if( this->hMrcExternalCheckItems->IsAppendCheck ) + { + this->mrcSDKVersion(fp); + } //if( *(this->hMrcExternalCheckItems->hIsCheck) ) + + return ECSrlResult::NOERROR; +} // mrcTWL() + +// ------------------------------------------------------------------- +// アプリ種別のチェック +// ------------------------------------------------------------------- +void RCSrl::mrcAppType(FILE *fp) +{ + u32 idH; + u8 idL[4]; + int apptype; + const int appUser = 0; + const int appSystem = 1; + const int appSecure = 2; + const int appLauncher = 3; + System::String ^appstrJ = gcnew System::String(""); + System::String ^appstrE = gcnew System::String(""); + + idH = this->pRomHeader->s.titleID_Hi; + memcpy( idL, &(this->pRomHeader->s.titleID_Lo[0]), 4 ); + + if( (idL[3]=='H') && (idL[2]=='N') && (idL[1]=='A') ) // ランチャアプリかどうかはTitleID_Loの値で決定 + { + apptype = appLauncher; + appstrJ = "ランチャーアプリ"; + appstrE = "Launcher-App."; + } + else if( idH & TITLE_ID_HI_SECURE_FLAG_MASK ) // 立ってたらセキュアアプリ + { + apptype = appSecure; + appstrJ = "セキュアアプリ"; + appstrE = "Secure-App."; + } + else if( (idH & TITLE_ID_HI_APP_TYPE_MASK) == 1 ) // 立ってたらシステムアプリ + { + apptype = appSystem; + appstrJ = "システムアプリ"; + appstrE = "System-App."; + } + else if( (idH & TITLE_ID_HI_APP_TYPE_MASK) == 0 ) // 残るはユーザアプリ + { + apptype = appUser; + appstrJ = "ユーザアプリ"; + appstrE = "User-App."; + } + else + { + apptype = -1; + } + + if( apptype < 0 ) + { + this->hWarnList->Add( gcnew RCMrcError( + "アプリ種別", 0x230, 0x237, "不正な値です。", + "Application Type", "Illigal type.", false, true ) ); + } + + System::Boolean bApp = false; +#ifdef METWL_VER_APPTYPE_LAUNCHER + if( apptype == appLauncher ) + { + bApp = true; + } + else +#endif //#ifdef METWL_VER_APPTYPE_LAUNCHER +#ifdef METWL_VER_APPTYPE_SECURE + if( apptype == appSecure ) + { + bApp = true; + } + else +#endif //#ifdef METWL_VER_APPTYPE_SECURE +#ifdef METWL_VER_APPTYPE_SYSTEM + if( apptype == appSystem ) + { + bApp = true; + } + else +#endif //#ifdef METWL_VER_APPTYPE_SYSTEM +#ifdef METWL_VER_APPTYPE_USER + if( apptype == appUser ) + { + bApp = true; + } +#endif //#ifdef METWL_VER_APPTYPE_USER + + if( !bApp ) + { + this->hWarnList->Add( gcnew RCMrcError( + "アプリ種別", 0x230, 0x237, "このROMデータは" + appstrJ + "です。本プログラムでは非対応です。", + "Application Type", "This ROM is " + appstrE + " which is unsurpported by this editor.", false, true ) ); + } +} //RCSrl::mrcAppType() + +// ------------------------------------------------------------------- +// アクセスコントロール情報のチェック +// ------------------------------------------------------------------- +void RCSrl::mrcAccessControl(FILE *fp) +{ + if( this->IsAppLauncher || this->IsAppSecure || this->IsAppSystem ) + { + if( (this->pRomHeader->s.access_control.game_card_on != 0) && + (this->pRomHeader->s.access_control.game_card_nitro_mode != 0) ) + { + this->hErrorList->Add( gcnew RCMrcError( + "アクセスコントロール情報", 0x1b4, 0x1b7, "ゲームカードアクセス設定にノーマルモードとNTRモードの両方を設定することはできません。", + "Access Control Info.", "Game card access setting is either normal mode or NTR mode.", false, true ) ); + } + } + else + { + if( this->pRomHeader->s.access_control.sd_card_access != 0 ) + { + this->hErrorList->Add( gcnew RCMrcError( + "アクセスコントロール情報", 0x1b4, 0x1b7, + "SDカードへのアクセスは許可されていません。", + "Access Control Info.", + "Application for Game Card doesn't access to NAND frash memory.", + false, true ) ); + } + if( !this->IsMediaNand ) // カードアプリのときのみ + { + if( this->pRomHeader->s.access_control.nand_access != 0 ) + { + this->hErrorList->Add( gcnew RCMrcError( + "アクセスコントロール情報", 0x1b4, 0x1b7, + "ゲームカード用ソフトは、NANDフラッシュメモリへのアクセスを許可されていません。", + "Access Control Info.", + "Application for Game Card doesn't access to NAND frash memory.", + false, true ) ); + } + } + u32 okbits; + if( !this->IsMediaNand ) + { + okbits = 0x00000008 | 0x00000010 | 0x00000040; + } + else + { + okbits = 0x00000008 | 0x00000010 | 0x00000040 | 0x00000400; // NANDアプリのときはJpegSignフラグは許される + } + u32 *p = (u32*)&(this->pRomHeader->s); + if( p[ 0x1b4 / 4 ] & ~okbits ) + { + this->hErrorList->Add( gcnew RCMrcError( + "アクセスコントロール情報", 0x1b4, 0x1b7, + "許可されていないアクセスが設定されています。この設定は許可されていません。", + "Access Control Info.", + "Illegal Access is setting. This setting is unavailable.", + false, true ) ); + } + } +} //RCSrl::mrcAccessControl() + +// ------------------------------------------------------------------- +// パディングのチェック +// ------------------------------------------------------------------- +void RCSrl::mrcPadding(FILE *fp) +{ + u32 romsize = 1 << (this->pRomHeader->s.rom_size); // ROM容量 + u32 padsize = 0; // 単位はByte + System::String ^padstrJ = gcnew System::String(""); + System::String ^padstrE = gcnew System::String(""); + System::String ^romstr = gcnew System::String(""); + + switch( romsize ) + { + case 1024: + padsize = 0x00280000; // 20Mbit = 2.5MB + padstrJ = "最終20Mbit"; + padstrE = "Last 20Mbit"; + romstr = "1Gbit"; + break; + case 2048: + padsize = 0x00500000; // 40Mbit = 5MB + padstrJ = "最終40Mbit"; + padstrE = "Last 40Mbit"; + romstr = "2Gbit"; + break; + case 4096: + padsize = 0x00A60000; // 83Mbit = 10.375MB + padstrJ = "最終83Mbit"; + padstrE = "Last 83Mbit"; + romstr = "4Gbit"; + break; + default: + padsize = 0; + break; + } + if( padsize == 0 ) + { + return; + } + + fseek( fp, 0, SEEK_END ); + u32 filesize = ftell(fp); // 実ファイルサイズ(単位Mbit) + u32 offset = ((romsize / 8) * 1024 * 1024) - padsize; + if( (offset + padsize) > filesize ) + { + this->hErrorList->Add( gcnew RCMrcError( + padstrJ, METWL_ERRLIST_NORANGE, METWL_ERRLIST_NORANGE, + "読み出すことができませんでした。", + padstrE, "This area couldn't be read", false, true ) ); + return; + } + + u8 *buf = new u8[ padsize ]; + fseek( fp, offset, SEEK_SET ); + if( padsize != fread( buf, 1, padsize, fp ) ) + { + this->hErrorList->Add( gcnew RCMrcError( + padstrJ, METWL_ERRLIST_NORANGE, METWL_ERRLIST_NORANGE, + "読み出すことができませんでした。", + padstrE, "This area couldn't be read", false, true ) ); + delete []buf; + return; + } + + System::Boolean bResult = true; + u32 i; + for( i=0; i < padsize; i++ ) + { + if( buf[i] != 0xff ) + { + bResult = false; + } + } + if( !bResult ) + { + this->hErrorList->Add( gcnew RCMrcError( + padstrJ, METWL_ERRLIST_NORANGE, METWL_ERRLIST_NORANGE, + "FFh以外の値が格納されています。 " + romstr + " ROMの容量制限が守られていません。", + padstrE, + "This area includes illegai data. " + romstr + " Volume constraint is violated.", + false, true ) ); + } + delete []buf; +} //RCSrl::mrcPadding + +// ------------------------------------------------------------------- +// 予約領域 +// ------------------------------------------------------------------- +void RCSrl::mrcReservedArea(FILE *fp) +{ + // 予約領域の情報はリストに格納されている + for each( MasterEditorTWL::VCReservedArea area in this->hMrcExternalCheckItems->hReservedAreaList ) + { + System::UInt32 begin = area.Begin; + System::UInt32 end = area.End; + System::UInt32 size = end - begin + 1; + System::UInt32 i; + System::Boolean bReserved = true; + for( i=0; i < size; i++ ) + { + u8 *p = (u8*)this->pRomHeader; + if( p[ begin + i ] != 0 ) + { + bReserved = false; + break; + } + } + if( !bReserved ) + { + this->hErrorList->Add( gcnew RCMrcError( + "予約領域", begin, end, "不正な値が含まれています。この領域をすべて0で埋めてください。", + "Reserved Area", "Invalid data is included. Please set 0 into this area.", false, true ) ); + } + } //for each +} + +// ------------------------------------------------------------------- +// Shared2ファイル +// ------------------------------------------------------------------- +void RCSrl::mrcShared2(FILE *fp) +{ + // ROMヘッダ中のアクセス許可ビットが立っていないとき + // Shared2ファイルサイズが定義されていないことを確認 + if( !this->IsShared2 ) + { + if( (this->hShared2SizeArray[0] != 0) || (this->hShared2SizeArray[1] != 0) || (this->hShared2SizeArray[2] != 0) || + (this->hShared2SizeArray[3] != 0) || (this->hShared2SizeArray[4] != 0) || (this->hShared2SizeArray[5] != 0) ) + { + this->hErrorList->Add( gcnew RCMrcError( + "Shared2ファイル", METWL_ERRLIST_NORANGE, METWL_ERRLIST_NORANGE, + "Shared2ファイルへのアクセスが指定されていないにもかかわらずファイルサイズが設定されています。", + "Shared2 File", + "Although access to Shared2 files is not setting, file size is setting.", + false, true ) ); + } + return; + } + + // アクセス許可ビットが立っているとき + // ファイルサイズのいずれかが設定されているかをまず確認する + if( (this->hShared2SizeArray[0] == 0) && (this->hShared2SizeArray[1] == 0) && (this->hShared2SizeArray[2] == 0) && + (this->hShared2SizeArray[3] == 0) && (this->hShared2SizeArray[4] == 0) && (this->hShared2SizeArray[5] == 0) ) + { + this->hErrorList->Add( gcnew RCMrcError( + "Shared2ファイル", METWL_ERRLIST_NORANGE, METWL_ERRLIST_NORANGE, + "Shared2ファイルへのアクセスが指定されているにもかかわらずファイルサイズが設定されていません。", + "Shared2 File", + "Although access to Shared2 files is setting, file size is not setting.", + false, true ) ); + return; + } + + // アクセス許可ビットが立っているとき + // ファイルごとにアクセス許可されているかどうかとファイルサイズの値を確認 + int i; + for( i=0; i < METWL_NUMOF_SHARED2FILES; i++ ) + { + if( this->hShared2SizeArray[i] > 0 ) // 0以外の値が設定されている = そのファイルを使用したい を意味する + { + System::String ^filenoJ = "Shared2ファイル(No." + i.ToString() + ")"; + System::String ^filenoE = "Shared File(No." + i.ToString() + ")"; + if( !this->hMrcExternalCheckItems->hIsPermitShared2Array[i] ) + { + this->hErrorList->Add( gcnew RCMrcError( + filenoJ, METWL_ERRLIST_NORANGE, METWL_ERRLIST_NORANGE, + filenoJ + "へのアクセスは許可されていません。", + filenoE, + "Access to " + filenoE + " is not permitted.", + false, true ) ); + } + if( this->hShared2SizeArray[i] != this->hMrcExternalCheckItems->hShared2SizeArray[i] ) + { + this->hErrorList->Add( gcnew RCMrcError( + filenoJ, METWL_ERRLIST_NORANGE, METWL_ERRLIST_NORANGE, + filenoJ + "のファイルサイズに不正な値が設定されています。", + filenoE, + "Illegal file size of " + filenoE + ".", + false, true ) ); + } + } //if( this->hShared2SizeArray[i] > 0 ) + } //for +} //RCSrl::mrcShared2() + +// ------------------------------------------------------------------- +// SDKバージョンのチェック +// ------------------------------------------------------------------- +void RCSrl::mrcSDKVersion(FILE *fp) +{ + // SDKバージョン + System::Boolean isOld = false; + System::Boolean isPR = false; + System::Boolean isRC = false; + for each( RCSDKVersion ^sdk in this->hSDKList ) + { + if( sdk->IsStatic ) + { + isPR = MasterEditorTWL::IsSDKVersionPR( sdk->Code ); + isRC = MasterEditorTWL::IsSDKVersionRC( sdk->Code ); + isOld = MasterEditorTWL::IsOldSDKVersion( sdk->Code, this->hMrcExternalCheckItems->SDKVer ); + } + } + if( isOld ) + { + this->hWarnList->Add( gcnew RCMrcError( + "SDKバージョン", METWL_ERRLIST_NORANGE, METWL_ERRLIST_NORANGE, "設定ファイルに登録されているバージョンよりも古いバージョンです。", + "SDK Version", "Older version (comparing with a setting file)", false, true ) ); + } + if( isPR ) + { + this->hWarnList->Add( gcnew RCMrcError( + "SDKバージョン", METWL_ERRLIST_NORANGE, METWL_ERRLIST_NORANGE, "ご使用のSDKバージョンはPR版です。", + "SDK Version", "Used version is PR.", false, true ) ); + } + if( isRC ) + { + this->hWarnList->Add( gcnew RCMrcError( + "SDKバージョン", METWL_ERRLIST_NORANGE, METWL_ERRLIST_NORANGE, "ご使用のSDKバージョンはRC版です。", + "SDK Version", "Used version is RC.", false, true ) ); + } +} + +// ------------------------------------------------------------------- +// バナー文字のチェック +// ------------------------------------------------------------------- +void RCSrl::mrcBanner(FILE *fp) +{ + u8 map[ 0x10000 ]; + u32 i; + + // 本体設定だけはガイドライン無視 + if( memcmp( this->pRomHeader->s.game_code, "HNB", 3 ) == 0 ) + { + //this->hWarnList->Add( gcnew RCMrcError( + // "バナーファイル", METWL_ERRLIST_NORANGE, METWL_ERRLIST_NORANGE, + // "本体設定アプリに限ってはバナーの文字コードチェックをスキップします。", + // "Banner File", + // "Only a machine setting app., a charactor code check of the banner file is skip.", + // false, true ) ); + return; + } + + // バナーオフセットにエラーがあるときには調べない + if( this->pRomHeader->s.banner_offset == 0 ) + { + return; + } + + // 使用可能な文字のマップをつくる + // 文字コードをインデックスとして使用可能なら 1 が入る + // そうでないなら 0 が入る + for( i=0; i < 0x10000; i++ ) + { + map[i] = 0; + } + for( i=2; ; i+=2 ) // 0個目の要素はマジックコードなので含めない + { + u16 index = (u16)gBannerFont[i+1]; + index = (index << 8) + gBannerFont[i]; + if( index == 0xFEFF ) + { + break; + } + map[ index ] = 1; + } + map[ 0x0000 ] = 1; // 0x0000は許される + + // バナーを読み込む + u32 size = this->pRomHeader->s.banner_size; + u8 *banner = new u8[size]; + fseek( fp, this->pRomHeader->s.banner_offset, SEEK_SET ); + if( size != fread( banner, 1, size, fp ) ) + { + this->hErrorList->Add( gcnew RCMrcError( + "バナーファイル", METWL_ERRLIST_NORANGE, METWL_ERRLIST_NORANGE, + "読み出すことができませんでした。", + "Banner File", + "The file can't be read.", + false, true ) ); + } + + // バナーの各文字がマップに登録されているかチェック + System::Boolean bResult = true; + u32 start = 0x240; + u32 end = (size < 0x1240)?(size):(0x1240); // NTR互換領域までのときはTWL拡張領域をサーチしない + for( i=0x240; i < end; i+=2 ) + { + if( (0x840 <= i) && (i < 0xA40) ) // 中韓のフォント箇所はチェックしない + { + continue; + } + u16 index = banner[i+1]; + u16 indexbak = index; + index = (index << 8) + banner[i]; + if( map[ index ] == 0 ) + { + //System::Diagnostics::Debug::WriteLine( i.ToString("X") + ":" + index.ToString("X") + ":" + indexbak.ToString("X") ); + bResult = false; + break; + } + } + if( !bResult ) + { + this->hErrorList->Add( gcnew RCMrcError( + "バナーファイル", METWL_ERRLIST_NORANGE, METWL_ERRLIST_NORANGE, + "使用不可能な文字セットが使用されています。", + "Banner File", + "A set of illegal charactor code is used.", + false, true ) ); + } + delete []banner; +} //RCSrl::mrcBanner() + +// バナーとして使用可能なフォントリスト(u16リトルエンディアン) +const u8 gBannerFont[] = +{ + 0xff, 0xfe, 0x20, 0x00, 0x21, 0x00, 0x22, 0x00, 0x23, 0x00, 0x24, 0x00, 0x25, 0x00, 0x26, 0x00, + 0x27, 0x00, 0x28, 0x00, 0x29, 0x00, 0x2a, 0x00, 0x2b, 0x00, 0x2c, 0x00, 0x2d, 0x00, 0x2e, 0x00, + 0x2f, 0x00, 0x30, 0x00, 0x31, 0x00, 0x32, 0x00, 0x33, 0x00, 0x34, 0x00, 0x35, 0x00, 0x36, 0x00, + 0x37, 0x00, 0x38, 0x00, 0x39, 0x00, 0x3a, 0x00, 0x3b, 0x00, 0x3c, 0x00, 0x3d, 0x00, 0x3e, 0x00, + 0x3f, 0x00, 0x40, 0x00, 0x41, 0x00, 0x42, 0x00, 0x43, 0x00, 0x44, 0x00, 0x45, 0x00, 0x46, 0x00, + 0x47, 0x00, 0x48, 0x00, 0x49, 0x00, 0x4a, 0x00, 0x4b, 0x00, 0x4c, 0x00, 0x4d, 0x00, 0x4e, 0x00, + 0x4f, 0x00, 0x50, 0x00, 0x51, 0x00, 0x52, 0x00, 0x53, 0x00, 0x54, 0x00, 0x55, 0x00, 0x56, 0x00, + 0x57, 0x00, 0x58, 0x00, 0x59, 0x00, 0x5a, 0x00, 0x5b, 0x00, 0x5c, 0x00, 0x5d, 0x00, 0x5e, 0x00, + 0x5f, 0x00, 0x60, 0x00, 0x61, 0x00, 0x62, 0x00, 0x63, 0x00, 0x64, 0x00, 0x65, 0x00, 0x66, 0x00, + 0x67, 0x00, 0x68, 0x00, 0x69, 0x00, 0x6a, 0x00, 0x6b, 0x00, 0x6c, 0x00, 0x6d, 0x00, 0x6e, 0x00, + 0x6f, 0x00, 0x70, 0x00, 0x71, 0x00, 0x72, 0x00, 0x73, 0x00, 0x74, 0x00, 0x75, 0x00, 0x76, 0x00, + 0x77, 0x00, 0x78, 0x00, 0x79, 0x00, 0x7a, 0x00, 0x7b, 0x00, 0x7c, 0x00, 0x7d, 0x00, 0x7e, 0x00, + 0x7f, 0x00, 0xac, 0x20, 0x1a, 0x20, 0x1e, 0x20, 0x26, 0x20, 0xc6, 0x02, 0x52, 0x01, 0x18, 0x20, + 0x19, 0x20, 0x1c, 0x20, 0x1d, 0x20, 0x22, 0x20, 0xdc, 0x02, 0x22, 0x21, 0x3a, 0x20, 0x53, 0x01, + 0xa1, 0x00, 0xa2, 0x00, 0xa3, 0x00, 0xa8, 0x00, 0xa9, 0x00, 0xae, 0x00, 0xb7, 0x00, 0xbf, 0x00, + 0xc0, 0x00, 0xc1, 0x00, 0xc2, 0x00, 0xc3, 0x00, 0xc4, 0x00, 0xc5, 0x00, 0xc6, 0x00, 0xc7, 0x00, + 0xc8, 0x00, 0xc9, 0x00, 0xca, 0x00, 0xcb, 0x00, 0xcc, 0x00, 0xcd, 0x00, 0xce, 0x00, 0xcf, 0x00, + 0xd0, 0x00, 0xd1, 0x00, 0xd2, 0x00, 0xd3, 0x00, 0xd4, 0x00, 0xd5, 0x00, 0xd6, 0x00, 0xd8, 0x00, + 0xd9, 0x00, 0xda, 0x00, 0xdb, 0x00, 0xdc, 0x00, 0xdd, 0x00, 0xdf, 0x00, 0xe0, 0x00, 0xe1, 0x00, + 0xe2, 0x00, 0xe3, 0x00, 0xe4, 0x00, 0xe5, 0x00, 0xe6, 0x00, 0xe7, 0x00, 0xe8, 0x00, 0xe9, 0x00, + 0xea, 0x00, 0xeb, 0x00, 0xec, 0x00, 0xed, 0x00, 0xee, 0x00, 0xef, 0x00, 0xf0, 0x00, 0xf1, 0x00, + 0xf2, 0x00, 0xf3, 0x00, 0xf4, 0x00, 0xf5, 0x00, 0xf6, 0x00, 0xf7, 0x00, 0xf8, 0x00, 0xf9, 0x00, + 0xfa, 0x00, 0xfb, 0x00, 0xfc, 0x00, 0xfd, 0x00, 0x00, 0x30, 0x01, 0x30, 0x02, 0x30, 0x0c, 0xff, + 0x0e, 0xff, 0xfb, 0x30, 0x3a, 0x00, 0x3b, 0x00, 0x1f, 0xff, 0x01, 0xff, 0xfc, 0x30, 0x41, 0x30, + 0x42, 0x30, 0x43, 0x30, 0x44, 0x30, 0x45, 0x30, 0x46, 0x30, 0x47, 0x30, 0x48, 0x30, 0x49, 0x30, + 0x4a, 0x30, 0x4b, 0x30, 0x4c, 0x30, 0x4d, 0x30, 0x4e, 0x30, 0x4f, 0x30, 0x50, 0x30, 0x51, 0x30, + 0x52, 0x30, 0x53, 0x30, 0x54, 0x30, 0x55, 0x30, 0x56, 0x30, 0x57, 0x30, 0x58, 0x30, 0x59, 0x30, + 0x5a, 0x30, 0x5b, 0x30, 0x5c, 0x30, 0x5d, 0x30, 0x5e, 0x30, 0x5f, 0x30, 0x60, 0x30, 0x61, 0x30, + 0x62, 0x30, 0x63, 0x30, 0x64, 0x30, 0x65, 0x30, 0x66, 0x30, 0x67, 0x30, 0x68, 0x30, 0x69, 0x30, + 0x6a, 0x30, 0x6b, 0x30, 0x6c, 0x30, 0x6d, 0x30, 0x6e, 0x30, 0x6f, 0x30, 0x70, 0x30, 0x71, 0x30, + 0x72, 0x30, 0x73, 0x30, 0x74, 0x30, 0x75, 0x30, 0x76, 0x30, 0x77, 0x30, 0x78, 0x30, 0x79, 0x30, + 0x7a, 0x30, 0x7b, 0x30, 0x7c, 0x30, 0x7d, 0x30, 0x7e, 0x30, 0x7f, 0x30, 0x80, 0x30, 0x81, 0x30, + 0x82, 0x30, 0x83, 0x30, 0x84, 0x30, 0x85, 0x30, 0x86, 0x30, 0x87, 0x30, 0x88, 0x30, 0x89, 0x30, + 0x8a, 0x30, 0x8b, 0x30, 0x8c, 0x30, 0x8d, 0x30, 0x8e, 0x30, 0x8f, 0x30, 0x90, 0x30, 0x91, 0x30, + 0x92, 0x30, 0x93, 0x30, 0x9b, 0x30, 0x9c, 0x30, 0x9d, 0x30, 0x9e, 0x30, 0xa1, 0x30, 0xa2, 0x30, + 0xa3, 0x30, 0xa4, 0x30, 0xa5, 0x30, 0xa6, 0x30, 0xa7, 0x30, 0xa8, 0x30, 0xa9, 0x30, 0xaa, 0x30, + 0xab, 0x30, 0xac, 0x30, 0xad, 0x30, 0xae, 0x30, 0xaf, 0x30, 0xb0, 0x30, 0xb1, 0x30, 0xb2, 0x30, + 0xb3, 0x30, 0xb4, 0x30, 0xb5, 0x30, 0xb6, 0x30, 0xb7, 0x30, 0xb8, 0x30, 0xb9, 0x30, 0xba, 0x30, + 0xbb, 0x30, 0xbc, 0x30, 0xbd, 0x30, 0xbe, 0x30, 0xbf, 0x30, 0xc0, 0x30, 0xc1, 0x30, 0xc2, 0x30, + 0xc3, 0x30, 0xc4, 0x30, 0xc5, 0x30, 0xc6, 0x30, 0xc7, 0x30, 0xc8, 0x30, 0xc9, 0x30, 0xca, 0x30, + 0xcb, 0x30, 0xcc, 0x30, 0xcd, 0x30, 0xce, 0x30, 0xcf, 0x30, 0xd0, 0x30, 0xd1, 0x30, 0xd2, 0x30, + 0xd3, 0x30, 0xd4, 0x30, 0xd5, 0x30, 0xd6, 0x30, 0xd7, 0x30, 0xd8, 0x30, 0xd9, 0x30, 0xda, 0x30, + 0xdb, 0x30, 0xdc, 0x30, 0xdd, 0x30, 0xde, 0x30, 0xdf, 0x30, 0xe0, 0x30, 0xe1, 0x30, 0xe2, 0x30, + 0xe3, 0x30, 0xe4, 0x30, 0xe5, 0x30, 0xe6, 0x30, 0xe7, 0x30, 0xe8, 0x30, 0xe9, 0x30, 0xea, 0x30, + 0xeb, 0x30, 0xec, 0x30, 0xed, 0x30, 0xee, 0x30, 0xef, 0x30, 0xf0, 0x30, 0xf1, 0x30, 0xf2, 0x30, + 0xf3, 0x30, 0xf4, 0x30, 0xf5, 0x30, 0xf6, 0x30, 0x01, 0x30, 0x02, 0x30, 0x0c, 0xff, 0x0e, 0xff, + 0xfb, 0x30, 0x1a, 0xff, 0x1b, 0xff, 0x1f, 0xff, 0x01, 0xff, 0x9b, 0x30, 0x9c, 0x30, 0xb4, 0x00, + 0x40, 0xff, 0x3e, 0xff, 0xe3, 0xff, 0x3f, 0xff, 0x05, 0x30, 0xfc, 0x30, 0x15, 0x20, 0x10, 0x20, + 0x0f, 0xff, 0x3c, 0xff, 0x5e, 0xff, 0x5c, 0xff, 0x26, 0x20, 0x18, 0x20, 0x19, 0x20, 0x1c, 0x20, + 0x1d, 0x20, 0x08, 0xff, 0x09, 0xff, 0x14, 0x30, 0x15, 0x30, 0x3b, 0xff, 0x3d, 0xff, 0x5b, 0xff, + 0x5d, 0xff, 0x08, 0x30, 0x09, 0x30, 0x0c, 0x30, 0x0d, 0x30, 0x0b, 0xff, 0x0d, 0xff, 0xb1, 0x00, + 0xd7, 0x00, 0xf7, 0x00, 0x1d, 0xff, 0x1e, 0x22, 0x34, 0x22, 0xb0, 0x00, 0x32, 0x20, 0x33, 0x20, + 0x06, 0xff, 0x06, 0x26, 0x05, 0x26, 0xcb, 0x25, 0xcf, 0x25, 0xce, 0x25, 0xc7, 0x25, 0xc6, 0x25, + 0xa1, 0x25, 0xa0, 0x25, 0xb3, 0x25, 0xb2, 0x25, 0xbd, 0x25, 0xbc, 0x25, 0x3b, 0x20, 0x12, 0x30, + 0x92, 0x21, 0x90, 0x21, 0x91, 0x21, 0x93, 0x21, 0x6f, 0x26, 0x6d, 0x26, 0x6a, 0x26, 0x0a, 0x00, + 0xff, 0xfe, // 終わりを表す意味で0xFEFFを最後につける +}; diff --git a/build/tools/MasterEditor/MasterEditorTWL/resource/ini.xml b/build/tools/MasterEditor/MasterEditorTWL/resource/ini.xml index 351d203..7746463 100644 --- a/build/tools/MasterEditor/MasterEditorTWL/resource/ini.xml +++ b/build/tools/MasterEditor/MasterEditorTWL/resource/ini.xml @@ -1,6 +1,13 @@ w + + + + + + 2097152 + 787f 16017f