/****************************************************************************  
 | 
**  
 | 
** Copyright (C) 2016 The Qt Company Ltd.  
 | 
** Contact: https://www.qt.io/licensing/  
 | 
**  
 | 
** This file is part of the Qt VS Tools.  
 | 
**  
 | 
** $QT_BEGIN_LICENSE:GPL-EXCEPT$  
 | 
** Commercial License Usage  
 | 
** Licensees holding valid commercial Qt licenses may use this file in  
 | 
** accordance with the commercial license agreement provided with the  
 | 
** Software or, alternatively, in accordance with the terms contained in  
 | 
** a written agreement between you and The Qt Company. For licensing terms  
 | 
** and conditions see https://www.qt.io/terms-conditions. For further  
 | 
** information use the contact form at https://www.qt.io/contact-us.  
 | 
**  
 | 
** GNU General Public License Usage  
 | 
** Alternatively, this file may be used under the terms of the GNU  
 | 
** General Public License version 3 as published by the Free Software  
 | 
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT  
 | 
** included in the packaging of this file. Please review the following  
 | 
** information to ensure the GNU General Public License requirements will  
 | 
** be met: https://www.gnu.org/licenses/gpl-3.0.html.  
 | 
**  
 | 
** $QT_END_LICENSE$  
 | 
**  
 | 
****************************************************************************/  
 | 
  
 | 
using System;  
 | 
using System.Collections;  
 | 
using System.Collections.Generic;  
 | 
using System.Diagnostics;  
 | 
using System.IO;  
 | 
using System.Linq;  
 | 
using System.Text;  
 | 
using System.Text.RegularExpressions;  
 | 
  
 | 
