Beispiel #1
0
            public static SalAttribute CreateFromCppAttribute(string attr)
            {
                SalAttribute ret   = new SalAttribute();
                var          parts = attr.Split(';');

                foreach (var part in parts)
                {
                    var nameAndValue = part.Split('=');
                    var name         = nameAndValue[0].Trim();
                    var value        = nameAndValue[1].Replace("\\\"", string.Empty);
                    switch (name)
                    {
                    case "Name":
                        ret.Name = value;
                        break;

                    case "p1":
                        ret.P1 = value;
                        break;

                    case "p2":
                        ret.P2 = value;
                        break;

                    case "p3":
                        ret.P3 = value;
                        break;
                    }
                }

                return(ret);
            }
Beispiel #2
0
            private SyntaxNode CreateAttributeListForSal(AttributeListSyntax cppAttrList)
            {
                ParameterSyntax paramNode      = (ParameterSyntax)cppAttrList.Parent;
                bool            marshalAsAdded = this.nodesWithMarshalAs.Contains(paramNode);

                AttributeSyntax        cppAttr        = cppAttrList.Attributes[0];
                List <AttributeSyntax> attributesList = new List <AttributeSyntax>();

                string salText = cppAttr.ArgumentList.Arguments[0].ToString();

                salText = salText.Substring(1, salText.Length - 2);

                string nativeArrayInfoParams = null;
                bool   isIn        = false;
                bool   isOut       = false;
                bool   isOpt       = false;
                bool   isComOutPtr = false;
                bool   isRetVal    = false;
                bool   isNullNullTerminated;
                bool?  pre  = null;
                bool?  post = null;

                var salAttrs = GetSalAttributes(salText);

                isNullNullTerminated = salAttrs.Any(a => a.Name == "SAL_name" && a.P1 == "_NullNull_terminated_");

                foreach (var salAttr in salAttrs)
                {
                    if (salAttr.Name == "SAL_name")
                    {
                        if (salAttr.P1.StartsWith("_COM_Outptr"))
                        {
                            isComOutPtr = true;
                            continue;
                        }
                        else if (salAttr.P1.StartsWith("_Outptr_") && !isComOutPtr)
                        {
                            isOut = true;
                            continue;
                        }
                        else if (salAttr.P1.StartsWith("__RPC__"))
                        {
                            // TODO: Handle ecount, xcount and others that deal with counts

                            string[] parts = salAttr.P1.Split('_');
                            foreach (var part in parts)
                            {
                                switch (part)
                                {
                                case "in":
                                    isIn = true;
                                    break;

                                case "out":
                                    isOut = true;
                                    break;

                                case "inout":
                                    isIn = isOut = true;
                                    break;

                                case "opt":
                                    isOpt = true;
                                    break;
                                }
                            }

                            break;
                        }
                    }

                    if (salAttr.Name == "SAL_null" && salAttr.P1 == "__maybe")
                    {
                        isOpt = true;
                        continue;
                    }

                    if (salAttr.Name == "SAL_retval")
                    {
                        isRetVal = true;
                        continue;
                    }

                    if (salAttr.Name == "SAL_pre")
                    {
                        pre = true;
                        continue;
                    }

                    if (salAttr.Name == "SAL_post")
                    {
                        pre  = false;
                        post = true;
                        continue;
                    }

                    if (salAttr.Name == "SAL_end")
                    {
                        pre = post = false;
                    }

                    if (salAttr.Name == "SAL_valid")
                    {
                        if (pre.HasValue && pre.Value)
                        {
                            isIn = true;
                        }
                        else if (post.HasValue && post.Value)
                        {
                            isOut = true;
                        }
                        else
                        {
                            isIn = isOut = true;
                        }

                        continue;
                    }

                    if (salAttr.Name == "SAL_name" && salAttr.P1 == "_Post_valid_")
                    {
                        isOut = true;
                        continue;
                    }

                    if (!marshalAsAdded && (salAttr.Name == "SAL_writableTo" || salAttr.Name == "SAL_readableTo") && pre.HasValue && pre.Value)
                    {
                        nativeArrayInfoParams = GetArrayMarshalAsFromP1(paramNode, salAttr.P1);
                        if (!string.IsNullOrEmpty(nativeArrayInfoParams))
                        {
                            marshalAsAdded = true;
                        }

                        continue;
                    }
                }

                // If we didn't add marshal as yet, try again without using pre
                if (!marshalAsAdded)
                {
                    var salAttr = salAttrs.FirstOrDefault(attr => attr.Name == "SAL_readableTo" || attr.Name == "SAL_writeableTo");
                    if (salAttr != null)
                    {
                        nativeArrayInfoParams = GetArrayMarshalAsFromP1(paramNode, salAttr.P1);
                        if (!string.IsNullOrEmpty(nativeArrayInfoParams))
                        {
                            marshalAsAdded = true;
                        }
                    }
                }

                if (!string.IsNullOrEmpty(nativeArrayInfoParams))
                {
                    var attrName  = SyntaxFactory.ParseName("NativeArrayInfo");
                    var args      = SyntaxFactory.ParseAttributeArgumentList(nativeArrayInfoParams.ToString());
                    var finalAttr = SyntaxFactory.Attribute(attrName, args);
                    attributesList.Add(finalAttr);
                }

                if (isIn)
                {
                    attributesList.Add(SyntaxFactory.Attribute(SyntaxFactory.ParseName("In")));
                }

                if (isComOutPtr)
                {
                    attributesList.Add(SyntaxFactory.Attribute(SyntaxFactory.ParseName("ComOutPtr")));
                }
                else if (isOut)
                {
                    attributesList.Add(SyntaxFactory.Attribute(SyntaxFactory.ParseName("Out")));
                }

                if (isOpt)
                {
                    attributesList.Add(SyntaxFactory.Attribute(SyntaxFactory.ParseName("Optional")));
                }

                if (isNullNullTerminated)
                {
                    attributesList.Add(SyntaxFactory.Attribute(SyntaxFactory.ParseName("NullNullTerminated")));
                }

                if (isRetVal)
                {
                    attributesList.Add(SyntaxFactory.Attribute(SyntaxFactory.ParseName("RetVal")));
                }

                if (attributesList.Count == 0)
                {
                    return(null);
                }

                return(SyntaxFactory.AttributeList(SyntaxFactory.SeparatedList(attributesList)));

                string GetArrayMarshalAsFromP1(ParameterSyntax paramNode, string p1Text)
                {
                    ParameterListSyntax parameterListNode = (ParameterListSyntax)paramNode.Parent;
                    var           match = elementCountRegex.Match(p1Text);
                    StringBuilder ret   = new StringBuilder("(");

                    if (match.Success)
                    {
                        string sizeOrParamName = match.Groups[1].Value;
                        if (int.TryParse(sizeOrParamName, out int size))
                        {
                            // Don't bother marking this as an array if it only has 1
                            if (size == 1)
                            {
                                return(string.Empty);
                            }

                            if (ret.Length != 1)
                            {
                                ret.Append(", ");
                            }

                            ret.Append($"SizeConst = {size}");
                        }
                        else
                        {
                            sizeOrParamName = sizeOrParamName.Replace("*", string.Empty);
                            for (int i = 0; i < parameterListNode.Parameters.Count; i++)
                            {
                                if (parameterListNode.Parameters[i].Identifier.ValueText == sizeOrParamName)
                                {
                                    if (ret.Length != 1)
                                    {
                                        ret.Append(", ");
                                    }

                                    string propName = p1Text.StartsWith("elementCount") ? "SizeParamIndex" : "BytesParamIndex";
                                    ret.Append($"{propName} = {i}");
                                    break;
                                }
                            }
                        }
                    }
                    else
                    {
                        // If it didn't match the regex and we don't see inexpressibleCount, we can't do
                        // anything but return an empty string, because we don't know how to interpret it
                        if (!p1Text.StartsWith("inexpressibleCount"))
                        {
                            ret = new StringBuilder();
                        }
                    }

                    if (ret.Length > 1)
                    {
                        ret.Append(')');
                        return(ret.ToString());
                    }

                    return(string.Empty);
                }

                IEnumerable <SalAttribute> GetSalAttributes(string salArgsText)
                {
                    foreach (var attr in salArgsText.Split('^'))
                    {
                        var salAttr = SalAttribute.CreateFromCppAttribute(attr);
                        if (salAttr != null)
                        {
                            yield return(salAttr);
                        }
                    }
                }
            }
Beispiel #3
0
            private SyntaxNode CreateAttributeListForSal(AttributeListSyntax cppAttrList)
            {
                ParameterSyntax paramNode      = (ParameterSyntax)cppAttrList.Parent;
                bool            marshalAsAdded = this.nodesWithMarshalAs.Contains(paramNode);

                AttributeSyntax        cppAttr        = cppAttrList.Attributes[0];
                List <AttributeSyntax> attributesList = new List <AttributeSyntax>();

                string salText = cppAttr.ArgumentList.Arguments[0].ToString();

                salText = salText.Substring(1, salText.Length - 2);

                string marshalAsParams = null;
                bool   isIn            = false;
                bool   isOut           = false;
                bool   isOpt           = false;
                bool   isComOutPtr     = false;
                bool   isNullNullTerminated;
                bool?  pre  = null;
                bool?  post = null;

                var salAttrs = GetSalAttributes(salText);

                isNullNullTerminated = salAttrs.Any(a => a.Name == "SAL_name" && a.P1 == "_NullNull_terminated_");

                foreach (var salAttr in salAttrs)
                {
                    if (salAttr.Name == "SAL_name" && salAttr.P1.StartsWith("_COM_Outptr"))
                    {
                        isComOutPtr = true;
                        continue;
                    }

                    if (salAttr.Name == "SAL_null" && salAttr.P1 == "__maybe")
                    {
                        isOpt = true;
                        continue;
                    }

                    if (salAttr.Name == "SAL_pre")
                    {
                        pre = true;
                        continue;
                    }

                    if (salAttr.Name == "SAL_post")
                    {
                        pre  = false;
                        post = true;
                        continue;
                    }

                    if (salAttr.Name == "SAL_end")
                    {
                        pre = post = false;
                    }

                    if (salAttr.Name == "SAL_valid")
                    {
                        if (pre.HasValue && pre.Value)
                        {
                            isIn = true;
                        }
                        else if (post.HasValue && post.Value)
                        {
                            isOut = true;
                        }
                        else
                        {
                            isIn = isOut = true;
                        }

                        continue;
                    }

                    if (salAttr.Name == "SAL_name" && salAttr.P1 == "_Post_valid_")
                    {
                        isOut = true;
                        continue;
                    }

                    if (!marshalAsAdded && (salAttr.Name == "SAL_writableTo" || salAttr.Name == "SAL_readableTo") && pre.HasValue && pre.Value)
                    {
                        marshalAsParams = GetArrayMarshalAsFromP1(paramNode, salAttr.P1, isNullNullTerminated);
                        if (!string.IsNullOrEmpty(marshalAsParams))
                        {
                            marshalAsAdded = true;
                        }

                        continue;
                    }
                }

                // If we didn't add marshal as yet, try again without using pre
                if (!marshalAsAdded)
                {
                    var salAttr = salAttrs.FirstOrDefault(attr => attr.Name == "SAL_readableTo" || attr.Name == "SAL_writeableTo");
                    if (salAttr != null)
                    {
                        marshalAsParams = GetArrayMarshalAsFromP1(paramNode, salAttr.P1, isNullNullTerminated);
                        if (!string.IsNullOrEmpty(marshalAsParams))
                        {
                            marshalAsAdded = true;
                        }
                    }
                }

                if (!string.IsNullOrEmpty(marshalAsParams))
                {
                    var attrName  = SyntaxFactory.ParseName("NativeTypeInfo");
                    var args      = SyntaxFactory.ParseAttributeArgumentList(marshalAsParams.ToString());
                    var finalAttr = SyntaxFactory.Attribute(attrName, args);
                    attributesList.Add(finalAttr);
                }

                if (isIn)
                {
                    attributesList.Add(SyntaxFactory.Attribute(SyntaxFactory.ParseName("In")));
                }

                if (isComOutPtr)
                {
                    attributesList.Add(SyntaxFactory.Attribute(SyntaxFactory.ParseName("ComOutPtr")));
                }
                else if (isOut)
                {
                    attributesList.Add(SyntaxFactory.Attribute(SyntaxFactory.ParseName("Out")));
                }

                if (isOpt)
                {
                    attributesList.Add(SyntaxFactory.Attribute(SyntaxFactory.ParseName("Optional")));
                }

                if (attributesList.Count == 0)
                {
                    return(null);
                }

                return(SyntaxFactory.AttributeList(SyntaxFactory.SeparatedList(attributesList)));

                string GetArrayMarshalAsFromP1(ParameterSyntax paramNode, string p1Text, bool isNullNullTerminated)
                {
                    ParameterListSyntax parameterListNode = (ParameterListSyntax)paramNode.Parent;
                    var           match        = elementCountRegex.Match(p1Text);
                    string        arraySubType = GetParameterArraySubtype(paramNode);
                    StringBuilder ret          = new StringBuilder("(UnmanagedType.LPArray");

                    if (arraySubType != null)
                    {
                        ret.Append($", ArraySubType = UnmanagedType.{arraySubType}");
                    }

                    if (isNullNullTerminated)
                    {
                        ret.Append(", IsNullNullTerminated = true");
                    }

                    if (match.Success)
                    {
                        string sizeOrParamName = match.Groups[1].Value;
                        if (int.TryParse(sizeOrParamName, out int size))
                        {
                            // Don't bother marking this as an array if it only has 1
                            if (size == 1)
                            {
                                return(string.Empty);
                            }

                            ret.Append($", SizeConst = {size}");
                        }
                        else
                        {
                            sizeOrParamName = sizeOrParamName.Replace("*", string.Empty);
                            for (int i = 0; i < parameterListNode.Parameters.Count; i++)
                            {
                                if (parameterListNode.Parameters[i].Identifier.ValueText == sizeOrParamName)
                                {
                                    ret.Append($", SizeParamIndex = {i}");
                                    break;
                                }
                            }
                        }
                    }
                    else
                    {
                        // If it didn't match the regex and we don't see inexpressibleCount, we can't do
                        // anything but return an empty string, because we don't know how to interpret it
                        if (!p1Text.StartsWith("inexpressibleCount"))
                        {
                            ret = new StringBuilder();
                        }
                    }

                    if (ret.Length != 0)
                    {
                        ret.Append(')');
                    }

                    return(ret.ToString());

                    string GetParameterArraySubtype(ParameterSyntax paramNode)
                    {
                        foreach (var attrList in paramNode.AttributeLists)
                        {
                            foreach (var attr in attrList.Attributes)
                            {
                                if (attr.Name.ToString() == "NativeTypeName")
                                {
                                    string nativeType = attr.ArgumentList.Arguments[0].ToString();
                                    nativeType = EncodeHelpers.RemoveQuotes(nativeType);
                                    if (nativeType.StartsWith("const "))
                                    {
                                        nativeType = nativeType.Substring("const ".Length);
                                    }

                                    if (nativeType.EndsWith(" *"))
                                    {
                                        nativeType = nativeType.Substring(0, nativeType.Length - 2);
                                    }

                                    string arraySubType = ConvertTypeToMarshalAsType(nativeType, out _, out _, out _);
                                    return(arraySubType);
                                }
                            }
                        }

                        return(null);
                    }
                }

                IEnumerable <SalAttribute> GetSalAttributes(string salArgsText)
                {
                    foreach (var attr in salArgsText.Split('^'))
                    {
                        var salAttr = SalAttribute.CreateFromCppAttribute(attr);
                        if (salAttr != null)
                        {
                            yield return(salAttr);
                        }
                    }
                }
            }