2015-03-04 09:33:04 +00:00
using System ;
using System.Text.RegularExpressions ;
using System.IO ;
using System.Collections.Generic ;
using System.Linq ;
namespace BizHawk.Build.Tool
{
class Program
{
static void Main ( string [ ] args )
{
string cmd = args [ 0 ] ;
string [ ] cmdArgs = Crop ( args , 1 ) ;
switch ( cmd . ToUpperInvariant ( ) )
{
2015-06-25 01:44:13 +00:00
case "SVN_REV" : SVN_REV ( true , cmdArgs ) ; break ;
case "GIT_REV" : SVN_REV ( false , cmdArgs ) ; break ;
2015-09-10 21:53:48 +00:00
case "NXCOMPAT" : NXCOMPAT ( cmdArgs ) ; break ;
2016-02-14 22:41:07 +00:00
case "LARGEADDRESS" : LARGEADDRESS ( cmdArgs ) ; break ;
2015-03-04 09:33:04 +00:00
}
}
static string [ ] Crop ( string [ ] arr , int from )
{
return arr . Reverse ( ) . Take ( arr . Length - from ) . Reverse ( ) . ToArray ( ) ;
}
static string EscapeArgument ( string s )
{
return "\"" + Regex . Replace ( s , @"(\\+)$" , @"$1$1" ) + "\"" ;
}
static string RunTool ( string path , params string [ ] args )
{
string args_combined = "" ;
foreach ( var a in args )
args_combined + = EscapeArgument ( a ) + " " ;
args_combined . TrimEnd ( ' ' ) ;
var psi = new System . Diagnostics . ProcessStartInfo ( ) ;
psi . Arguments = args_combined ;
psi . FileName = path ;
psi . UseShellExecute = false ;
psi . CreateNoWindow = true ;
psi . RedirectStandardOutput = true ;
var proc = new System . Diagnostics . Process ( ) ;
proc . StartInfo = psi ;
proc . Start ( ) ;
string output = "" ;
while ( ! proc . StandardOutput . EndOfStream )
{
output + = proc . StandardOutput . ReadLine ( ) ;
// do something with line
}
return output ;
}
static void WriteTextIfChanged ( string path , string content )
{
if ( ! File . Exists ( path ) )
goto WRITE ;
string old = File . ReadAllText ( path ) ;
if ( old = = content ) return ;
WRITE :
File . WriteAllText ( path , content ) ;
}
2016-02-14 22:41:07 +00:00
static void LARGEADDRESS ( string [ ] args )
{
string target = null , strValue = "0" ;
int idx = 0 ;
while ( idx < args . Length )
{
string a = args [ idx + + ] ;
string au = a . ToUpperInvariant ( ) ;
if ( au = = "--TARGET" )
target = args [ idx + + ] ;
if ( au = = "--VALUE" )
strValue = args [ idx + + ] ;
}
if ( target = = null )
{
Console . WriteLine ( "LARGEADDRESS: No target EXE specified" ) ;
return ;
}
//http://stackoverflow.com/questions/9054469/how-to-check-if-exe-is-set-as-largeaddressaware
using ( var fs = new FileStream ( target , FileMode . Open , FileAccess . ReadWrite , FileShare . Read ) )
{
var br = new BinaryReader ( fs ) ;
if ( br . ReadInt16 ( ) ! = 0x5A4D ) //No MZ Header
return ;
br . BaseStream . Position = 0x3C ;
var peloc = br . ReadInt32 ( ) ; //Get the PE header location.
br . BaseStream . Position = peloc ;
if ( br . ReadInt32 ( ) ! = 0x4550 ) //No PE header
return ;
br . BaseStream . Position + = 0x12 ;
var characteristics = br . ReadUInt16 ( ) ;
characteristics & = unchecked ( ( ushort ) ~ 0x20 ) ; //IMAGE_FILE_LARGE_ADDRESS_AWARE
if ( strValue = = "1" ) characteristics | = 0x20 ;
fs . Position - = 2 ; //move back to characteristics
var bw = new BinaryWriter ( fs ) ;
bw . Write ( characteristics ) ;
bw . Flush ( ) ;
}
}
2015-09-10 21:53:48 +00:00
//sets NXCOMPAT bit in PE header
static void NXCOMPAT ( string [ ] args )
{
string target = null , strValue = "0" ;
int idx = 0 ;
while ( idx < args . Length )
{
string a = args [ idx + + ] ;
string au = a . ToUpperInvariant ( ) ;
if ( au = = "--TARGET" )
target = args [ idx + + ] ;
if ( au = = "--VALUE" )
strValue = args [ idx + + ] ;
}
if ( target = = null )
{
Console . WriteLine ( "NXCOMPAT: No target EXE specified" ) ;
return ;
}
//we're going to skip around through the file and edit only the minimum required bytes (to speed things up by avoiding loading and rewriting the entire exe)
using ( var fs = new FileStream ( target , FileMode . Open , FileAccess . ReadWrite , FileShare . Read ) )
{
var br = new BinaryReader ( fs ) ;
fs . Position = 0x3C ;
fs . Position = br . ReadUInt16 ( ) ; //move to NT_HEADERS
fs . Position + = 0x18 ; //move to OPTIONAL_HEADER
fs . Position + = 0x46 ; //move to DllCharacteristics
var dllCharacteristics = br . ReadUInt16 ( ) ;
dllCharacteristics & = unchecked ( ( ushort ) ~ 0x100 ) ;
if ( strValue = = "1" ) dllCharacteristics | = 0x100 ;
fs . Position - = 2 ; //move back to DllCharacteristics
var bw = new BinaryWriter ( fs ) ;
bw . Write ( dllCharacteristics ) ;
bw . Flush ( ) ;
}
}
2015-03-04 09:33:04 +00:00
//gets the working copy version. use this command:
//BizHawk.Build.Tool.exe SCM_REV --wc c:\path\to\wcdir --template c:\path\to\templatefile --out c:\path\to\outputfile.cs
//if the required tools aren't found
2015-06-25 01:44:13 +00:00
static void SVN_REV ( bool svn , string [ ] args )
2015-03-04 09:33:04 +00:00
{
string wcdir = null , templatefile = null , outfile = null ;
int idx = 0 ;
while ( idx < args . Length )
{
string a = args [ idx + + ] ;
string au = a . ToUpperInvariant ( ) ;
if ( au = = "--WC" )
wcdir = args [ idx + + ] ;
if ( au = = "--TEMPLATE" )
templatefile = args [ idx + + ] ;
if ( au = = "--OUT" )
outfile = args [ idx + + ] ;
}
//first read the template
string templateContents = File . ReadAllText ( templatefile ) ;
//pick revision 0 in case the WC investigation fails
int rev = 0 ;
2015-06-25 01:44:13 +00:00
//pick branch unnamed in case investigation fails (or isnt git)
string branch = "" ;
2015-06-25 02:44:03 +00:00
//pick no hash in case investigation fails (or isnt git)
string shorthash = "" ;
2015-06-25 01:44:13 +00:00
//try to find an SVN or GIT and run it
if ( svn )
2015-03-04 09:33:04 +00:00
{
2015-06-25 01:44:13 +00:00
string svntool = FileLocator . LocateTool ( "svnversion" ) ;
if ( svntool ! = "" )
{
try
{
string output = RunTool ( svntool , wcdir ) ;
var parts = output . Split ( ':' ) ;
var rstr = parts [ parts . Length - 1 ] ;
rstr = Regex . Replace ( rstr , "[^0-9]" , "" ) ;
rev = int . Parse ( rstr ) ;
}
catch ( Exception ex )
{
Console . WriteLine ( ex ) ;
}
2015-03-04 09:33:04 +00:00
}
2015-06-25 01:44:13 +00:00
}
else
{
string gittool = FileLocator . LocateTool ( "git" ) ;
if ( gittool ! = "" )
2015-03-04 09:33:04 +00:00
{
2015-06-25 01:44:13 +00:00
try
{
string output = RunTool ( gittool , "-C" , wcdir , "rev-list" , "HEAD" , "--count" ) ;
if ( int . TryParse ( output , out rev ) )
{
output = RunTool ( gittool , "-C" , wcdir , "rev-parse" , "--abbrev-ref" , "HEAD" ) ;
if ( output . StartsWith ( "fatal" ) ) { }
else branch = output ;
2015-06-25 02:44:03 +00:00
output = RunTool ( gittool , "-C" , wcdir , "log" , "-1" , "--format=\"%h\"" ) ;
if ( output . StartsWith ( "fatal" ) ) { }
else shorthash = output ;
2015-06-25 01:44:13 +00:00
}
}
catch ( Exception ex )
{
Console . WriteLine ( ex ) ;
}
2015-03-04 09:33:04 +00:00
}
}
//replace the template and dump the results if needed
templateContents = templateContents . Replace ( "$WCREV$" , rev . ToString ( ) ) ;
2015-06-25 01:44:13 +00:00
templateContents = templateContents . Replace ( "$WCBRANCH$" , branch ) ;
2015-06-25 02:44:03 +00:00
templateContents = templateContents . Replace ( "$WCSHORTHASH$" , shorthash ) ;
2015-03-04 09:33:04 +00:00
WriteTextIfChanged ( outfile , templateContents ) ;
}
}
}