unit main; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, FileCtrl, ComCtrls, ShellCtrls, ExtCtrls; type TForm1 = class(TForm) ListBox_log: TListBox; Button1: TButton; DriveBox: TDriveComboBox; DirListBox: TDirectoryListBox; StatusBar: TStatusBar; StaticText3: TStaticText; RG_select: TRadioGroup; StatusBar1: TStatusBar; CB_add_ovt: TCheckBox; procedure Button1Click(Sender: TObject); procedure DriveBoxChange(Sender: TObject); procedure DirListBoxChange(Sender: TObject); procedure FormCreate(Sender: TObject); private { Private 宣言 } function CheckSrlHeader:integer; function fstring(s:string):string; public { Public 宣言 } end; TRom_Fat = record top:Longword; // file region start bottom:Longword; // end; end; TRom_Ovl = record id:Longword; // Overlay ID ram_address:Longword; // ram address ram_size:Longword; // ram size bss_size:Longword; // bss size sinit_init:Longword; // static initializer start sinit_init_end:Longword; // static initializer end file_id:Longword; // file id in FAT flag:Longword; // オーバーレイ情報フラ end; TRomh = record //ROMヘッダ(nitro_romheader.hより) title: array[1..12] of Char; game_code: array[1..4] of Char; //0x10 maker_code: array[1..2] of Byte; machine_code: Byte; rom_type: Byte; rom_size: Byte; resv_A: array[1..8] of Byte; //Reserve(All 0) region: Byte; // b0 = china,b1 = koria rom_version: Byte; comp_boot_area: Byte;//b7 =A9,b6=A7 // // 0x020 for Static modules (Section:B) //ARM9 A9_main_rom_offset: Longword; // ROM offset A9_main_entry_address: Longword; // Entry point A9_main_ram_address: Longword; // RAM address A9_main_size: Longword; // Module size //ARM7 A7_main_rom_offset: Longword; // ROM offset A7_main_entry_address: Longword; // Entry point A7_main_ram_address: Longword; // RAM address A7_main_size: Longword; // Module size //0x40 dumy2:array[1..8] of Byte;//ツールで使用しない部分 // // 0x048 for File Allocation Table[FAT] (Section:E) // fat_offset: Longword; // ROM offset fat_size:Longword; // Table size // // 0x050 for Overlay Tables[OVT] (Section:D) // // ARM9 main_ovt_offset: Longword; // ROM offset main_ovt_size:Longword; // Table size end; var Form1: TForm1; LogDir,SrlDir: String;//ディレクトリパス ng_all: longword;//総NGエントリ数 implementation function TForm1.fstring(s:string):string; var s1,s2,s3:string; n,nn:integer; begin //'='まで切り出す n := pos('=',s); s1 := copy(s,0,n-1); while length(s1) < 16 do s1 := s1+' '; //';'まで切り出す nn := pos(';',s); s2 := copy(s,n,nn-n); while length(s2) < 16 do s2 := s2+' '; //残り s3 := copy(s,nn,length(s)); Result := s1+s2+s3; end; function TForm1.CheckSrlHeader: integer; var Rec: TSearchRec; sf,s,ss: String; i,j,n,Count,err_files,ng_entry: integer; fsrl: file; flog:TextFile; romh: TRomh; noc_size,noc_sectors,size,sectors,nums,max_sectors,total_sectors: integer; fat: TRom_Fat; ovl: TRom_Ovl; top,btm,all_sectors: Longword; ng_flg:boolean; begin {$I-} //ログファイル作成 ListBox_log.Items.Add('Create Log file'); //s := ExtractFilePath(Application.Exename)+'log.txt'; s := LogDir+'log.txt'; AssignFile (flog,s); Rewrite(flog); if IOResult <> 0 then begin Count := -1; ListBox_log.Items.Add('faild') end else begin Count := 0; err_files := 0; ng_all := 0; //指定ディレクトリからファイルを取り出す // ** 内容で判別しないので違うファイル置かないよう注意 ** if FindFirst(SrlDir + '*.*', faAnyFile, Rec) = 0 then try repeat //フォルダやカレントディレクトリや親ディレクトリは対象外 if not((Rec.Attr and faDirectory > 0)) and (Rec.Name <> '.') and (Rec.Name <> '..') and (Rec.name<>'log.txt')then begin //ListBox_log.Items.Add('**********************************'); Writeln(flog,'**********************************'); sf := 'file: '+Rec.Name; //ListBox_log.Items.Add(sf); Writeln(flog,sf); AssignFile (fsrl,SrlDir+Rec.Name); FileMode := fmOpenRead;//リード専用指定 Reset(fsrl,1);//ファイル開く if IOResult = 0 then begin BlockRead(fsrl,romh,SizeOf(TRomh),n);//ヘッダリード if SizeOf(TRomh) <> n then s := ' header read error' else begin //SetLength(s,12); s := '[ ( )]'; for i:=1 to 12 do begin if romh.title[i] = char(0) then break; s[i+1] := romh.title[i]; end; s[15] := romh.game_code[4];//idの4文字目(仕向地) //ListBox_log.Items.Add(s); //title Writeln(flog,s); s := 'game_code = '; for i:=1 to 4 do s[12+i] := romh.game_code[i]; //ListBox_log.Items.Add(s); //game code //ListBox_log.Items.Add('rom version = '+inttostr(romh.rom_version)); //ListBox_log.Items.Add(' '); Writeln(flog,s); Writeln(flog,'rom_version = '+inttostr(romh.rom_version)); Writeln(flog);//改行 //オーバレイチェック if romh.main_ovt_size >31 then begin //DHT_OVERLAY_MAX (512*1024) ng_entry := 0; total_sectors := 0; all_sectors := 0; nums := romh.main_ovt_size div 32;//Ovl count noc_size :=0;//範囲外トータルsize noc_sectors := 0;// 同セクタ j := 0;//通し番号 for i := 0 to nums-1 do begin if CB_add_ovt.Checked then begin //OVT seek( fsrl,romh.main_ovt_offset+sizeof(TRom_Ovl)*i); BlockRead( fsrl,ovl,sizeof(ovl),n);//top,bottom取得 Writeln(flog,'ovt_id = '+inttostr(ovl.id)); Writeln(flog,' address = '+inttostr(ovl.ram_address)); Writeln(flog,' file_id = '+inttostr(ovl.file_id)); Writeln(flog);//改行 end; //FAT top := 0;btm := 0; seek( fsrl,romh.fat_offset+sizeof(TRom_Fat)*i); BlockRead( fsrl,fat,sizeof(fat),n);//top,bottom取得 if n <> sizeof(fat) then begin s := 'file error'; break; end; ng_flg:=false; ss := '(A9 Overlay'+inttostr(i); //max_sectors = (DHT_OVERLAY_MAX/512 - total_sectors) / (nums-i); if (total_sectors < 1024)then max_sectors := (1024 - total_sectors) div (nums-i) else max_sectors := 0; //CARDブート時、マイナスはエラー(FAT Broken)になる btm := fat.bottom and $fffffe00; //512単位 if (fat.bottom and $1ff)<>0 then inc(btm,512);//上方向に丸める if max_sectors = 0 then begin//丸ごと検証外 top := fat.top; sectors := (btm-top) shr 9;//div 512 if (top and $1ff)<>0 then inc(sectors); ss := ss+' の全部)'; ng_flg:=true; end else begin ss := ss+' の一部)'; top := fat.top and $fffffe00; //512単位 size := fat.top and $01ff; if size<>0 then begin inc(top,512);////上方向に丸める //先頭の未検証部分 .. 不要? s := 'offset'+inttostr(j)+' = 0x'+ inttohex(fat.top,8) +' ; 0x'+ inttohex(fat.top,8) +'-0x' + inttohex(top-1,8)+ss; //ListBox_log.Items.Add(s); s := fstring(s);//整形 Writeln(flog,s); s := 'length'+ inttostr(j) + ' = 0x' + inttohex(size,4) + ' ; '+ inttostr(size)+' bytes'; //ListBox_log.Items.Add(s); s := fstring(s);//整形 Writeln(flog,s); inc(noc_size,512); inc(noc_sectors); inc(all_sectors); inc(j); ng_flg:=true; end; size := btm - top; sectors := size shr 9;//div 512 inc(all_sectors,sectors); if sectors > max_sectors then begin //最大割当サイズ超 sectors := sectors - max_sectors;//残りセクタ数 inc(top,max_sectors*512);//残り先頭 inc(total_sectors,max_sectors); ng_flg:=true; end else begin //超過なし inc(total_sectors,sectors); sectors := 0; end; end; if sectors > 0 then begin//残りあり size := sectors shl 9; s := 'offset'+inttostr(j)+' = 0x'+ inttohex(top,8) +' ; 0x'+ inttohex(top,8) +'-0x' + inttohex(btm-1,8)+ss; //ListBox_log.Items.Add(s); s :=fstring(s);//整形 Writeln(flog,s); s := 'length'+ inttostr(j) + ' = 0x' + inttohex(size,4) + ' ; '+ inttostr(size)+' bytes'; //ListBox_log.Items.Add(s); s := fstring(s);//整形 Writeln(flog,s); inc(noc_size,size); inc(noc_sectors,sectors); inc(j); end; if ng_flg then inc(ng_entry); end; if i = nums then begin //中断なし //ListBox_log.Items.Add(' '); //ListBox_log.Items.Add('total sectors = '+inttostr(all_sectors)); //ListBox_log.Items.Add('no check sectors = '+inttostr(noc_sectors)); //ListBox_log.Items.Add('no check size = '+inttostr(noc_size)); Writeln(flog); //改行 Writeln(flog,'total sectors = '+inttostr(all_sectors)); Writeln(flog,'check sectors = '+inttostr(total_sectors)); Writeln(flog,'no check sectors = '+inttostr(noc_sectors)); Writeln(flog,'no check size = '+inttostr(noc_size)); if noc_size <> 0 then s:= 'NG' else s:= 'OK'; end; end else begin Writeln(flog); //改行 //s := 'no OVL'; s := 'OK'; end; end; end else s := ' Open Error'; CloseFile(fsrl); Writeln(flog,s);//結果 if (s='OK') or (s='NG') then begin if s = 'NG' then begin s := 'done, '+ inttostr(ng_entry) + ' enties NG'; inc(ng_all,ng_entry); end else s := 'done, OK'; Inc(Count); end else inc(err_files); ss := sf + ' : ' + s; ListBox_log.Items.Add(ss); end; until (FindNext(Rec) <> 0); finally FindClose(Rec); end; Writeln(flog,'********************************'); Writeln(flog,'check files = '+ inttostr(Count)); Writeln(flog,'error files = '+ inttostr(err_files)); CloseFile(flog); end; {$I+} Result :=Count; end; {$R *.dfm} procedure TForm1.Button1Click(Sender: TObject); var FileCount :integer; s :string; begin ListBox_log.Clear; //指定ディレクトリのsrlファイルをチェック FileCount := CheckSrlHeader; if FileCount>=0 then begin ListBox_log.Items.Add(' ------------------------------ '); s := ' '+inttostr(FileCount)+' files done, ' + inttostr(ng_all)+' entries NG'; ListBox_log.Items.Add(s); end; end; procedure TForm1.DriveBoxChange(Sender: TObject); begin DirListBox.Drive := DriveBox.Drive; end; procedure TForm1.DirListBoxChange(Sender: TObject); begin if RG_select.ItemIndex = 0 then begin SrlDir := IncludeTrailingPathDelimiter(DirListBox.Directory); StatusBar.SimpleText := '[srl dir] ' + DirListBox.Directory; end else begin LogDir := IncludeTrailingPathDelimiter(DirListBox.Directory); StatusBar1.SimpleText := '[log dir] ' + DirListBox.Directory; end; end; procedure TForm1.FormCreate(Sender: TObject); begin SrlDir := IncludeTrailingPathDelimiter(DirListBox.Directory); StatusBar.SimpleText := '[srl dir] ' + DirListBox.Directory; LogDir := IncludeTrailingPathDelimiter(DirListBox.Directory); StatusBar1.SimpleText := '[log dir] ' + DirListBox.Directory; end; end.