// Detect It Easy: detection rule file
// Author: hbasrc <rob.cheung+git@gmail.com>

meta("library", "Perl5 xs");

function detect() {
    if (!PE.isDll()) return;

    var sLib = PE.isLibraryPresentExp(/perl(5)_?(\d\d*)/i);
    if (sLib) {
        sVersion = sLib[1] + "." + sLib[2];
        bDetected = true;
    }

    if (PE.isExportFunctionPresentExp("Perl_sv_bless|perl_parse")) {
        bDetected = true;
        sVersion = getPerlVersion();

        _setLang("Perl");

        return _setResult("library", "Perl Runtime", sVersion, String());
    }

    sLang = "Perl";

    return result();
}

function getPerlVersion() {
    const verSig = [
        "'erl5' %% '.dll'", // v5.X
        "'erl5' %% %% '.dll'", // v5.XX
        "'erl5_' %% '.dll'", // cygwin or msys
        "'erl5_' %% %% '.dll'"
    ];

    var nExp = PE.getExportSection(),
        sPLVersion = String(),
        nMinorVer = 0,
        nGot = -1;

    for (var i = 0; i < verSig.length; ++i) {
        nGot = PE.findSignature(PE.section[nExp].FileOffset, PE.getSize(), verSig[i]);
        if (nGot > -1) break;
    }

    if (nGot > 0) {
        var sRes = PE.getString(nGot, 12);

        sRes = sRes.match(/(5)_?(\d\d*)/);

        if (sRes) {
            sPLVersion = sRes[1] + "." + sRes[2];
            nMinorVer = Number(sRes[2]);
        } else {
            return sPLVersion;
        }

        // find 5.X.X or 5.XX.X
        var sSign = nMinorVer > 9 ? "'5.' %% %% '.' %% " : "'5.' %% '.' %%",
            patchVer = findPatchVersion(sSign);

        if (patchVer > 0) sPLVersion += "." + patchVer;
    }

    return sPLVersion;
}

function findPatchVersion(sSign) {
    var nOffset = 0,
        nSize = PE.getSize(),
        nPatchVer = 0,
        nGot = -1;

    // Traverse and find the max number
    while ((nGot = PE.findSignature(nOffset, nSize, sSign)) != -1) {
        var sRes = PE.getString(nGot, 12);
        nOffset = nGot + sRes.length;

        sRes = sRes.match(/5\.\d\d*\.(\d\d*)/);
        if (sRes && sRes[1] > nPatchVer) nPatchVer = sRes[1];
    }

    return nPatchVer;
}