(.+)<\/ProjectName>/);
if (filename) {
//return only first item of regexp
return filename[1];
} else {
//There is no specified ProjectName, thus use filename without extension as our langpack name
return FSO.GetBaseName(plugin_project_file);
}
}
//Get MUUID of plugin from source file.
function GetMUUID (folder,array) {
//first, find necessary file list, we are looking for UNICODE_AWARE function, usually this function are in *.cpp, sometimes in *.c and *.h
//init fillelist array
muuidfilelist=new Array();
//search for files in "folder" by mask, put result into muuidfilelist
FindFiles (folder,"\\.cpp$|\\.c$|\\.h$",muuidfilelist);
//now we have files, let's put them to Enumerator
filesenum=new Enumerator(muuidfilelist);
//cycle through file list and lookup each file for UNICODE_AWARE
while (!filesenum.atEnd()) {
//curfile is our current file in files enumerator
curfile=filesenum.item();
//If file not zero size, read it and do the job
if (FSO.GetFile(curfile).Size!=0) {
//open file as text stream
file_stream=FSO.GetFile(curfile).OpenAsTextStream(ForReading, TristateUseDefault);
//this is a regexp to search UNICODE_AWARE
var find=/(?:UNICODE_AWARE(?:\s*?\|\s*?STATIC_PLUGIN)?,[\s\S]*?\{)(.+?)(?=\}\s{0,2}\})/g;
//read file fully into var "allstrings"
allstrings=file_stream.ReadAll();
//search regexp in "allstrings" and put results into var "string"
string=find.exec(allstrings);
//if current file have found UNICODE_AWARE, var "string" exists, so parse it.
if (string) {
//remove spaces, "0x" and "{", in second [1] item of array "string". RegExp "find" have subregexp (.+?), which are our MUUID in "string[1]"
vals=string[1].replace(/0x|\{|\x20/g,"");
//now split values of muuid in "vals" by "," into array "values"
values=vals.split(",");
//we get array of values, if length of this array not equal to 12 values (starting from zero, thus length is 11), that's mean we found something else, not MUUID. Log it and quit, if length is 12, so check it and generate MUUID
if (values.length==11) {
//now check, is there some values, which have omitted zero after 0x, like in alarms: " 0x4dd7762b, 0xd612, 0x4f84, { 0xaa, 0x86, 0x(no_zero_here_)6, 0x8f, 0x17, 0x85, 0x9b, 0x6d}"
//first value in values have to be 8 bytes, while length less than 8, add leading "0" to values[0],
while (values[0].length<8) {values[0]="0"+values[0]};
//next two values have to be 4 bytes, adding leading zeroes, while length less than 4.
for (i=1;i<=2;i++) {
while (values[i].length<4) {
values[i]="0"+values[i];
}
}
//other values have to be 2 bytes, same as above, adding zeroes
for (i=3;i<=10;i++) {
while (values[i].length<2) {
values[i]="0"+values[i];
}
}
//Push to array founded #muuid
var muuid="#muuid {"+values[0]+"-"+values[1]+"-"+values[2]+"-"+values[3]+values[4]+"-"+values[5]+values[6]+values[7]+values[8]+values[9]+values[10]+"}";
};
};
//close file
file_stream.Close();
}
//move to next file
filesenum.moveNext();
};
//if we didn't find muuid, put alarm into "muuid"
if (!muuid) {muuid=";#muuid for "+plugin+" not found, please specify manually!"}
//output result into array
array.push(muuid)
//log output
if (log) WScript.Echo(muuid);
};
//For status plugins, namely KeepStatus, StartupStatus and AdvancedAutoAway we need add for all of them common source files to parsing array, because they exist one layer upper of pluginfolder
function CheckStatusPlugins (plug) {
if (plug.match(/(KeepStatus|StartupStatus|AdvancedAutoAway)/)) {
resourcefiles.push(trunk+"\\Plugins\\StatusPlugins\\resource.rc");
sourcefiles.push(trunk+"\\Plugins\\StatusPlugins\\commonstatus.cpp");
sourcefiles.push(trunk+"\\Plugins\\StatusPlugins\\confirmdialog.cpp");
}
}
//Parsing filelist into stringsarray by parsefunction (ParseSourceFile OR ParseRCFile)
function ParseFiles (filelist,stringsarray, parsefunction) {
//create enumerator filesenum from filelist
filesenum=new Enumerator(filelist);
//cycle through file list
while (!filesenum.atEnd()) {
//record into current_strings current length of stringsarray
var current_strings=stringsarray.length;
//record into crap_strings current length of crap array
var crap_strings=crap.length;
//curfile is our current file in files enumerator
curfile=filesenum.item();
//now apply a parsing function to current file, and put result into stringsarray
parsefunction(curfile,stringsarray);
//string variable to cut out a trunkPath from absolute path
curfilepath=new String(curfile);
//if after parsing file our stringsarray length greater then var "current_strings", so parsed file return some strings. Thus, we need add a comment with filename
if (stringsarray.length>current_strings) stringsarray.splice(current_strings,0,";file "+curfilepath.substring(trunkPath.length));
//do the same for crap array, add a ;file +relative path to file with crap
if (crap.length>crap_strings) crap.splice(crap_strings,0,";file "+curfilepath.substring(trunkPath.length));
//move to next file
filesenum.moveNext();
};
}
//*.RC files line-by-line parser for RC_File, return result into "array"
function ParseRCFile(RC_File,array) {
//If file zero size, return;
if (FSO.GetFile(RC_File).Size==0) return;
//reading current file
RC_File_stream=FSO.GetFile(RC_File).OpenAsTextStream(ForReading, TristateUseDefault);
//Reading line-by-line
while (!RC_File_stream.AtEndOfStream) {
//Init regexp array for getting only $1 from regexp search
rc_regexp=new Array();
//clear up variable
stringtolangpack="";
//read on line into rcline
rcline=RC_File_stream.ReadLine();
//find string to translate in rcline by regexp
rc_regexp=rcline.match(/^(?!\/{1,2})\s*(?:CONTROL|(?:DEF)?PUSHBUTTON|[LRC]TEXT|AUTORADIOBUTTON|GROUPBOX|(?:AUTO)?CHECKBOX|CAPTION|MENUITEM|POPUP)\s*"((?:(?:""[^"]+?"")*[^"]*?)*)"\s*?(,|$|\\)/i);
// if exist rc_regexp, and our string length at least one symbol do checks, double "" removal and add strings into array
if (rc_regexp && rc_regexp[1].length>0) {
// check for some garbage like "List1","Tab1" etc. in *.rc files, we do not need this.
switch (rc_regexp[1]) {
case "List1": {break};
case "List2": {break};
case "Tab1": {break};
case "Tree1": {break};
case "Tree2": {break};
case "Spin1": {break};
case "Spin2": {break};
case "Spin3": {break};
case "Spin4": {break};
case "Spin5": {break};
case "Custom1": {break};
case "Custom2": {break};
case "Slider1": {break};
case "Slider2": {break};
//default action is to wrote text inside quoted into array
default:
//check result. If it does not match [a-z] (no any letter in results, such as "..." or "->") it's a crap, break further actions.
if (!rc_regexp[1].match(/[a-z]/gi)) {break};
//if there is double "", replace with single one
stringtolangpack=rc_regexp[1].replace(/\"{2}/g,"\"");
//add string to array
array.push("["+stringtolangpack+"]");
}
}
}
//closing file
RC_File_stream.Close();
};
//Source files C++ (*.h,*.c,*.cpp) and *.pas,*.dpr,*.inc (Pascal) multiline parser for translations using LPGEN() LPGENT() TranslateT() Translate() _T() TranslateW()
function ParseSourceFile (SourceFile,array) {
//If file zero size, return;
if (FSO.GetFile(SourceFile).Size==0) return;
//open file
sourcefile_stream=FSO.GetFile(SourceFile).OpenAsTextStream(ForReading, TristateUseDefault);
//not store ?: functions LPGEN or LPGENT? or Translate(T or W) or _T, than any unnecessary space \s, than not stored ?: "(" followed by ' or " (stored and used as \1) than \S\s - magic with multiline capture, ending with not stored ?= \1 (we get " or ' after "("), than none or few spaces \x20 followed by )/m=multiline g=global
//var find= /(?:LPGENT?|Translate[TW]?|_T)(?:\s*?\()(['"])([\S\s]*?)(?=\1,?\x20*?(?:tmp)?\))/mg;
//comment previous line and uncomment following line to output templates without _T() function in source files. Too many garbage from _T()..
var find= /(?:LPGENT?|Translate[TW]?)(?:\s*?\(\s*?L?\s*)(['"])([\S\s]*?)(?=\1,?\x20*?(?:tmp)?\))/mg;
//read file fully into var
allstrings=sourcefile_stream.ReadAll();
//remove all comments. The text starting with \\ (but not with ":\\" it's a links like http://miranda-ng.org/ and ")//" -there is one comment right after needed string)
//and remove multi-line comments, started with /* and ended with */
allstrings_without_comments=allstrings.replace(/(?:[^\):])(\/{2}.+?(?=$))|(\s\/\*[\S\s]+?\*\/)/mg,".")
//now make a job, till end of matching regexp
while ((string = find.exec(allstrings_without_comments)) != null) {
//first, init empty var
var string;
//replace newlines with "" in second [1] subregexp ([\S\s]*?), and Delphi newlines "'#13#10+" replace
onestring=string[2].replace(/'?(\#13\#10)*?\\?\r\n(\x20*?\')?/g,"");
//remove escape slashes before ' and "
stringtolangpack=onestring.replace(/\\(['"])/g,"$1");
//if our string still exist, and length more than 1 symbol (nothing to translate if only one symbol)
if (stringtolangpack.length>1) {
//brand new _T() crap filtering engine :)
clearstring=filter_T(stringtolangpack);
//finally put string into array including cover brackets []
if (clearstring) {array.push("["+clearstring+"]")}
};
}
//close file, we've finish.
sourcefile_stream.Close();
};
//filter _T() function results
function filter_T(string) {
//filter not begin with symbols :.]?;#~{!/_+$
//var filter1=/^[^\:\]\?\;\#\~\|\{\!\/\_\+\\$].+$/g;
//filter string starting from following words
var filter2=/^(SOFTWARE\\|SYSTEM\\|http|ftp|UTF-|utf-|TEXT|EXE|exe|txt|css|html|dat|txt|MS\x20|CLVM|TM_|CLCB|CLSID|CLUI|HKEY_|MButton|BUTTON|WindowClass|MHeader|RichEdit|RICHEDIT|STATIC|EDIT|CList|listbox|LISTBOX|combobox|COMBOBOX|TitleB|std\w|iso-|windows-||\w\\\w|urn\:|<\?xml|<\!|h\d|\.!\.).*$/g;
//filter string ending with following words
var filter3=/^.+(001|\/value|\*!\*|=)$/g;
//filter from Kildor
var filter4=/^((%(\d+)?\w\w?)|(d\s\w)|\[\/?(\w|url|img|size|quote|color)(=\w*)?\]?|(\\\w)|(%\w+%)|(([\w-]+\.)*\.(\w{2,4}|travel|museum|xn--\w+))|\W|\s|\d)+$/gi;
//filter from Kildor for remove filenames and pathes.
var filter5=/^[\w_:%.\\\/*-]+\.\w+$/g;
//apply filters to our string
//test1=filter1.test(string);
test2=filter2.test(string);
test3=filter3.test(string);
test4=filter4.test(string);
test5=filter5.test(string);
//if match (test1) first filter and NOT match other tests, thus string are good, return this string back.
//if (test1 && !test2 && !test3 && !test4 && !test5) {
if (!test2 && !test3 && !test4 && !test5) {
return string;
} else {
//in other case, string is a garbage, put into crap array.
crap.push(string);
return;
}
};
//Parse Version.h file to get one translated stirng from "Description" and make a pluging template header.
function ParseVersion_h (pluginfolder,array) {
//cleanup var
var VersionFile;
//Let's try default locations of version.h file;
//Check pluginfolder root.
if (FSO.FileExists(FSO.BuildPath(pluginfolder,"version.h"))) VersionFile=FSO.BuildPath(pluginfolder,"version.h");
//Check src\include subfolder of plugin root folder
if (FSO.FileExists(FSO.BuildPath(pluginfolder,"src\\include\\version.h"))) VersionFile=FSO.BuildPath(pluginfolder,"src\\include\\version.h");
//Check .\src subfolder
if (FSO.FileExists(FSO.BuildPath(pluginfolder,"src\\version.h"))) VersionFile=FSO.BuildPath(pluginfolder,"src\\version.h");
//If we still not found version.h, return
if (!VersionFile) return;
//open file
versionfile_stream=FSO.GetFile(VersionFile).OpenAsTextStream(ForReading, TristateUseDefault);
//read file fully into var allstrings
allstrings=versionfile_stream.ReadAll();
//define RegExp for defines.
var filename=/(?:#define\s+_*?FILENAME\s+")(.+)(?=")/m;
var pluginname=/(?:#define\s+_*?PLUG(?:IN)?_?NAME\s+")(.+)(?=")/i;
var author=/(?:#define\s+_*?(?:PLUGIN_?)?AUTHORS?\s+")(.+)(?=")/i;
var MAJOR_VERSION=/(?:#define\s+_*?(?:MAJOR_VERSION|VER_MAJOR)\s+)(\d+)/i;
var MINOR_VERSION=/(?:#define\s+_*?(?:MINOR_VERSION|VER_MINOR)\s+)(\d+)/i;
var RELEASE_NUM=/(?:#define\s+_*?(?:RELEASE_NUM|VER_REVISION|VER_RELEASE)\s+)(\d+)/i;
var BUILD_NUM=/(?:#define\s+_*?(?:BUILD_NUM|VER_BUILD)\s+)(\d+)/i;
var VERSION_STRING=/(?:#define\s+_*?VERSION_STRING\s+")([\d\.]+)\"/i;
var description=/(?:#define\s+_*?(?:PLUGIN_|MTEXT_)?DESC(?:RIPTION|_STRING)?\s+")(.+)(?=")/i;
//exec RegExps
filename=filename.exec(allstrings);
pluginname=pluginname.exec(allstrings);
MAJOR_VERSION=MAJOR_VERSION.exec(allstrings);
MINOR_VERSION=MINOR_VERSION.exec(allstrings);
RELEASE_NUM=RELEASE_NUM.exec(allstrings);
BUILD_NUM=BUILD_NUM.exec(allstrings);
VERSION_STRING=VERSION_STRING.exec(allstrings);
author=author.exec(allstrings);
description=description.exec(allstrings);
//add a header start mark
array.push(";============================================================");
//push results of regexp vars into array
if (filename) array.push("; File: "+filename[1]); else array.push("; File: "+plugin+".dll");
if (pluginname) array.push("; Plugin: "+pluginname[1]); else array.push("; Plugin: "+plugin);
if (MAJOR_VERSION) array.push("; Version: "+MAJOR_VERSION[1]+"."+MINOR_VERSION[1]+"."+RELEASE_NUM[1]+"."+BUILD_NUM[1]);
if (VERSION_STRING) array.push("; Version: "+VERSION_STRING[1]);
if (!MAJOR_VERSION && !VERSION_STRING) array.push("; Version: x.x.x.x");
if (author) array.push("; Authors: "+fixHexa(author[1])); else array.push("; Authors: ");
//add a header end mark
array.push(";============================================================");
if (description) array.push("["+description[1]+"]");
//close file
versionfile_stream.Close();
}
//Replaces \x?? hexa codes with their char representation
function fixHexa(string) {
return string.replace(/\\x([a-fA-F0-9]{2})" "/g,function() {
return String.fromCharCode(parseInt(arguments[1],16));
});
}
//Removes duplicates, not mine, found at http://dreaminginjavascript.wordpress.com/2008/08/22/eliminating-duplicates/
function eliminateDuplicates(arr) {
var i,
len=arr.length,
out=[],
obj={};
for (i=0;i