mirror of
https://github.com/nillerusr/source-engine.git
synced 2024-12-22 22:27:05 +00:00
330 lines
6.1 KiB
Perl
Executable File
330 lines
6.1 KiB
Perl
Executable File
###############################################################
|
|
#
|
|
# generateDEF.pl
|
|
#
|
|
# Parses a .map file and generates a .def file
|
|
# for exporting functions from a dll.
|
|
#
|
|
# Note: Map Exports must be enabled in the project properties
|
|
#
|
|
###############################################################
|
|
|
|
my @baselist;
|
|
my @output;
|
|
my $baseLen = 63;
|
|
|
|
######################################
|
|
# Adds tabs for better formatting
|
|
|
|
sub Add_Tabs
|
|
{
|
|
my $name = shift;
|
|
my $num = int( ($baseLen - length( $name )) / 8 );
|
|
|
|
for( $i = 0; $i < $num; $i++ )
|
|
{
|
|
push( @output, "\t" );
|
|
}
|
|
}
|
|
|
|
######################################
|
|
# Open, validate, and read a file (not implemented yet)
|
|
|
|
sub Read_File
|
|
{
|
|
my $name = shift;
|
|
my @file = shift;
|
|
|
|
# read in the file
|
|
if ( open(INFILE, "$name" ) )
|
|
{
|
|
@file = <INFILE>;
|
|
close( INFILE );
|
|
}
|
|
else
|
|
{
|
|
print( "Error opening file $name\n" );
|
|
exit 1;
|
|
}
|
|
}
|
|
|
|
#####################################
|
|
# Start of script
|
|
|
|
print( "Valve Software - make360def.pl\n" );
|
|
print( "Copyright (c) 1996-2006, Valve LLC, All rights reserved.\n" );
|
|
|
|
my $filename = $ARGV[0];
|
|
my $numArgs = 1;
|
|
my @lines = ();
|
|
my @deflines = ();
|
|
|
|
if ( $ARGV[0] =~ /-check$/i )
|
|
{
|
|
$numArgs = 3;
|
|
$check = 1;
|
|
$filename = $ARGV[1];
|
|
$defname = $ARGV[2];
|
|
}
|
|
elsif ( $ARGV[0] =~ /-checkauto/i )
|
|
{
|
|
$defname = $ARGV[1];
|
|
$check = 2;
|
|
}
|
|
|
|
if ( @ARGV < $numArgs )
|
|
{
|
|
print( "ERROR: Missing filename(s)\n" );
|
|
exit 1;
|
|
}
|
|
|
|
if ( $check == 1 )
|
|
{
|
|
# swap filenames if necessary
|
|
if ( $filename =~ /.def/ )
|
|
{
|
|
my $temp = $filename;
|
|
$filename = $defname;
|
|
$defname = $temp;
|
|
}
|
|
|
|
# validate extensions
|
|
unless ( $filename =~ /.map/ && $defname =~ /.def/ )
|
|
{
|
|
print( "ERROR: Invalid file extensions. -check requires a .map file and a .def file.\n" );
|
|
exit 1;
|
|
}
|
|
|
|
# read in the def file
|
|
if ( open(INFILE, "$defname" ) )
|
|
{
|
|
@deflines = <INFILE>;
|
|
close( INFILE );
|
|
}
|
|
else
|
|
{
|
|
print( "ERROR: Couldn't open file $defname.\n" );
|
|
exit 1;
|
|
}
|
|
}
|
|
elsif ( $check == 2 )
|
|
{
|
|
# read in the def file
|
|
if ( open(INFILE, "$defname" ) )
|
|
{
|
|
@deflines = <INFILE>;
|
|
close( INFILE );
|
|
}
|
|
else
|
|
{
|
|
print( "ERROR: Couldn't open file $defname.\n" );
|
|
exit 1;
|
|
}
|
|
|
|
# validate that the first export is CreateInterface*
|
|
# validate that the export ordinals are sequential and ordered
|
|
|
|
my $line;
|
|
my $start = false;
|
|
my $idx = 1;
|
|
for ( @deflines )
|
|
{
|
|
$line = $_;
|
|
|
|
if ( $line =~ /@(\d+)[ |\n]/ )
|
|
{
|
|
if ( $1 == 1 )
|
|
{
|
|
unless ( $line =~ /CreateInterface/ )
|
|
{
|
|
# first export must be CreateInterface*
|
|
$line =~ /\s+([\S]*)/;
|
|
|
|
print( "**************************************************\n" );
|
|
print( " ERROR: First export must be CreateInterface*. \n" );
|
|
print( " Export \"", $1, "\" found instead! \n" );
|
|
print( " This is a FATAL ERROR with the def file. \n" );
|
|
print( " Please contact an Xbox 360 engineer immediately.\n" );
|
|
print( "**************************************************\n" );
|
|
exit 1;
|
|
}
|
|
}
|
|
|
|
if ( $1 != $idx )
|
|
{
|
|
# exports are out of order
|
|
print( "**************************************************\n" );
|
|
print( " ERROR: Def file exports are not sequential \n" );
|
|
print( " This may cause unexpected behavior at runtime. \n" );
|
|
print( " Please contact an Xbox 360 engineer immediately.\n" );
|
|
print( "**************************************************\n" );
|
|
exit 1;
|
|
}
|
|
|
|
++$idx;
|
|
}
|
|
}
|
|
|
|
exit 0;
|
|
}
|
|
|
|
# Get the base name
|
|
|
|
$filename =~ /(\w+(\.360)?).map/;
|
|
my $basename = $1;
|
|
|
|
# Read in the source file
|
|
|
|
if ( open(INFILE, "$filename" ) )
|
|
{
|
|
@lines = <INFILE>;
|
|
close( INFILE );
|
|
}
|
|
else
|
|
{
|
|
print( "ERROR: Couldn't open file $filename.\n" );
|
|
exit 1;
|
|
}
|
|
|
|
# Delete the lines up to the exports section
|
|
|
|
my $len = 0;
|
|
my $exportsFound = 0;
|
|
for( @lines )
|
|
{
|
|
$len++;
|
|
if( /^ Exports$/ )
|
|
{
|
|
splice( @lines, 0, $len+3 );
|
|
$exportsFound = 1;
|
|
}
|
|
}
|
|
|
|
if ( $exportsFound == 0 )
|
|
{
|
|
print( "ERROR: No Exports section found in $filename. " );
|
|
print( "Relink the project with 'Map Exports' enabled.\n" );
|
|
exit 1;
|
|
}
|
|
|
|
if ( $check == 1 )
|
|
{
|
|
# Check for exports in the map that aren't in the def
|
|
print( "make360def: Comparing $filename and $defname\n" );
|
|
|
|
# strip the first 2 lines from the def
|
|
splice( @deflines, 0, 2 );
|
|
|
|
my $defEntryCt = $#deflines + 1;
|
|
my $defMatches = 0;
|
|
|
|
# for each line in the map
|
|
for( @lines )
|
|
{
|
|
my $found = 0;
|
|
|
|
# Pull the export name from the map line
|
|
|
|
my $mapline;
|
|
if ( /(\d+)\s+(\S+)/ )
|
|
{
|
|
$mapline = $2;
|
|
}
|
|
else
|
|
{
|
|
# ignore this line
|
|
next;
|
|
}
|
|
|
|
# for each line in the def
|
|
for( @deflines )
|
|
{
|
|
/(\S+)/;
|
|
|
|
if ( $1 =~ /^\Q$mapline\E$/ )
|
|
{
|
|
$found = 1;
|
|
$defMatches++;
|
|
last;
|
|
}
|
|
}
|
|
|
|
if ( $found == 0 )
|
|
{
|
|
print( "ERROR: New export found in $filename, " );
|
|
print( "so the map file and def file are out of sync. " );
|
|
print( "You must relink the project to generate a new def file.\n" );
|
|
exit 1;
|
|
}
|
|
}
|
|
|
|
# Make sure all the def lines were matched
|
|
if ( $defMatches != $defEntryCt )
|
|
{
|
|
print( "ERROR: An export was removed from $filename, " );
|
|
print( "so the map file and def file are out of sync. " );
|
|
print( "You must relink the project to generate a new def file.\n" );
|
|
exit 1;
|
|
}
|
|
|
|
print( "make360def: Comparison complete, files match.\n" );
|
|
exit 0;
|
|
}
|
|
|
|
# start the def file
|
|
|
|
print( "make360def: Generating $basename.def\n" );
|
|
|
|
push( @output, "LIBRARY\t$basename.dll\n" );
|
|
push( @output, "EXPORTS\n" );
|
|
|
|
# process each line in the export section
|
|
|
|
my $interfacePrefix = "0000000000";
|
|
for( @lines )
|
|
{
|
|
if ( /(\d+)\s+(\S+)/ )
|
|
{
|
|
my $func = $2;
|
|
if ( $func =~ /CreateInterface/ )
|
|
{
|
|
# Force createInterface to sort first
|
|
$func = join( '', $interfacePrefix, $func );
|
|
}
|
|
|
|
push( @baselist, $func );
|
|
}
|
|
}
|
|
|
|
# sort the list
|
|
my @sortedlist = sort {uc($a) cmp uc($b)} @baselist;
|
|
#my @sortedlist = @baselist;
|
|
|
|
my $ordinal = 1;
|
|
for( @sortedlist )
|
|
{
|
|
my $func = $_;
|
|
if ( /$interfacePrefix(.*)/ )
|
|
{
|
|
# Strip the added characters
|
|
$func = $1;
|
|
}
|
|
|
|
push( @output, "\t$func\t" );
|
|
Add_Tabs( $func );
|
|
push( @output, "\@$ordinal\n" );
|
|
$ordinal++;
|
|
}
|
|
|
|
# write the def file
|
|
|
|
print( "make360def: Saving $basename.def.\n" );
|
|
|
|
open ( OUTFILE, ">$basename.def" );
|
|
print OUTFILE @output;
|
|
close ( OUTFILE );
|
|
|
|
print( "make360def: Finished.\n" );
|
|
|
|
exit 0;
|