// DIE's signature file
// 1995-2007 Borland Delphi
// 2007-2014 Embarcadero Delphi;
// https://docwiki.embarcadero.com/RADStudio/Alexandria/en/Compiler_Versions
// coauthor: sendersu

init("compiler", "Borland Delphi");

includeScript("Borland");

function getVersion() {
    if (PE.isNET()) {
        if (PE.isNetObjectPresent("Borland.Vcl.Types")) {
            sVersion = "8";
        } else if (PE.isNetObjectPresent("Borland.Eco.Interfaces")) {
            sVersion = "8 Eco WinForm";
        } else if (PE.isNetObjectPresent("Borland.Delphi.System") &&
            PE.isNetObjectPresent("WinForm")) {
            sVersion = "8 WinForm";
        } else if (PE.isNetObjectPresent("Borland.Delphi.Units")) {
            sVersion = "2005 for .NET";
        } else if (PE.isNetObjectPresent("Borland.Studio.Delphi")) {
            sName = "Embarcadero Delphi";
            sVersion = "XE*";
            sOptions = ".NET";
        } else {
            return 0;
        }
        return 1;
    }

    var nSectionOffset = PE.section[0].FileOffset,
        nSectionSize = PE.section[0].FileSize,
        nOffset = nSectionOffset,
        nSize = nSectionSize,
        nOffset2,
        nAddress,
        nLng,
        nLng1,
        bNewVersion = 0;

    var nAddressSize = PE.isPEPlus() ? 8 : 4;

    while (nSize > 0) {
        nOffset = PE.findSignature(nOffset, nSize, "0708'TControl'");
        if (nOffset == -1) {
            break;
        }
        nAddress = PE.readDword(nOffset + 10);
        nOffset2 = PE.VAToOffset(nAddress);
        if (nOffset2 != -1) {
            if ((nOffset2 >= nSectionOffset) && (nOffset2 < nSectionOffset + nSectionSize)) {
                nLng = PE.readDword(nOffset2 - 10 * nAddressSize);
                nLng1 = PE.readDword(nOffset2 - 10 * nAddressSize - 11 * nAddressSize);

                switch (nLng) {
                    case 0:
                        if (nLng1 == 0x746E4907) {
                            sVersion = "3";
                        } else if (nLng1 == 0x4F540774) {
                            sVersion = "2";
                        }
                        break;

                    case 0x0B4:
                        sVersion = "C++ Builder";
                        break;
                    case 0x114:
                        sVersion = "4";
                        break;
                    case 0x120:
                        sVersion = "5";
                        break;
                    case 0x128:
                        sVersion = "6 CLX";
                        break;
                    case 0x12C:
                        sVersion = "7 CLX";
                        break;
                    case 0x138:
                        sVersion = "Kylix";
                        break;
                    case 0x15C:
                    case 0x160:
                        sVersion = (nLng1 == 0x40100000 || nLng1 == 0x100000) ? "7" : "6";
                        break;

                    case 0x164:
                        sVersion = "2005";
                        break;
                    case 0x190:
                        sVersion = "2006";
                        break;

                    default:
                        nLng = PE.readDword(nOffset2 - 13 * nAddressSize);

                        if (nLng == 0x1A4) {
                            sName = "Embarcadero Delphi";
                            sVersion = "2009";
                        } else if (nLng == 0x1AC) {
                            if (PE.resource["PACKAGEINFO"]) {
                                nOffset = PE.resource["PACKAGEINFO"].Offset;
                                nSize = PE.resource["PACKAGEINFO"].Size;
                                if (PE.isSignaturePresent(nOffset, nSize, "'ExcUtils'")) {
                                    sName = "Embarcadero Delphi";
                                    sVersion = "XE";
                                } else if (PE.isSignaturePresent(nOffset, nSize, "'StrUtils'")) {
                                    sName = "Embarcadero Delphi";
                                    sVersion = "2010";
                                } else {
                                    sName = "Embarcadero Delphi";
                                    sVersion = "2010 or XE";
                                }
                            }
                        } else if (nLng == 0x1B4) {
                            // 32
                            sName = "Embarcadero Delphi";
                            sVersion = "XE2-XE4";
                        } else if ((nLng == 0x2F0) || (nLng == 0x2F8)) {
                            // 64
                            sName = "Embarcadero Delphi";
                            sVersion = "XE2";
                        } else if (nLng == 0x1BC) {
                            // 32
                            sName = "Embarcadero Delphi";
                            sVersion = "XE5-XE6";
                            bNewVersion = 1;
                        } else {
                            if (nAddressSize == 8) {
                                nLng = PE.readDword(nOffset2 - 16 * nAddressSize);
                                if (nLng == 0x2F8) {
                                    // 64
                                    sName = "Embarcadero Delphi";
                                    sVersion = "XE3-X4";
                                } else if (nLng == 0x308) {
                                    // 64
                                    sName = "Embarcadero Delphi";
                                    sVersion = "XE5-XE6";
                                    bNewVersion = 1;
                                }
                            }
                        }
                }

                if ((sVersion != "") && (!bNewVersion)) {
                    return 1;
                }
            }
        }

        nOffset++;
        nSize = nSectionSize - (nOffset - nSectionOffset + 1);
    }

    if (PE.resource["PACKAGEINFO"]) {
        nOffset = PE.resource["PACKAGEINFO"].Offset;
        nSize = PE.resource["PACKAGEINFO"].Size;

        if (PE.isSignaturePresent(nOffset, nSize, "'System.SysUtils'")) {
            sName = "Embarcadero Delphi";
            sVersion = "XE2-XE6";
            bNewVersion = 1;
        } else if (PE.isSignaturePresent(nOffset, nSize, "'ExcUtils'")) {
            sName = "Embarcadero Delphi";
            sVersion = "XE";
        } else if (PE.isSignaturePresent(nOffset, nSize, "'StrUtils'")) {
            sName = "Embarcadero Delphi";
            sVersion = "2009-2010";
        } else if (PE.isSignaturePresent(nOffset, nSize, "'ImageHlp'")) {
            sVersion = "2006";
        } else if (PE.isSignaturePresent(nOffset, nSize, "'SysInit'")) {
            sVersion = "6-7 or 2005";
        }

        if ((sVersion != "") && (!bNewVersion)) {
            return 1;
        }
    } else {
        if (PE.findString(PE.section[0].FileOffset, PE.section[0].FileSize, "Borland\\Delphi") != -1) {
            sVersion = "2-3";
            return 1;
        }
    }

    if (bNewVersion) {
        if (PE.section[".rdata"]) {
            var nRDataOffset = PE.section[".rdata"].FileOffset;
            var nRDataSize = PE.section[".rdata"].FileSize;
            var nVersionOffset = PE.findString(nRDataOffset, nRDataSize, "Embarcadero Delphi for Win");
            if (nVersionOffset != -1) {
                var sCompilerVersion = PE.getString(nVersionOffset + 46, 4);
                if (sCompilerVersion == "28.0") {
                    sVersion = "XE7";
                } else if (sCompilerVersion == "29.0") {
                    sVersion = "XE8";
                } else if (sCompilerVersion == "30.0") {
                    sVersion = "10 Seattle";
                } else if (sCompilerVersion == "31.0") {
                    sVersion = "10.1 Berlin";
                } else if (sCompilerVersion == "32.0") {
                    sVersion = "10.2 Tokyo";
                } else if (sCompilerVersion == "33.0") {
                    sVersion = "10.3 Rio";
                } else if (sCompilerVersion == "34.0") {
                    sVersion = "10.4 Sydney";
                } else if (sCompilerVersion == "35.0") {
                    sVersion = "11.0 Alexandria";
                } else if (sCompilerVersion == "36.0") {
                    sVersion = "12.0 Athens";
                } else {
                    sVersion = "12.x Athens++";
                }
            }
        }

        return 1;
    }

    return 0;
}

function detect(bShowType, bShowVersion, bShowOptions) {
    if (bBorlandC) { // can't be Delphi if it's already C/C++
        return null;
    }

    if (PE.resource["PACKAGEINFO"]) {
        bDetected = true;
        getVersion();
    }
    if (PE.resource["DVCLAL"]) {
        bDetected = true;
        getVersion();

        // try to decode DVCLAL (Delphi Visual Component Library Access License) values
        nOffset = PE.getResourceNameOffset("DVCLAL");
        if (PE.compare("A28CDF987B3C3A7926713F090F2A2517", nOffset)) {
            sOptions = "Professional";
        } else if (PE.compare("23785D23B6A5F31943F3400226D111C7", nOffset)) {
            sOptions = "Standard";
        } else if (PE.compare("263D4F38C28237B8F3244203179B3A83", nOffset)) {
            sOptions = "Enterprise";
        }
    } else if (PE.resource["TMAINFORM"]) {
        bDetected = true;
        getVersion();
    } else if (PE.isNET()) {
        if (getVersion()) {
            bDetected = true;
        }
    } else if (PE.compare("0A06'string'", PE.section[0].FileOffset)) {
        sVersion = "2";
        bDetected = true;
    } else if (PE.findSignature(PE.section[0].FileOffset, 100, "07'Boolean'") != -1) {
        bDetected = true;
        getVersion();
    } else if (PE.findSignature(PE.section[0].FileOffset, 100, "06'String'") != -1) {
        bDetected = true;
        getVersion();
    } else if (PE.findSignature(PE.section[0].FileOffset, 0x100, "FF25........8BC0FF25........8BC0")) {
        if (getVersion()) {
            bDetected = true;
        }
    }

    _setLang("Object Pascal (Delphi)", bDetected);
    return result(bShowType, bShowVersion, bShowOptions);
}