📄 filemap.pl
字号:
#!/usr/bin/perl
#BEGIN {
#@INC = ("./RscFile/",@INC);
#}
use BuildRscCFile;
#### global const
$SIZE_OF_FTH = 16; # for version 1.0 SFT
$SIZE_OF_FI = 16; # for version 1.0 SFT
$SIZE_OF_CFI = 8; # for version 1.0 SFT
@FILE_EXT = ("dir","ibn","fbn","sbn","plt","dbn","lbn","bin");
#### step 1: get arguments
if (@ARGV != 0)
{
open (H_FM_CONFIG, "$ARGV[0]") || die ("Error: Can not open file \"$ARGV[0]\"\n");
}
else
{
open (H_FM_CONFIG, "FileMapConfig") || die ("Error: Can not open file \"FileMapConfig\"\n");
}
#const
my $FM_STEP_GENERAL = "general";
my $FM_STEP_ENTRY = "entryprogram";
my $FM_STEP_MAIN = "mainprogram";
my $FM_STEP_DIR = "dir";
my $FM_STEP_COMPACT_DIR = "compactdir";
my $FM_STEP_FILE = "file";
my $ROOT_DIR_FILE = "__fmroot.dir";
#### remove old output files
my @proglist = ("rm","-f","$ROOT_DIR_FILE");
system(@proglist);
#var
my $fm_step;
my $line;
my $linenum = 0;
my $OutputBinFile = "xproduct.bin";
my $AddrStart = 0xbfc00000;
my $EntryFileName = "headfile.bin";
my $EntryAddress = 0xbfc00000;
my $MainFileName = "tmp2.gz";
my $MainFileAddress = 0xbfc03500;
my $p_RootDirAddr = $MainFileAddress -4; #$RootDirAddr value will be put here.
my $RootDirAddr;
my @DirFileNames = ();
my @CompactDirFileNames = ();
my @RootFileNames = ();
my @RootFileSaveNames = ();
my @RootFileIszip = ();
my @file_state;
#### step 2: read infomation from the config file
foreach $line(<H_FM_CONFIG>)
{
$linenum ++;
$line =~ s/(\;.*)//; #remove lines marked by ;
$line =~ s/(\s*)//g; #remove all space for all of them can be ignord in format
$line =~ tr/A-Z/a-z/; #lower case only;
if ($line =~ /^\[(.+)\]$/) # [] line
{
if (($1 eq $FM_STEP_GENERAL) || ($1 eq $FM_STEP_ENTRY) || ($1 eq $FM_STEP_MAIN) || ($1 eq $FM_STEP_DIR) || ($1 eq $FM_STEP_COMPACT_DIR) || ($1 eq $FM_STEP_FILE))
{
$fm_step = $1;
# print "Parsing: find section [$fm_step] at line $linenum.\n";
}
else
{
print "Warning: unknown seciotn type [$1] at line $linenum, ignored.\n";
}
next;
}
elsif ($line =~ /^$/) #empty line
{
# print "OK: find an empty line at line $linenum.\n";
next;
}
if ($fm_step eq $FM_STEP_GENERAL)
{
if ($line =~ /^OutputBinFile=([0-9a-zA-Z_\.\/\\]+),*/i)
{
$OutputBinFile = $1;
}
elsif ($line =~ /^AddrStart=(0x[0-9a-fA-F]+)/i)
{
$AddrStart = hex($1);
}
else
{
print "Warning: format mismatch for [general] section, line $linenum has been ignored.\n";
}
}
elsif ($fm_step eq $FM_STEP_ENTRY)
{
if ($line =~ /^EntryFileName=([0-9a-zA-Z_\.\/\\]+),*/i)
{
$EntryFileName = $1;
}
elsif ($line =~ /^EntryAddress=(0x[0-9a-fA-F]+)/i)
{
$EntryAddress = hex($1);
}
else
{
print "Warning: format mismatch for [entryprogram] section, line $linenum has been ignored.\n";
}
}
elsif ($fm_step eq $FM_STEP_MAIN)
{
if ($line =~ /^MainFileName=([0-9a-zA-Z_\.\/\\]+),*/i)
{
$MainFileName = $1;
}
elsif ($line =~ /^MainFileAddress=(0x[0-9a-fA-F]+)/i)
{
$MainFileAddress = hex($1);
$p_RootDirAddr = $MainFileAddress -4;
}
else
{
print "Warning: format mismatch for [mainprogram] section, line $linenum has been ignored.\n";
}
}
elsif ($fm_step eq $FM_STEP_DIR)
{
if ($line =~ /^DirFileName=([0-9a-zA-Z_\.\/\\]+),*/i)
{
@DirFileNames = (@DirFileNames,$1);
}
else
{
print "Warning: format mismatch for [dir] section, line $linenum has been ignored.\n";
}
}
elsif ($fm_step eq $FM_STEP_COMPACT_DIR)
{
if ($line =~ /^DirFileName=([0-9a-zA-Z_\.\/\\]+)/i)
{
@CompactDirFileNames = (@CompactDirFileNames,$1);
}
else
{
print "Warning: format mismatch for [compactdir] section, line $linenum has been ignored.\n";
}
}
elsif ($fm_step eq $FM_STEP_FILE)
{
if ($line =~ /^FileName=([0-9a-zA-Z_\.\/\\]+),SaveName=([0-9a-zA-Z_]+),iszip=(\d)+$/i)
{
@RootFileNames = (@RootFileNames, $1);
@RootFileSaveNames = (@RootFileSaveNames, $2);
@RootFileIszip = (@RootFileIszip, $3);
}
else
{
print "Warning: format mismatch for [file] section, line $linenum has been ignored.\n";
}
}
else
{
die("Error: how can I run to here !!!\n");
}
}
# print "\n";
#print "$OutputBinFile,$AddrStart,$p_RootDirAddr,$EntryFileName,$EntryAddress,$MainFileName,$MainFileAddress\n";
#print "@DirFileNames \n";
#print "@CompactDirFileNames \n";
#### step 3: check infomation
die ("Error: EntryAddress must be after AddrStart !!! \n") if ($EntryAddress < $AddrStart);
#die ("Error: MainFileAddress must be after EntryAddress!!! \n") if ($MainFileAddress< $EntryAddress);
@file_state = stat("$EntryFileName");
#die ("Error: EntryProgram ==>\"$EntryFileName\"'s size is larger than available room \n given by \"room size = MainFileAddress - 4 -EntryAddress\"\n\n") if ( $file_state[7] > $MainFileAddress - 4 -$EntryAddress);
#### step 4: handle static data.
open(H_OUTPUT_BIN,">$OutputBinFile") || die ("Error: Can not open file \"$OutputBinFile\"\n");
binmode(H_OUTPUT_BIN);
### 4.1 jump
seek(H_OUTPUT_BIN,$EntryAddress - $AddrStart,0);
### 4.2 put [entryprogram] file
my $char;
open(H_ENTRY_FILE,"$EntryFileName") || die ("Error: Can not open file \"$EntryFileName\"\n");
binmode(H_ENTRY_FILE);
while(sysread(H_ENTRY_FILE,$char,1,0))
{
syswrite(H_OUTPUT_BIN,$char,1,0);
}
close(H_ENTRY_FILE);
### 4.3 put $RootDirAddr value here. now it is not available, so just put 0xFFFFFFFF.
#seek(H_OUTPUT_BIN,$MainFileAddress - 4 -$AddrStart,0);
#syswrite H_OUTPUT_BIN, pack("$BuildRscCFile::ui32",0xFFFFFFFF);
#seek(H_OUTPUT_BIN,$MainFileAddress -$AddrStart,0); # not need put $RootDirAddr here, we will put it at the beginning of the H_OUTPUT_BIN
### 4.4 put [mainprogram] file
#open(H_MAIN_FILE,"$MainFileName") || die ("Error: Can not open file \"$MainFileName\"\n");
#binmode(H_MAIN_FILE);
#while(sysread(H_MAIN_FILE,$char,1,0))
#{
# syswrite(H_OUTPUT_BIN,$char,1,0);
#}
#close(H_MAIN_FILE);
### 4.5 find a 16 bytes bound free address for Root Dir file
@file_state = stat("$OutputBinFile");
my $RootDirOffSet = $file_state[7];
$RootDirOffSet = int(($RootDirOffSet+15)/16)*16;
$RootDirAddr = $RootDirOffSet + $AddrStart;
#print "$RootDirOffSet\n";
#print "$RootDirAddr\n";
### 4.6 rewrite this value to ##4.3, no, not 4.3 , but the bytes 28-31 of the H_OUTPUT_BIN, we have reserved room for it in 51head.s.
seek(H_OUTPUT_BIN,28,0);
syswrite H_OUTPUT_BIN, pack("$BuildRscCFile::ui32",$RootDirAddr);
#### step 5: save file part
## 1 count total record in root dir
my $RootRecordNum = @RootFileNames + @CompactDirFileNames + @DirFileNames;
my $SizeOfRootDir = $RootRecordNum*$SIZE_OF_FI + $SIZE_OF_FTH;
# print "$RootRecordNum\n";
## 2 write FTH (16 bytes)
seek(H_OUTPUT_BIN,$RootDirOffSet,0);
# print "Root Dir offset is $RootDirOffSet\n";
syswrite H_OUTPUT_BIN,"SFT"; #signature
syswrite H_OUTPUT_BIN,pack("C",0x10); # SFT Verion number : 0x10 for V1.0
syswrite H_OUTPUT_BIN,pack("$BuildRscCFile::ui32",$SizeOfRootDir); # size of Root Dir File including FTH
my @CurrentTime = localtime;
my $Year = $CurrentTime[5] +1900;
my $Month = $CurrentTime[4] + 1;
my $Day = $CurrentTime[3];
my $Hour = $CurrentTime[2];
my $Min = $CurrentTime[1];
syswrite H_OUTPUT_BIN, pack("C",($Year/1000)%10*16+($Year/100)%10);
syswrite H_OUTPUT_BIN, pack("C",($Year/10)%10*16 + $Year%10);
syswrite H_OUTPUT_BIN, pack("C",($Month/10)%10*16 + $Month%10); # month
syswrite H_OUTPUT_BIN, pack("C",($Day/10)%10*16 + $Day%10); # day
syswrite H_OUTPUT_BIN, pack("C",($Hour/10)%10*16 + $Hour%10); # hour
syswrite H_OUTPUT_BIN, pack("C",($Min/10)%10*16 + $Min%10); # min
syswrite H_OUTPUT_BIN, pack("C",0); # reserved 2 bytes
syswrite H_OUTPUT_BIN, pack("C",0);
## 3 build up root dir info
my $file_index = 0;
foreach (@RootFileNames)
{
BuildRscCFile::CopyAndSave($RootFileNames[$file_index],$RootFileSaveNames[$file_index],$ROOT_DIR_FILE,$RootFileIszip[$file_index]);
$file_index ++ ;
}
$file_index = 0;
foreach (@CompactDirFileNames)
{
BuildRscCFile::BuildCompactDir($CompactDirFileNames[$file_index],$ROOT_DIR_FILE);
$file_index ++ ;
}
$file_index = 0;
foreach (@DirFileNames)
{
BuildRscCFile::BuildDir($DirFileNames[$file_index],$ROOT_DIR_FILE);
$file_index ++ ;
}
## 4 deal with all *.dir and related files
local $recursion_level = 0; # for SettleFileMap use, work as static var
my $TotalRscSize = SettleFileMap(\*H_OUTPUT_BIN,$AddrStart,$ROOT_DIR_FILE) if (-e $ROOT_DIR_FILE);
$TotalRscSize += 16; # SFT used 16 bytes;
print " DVD Resource Data Total Size is $TotalRscSize .\n";
#### over, close output bin file
close(H_OUTPUT_BIN);
sub SettleFileMap
{
my ($r_H_OUTPUT,$AbsoluteHeadAddr,$DirFile) = @_;
my @file_state = stat($r_H_OUTPUT);
my $MyOffset = $file_state[7];
#<1>print " Input offset of $DirFile is $MyOffset\n";
$MyOffset = int(($MyOffset+15)/16)*16; #set to 16 bytes boundary
#<1>print " Adjusted offset of $DirFile is $MyOffset\n";
my @file_state = stat("$DirFile");
my $MyDirSize = $file_state[7];
$MyDirSize = int($MyDirSize/16)*16; # for safty, also set to 16 bytes boundary
#<1>print " size of $DirFile is $MyDirSize\n\n";
my $MyUsedSize = 0;
my $FileSettleOffset;
my $char;
# print "recursion level is $recursion_level\n";
my $FILE_HANDLE_STR = "H_MY_DIR".$recursion_level;
# print "file handle is $FILE_HANDLE_STR\n";
$recursion_level ++;
open ($FILE_HANDLE_STR,"$DirFile") || die ("Error: Can not open file \"$DirFile\"\n");
binmode ($FILE_HANDLE_STR);
my $DirRecord;
my $RecordName;
my $RecordAttr;
my $RecordExtIndex;
my $RecordIndex = 0;
my $RecordFileNames;
my $temp;
while (sysread($FILE_HANDLE_STR,$DirRecord,$SIZE_OF_FI) == $SIZE_OF_FI )
{
$RecordName = substr($DirRecord,0,6);
$RecordName =~ s/\0//g; #remove null char in the 6 bytes
$RecordAttr = substr($DirRecord,7,1);
$RecordAttr = unpack("C",$RecordAttr);
$RecordExtIndex = $RecordAttr&0x0F;
if ($RecordExtIndex > @FILE_EXT)
{
print "Warning: unknown file type, file \"$file_path $RecordName.???\" has been ignored!!!\n";
next;
}
# print "$RecordAttr\n";
$RecordFileNames = "$RecordName".".$FILE_EXT[$RecordExtIndex]";
if (($RecordAttr & 0xC0) == 0x80) #normal dir
{
#<1>print " >> go to dir \\$RecordName\\\n";
# give new dir a 16 bytes bound offset
$temp = int(($MyUsedSize+15)/16)*16;#start from 16 bytes boundary
$FileSettleOffset = $MyOffset+$MyDirSize+$temp;
# tom gao 2003.9.12
# if $MyUsedSize is at 16 bytes boundary, we should not do following, otherwise data will be change at the last byte
if ($temp != $MyUsedSize)
{
$MyUsedSize = $temp;
# tom gao 2003.8.27
# because seek can not effect the size of $r_H_OUTPUT even if it jumps after EOF.
# So we must seek(target-1) and syswrite a byte, and then go on call SettleFileMap.
seek($r_H_OUTPUT, $FileSettleOffset - 1,0);
syswrite $r_H_OUTPUT,pack("C",0);
}
$MyUsedSize += SettleFileMap(\*$r_H_OUTPUT, $AbsoluteHeadAddr, $RecordFileNames);
$MyUsedSize = int(($MyUsedSize+15)/16)*16;#end with 16 bytes boundary
#<1>print " << back from dir \\$RecordName\\\n";
# step 2 : write record string.
seek($r_H_OUTPUT, $MyOffset + $SIZE_OF_FI*$RecordIndex,0);
syswrite($r_H_OUTPUT,$DirRecord,16,0);
seek($r_H_OUTPUT, $MyOffset + $SIZE_OF_FI*$RecordIndex+8,0);
$FileSettleAddress = $FileSettleOffset + $AbsoluteHeadAddr;
syswrite($r_H_OUTPUT,pack("$BuildRscCFile::ui32","$FileSettleAddress"),4,0); # rewrite the file settle address
}
elsif (($RecordAttr & 0xC0) == 0xC0) # compact dir
{
# print "... handle Compact Dir : $RecordFileNames\n";
# step 1: copy compact dir file to output
# give compact dir a 16 bytes bound offset, in fact 8 bytes boundary is enough.
$MyUsedSize = int(($MyUsedSize+15)/16)*16;#start from 16 bytes boundary
$FileSettleOffset = $MyOffset+$MyDirSize+$MyUsedSize;
seek($r_H_OUTPUT, $FileSettleOffset,0);
open (H_CDIR_FILE,"$RecordFileNames") || die ("Error: Can not open file \"$RecordFileNames\"\n");
binmode (H_CDIR_FILE);
while(sysread(H_CDIR_FILE,$char,1,0))
{
syswrite($r_H_OUTPUT,$char,1,0);
}
close (H_CDIR_FILE);
@file_state = stat("$RecordFileNames");
$MyUsedSize += $file_state[7];
# step 2: copy CDD file to output
my $CDDFileName = $RecordFileNames;
$CDDFileName =~ s/\.dir/\.cdd/i;
# print "... handle CDD File : $CDDFileName\n";
open (H_CDD_FILE,"$CDDFileName")|| die ("Error: Can not open file \"$CDDFileName\"\n");
binmode (H_CDD_FILE);
while(sysread(H_CDD_FILE,$char,1,0))
{
syswrite($r_H_OUTPUT,$char,1,0);
}
close (H_CDD_FILE);
@file_state = stat("$CDDFileName");
$MyUsedSize += $file_state[7];
$MyUsedSize = int(($MyUsedSize+15)/16)*16;#end with 16 bytes boundary
# step 3 : write record string.
seek($r_H_OUTPUT, $MyOffset + $SIZE_OF_FI*$RecordIndex,0);
syswrite($r_H_OUTPUT,$DirRecord,16,0);
seek($r_H_OUTPUT, $MyOffset + $SIZE_OF_FI*$RecordIndex+8,0);
$FileSettleAddress = $FileSettleOffset + $AbsoluteHeadAddr;
syswrite($r_H_OUTPUT,pack("$BuildRscCFile::ui32","$FileSettleAddress"),4,0); # rewrite the file settle address
}
else # normal file
{
# step 1: copy file to output
$MyUsedSize = int(($MyUsedSize+15)/16)*16; #start from 16 bytes boundary
$FileSettleOffset = $MyOffset+$MyDirSize+$MyUsedSize;
#<1>print "... handle File : $RecordFileNames, offset is $FileSettleOffset\n";
seek($r_H_OUTPUT, $FileSettleOffset,0);
open (H_NORMAL_FILE,"$RecordFileNames") || die ("Error: Can not open file \"$RecordFileNames\"\n");
binmode (H_NORMAL_FILE);
while(sysread(H_NORMAL_FILE,$char,1,0))
{
syswrite($r_H_OUTPUT,$char,1,0);
}
close (H_NORMAL_FILE);
@file_state = stat("$RecordFileNames");
$MyUsedSize += $file_state[7];
$MyUsedSize = int(($MyUsedSize+15)/16)*16;#end with 16 bytes boundary
# step 2 : write record string.
seek($r_H_OUTPUT, $MyOffset + $SIZE_OF_FI*$RecordIndex,0);
syswrite($r_H_OUTPUT,$DirRecord,16,0);
seek($r_H_OUTPUT, $MyOffset + $SIZE_OF_FI*$RecordIndex+8,0);
$FileSettleAddress = $FileSettleOffset + $AbsoluteHeadAddr;
syswrite($r_H_OUTPUT,pack("$BuildRscCFile::ui32","$FileSettleAddress"),4,0); # rewrite the file settle address
}
$RecordIndex ++;
}
$recursion_level --;
close($FILE_HANDLE_STR);
#<1>print "\n size $DirFile uses is $MyUsedSize\n";
return ($MyDirSize + $MyUsedSize);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -