public static bool TryParse(XmlElement command, List <string> errors, out CommandBinding binding)
        {
            XmlElement proto = (XmlElement)command.GetElementsByTagName("proto").Item(0);

            binding = new CommandBinding {
                ReturnCType = (proto.GetElementsByTagName("ptype").OfType <XmlElement>().FirstOrDefault()?.InnerText
                               ?? proto.ChildNodes.OfType <XmlText>().First().Value).Trim()
            };
            if (TypeConverter.Convert(command.OwnerDocument, binding.ReturnCType, out binding.ReturnCSType) && binding.ReturnCSType.ReturnType != null)
            {
                binding.CName  = proto.GetElementsByTagName("name").Item(0).InnerText.Trim();
                binding.CSName = binding.CName.CommandToPascal();
                foreach (XmlElement param in command.GetElementsByTagName("param"))
                {
                    ParameterBinding parameterBinding;
                    if (ParameterBinding.TryParse(param, errors, out parameterBinding))
                    {
                        binding.Parameters.Add(parameterBinding);
                    }
                    else
                    {
                        return(false);
                    }
                }
                return(true);
            }
            else
            {
                errors.Add(string.Format("Unable to find method to convert type '{0}.'", binding.ReturnCType));
                return(false);
            }
        }
 void ImplementMethod(StringBuilder code, List <string> errors, CommandBinding binding, int i, string indent)
 {
     if (i < binding.Parameters.Count)
     {
         ParameterBinding param = binding.Parameters[i];
         if (param.CSType.ParameterType.EndsWith("[][][]"))
         {
             errors.Add("Type has too many array dimensions.");
             code.Append(indent);
             code.AppendLine("throw new NotSupportedException();");
         }
         else if (param.CSType.ParameterType.EndsWith("[][]"))
         {
             ImplementDoubleArrayMethod(code, errors, binding, i, indent, param.Name, param.CSType.ParameterType.Substring(0, param.CSType.ParameterType.Length - 4), param);
         }
         else if (param.CSType.ParameterType.EndsWith("[]"))
         {
             code.AppendFormat("{0}fixed ({1} *ptr_{2} = @{2}) {3}", indent, param.CSType.ParameterType.Substring(0, param.CSType.ParameterType.Length - 2), param.Name, '{');
             code.AppendLine();
             param.Name = string.Concat("ptr_", param.Name);
             ImplementMethod(code, errors, binding, i + 1, string.Concat(indent, "    "));
             code.Append(indent);
             code.AppendLine("}");
         }
         else
         {
             ImplementMethod(code, errors, binding, i + 1, indent);
         }
     }
     else
     {
         code.Append(indent);
         if (binding.ReturnCSType.ReturnType != "void")
         {
             code.Append("return ");
         }
         code.AppendFormat("Native_{0}(", binding.CSName);
         bool first = true;
         foreach (ParameterBinding param in binding.Parameters)
         {
             if (first)
             {
                 first = false;
             }
             else
             {
                 code.Append(", ");
             }
             if (param.Name[0] >= 'a' && param.Name[0] <= 'z')
             {
                 code.Append("@");
             }
             code.AppendFormat(param.Name);
         }
         code.AppendLine(");");
     }
 }
Exemple #3
0
        public static bool TryParse(XmlElement param, List <string> errors, out ParameterBinding binding)
        {
            ParameterBinding _binding = binding = new ParameterBinding();

            if (param.HasAttribute("group"))
            {
                XmlElement groups = (XmlElement)param.OwnerDocument.GetElementsByTagName("groups").Item(0);
                binding.CType = param.Attributes["group"].Value;
                if (groups.ChildNodes.OfType <XmlElement>().Any(e => e.Attributes["name"].Value == _binding.CType))
                {
                    string csType = string.Concat("Gl", binding.CType);
                    csType         = string.Concat(csType, new string(param.ChildNodes.OfType <XmlText>().SelectMany(n => n.Value).Where(v => v == '*').SelectMany(c => "[]").ToArray()));
                    binding.CSType = new ConvertedType(csType);
                }
            }
            if (binding.CSType == null)
            {
                XmlElement ptype = (XmlElement)param.GetElementsByTagName("ptype").Item(0);
                if (ptype == null)
                {
                    binding.CType = param.ChildNodes.OfType <XmlText>().First().Value.Trim();
                }
                else
                {
                    binding.CType = ptype.InnerText.Trim();
                    binding.CType = string.Concat(binding.CType, new string(param.ChildNodes.OfType <XmlText>().SelectMany(n => n.Value).Where(v => v == '*').ToArray()));
                }
                ConvertedType t;
                if (TypeConverter.Convert(param.OwnerDocument, binding.CType, out t) && t.ParameterType != null)
                {
                    binding.CSType = t;
                }
                else
                {
                    errors.Add(string.Format("Unable to find method to convert type '{0}.'", binding.CType));
                    return(false);
                }
            }
            XmlElement paramName = (XmlElement)param.GetElementsByTagName("name").Item(0);

            binding.Name = paramName.InnerText.Trim();
            return(true);
        }
        void ImplementDoubleArrayMethod(StringBuilder code, List <string> errors, CommandBinding binding, int i, string indent, string paramName, string arrayType, ParameterBinding param)
        {
            code.AppendFormat("{0}IntPtr ptr_{1} = Marshal.AllocHGlobal(@{1}.Length * sizeof(void *));", indent, paramName);
            code.AppendLine();
            code.AppendFormat("{0}try {1}", indent, '{');
            code.AppendLine();
            code.AppendFormat("{0}    {4}ConvertDoubleArray_{1}(ptr_{2}, @{2}, (void **) ptr_{2}.ToPointer(), 0, __fixedLocals => {3}",
                              indent,
                              arrayType,
                              paramName,
                              '{',
                              binding.ReturnCSType.ReturnType == "void" ? "" : "return ");
            code.AppendLine();
            param.Name = string.Format("({0} **) ptr_{1}.ToPointer()", arrayType, paramName);
            List <string> fixedLocals = new List <string>();

            for (int j = 0, k = 0; j < i; ++j)
            {
                if (binding.Parameters[j].CSType.ParameterType.EndsWith("[]"))
                {
                    fixedLocals.Add(binding.Parameters[j].Name);
                    binding.Parameters[j].Name = string.Format("({0} *) __fixedLocals[{1}]", binding.Parameters[j].CSType.ParameterType.Substring(0, binding.Parameters[j].CSType.ParameterType.Length - 2), k++);
                }
            }
            ImplementMethod(code, errors, binding, i + 1, string.Concat(indent, "        "));
            code.AppendFormat("{0}    {1}", indent, '}');
            if (fixedLocals.Count == 0)
            {
                code.Append(", new void *[0]");
            }
            else
            {
                foreach (string fixedLocal in fixedLocals)
                {
                    code.AppendFormat(", {0}", fixedLocal);
                }
            }
            code.AppendLine(");");
            code.AppendFormat("{0}{1} finally {2}", indent, '}', '{');
            code.AppendLine();
            code.AppendFormat("{0}    Marshal.FreeHGlobal(ptr_{1});", indent, paramName);
            code.AppendLine();
            code.AppendFormat("{0}{1}", indent, '}');
            code.AppendLine();
        }