⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 filemap.pl

📁 M3355的源代码
💻 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 + -