namespace QtVsTools.Core  
 | 
{  
 | 
    [DebuggerDisplay("Name = {name}, Version = {qtMajor}.{qtMinor}.{qtPatch}")]  
 | 
    public class VersionInformation  
 | 
    {  
 | 
        //fields  
 | 
        public string name;  
 | 
        public string qtDir;  
 | 
        public uint qtMajor; // X in version x.y.z  
 | 
        public uint qtMinor; // Y in version x.y.z  
 | 
        public uint qtPatch; // Z in version x.y.z  
 | 
        public bool qt5Version = true;  
 | 
        private QtConfig qtConfig;  
 | 
        private QMakeConf qmakeConf;  
 | 
        private string vsPlatformName;  
 | 
        private static readonly Hashtable _cache = new Hashtable();  
 | 
  
 | 
        public static VersionInformation Get(string qtDir)  
 | 
        {  
 | 
            qtDir = qtDir ?? Environment.GetEnvironmentVariable("QTDIR");  
 | 
            if (qtDir == null)  
 | 
                return null;  
 | 
  
 | 
            try {  
 | 
                qtDir = new FileInfo(qtDir).FullName.ToUpperInvariant();  
 | 
            } catch {  
 | 
                return null;  
 | 
            }  
 | 
            var versionInfo = _cache[qtDir] as VersionInformation;  
 | 
            if (versionInfo == null) {  
 | 
                versionInfo = new VersionInformation(qtDir);  
 | 
                _cache.Add(qtDir, versionInfo);  
 | 
            } else if (versionInfo.qtDir == null) {  
 | 
                versionInfo = new VersionInformation(qtDir);  
 | 
                _cache[qtDir] = versionInfo;  
 | 
            }  
 | 
            return versionInfo;  
 | 
        }  
 | 
  
 | 
        public static void Clear()  
 | 
        {  
 | 
            _cache.Clear();  
 | 
        }  
 | 
  
 | 
        Dictionary<string, bool> _IsModuleAvailable;  
 | 
        public bool IsModuleAvailable(string module)  
 | 
        {  
 | 
            return _IsModuleAvailable?[module] ?? false;  
 | 
        }  
 | 
  
 | 
        public string VC_MinimumVisualStudioVersion { get; private set; }  
 | 
        public string VC_ApplicationTypeRevision { get; private set; }  
 | 
        public string VC_WindowsTargetPlatformMinVersion { get; private set; }  
 | 
        public string VC_WindowsTargetPlatformVersion { get; private set; }  
 | 
        public string VC_Link_TargetMachine { get; private set; }  
 | 
        public string VC_PlatformToolset { get; private set; }  
 | 
  
 | 
        private VersionInformation(string qtDirIn)  
 | 
        {  
 | 
            qtDir = qtDirIn;  
 | 
  
 | 
            try {  
 | 
                var qmakeQuery = new QMakeQuery(this);  
 | 
                SetupPlatformSpecificData(qmakeQuery);  
 | 
  
 | 
                // Find version number  
 | 
                var strVersion = qmakeQuery["QT_VERSION"];  
 | 
                if (!string.IsNullOrEmpty(strVersion)) {  
 | 
                    var versionParts = strVersion.Split('.');  
 | 
                    if (versionParts.Length != 3) {  
 | 
                        qtDir = null;  
 | 
                        return;  
 | 
                    }  
 | 
                    qtMajor = uint.Parse(versionParts[0]);  
 | 
                    qtMinor = uint.Parse(versionParts[1]);  
 | 
                    qtPatch = uint.Parse(versionParts[2]);  
 | 
                } else {  
 | 
                    var inF = new StreamReader(Locate_qglobal_h());  
 | 
                    var rgxpVersion = new Regex("#define\\s*QT_VERSION\\s*0x(?<number>\\d+)", RegexOptions.Multiline);  
 | 
                    var contents = inF.ReadToEnd();  
 | 
                    inF.Close();  
 | 
                    var matchObj = rgxpVersion.Match(contents);  
 | 
                    if (!matchObj.Success) {  
 | 
                        qtDir = null;  
 | 
                        return;  
 | 
                    }  
 | 
  
 | 
                    strVersion = matchObj.Groups[1].ToString();  
 | 
                    var version = Convert.ToUInt32(strVersion, 16);  
 | 
                    qtMajor = version >> 16;  
 | 
                    qtMinor = (version >> 8) & 0xFF;  
 | 
                    qtPatch = version & 0xFF;  
 | 
                }  
 | 
                qt5Version = (qtMajor == 5);  
 | 
  
 | 
                try {  
 | 
                    QtInstallDocs = qmakeQuery["QT_INSTALL_DOCS"];  
 | 
                } catch { }  
 | 
            } catch {  
 | 
                qtDir = null;  
 | 
                return;  
 | 
            }  
 | 
  
 | 
            // Get VS project settings  
 | 
            try {  
 | 
                var tempProData = new StringBuilder();  
 | 
                tempProData.AppendLine("SOURCES = main.cpp");  
 | 
  
 | 
                var modules = QtModules.Instance.GetAvailableModules()  
 | 
                    .Where((QtModule mi) => mi.Selectable);  
 | 
  
 | 
                foreach (QtModule mi in modules) {  
 | 
                    tempProData.AppendLine(string.Format(  
 | 
                        "qtHaveModule({0}): HEADERS += {0}.h", mi.proVarQT));  
 | 
                }  
 | 
  
 | 
                var randomName = Path.GetRandomFileName();  
 | 
                var tempDir = Path.Combine(Path.GetTempPath(), randomName);  
 | 
                Directory.CreateDirectory(tempDir);  
 | 
  
 | 
                var tempPro = Path.Combine(tempDir, string.Format("{0}.pro", randomName));  
 | 
                File.WriteAllText(tempPro, tempProData.ToString());  
 | 
  
 | 
                var qmake = new QMakeImport(this, tempPro);  
 | 
                qmake.DisableWarnings = true;  
 | 
                qmake.Run(setVCVars: true);  
 | 
  
 | 
                var tempVcxproj = Path.Combine(tempDir, string.Format("{0}.vcxproj", randomName));  
 | 
                var msbuildProj = MsBuildProject.Load(tempVcxproj);  
 | 
  
 | 
                Directory.Delete(tempDir, recursive: true);  
 | 
  
 | 
                var availableModules = msbuildProj.GetItems("ClInclude")  
 | 
                    .Select((string s) => Path.GetFileNameWithoutExtension(s));  
 | 
  
 | 
                _IsModuleAvailable = modules.ToDictionary(  
 | 
                    (QtModule mi) => mi.proVarQT,  
 | 
                    (QtModule mi) => availableModules.Contains(mi.proVarQT));  
 | 
  
 | 
                VC_MinimumVisualStudioVersion =  
 | 
                    msbuildProj.GetProperty("MinimumVisualStudioVersion");  
 | 
                VC_ApplicationTypeRevision =  
 | 
                    msbuildProj.GetProperty("ApplicationTypeRevision");  
 | 
                VC_WindowsTargetPlatformVersion =  
 | 
                    msbuildProj.GetProperty("WindowsTargetPlatformVersion");  
 | 
                VC_WindowsTargetPlatformMinVersion =  
 | 
                    msbuildProj.GetProperty("WindowsTargetPlatformMinVersion");  
 | 
                VC_PlatformToolset =  
 | 
                    msbuildProj.GetProperty("PlatformToolset");  
 | 
                VC_Link_TargetMachine =  
 | 
                    msbuildProj.GetProperty("Link", "TargetMachine");  
 | 
  
 | 
            } catch (Exception e) {  
 | 
                throw new QtVSException("Error reading VS project settings", e);  
 | 
            }  
 | 
        }  
 | 
  
 | 
        public string QtInstallDocs  
 | 
        {  
 | 
            get; private set;  
 | 
        }  
 | 
  
 | 
        public string QMakeSpecDirectory  
 | 
        {  
 | 
            get { return qmakeConf.QMakeSpecDirectory; }  
 | 
        }  
 | 
  
 | 
        public bool IsStaticBuild()  
 | 
        {  
 | 
            if (qtConfig == null)  
 | 
                qtConfig = new QtConfig(qtDir);  
 | 
            return qtConfig.BuildType == BuildType.Static;  
 | 
        }  
 | 
  
 | 
        public string LibInfix()  
 | 
        {  
 | 
            if (qtConfig == null)  
 | 
                qtConfig = new QtConfig(qtDir);  
 | 
            return qtConfig.LibInfix;  
 | 
        }  
 | 
  
 | 
        public string Namespace()  
 | 
        {  
 | 
            if (qtConfig == null)  
 | 
                qtConfig = new QtConfig(qtDir);  
 | 
            return qtConfig.Namespace;  
 | 
        }  
 | 
  
 | 
        public string GetQMakeConfEntry(string entryName)  
 | 
        {  
 | 
            if (qmakeConf == null)  
 | 
                qmakeConf = new QMakeConf(this);  
 | 
            return qmakeConf.Entries[entryName].ToString();  
 | 
        }  
 | 
  
 | 
        /// <summary>  
 | 
        /// Returns the platform name in a way Visual Studio understands.  
 | 
        /// </summary>  
 | 
        public string GetVSPlatformName()  
 | 
        {  
 | 
            return vsPlatformName;  
 | 
        }  
 | 
  
 | 
        /// <summary>  
 | 
        /// Read platform name from qmake.conf.  
 | 
        /// </summary>  
 | 
        private void SetupPlatformSpecificData(QMakeQuery qmakeQuery)  
 | 
        {  
 | 
            if (qmakeConf == null)  
 | 
                qmakeConf = new QMakeConf(this, qmakeQuery);  
 | 
            vsPlatformName = (is64Bit()) ? @"x64" : @"Win32";  
 | 
        }  
 | 
  
 | 
        private string Locate_qglobal_h()  
 | 
        {  
 | 
            string[] candidates = {qtDir + "\\include\\qglobal.h",  
 | 
                                   qtDir + "\\src\\corelib\\global\\qglobal.h",  
 | 
                                   qtDir + "\\include\\QtCore\\qglobal.h"};  
 | 
  
 | 
            foreach (var filename in candidates) {  
 | 
                if (File.Exists(filename)) {  
 | 
                    // check whether we look at the real qglobal.h or just a "pointer"  
 | 
                    var inF = new StreamReader(filename);  
 | 
                    var rgxpVersion = new Regex("#include\\s+\"(.+global.h)\"", RegexOptions.Multiline);  
 | 
                    var matchObj = rgxpVersion.Match(inF.ReadToEnd());  
 | 
                    inF.Close();  
 | 
                    if (!matchObj.Success)  
 | 
                        return filename;  
 | 
  
 | 
                    if (matchObj.Groups.Count >= 2) {  
 | 
                        var origCurrentDirectory = Directory.GetCurrentDirectory();  
 | 
                        Directory.SetCurrentDirectory(filename.Substring(0, filename.Length - 10));   // remove "\\qglobal.h"  
 | 
                        var absIncludeFile = Path.GetFullPath(matchObj.Groups[1].ToString());  
 | 
                        Directory.SetCurrentDirectory(origCurrentDirectory);  
 | 
                        if (File.Exists(absIncludeFile))  
 | 
                            return absIncludeFile;  
 | 
                    }  
 | 
                }  
 | 
            }  
 | 
  
 | 
            throw new QtVSException("qglobal.h not found");  
 | 
        }  
 | 
  
 | 
        public bool is64Bit()  
 | 
        {  
 | 
            if (qtConfig == null)  
 | 
                qtConfig = new QtConfig(qtDir);  
 | 
            return qtConfig.Is64Bit;  
 | 
        }  
 | 
  
 | 
        public bool isWinRT()  
 | 
        {  
 | 
            var qmakeQuery = new QMakeQuery(this);  
 | 
            string qmakeXSpec;  
 | 
            try {  
 | 
                qmakeXSpec = qmakeQuery["QMAKE_XSPEC"];  
 | 
            } catch {  
 | 
                throw new QtVSException("Error starting qmake process");  
 | 
            }  
 | 
  
 | 
            if (string.IsNullOrEmpty(qmakeXSpec))  
 | 
                throw new QtVSException("Error: unexpected result of qmake query");  
 | 
  
 | 
            return qmakeXSpec.StartsWith("winrt");  
 | 
        }  
 | 
    }  
 | 
}  
 |