예제 #1
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);
            }
예제 #2
0
            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);
                                    }
                                }
                            }
                        }
                    }
                }
            }