; ================================================================================
; 								ResCompile
; ================================================================================
;
; 	By fat115
; 	License : GNU/LGPL v2.1
; 	Cette bibliothèque contient des fonctions permettant de créer un fichier 
;	ressource VersionInfo pouvant ensuite être utilisé pour patcher un fichier binaire.
; 	This library contains some functions allowing to create a VersionInfo resource
;	file wich can be further used to patch a binary file.

; 	Compiler: AutoHotkey (http://www.autohotkey.com/).
; 	$id=ResCompile.ahk $date=2010-02-21
;
; --------------------------------------------------------------------------------
;						Copyright (C) 2010 Framakey

;						Website: http://www.framakey.org

;	This library is free software; you can redistribute it and/or
;	modify it under the terms of the GNU Lesser General Public
;	License as published by the Free Software Foundation; either
;	version 2.1 of the License, or (at your option) any later version.

;	This library is distributed in the hope that it will be useful,
;	but WITHOUT ANY WARRANTY; without even the implied warranty of
;	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
;	Lesser General Public License for more details.

;	You should have received a copy of the GNU Lesser General Public
;	License along with this library; if not, write to the Free Software
;	Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA

; --------------------------------------------------------------------------------


/*
******************************************************************************
|
***************************** Creation Functions *****************************
|
|	- CreateVar:			create the Var Structure (no need to call this)
|	- CreateVarFileInfo:	create the VarFileInfo Structure (using CreateVar)
|	- CreateString:			create a String Structure, child of StringTable
|	- CreateStringTable:	create StringTable Structure using all previous
|							String Structure children
|	- CreateStringFileInfo:	create StringFileInfo Structure using previous
|							StringTable
|	- CreateVSFixed:		create VS_FIXEDFILEINFO (see TODO)
|	- CreateVSVersion:		create complete VS_VERSIONINFO Structure, the
|							string returned need to be written as a binary
|							file to create the resource file.
|							This can be done with BinWrite function from :
|								http://www.autohotkey.com/forum/topic4546.html
|
******************************************************************************
*/

CreateVar(h_LangCode, h_CharSet, i_Type = 0)
{
; Var Structure / Element Reference
;	WORD   wLength;			/ Elem1
;	WORD   wValueLength;	/ Elem2
;	WORD   wType;			/ Elem3 = i_Type
;	WCHAR  szKey[];			/ Elem4 = Translation
;	WORD   Padding[];		/ Elem5
;	WORD   Value[];			/ Elem6 = h_LangCode + h_CharSet

/*
Language codes
	0000 Neutral
	0401 Arabic
	0402 Bulgarian
	0403 Catalan
	0404 Traditional Chinese
	0405 Czech
	0406 Danish
	0407 German
	0408 Greek
	0409 U.S. English
	040A Castilian Spanish
	040B Finnish
	040C French
	040D Hebrew
	040E Hungarian
	040F Icelandic
	0410 Italian
	0411 Japanese
	0412 Korean
	0413 Dutch
	0414 Norwegian - Bokml
	0810 Swiss Italian
	0813 Belgian Dutch (Cyrillic)
	0814 Norwegian - Nynorsk
	0415 Polish
	0416 Brazilian Portuguese
	0417 Rhaeto-Romanic
	0418 Romanian
	0419 Russian
	041A Croato-Serbian (Latin)
	041B Slovak
	041C Albanian
	041D Swedish
	041E Thai
	041F Turkish
	0420 Urdu
	0421 Bahasa
	0804 Simplified Chinese
	0807 Swiss German
	0809 U.K. English
	080A Mexican Spanish
	080C Belgian French
	0C0C Canadian French
	100C Swiss French
	0816 Portuguese
	081A Serbo-Croatian (Cyrillic)

Character Set
	0000  7-bit ASCII
	03A4  Windows, Japan (Shift - JIS X-0208)
	03B5  Windows, Korea (Shift - KSC 5601)
	03B6  Windows, Taiwan (GB5)
	04B0  Unicode
	04E2  Windows, Latin-2 (Eastern European)
	04E3  Windows, Cyrillic
	04E4  Windows, Multilingual
	04E5  Windows, Greek
	04E6  Windows, Turkish
	04E7  Windows, Hebrew
	04E8  Windows, Arabic
*/

	Elem3 := IntToWord(i_Type)
	Elem4 := IsszKey(TextToHex("Translation"))
	Elem5 := iif(Mod(CountWords(Elem4),2),"","0000")
	Elem6 := HexToWord(h_LangCode) . HexToWord(h_CharSet)
	Elem2 := IntToWord(CountWords(Elem6)*2)
	Elem1 := IntToWord((1+CountWords(Elem2 . Elem3 . Elem4 . Elem5 . Elem6))*2)
	s_Element := Elem1 . Elem2 . Elem3 . Elem4 . Elem5 . Elem6
	s_Padding := iif(Mod(CountWords(s_Element),2),"0000","")
	s_Element .= s_Padding
Return %s_Element%
}

CreateVarFileInfo(h_LangCode, h_CharSet, i_Type = 1, i_VarType = 0)
{
; VarFileInfo Structure / Element Reference
;	WORD   wLength;			/ Elem1
;	WORD   wValueLength;	/ Elem2
;	WORD   wType;			/ Elem3
;	WCHAR  szKey[];			/ Elem4
;	WORD   Padding[];		/ Elem5
;	Var    Children[];		/ Elem6

	Elem3 := IntToWord(i_Type)
	Elem4 := IsszKey(TextToHex("VarFileInfo"))
	Elem5 := iif(Mod(CountWords(Elem4),2),"","0000")
	Elem6 := CreateVar(h_LangCode, h_CharSet, i_VarType)
	Elem2 := IntToWord(0)
	Elem1 := IntToWord((1+CountWords(Elem2 . Elem3 . Elem4 . Elem5 . Elem6))*2)
	s_Element := Elem1 . Elem2 . Elem3 . Elem4 . Elem5 . Elem6
	s_Padding := iif(Mod(CountWords(s_Element),2),"0000","")
	s_Element .= s_Padding
Return %s_Element%
}

CreateString(s_szKey, s_Value, i_Type = 1)
{
; String Structure / Element Reference
;	WORD   wLength;			/ Elem1
;	WORD   wValueLength;	/ Elem2
;	WORD   wType;			/ Elem3
;	WCHAR  szKey[];			/ Elem4
;	WORD   Padding[];		/ Elem5
;	WORD   Value[];			/ Elem6

/*
Guidelines values for szKey :
	Comments
	CompanyName
	FileDescription
	FileVersion
	InternalName
	LegalCopyright
	LegalTrademarks
	OriginalFilename
	PrivateBuild
	ProductName
	ProductVersion
	BuilID
	SpecialBuild
*/

	Elem3 := IntToWord(i_Type)
	Elem4 := IsszKey(TextToHex(s_szKey))
	Elem5 := iif(Mod(CountWords(Elem4),2),"","0000")
	Elem6 := IsszKey(TextToHex(s_Value))
	Elem2 := IntToWord(CountWords(Elem6))
	Elem1 := IntToWord((1+CountWords(Elem2 . Elem3 . Elem4 . Elem5 . Elem6))*2)
	s_Element := Elem1 . Elem2 . Elem3 . Elem4 . Elem5 . Elem6
	s_Padding := iif(Mod(CountWords(s_Element),2),"0000","")
	s_Element .= s_Padding
Return %s_Element%
}

CreateStringTable(h_LangCode, h_CharSet, s_StringList, i_Type = 1)
{
; StringTable Structure / Element Reference
;	WORD   wLength;			/ Elem1
;	WORD   wValueLength;	/ Elem2
;	WORD   wType;			/ Elem3
;	WCHAR  szKey[];			/ Elem4
;	WORD   Padding[];		/ Elem5
;	String    Children[];	/ Elem6

	StringReplace, h_LangCode, h_LangCode, 0x
	StringReplace, h_CharSet, h_CharSet, 0x
	Elem3 := IntToWord(i_Type)
	Elem4 := IsszKey(TextToHex(h_LangCode) . TextToHex(h_CharSet))
	Elem5 := iif(Mod(CountWords(Elem4),2),"","0000")
	Elem6 := s_StringList
	Elem2 := IntToWord(0)
	Elem1 := IntToWord((1+CountWords(Elem2 . Elem3 . Elem4 . Elem5 . Elem6))*2-iif(SubStr(s_StringList, StrLen(s_StringList)-7)="00000000",2,0))
	s_Element := Elem1 . Elem2 . Elem3 . Elem4 . Elem5 . Elem6
	s_Padding := iif(Mod(CountWords(s_Element),2),"0000","")
	s_Element .= s_Padding
Return %s_Element%
}

CreateStringFileInfo(s_StringTable, i_Type = 1)
{
; StringFileInfo Structure / Element Reference
;	WORD   wLength;			/ Elem1
;	WORD   wValueLength;	/ Elem2
;	WORD   wType;			/ Elem3
;	WCHAR  szKey[];			/ Elem4
;	WORD   Padding[];		/ Elem5
;	StringTable Children[];	/ Elem6

	Elem3 := IntToWord(i_Type)
	Elem4 := IsszKey(TextToHex("StringFileInfo"))
	Elem5 := iif(Mod(CountWords(Elem4),2),"","0000")
	Elem6 := s_StringTable
	Elem2 := IntToWord(0)
	Elem1 := IntToWord((1+CountWords(Elem2 . Elem3 . Elem4 . Elem5 . Elem6))*2-iif(SubStr(StringTable, StrLen(StringTable)-7)="00000000",2,0))
	s_Element := Elem1 . Elem2 . Elem3 . Elem4 . Elem5 . Elem6
	s_Padding := iif(Mod(CountWords(s_Element),2),"0000","")
	s_Element .= s_Padding
Return %s_Element%
}

CreateVSFixed(dwFileVersion= "1,0,0,0", dwProductVersion= "1,0,0,0", dwSignature= "0xFEEF04BD", dwStrucVersion= "0x10000", dwFileFlagsMask= "0x3f", dwFileFlags= "0x0", dwFileOS= "0x4", dwFileType= "0x2", dwFileSubtype= "0x0", dwFileDateMS= "0x0", dwFileDateLS= "0x0")
{
; VX_FIXEDFILEINFO Structure
;	DWORD dwSignature;
;	DWORD dwStrucVersion;
;	DWORD dwFileVersionMS;
;	DWORD dwFileVersionLS;
;	DWORD dwProductVersionMS;
;	DWORD dwProductVersionLS;
;	DWORD dwFileFlagsMask;
;	DWORD dwFileFlags;
;	DWORD dwFileOS;
;	DWORD dwFileType;
;	DWORD dwFileSubtype;
;	DWORD dwFileDateMS;
;	DWORD dwFileDateLS;

; TODO : improve support for StrucVersion, FileFlags, FileSubType and FileDate

	Elem1 := HexToDWord(dwSignature)
	Elem2 := HexToDWord(dwStrucVersion)
	Elem3 := VerToQWord(dwFileVersion)
	Elem5 := VerToQWord(dwProductVersion)
	Elem7 := HexToWord(dwFileFlagsMask) . "0000"
	Elem8 := HexToWord(dwFileFlags) . "0000"
	Elem9 := HexToWord(dwFileOS) . "0000"
	Elem10 := HexToWord(dwFileType) . "0000"
	Elem11 := HexToWord(dwFileSubtype) . "0000"
	Elem12 := HexToDWord(dwFileDateMS)
	Elem13 := HexToDWord(dwFileDateLS)
	s_Element := Elem1 . Elem2 . Elem3 . Elem5 . Elem7 . Elem8 . Elem9 . Elem10 . Elem11 . Elem12 . Elem13
Return %s_Element%
}

CreateVSVersion(s_VSFixed, s_StringFileInfo, s_VarFileInfo, i_Type = 0)
{
; StringFileInfo Structure / Element Reference
;	WORD   wLength;			/ Elem1
;	WORD   wValueLength;	/ Elem2
;	WORD   wType;			/ Elem3
;	WCHAR  szKey[];			/ Elem4
;	WORD   Padding[];		/ Elem5
;	VS_FIXEDFILEINFO  Value	/ Elem6
;	WORD   Padding[];		/ Optional
;	WORD   Children[];		/ Elem7

	Elem3 := IntToWord(i_Type)
	Elem4 := IsszKey(TextToHex("VS_VERSION_INFO"))
	Elem5 := iif(Mod(CountWords(Elem4),2),"","0000")
	Elem6 := s_VSFixed
	Elem7 := s_StringFileInfo . s_VarFileInfo
	Elem2 := IntToWord(CountWords(s_VSFixed)*2)
	Elem1 := IntToWord((1+CountWords(Elem2 . Elem3 . Elem4 . Elem5 . Elem6 . Elem7))*2)
	s_Element := Elem1 . Elem2 . Elem3 . Elem4 . Elem5 . Elem6 . Elem7
Return %s_Element%
}

/*
******************************************************************************
|
**************************** Conversion Functions ****************************
|
|	- IntToWord :	convert an integer value to a little-endian Word
|	- HexToWord :	convert an hexadecimal value (0xFFFF or FFFF supported) to
|					a little-endian Word
|	- HexToDWord :	same as above but to a little endian DWord
|	- VerToQWord :	convert a version string (ie : 1,2,3,4) to a little-endian
|					QWord. Use commas not dots !
|	- TextToHex :	convert a string (iso8859-1 or similar ? ) to hexadecimal
|					(each char = one word, MS talks about "Unicode string" ??)
|
******************************************************************************
*/

IntToWord(i_entier)
{
	FormatInt := A_FormatInteger
	SetFormat Integer, Hex
	; conversion to hex value
	i_entier += 0
	SetFormat Integer, %FormatInt%
	; conversion to Word (4 hexa digits)
	StringTrimLeft, i_entier, i_entier, 2
	i_entier := "0000" . i_entier
	StringRight, i_entier, i_entier, 4
	w_mot := SubStr(i_entier, 3, 2) . SubStr(i_entier, 1, 2)
Return %w_mot%
}

HexToWord(h_hexa)
{
	StringReplace, h_hexa, h_hexa, 0x
	h_hexa := "0000" . h_hexa
	StringRight, h_hexa, h_hexa, 4
	w_mot := SubStr(h_hexa, 3, 2) . SubStr(h_hexa, 1, 2)
Return %w_mot%
}

HexToDWord(h_hexa)
{
	StringReplace, h_hexa, h_hexa, 0x
	h_hexa := "00000000" . h_hexa
	StringRight, h_hexa, h_hexa, 8
	dw_mot := HexToWord(SubStr(h_hexa, 5, 4)) . HexToWord(SubStr(h_hexa, 1, 4))
Return %dw_mot%
}

VerToQWord(s_chaine)
{
	qw_Result =
	StringSplit, Num, s_chaine, `,
	Loop, 4
		Num%A_Index% := IntToWord(Num%A_Index%)
	qw_Result := NUm2 . Num1 . Num4 . Num3
Return %qw_Result%
}

TextToHex(s_chaine)
{
	FormatInt := A_FormatInteger
	s_Result =
	SetFormat Integer, Hex
	Loop % StrLen(s_chaine)
	{
		Conv := Asc(SubStr(s_chaine, A_Index, 1))
		; conversion to Byte (2 digits)
		StringTrimLeft, Conv, Conv, 2
		Conv := "00" . Conv
		StringRight, Conv, Conv, 2
		; concatenation and storage in Word (4 digits) (Unicode string ??)
		s_Result .= Conv . "00"
	}
	SetFormat Integer, %FormatInt%
Return %s_Result%
}



/*
******************************************************************************
|
************************** Miscellaneous Functions ***************************
|
|	- IsszKey :		add NULL Word to terminate szKey
|	- CountWords :	count the number of Words in the string (integer result)
|	- iif :			test function, uncomment if you don't use w0xx0m's
|					FileGetFullVer function :
|					(http://www.autohotkey.com/forum/topic8618.html
|
******************************************************************************
*/

IsszKey(s_chaine)
{
Return %s_chaine%0000
}

CountWords(s_chaine)
{
	i_NbWords := StrLen(s_chaine)//4
Return %i_NbWords%
}

/*
iif(expr, a, b)
{
   if (expr)
      return a
   else
      return b
}
*/

