Example #1
0
                public override void VisitEnumDeclaration(EnumDeclarationSyntax node)
                {
                    base.VisitEnumDeclaration(node);

                    EnumObject enumObject = new EnumObject();

                    enumObject.@namespace = this.currentNamespace;
                    enumObject.name       = node.Identifier.ValueText;
                    enumObject.flags      = node.AttributeLists.Any(list => list.Attributes.Any(attr => attr.Name.ToString().StartsWith("Flags")));
                    enumObject.FromCSharp = true;

                    foreach (EnumMemberDeclarationSyntax member in node.Members)
                    {
                        EnumObject.Member m = new EnumObject.Member();
                        m.name = member.Identifier.ValueText;

                        if (member.EqualsValue != null)
                        {
                            m.value = member.EqualsValue.Value.ToString();
                        }

                        enumObject.members.Add(m);
                    }

                    this.enumObjects.Add(enumObject);
                }
Example #2
0
            private bool TryMergingWithExistingObject(EnumObject enumObject)
            {
                if (enumObject.finished)
                {
                    return(false);
                }

                bool merged = false;

                foreach (var member in enumObject.members)
                {
                    if (this.enumMemberNameToEnumObj.TryGetValue(member.name, out var matchedObj))
                    {
                        merged = this.MergeObjIntoOther(enumObject, matchedObj);
                        if (merged)
                        {
                            break;
                        }
                    }
                }

                foreach (var use in enumObject.uses)
                {
                    if (this.enumMemberNameToEnumObj.TryGetValue(use.ToString(), out var matchedObj))
                    {
                        merged = this.MergeObjIntoOther(enumObject, matchedObj);
                        if (merged)
                        {
                            break;
                        }
                    }
                }

                return(merged);
            }
Example #3
0
 private void LoadEnumsFromSourcesFiles(string sourcesDir)
 {
     foreach (var file in Directory.GetFiles(sourcesDir, "*.cs").Where(f => !f.EndsWith(".enums.cs") && !f.EndsWith(".constants.cs")))
     {
         foreach (var enumObj in EnumObject.LoadFromFile(file))
         {
             this.LoadObjMembersIntoMap(enumObj);
         }
     }
 }
Example #4
0
        public static EnumObject Normalize(EnumObject enumObject)
        {
            EnumObject fixedObject = Newtonsoft.Json.JsonConvert.DeserializeObject <EnumObject>(Newtonsoft.Json.JsonConvert.SerializeObject(enumObject));

            if (fixedObject.name != null && fixedObject.name.Contains('.'))
            {
                fixedObject.name = fixedObject.name.Replace('.', '_');
            }

            var firstUse = fixedObject.uses.FirstOrDefault();

            if (firstUse == null)
            {
                return(fixedObject);
            }

            if (fixedObject.name == null || !fixedObject.name.Contains('_'))
            {
                List <string> namesToMatch = new List <string>();
                const int     MaxToCheck   = 4;
                for (int i = 0; i < fixedObject.uses.Count; i++)
                {
                    var use = fixedObject.uses[i];
                    if (use.method != null)
                    {
                        namesToMatch.Add(use.method);
                        if (namesToMatch.Count == MaxToCheck)
                        {
                            break;
                        }
                    }
                }

                string varName     = firstUse.method != null ? firstUse.parameter : firstUse.field;
                string matchedName = GetCommonCamelCaseName(namesToMatch.ToArray());
                if (string.IsNullOrEmpty(matchedName))
                {
                    matchedName = firstUse.method != null ? firstUse.method : firstUse.@struct;
                }

                fixedObject.name = $"{matchedName}_{varName}";
            }

            foreach (var member in fixedObject.members)
            {
                if (int.TryParse(member.name, out var value))
                {
                    string name = firstUse.parameter != null ? firstUse.parameter : firstUse.field;
                    member.value = member.name;
                    member.name  = $"{name}{value}";
                }
            }

            return(fixedObject);
        }
            private static List <EnumObject> LoadEnumsFromSourceFiles(IEnumerable <string> fileNames)
            {
                List <EnumObject> enumObjects = new List <EnumObject>();

                foreach (var file in fileNames)
                {
                    enumObjects.AddRange(EnumObject.LoadFromFile(file));
                }

                return(enumObjects);
            }
Example #6
0
        public bool AddEnum(EnumObject enumObject)
        {
            if (enumObject.name == null || !enumObject.members.Any(m => m.value != null))
            {
                // Skip if we have no name or values to write
                return(false);
            }

            this.EnsureStarted();
            if (enumObject.flags)
            {
                this.writer.WriteLine(
                    $"    [Flags]");
            }

            string type          = enumObject.type ?? "uint";
            bool   forceUnsigned = enumObject.flags || (enumObject.type != null && (enumObject.type == "uint" || enumObject.type == "ulong" || enumObject.type == "ushort"));

            StringWriter enumBodyWriter = new StringWriter();

            foreach (var member in enumObject.members.Where(m => m.value != null))
            {
                var    currentType = type;
                string valueText   = ConstantWriter.FixIntValueText(forceUnsigned, ref currentType, member.value);

                enumBodyWriter.Write(
                    $@"        {member.name} = {valueText},
");
                // Make the type more specific if it's signed
                if (currentType != type && (type != "int" && type != "long"))
                {
                    type = currentType;
                }
            }

            if (enumObject.type != null)
            {
                type = enumObject.type;
            }

            string typePart = type != "int" ? $" : {type}" : string.Empty;

            this.writer.WriteLine(
                $@"    public enum {enumObject.name}{typePart}
    {{");

            this.writer.Write(enumBodyWriter.ToString());

            this.writer.WriteLine(
                $@"    }}
");

            return(true);
        }
            private List <EnumObject> LoadEnumsFromJsonFiles(string[] enumJsonFiles)
            {
                List <EnumObject> enumObjects = new List <EnumObject>();

                if (enumJsonFiles != null)
                {
                    foreach (var enumJsonFile in enumJsonFiles)
                    {
                        enumObjects.AddRange(EnumObject.LoadFromFile(enumJsonFile));
                    }
                }

                return(enumObjects);
            }
            private static List <EnumObject> LoadEnumsFromSourceFiles(string sourcesDir)
            {
                List <EnumObject> enumObjects = new List <EnumObject>();

                if (Directory.Exists(sourcesDir))
                {
                    foreach (var file in Directory.GetFiles(sourcesDir, "*.cs"))
                    {
                        enumObjects.AddRange(EnumObject.LoadFromFile(file));
                    }
                }

                return(enumObjects);
            }
Example #9
0
            private bool MergeObjIntoOther(EnumObject src, EnumObject dest)
            {
                // If the dest is from C# code, make src point to dest. In effect,
                // it will give its uses to the C# version
                if (dest.FromCSharp)
                {
                    src.name = null;
                    src.members.Clear();
                    src.addUsesTo = dest.name;
                    return(true);
                }

                // Don't mess with an object that was declared to be finished in the json
                if (src.finished)
                {
                    return(false);
                }

                foreach (var m in src.members)
                {
                    if (StringComparer.OrdinalIgnoreCase.Equals(m.name, "None"))
                    {
                        continue;
                    }

                    dest.AddIfNotSet(m.name, m.value);
                    if (this.enumMemberNameToEnumObj.TryGetValue(m.name, out var memberOwner))
                    {
                        if (memberOwner != dest && memberOwner != src)
                        {
                            this.enumMemberNameToEnumObj[m.name] = dest;
                            this.MergeObjIntoOther(memberOwner, dest);
                        }
                    }

                    this.enumMemberNameToEnumObj[m.name] = dest;
                }

                foreach (var u in src.uses)
                {
                    dest.AddUse(u);
                }

                return(true);
            }
            private void AddEnumWarningAndSuggestedMapping(string message, EnumObject enumObject)
            {
                this.output.Add(message);
                StringBuilder suggestedName = new StringBuilder();

                foreach (var match in NamePartsRegex.Matches(enumObject.name))
                {
                    if (suggestedName.Length != 0)
                    {
                        suggestedName.Append('_');
                    }

                    suggestedName.Append(match.ToString().ToUpperInvariant());
                }

                if (suggestedName.Length != 0)
                {
                    this.suggestedEnumRenames.Add($"{enumObject.name}={suggestedName}");
                }
            }
Example #11
0
            private void LoadObjMembersIntoMap(EnumObject obj)
            {
                foreach (var member in obj.members)
                {
                    if (StringComparer.OrdinalIgnoreCase.Equals(member.name, "None"))
                    {
                        continue;
                    }

                    if (!this.enumMemberNameToEnumObj.ContainsKey(member.name))
                    {
                        this.enumMemberNameToEnumObj[member.name] = obj;
                    }
                }

                foreach (var use in obj.uses)
                {
                    if (!this.enumMemberNameToEnumObj.ContainsKey(use.ToString()))
                    {
                        this.enumMemberNameToEnumObj[use.ToString()] = obj;
                    }
                }
            }
            private void ScrapeConstantsFromTraversedFiles(Dictionary <string, string> traversedFileMap)
            {
                Dictionary <string, string> autoReplacements = GetAutoValueReplacements();

                HashSet <string> manualEnumMemberNames = this.GetManualEnumMemberNames();

                // For each traversed header, scrape the constants
                foreach (KeyValuePair <string, string> item in traversedFileMap)
                {
                    var header           = item.Key;
                    var currentNamespace = item.Value;

                    if (!File.Exists(header))
                    {
                        continue;
                    }

                    string currentHeaderName = Path.GetFileName(header).ToLowerInvariant();

                    List <EnumObject> autoEnumObjsForCurrentHeader =
                        new List <EnumObject>(this.enumObjectsFromJsons.Where(e => e.autoPopulate != null && e.autoPopulate.header.ToLowerInvariant() == currentHeaderName));
                    Regex autoPopulateReg = null;

                    if (autoEnumObjsForCurrentHeader.Count != 0)
                    {
                        StringBuilder autoPopulateRegexPattern = new StringBuilder();
                        foreach (EnumObject autoEnumObj in autoEnumObjsForCurrentHeader)
                        {
                            if (autoPopulateRegexPattern.Length != 0)
                            {
                                autoPopulateRegexPattern.Append('|');
                            }

                            autoPopulateRegexPattern.Append($"(^{autoEnumObj.autoPopulate.filter})");
                        }

                        autoPopulateReg = new Regex(autoPopulateRegexPattern.ToString());
                    }

                    string continuation            = null;
                    bool   processingGuidMultiLine = false;
                    string defineGuidKeyword       = null;
                    foreach (string currentLine in File.ReadAllLines(header))
                    {
                        string fixedCurrentLine = currentLine;

                        if (continuation != null && continuation.EndsWith('"') && currentLine.StartsWith('"'))
                        {
                            continuation     = continuation.Substring(0, continuation.Length - 1);
                            fixedCurrentLine = currentLine.Substring(1);
                        }

                        string line = continuation == null ? fixedCurrentLine : continuation + fixedCurrentLine;
                        if (line.EndsWith("\\"))
                        {
                            continuation = line.Substring(0, line.Length - 1);
                            continue;
                        }

                        if (processingGuidMultiLine)
                        {
                            continuation = StripComments(line).Trim();
                            if (continuation.EndsWith(';'))
                            {
                                processingGuidMultiLine = false;
                                this.AddConstantGuid(defineGuidKeyword, currentNamespace, continuation);
                                continuation = null;
                            }

                            continue;
                        }

                        continuation = null;

                        Match defineGuidMatch = DefineGuidConstRegex.Match(line);
                        if (defineGuidMatch.Success)
                        {
                            defineGuidKeyword = defineGuidMatch.Groups[1].Value;
                            line = defineGuidMatch.Groups[2].Value;
                            line = StripComments(line).Trim();
                            if (line.EndsWith(';'))
                            {
                                this.AddConstantGuid(defineGuidKeyword, currentNamespace, line);
                            }
                            else
                            {
                                continuation            = line;
                                processingGuidMultiLine = true;
                            }

                            continue;
                        }

                        Match defineAviGuidMatch = DefineAviGuidConstRegex.Match(line);
                        if (defineAviGuidMatch.Success)
                        {
                            defineGuidKeyword = defineAviGuidMatch.Groups[1].Value;
                            var guidName       = defineAviGuidMatch.Groups[2].Value;
                            var l              = defineAviGuidMatch.Groups[3].Value;
                            var w1             = defineAviGuidMatch.Groups[4].Value;
                            var w2             = defineAviGuidMatch.Groups[5].Value;
                            var defineGuidLine = $"{guidName}, {l}, {w1}, {w2}, 0xC0,0,0,0,0,0,0,0x46)";
                            this.AddConstantGuid(defineGuidKeyword, currentNamespace, defineGuidLine);
                            continue;
                        }

                        Match defineMediaTypeGuidMatch = DefineMediaTypeGuidConstRegex.Match(line);
                        if (defineMediaTypeGuidMatch.Success)
                        {
                            defineGuidKeyword = defineMediaTypeGuidMatch.Groups[1].Value;
                            var guidName = defineMediaTypeGuidMatch.Groups[2].Value;
                            var value    = defineMediaTypeGuidMatch.Groups[3].Value;
                            var fccMatch = FccRegex.Match(value);
                            if (fccMatch.Success)
                            {
                                var  fccValue       = fccMatch.Groups[1].Value.ToArray();
                                uint convertedValue =
                                    (uint)(fccValue[0]) |
                                    (uint)(fccValue[1] << 8) |
                                    (uint)(fccValue[2] << 16) |
                                    (uint)(fccValue[3] << 24);
                                value = $"0x{convertedValue:x}";
                            }

                            var defineGuidLine = $"{guidName}, {value}, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71)";
                            this.AddConstantGuid(defineGuidKeyword, currentNamespace, defineGuidLine);
                            continue;
                        }

                        Match defineMatch = DefineRegex.Match(line);

                        // Skip if not #define ...
                        if (!defineMatch.Success)
                        {
                            this.TryScrapingEnumFlags(line);
                            continue;
                        }

                        string name = defineMatch.Groups[1].Value;
                        if (this.ShouldExclude(name))
                        {
                            continue;
                        }

#if DEBUG
                        if (name == "SOME_CONST_NAME")
                        {
                        }
#endif

                        // Get rid of trailing comments
                        string rawValue = StripComments(defineMatch.Groups[2].Value.Trim());

                        if (autoReplacements.TryGetValue(rawValue, out var updatedRawValue))
                        {
                            rawValue = updatedRawValue;
                        }

                        string fixedRawValue = rawValue;
                        // Get rid of enclosing parens. Makes it easier to parse with regex
                        if (fixedRawValue.StartsWith('(') && fixedRawValue.EndsWith(')'))
                        {
                            fixedRawValue = fixedRawValue.Substring(1, rawValue.Length - 2).Trim();
                        }

                        Match ctlCodeMatch = CtlCodeRegex.Match(fixedRawValue);
                        if (ctlCodeMatch.Success)
                        {
                            var parts = ctlCodeMatch.Groups[1].Value.Split(',');
                            if (parts.Length == 4)
                            {
                                this.AddCtlCodeConstant(currentNamespace, name, parts[0].Trim(), parts[1].Trim(), parts[2].Trim(), parts[3].Trim());
                                continue;
                            }
                        }

                        Match usageMatch = HidUsageRegex.Match(fixedRawValue);
                        if (usageMatch.Success)
                        {
                            this.AddConstantValue(currentNamespace, "ushort", name, usageMatch.Groups[1].Value);
                            continue;
                        }

                        if (fixedRawValue.StartsWith("AUDCLNT_ERR("))
                        {
                            fixedRawValue = fixedRawValue.Replace("AUDCLNT_ERR(", "MAKE_HRESULT(SEVERITY_ERROR, FACILITY_AUDCLNT, ");
                        }
                        else if (fixedRawValue.StartsWith("AUDCLNT_SUCCESS("))
                        {
                            fixedRawValue = fixedRawValue.Replace("AUDCLNT_SUCCESS(", "MAKE_HRESULT(SEVERITY_SUCCESS, FACILITY_AUDCLNT, ");
                        }

                        Match makeHresultMatch = MakeHresultRegex.Match(fixedRawValue);
                        if (makeHresultMatch.Success)
                        {
                            var parts = makeHresultMatch.Groups[1].Value.Split(',');
                            if (parts.Length == 3)
                            {
                                this.AddMakeHresultConstant(currentNamespace, name, parts[0].Trim(), parts[1].Trim(), parts[2].Trim());
                                continue;
                            }
                        }

                        Match intCastToLpcstrMatch = IntCastToLpcstrRegex.Match(fixedRawValue);
                        if (intCastToLpcstrMatch.Success)
                        {
                            var nativeStrType = intCastToLpcstrMatch.Groups[1].Value;
                            var value         = intCastToLpcstrMatch.Groups[2].Value;
                            this.AddConstantInteger(currentNamespace, nativeStrType, name, value);
                            continue;
                        }

                        if (this.regexConstHelper.TryProcessingLine(currentNamespace, name, fixedRawValue))
                        {
                            continue;
                        }

                        // See if matches one of our well known constants formats
                        Match  match = DefineConstantRegex.Match(fixedRawValue);
                        string valueText;
                        string nativeTypeName      = null;
                        string matchedConstantType = null;
                        bool   matchedToOtherName  = false;

                        if (match.Success)
                        {
                            // #define E_UNEXPECTED _HRESULT_TYPEDEF_(0x8000FFFF)
                            if (!string.IsNullOrEmpty(match.Groups[2].Value))
                            {
                                if (match.Groups[2].Value == "_HRESULT_TYPEDEF_")
                                {
                                    nativeTypeName = "HRESULT";
                                }

                                valueText = match.Groups[3].Value;
                            }
                            // #define E_UNEXPECTED ((HRESULT)0x8000FFFF)
                            else if (!string.IsNullOrEmpty(match.Groups[5].Value))
                            {
                                nativeTypeName = "HRESULT";
                                valueText      = match.Groups[5].Value;
                            }
                            // #define DXGI_RESOURCE_PRIORITY_MINIMUM	( 0x28000000 )
                            else if (!string.IsNullOrEmpty(match.Groups[7].Value))
                            {
                                valueText = match.Groups[7].Value;
                            }
                            // 1.0, -2.0f
                            else if (!string.IsNullOrEmpty(match.Groups[6].Value))
                            {
                                valueText = match.Groups[6].Value;
                                string type = valueText.EndsWith('f') ? "float" : "double";
                                this.AddConstantValue(currentNamespace, type, name, valueText);
                                continue;
                            }
                            // 1 << 5
                            else if (!string.IsNullOrEmpty(match.Groups[8].Value))
                            {
                                string part1 = match.Groups[9].Value + "u";
                                string part2 = match.Groups[10].Value;
                                valueText = part1 + part2;
                            }
                            // MAKEINTRESOURCE(-4), MAKEINTRESOURCEA(-1), MAKEINTRESOURCEW(42)
                            else if (!string.IsNullOrEmpty(match.Groups[11].Value))
                            {
                                if (match.Groups[11].Value.StartsWith("MAKEINTRESOURCEA"))
                                {
                                    nativeTypeName = "LPCSTR";
                                }
                                else
                                {
                                    nativeTypeName = "LPCWSTR";
                                }
                                valueText = match.Groups[12].Value;
                                this.AddConstantInteger(currentNamespace, nativeTypeName, name, valueText);
                                continue;
                            }
                            // (HWND)-4
                            else if (!string.IsNullOrEmpty(match.Groups[13].Value))
                            {
                                nativeTypeName = "HWND";
                                valueText      = match.Groups[14].Value;
                                this.AddConstantInteger(currentNamespace, nativeTypeName, name, valueText);
                                continue;
                            }
                            // (IDENT_FOO + 4)
                            else if (match.Groups[15].Success)
                            {
                                valueText = match.Groups[15].Value;
                            }
                            // (NTSTATUS)0x00000000L
                            else if (match.Groups[17].Success)
                            {
                                nativeTypeName = "NTSTATUS";
                                valueText      = match.Groups[18].Value;
                            }
                            // (DWORD)-1
                            else if (match.Groups[20].Success)
                            {
                                valueText = "0xFFFFFFFF";
                            }
                            // (BCRYPT_ALG_HANDLE) 0x000001a1
                            else if (match.Groups[21].Success)
                            {
                                nativeTypeName = "BCRYPT_ALG_HANDLE";
                                valueText      = match.Groups[22].Value;
                            }
                            // SOME_OTHER_CONSTANT
                            else if (match.Groups[23].Success)
                            {
                                string otherName = match.Groups[23].Value;

                                matchedToOtherName = true;

                                // Only use a constant as the value if we have seen the constant before
                                // and we know its type
                                if (this.writtenConstants.TryGetValue(otherName, out var otherType))
                                {
                                    // Skip guids for now
                                    if (otherType != "Guid")
                                    {
                                        matchedConstantType = otherType;
                                    }
                                }

                                // If we didn't match it to another constant, keep going as we may be setting an enum
                                valueText = otherName;
                            }
                            else
                            {
                                continue;
                            }
                        }
                        else
                        {
                            valueText = rawValue;

                            if (valueText.StartsWith("__TEXT("))
                            {
                                valueText = valueText.Substring(2);
                            }

                            if (valueText.StartsWith("TEXT("))
                            {
                                valueText = valueText.Substring("TEXT(".Length);
                                if (valueText.EndsWith(')'))
                                {
                                    valueText = valueText.Substring(0, valueText.Length - 1);
                                }
                            }
                            else if (valueText.StartsWith("L\""))
                            {
                                valueText = valueText.Substring(1);
                            }

                            // Strings can't be part of enums so go ahead and add the constant directly
                            if (valueText.StartsWith('"'))
                            {
                                this.AddConstantValue(currentNamespace, "string", name, valueText);
                                continue;
                            }

                            valueText = valueText.Replace("(DWORD)", "(uint)");
                            valueText = valueText.Replace("(ULONG)", "(uint)");
                        }

                        bool updatedEnum = false;

                        // If we see the member is part of an enum, update the member value
                        if (this.enumMemberNameToEnumObj.TryGetValue(name, out var enumObjList))
                        {
                            foreach (EnumObject enumObj in enumObjList)
                            {
                                enumObj.AddIfNotSet(name, valueText);
                                updatedEnum = true;
                            }
                        }

                        if (autoPopulateReg != null && nativeTypeName == null)
                        {
                            Match autoPopulate = autoPopulateReg.Match(name);
                            if (autoPopulate.Success)
                            {
                                for (int i = 1; i < autoPopulate.Groups.Count; i++)
                                {
                                    if (!string.IsNullOrEmpty(autoPopulate.Groups[i].Value))
                                    {
                                        EnumObject foundObjEnum = autoEnumObjsForCurrentHeader[i - 1];
                                        foundObjEnum.AddIfNotSet(name, valueText);
                                        updatedEnum = true;
                                        if (!this.enumMemberNameToEnumObj.TryGetValue(name, out var list))
                                        {
                                            list = new List <EnumObject>();
                                            this.enumMemberNameToEnumObj.Add(name, list);
                                        }

                                        list.Add(foundObjEnum);

                                        break;
                                    }
                                }
                            }
                        }

                        // If we haven't used the member to update an enum, skip it...
                        // ...unless it's an HRESULT. Always emit them as constants too
                        if (match.Success && (!updatedEnum || nativeTypeName != null))
                        {
                            // Only add the constant if it's not part of a manual enum
                            if (!manualEnumMemberNames.Contains(name))
                            {
                                if (matchedConstantType != null)
                                {
                                    this.AddConstantValue(currentNamespace, matchedConstantType, name, valueText);
                                }
                                else
                                {
                                    // Only add as an int if it didn't match some other constant/enum name
                                    if (!matchedToOtherName)
                                    {
                                        this.AddConstantInteger(currentNamespace, nativeTypeName, name, valueText);
                                    }
                                }
                            }
                        }
                    }
                }
            }