Esempio n. 1
0
        /// <summary>
        /// Prepares a transformer from C++ to C# model.
        /// </summary>
        /// <typeparam name="TCppElement">The C++ type of data to process</typeparam>
        /// <param name="transform">The transform.</param>
        /// <param name="typeToProcess">The type to process.</param>
        private IEnumerable <TCsElement> PrepareTransform <TCppElement, TCsElement>(CppModule cppModule, ITransformPreparer <TCppElement, TCsElement> transform)
            where TCppElement : CppElement
            where TCsElement : CsBase
        {
            var csElements = new List <TCsElement>();

            // Predefine all structs, typedefs and interfaces
            foreach (var cppInclude in cppModule.Includes)
            {
                foreach (var cppItem in cppInclude.Iterate <TCppElement>())
                {
                    Logger.RunInContext(
                        cppItem.ToString(),
                        () =>
                    {
                        // If already mapped, it means that there is already a predefined mapping
                        if (typeRegistry.FindBoundType(cppItem.Name) == null)
                        {
                            var csElement = transform.Prepare(cppItem);
                            if (csElement != null)
                            {
                                csElements.Add(csElement);
                            }
                        }
                    });
                }
            }
            return(csElements);
        }
Esempio n. 2
0
        /// <summary>
        /// Maps the C++ struct to C# struct.
        /// </summary>
        /// <param name="csStruct">The c sharp struct.</param>
        public override void Process(CsStruct csStruct)
        {
            // TODO: this mapping must be robust. Current calculation for field offset is not always accurate for union.
            // TODO: need to handle align/packing correctly.

            // If a struct was already mapped, then return immediately
            // The method MapStruct can be called recursively
            if (csStruct.IsFullyMapped)
            {
                return;
            }

            // Set IsFullyMappy in order to avoid recursive mapping
            csStruct.IsFullyMapped = true;

            // Get the associated CppStruct and CSharpTag
            var  cppStruct      = (CppStruct)csStruct.CppElement;
            bool hasMarshalType = csStruct.HasMarshalType;

            // If this structure need to me moved to another container, move it now
            foreach (var keyValuePair in _mapMoveStructToInner)
            {
                if (keyValuePair.Key.Match(csStruct.CppElementName).Success)
                {
                    string cppName         = keyValuePair.Key.Replace(csStruct.CppElementName, keyValuePair.Value);
                    var    destSharpStruct = (CsStruct)typeRegistry.FindBoundType(cppName);
                    // Remove the struct from his container
                    csStruct.Parent.Remove(csStruct);
                    // Add this struct to the new container struct
                    destSharpStruct.Add(csStruct);
                }
            }

            // Current offset of a field
            int currentFieldAbsoluteOffset = 0;

            // Last field offset
            int previousFieldOffsetIndex = -1;

            // Size of the last field
            int previousFieldSize = 0;

            //
            int maxSizeOfField = 0;

            bool isNonSequential = false;

            int cumulatedBitOffset = 0;

            var inheritedStructs = new Stack <CppStruct>();
            var currentStruct    = cppStruct;

            while (currentStruct != null && currentStruct.Base != currentStruct.Name)
            {
                inheritedStructs.Push(currentStruct);
                currentStruct = typeRegistry.FindBoundType(currentStruct.Base)?.CppElement as CppStruct;
            }

            while (inheritedStructs.Count > 0)
            {
                currentStruct = inheritedStructs.Pop();

                int fieldCount = currentStruct.IsEmpty ? 0 : currentStruct.Items.Count;

                // -------------------------------------------------------------------------------
                // Iterate on all fields and perform mapping
                // -------------------------------------------------------------------------------
                for (int fieldIndex = 0; fieldIndex < fieldCount; fieldIndex++)
                {
                    var cppField = (CppField)currentStruct.Items[fieldIndex];
                    Logger.RunInContext(cppField.ToString(), () =>
                    {
                        var csField = factory.Create(cppField);
                        csStruct.Add(csField);

                        // Get name
                        csField.Name = NamingRules.Rename(cppField);

                        var fieldHasMarshalType = csField.PublicType != csField.MarshalType ||
                                                  (csField.PublicType is CsStruct fieldStruct && fieldStruct.HasMarshalType) ||
                                                  csField.IsArray;

                        // BoolToInt doesn't generate native Marshaling although they have a different marshaller
                        if (((!csField.IsBoolToInt || csField.IsArray) && fieldHasMarshalType) || csField.Relation != null)
                        {
                            hasMarshalType = true;
                        }

                        // If last field has same offset, then it's a union
                        // CurrentOffset is not moved
                        if (isNonSequential && previousFieldOffsetIndex != cppField.Offset)
                        {
                            previousFieldSize = maxSizeOfField;
                            maxSizeOfField    = 0;
                            isNonSequential   = false;
                        }

                        currentFieldAbsoluteOffset += previousFieldSize;
                        var fieldAlignment          = (csField.MarshalType ?? csField.PublicType).CalculateAlignment();

                        // If field alignment is < 0, then we have a pointer somewhere so we can't align
                        if (fieldAlignment > 0)
                        {
                            // otherwise, align the field on the alignment requirement of the field
                            int delta = (currentFieldAbsoluteOffset % fieldAlignment);
                            if (delta != 0)
                            {
                                currentFieldAbsoluteOffset += fieldAlignment - delta;
                            }
                        }

                        // Get correct offset (for handling union)
                        csField.Offset = currentFieldAbsoluteOffset;

                        // Handle bit fields : calculate BitOffset and BitMask for this field
                        if (previousFieldOffsetIndex != cppField.Offset)
                        {
                            cumulatedBitOffset = 0;
                        }
                        if (cppField.IsBitField)
                        {
                            int lastCumulatedBitOffset = cumulatedBitOffset;
                            cumulatedBitOffset        += cppField.BitOffset;
                            csField.BitMask            = ((1 << cppField.BitOffset) - 1);
                            csField.BitOffset          = lastCumulatedBitOffset;
                        }

                        var nextFieldIndex = fieldIndex + 1;
                        if ((previousFieldOffsetIndex == cppField.Offset) ||
                            (nextFieldIndex < fieldCount && ((CppField)currentStruct.Items[nextFieldIndex]).Offset == cppField.Offset))
                        {
                            if (previousFieldOffsetIndex != cppField.Offset)
                            {
                                maxSizeOfField = 0;
                            }
                            maxSizeOfField          = csField.Size > maxSizeOfField ? csField.Size : maxSizeOfField;
                            isNonSequential         = true;
                            csStruct.ExplicitLayout = true;
                            previousFieldSize       = 0;
                        }
                        else
                        {
                            previousFieldSize = csField.Size;
                        }
                        previousFieldOffsetIndex = cppField.Offset;
                    });
        /// <summary>
        /// Gets the C# type from a C++ type.
        /// </summary>
        /// <typeparam name="T">The C# type to return</typeparam>
        /// <param name="marshallable">The marshallable element to create the C# type from.</param>
        /// <returns>An instantiated C# type</returns>
        private T CreateCore <T>(CppMarshallable marshallable) where T : CsMarshalBase, new()
        {
            CsTypeBase publicType     = null;
            CsTypeBase marshalType    = null;
            var        csMarshallable = new T
            {
                CppElement = marshallable,
                IsArray    = marshallable.IsArray,
                HasPointer = !string.IsNullOrEmpty(marshallable.Pointer) && (marshallable.Pointer.Contains("*") || marshallable.Pointer.Contains("&")),
            };

            // TODO: handle multidimensional arrays
            // Calculate ArrayDimension
            int arrayDimensionValue = 0;

            if (marshallable.IsArray)
            {
                if (string.IsNullOrEmpty(marshallable.ArrayDimension))
                {
                    arrayDimensionValue = 0;
                }
                else if (!int.TryParse(marshallable.ArrayDimension, out arrayDimensionValue))
                {
                    arrayDimensionValue = 1;
                }
            }

            // If array Dimension is 0, then it is not an array
            if (arrayDimensionValue == 0)
            {
                marshallable.IsArray   = false;
                csMarshallable.IsArray = false;
            }
            csMarshallable.ArrayDimensionValue = arrayDimensionValue;

            string publicTypeName = marshallable.GetTypeNameWithMapping();

            switch (publicTypeName)
            {
            case "char":
                publicType = typeRegistry.ImportType(typeof(byte));
                if (csMarshallable.HasPointer)
                {
                    publicType = typeRegistry.ImportType(typeof(string));
                }
                if (csMarshallable.IsArray)
                {
                    publicType  = typeRegistry.ImportType(typeof(string));
                    marshalType = typeRegistry.ImportType(typeof(byte));
                }
                break;

            case "wchar_t":
                publicType = typeRegistry.ImportType(typeof(char));
                csMarshallable.IsWideChar = true;
                if (csMarshallable.HasPointer)
                {
                    publicType = typeRegistry.ImportType(typeof(string));
                }
                if (csMarshallable.IsArray)
                {
                    publicType  = typeRegistry.ImportType(typeof(string));
                    marshalType = typeRegistry.ImportType(typeof(char));
                }
                break;

            default:

                // If CppType is an array, try first to get the binding for this array
                if (marshallable.IsArray)
                {
                    publicType = typeRegistry.FindBoundType(publicTypeName + "[" + marshallable.ArrayDimension + "]");
                }

                // Else get the typeName
                if (publicType == null)
                {
                    // Try to get a declared type
                    // If it fails, then this type is unknown
                    publicType = typeRegistry.FindBoundType(publicTypeName);
                    if (publicType == null)
                    {
                        logger.Fatal("Unknown type found [{0}]", publicTypeName);
                    }
                }
                else
                {
                    csMarshallable.ArrayDimensionValue = 0;
                    csMarshallable.IsArray             = false;
                }

                // By default, use the underlying native type as the marshal type
                // if it differs from the public type.
                marshalType = typeRegistry.FindBoundType(marshallable.TypeName);
                if (publicType == marshalType)
                {
                    marshalType = null;
                }

                if (marshalType == null)
                {
                    // Otherwise, get the registered marshal type if one exists
                    marshalType = typeRegistry.FindBoundMarshalType(publicTypeName);
                }

                if (publicType is CsStruct csStruct)
                {
                    // If a structure was not already parsed, then parse it before going further
                    if (!csStruct.IsFullyMapped)
                    {
                        RequestStructProcessing?.Invoke(csStruct);
                    }

                    if (!csStruct.IsFullyMapped)     // No one tried to map the struct so we can't continue.
                    {
                        logger.Fatal($"No struct processor processed {csStruct.QualifiedName}. Cannot continue processing");
                    }

                    // If referenced structure has a specialized marshalling, then use the structure's built-in marshalling
                    if (csStruct.HasMarshalType && !csMarshallable.HasPointer)
                    {
                        marshalType = publicType;
                    }
                }
                else if (publicType is CsEnum referenceEnum)
                {
                    marshalType = null;     // enums don't need a marshal type. They can always marshal as their underlying type.
                }
                break;
            }

            // Set bool to int conversion case
            csMarshallable.IsBoolToInt =
                marshalType is CsFundamentalType marshalFundamental && IsIntegerFundamentalType(marshalFundamental) &&
                publicType is CsFundamentalType publicFundamental && publicFundamental.Type == typeof(bool);

            if (publicType.QualifiedName == globalNamespace.GetTypeName(WellKnownName.PointerSize))
            {
                marshalType = typeRegistry.ImportType(typeof(IntPtr));
            }

            // Present void* elements as IntPtr. Marshal strings as IntPtr
            if (csMarshallable.HasPointer)
            {
                if (publicTypeName == "void")
                {
                    publicType  = typeRegistry.ImportType(typeof(IntPtr));
                    marshalType = typeRegistry.ImportType(typeof(IntPtr));
                }
                else if (publicType == typeRegistry.ImportType(typeof(string)))
                {
                    marshalType = typeRegistry.ImportType(typeof(IntPtr));
                }
            }

            csMarshallable.PublicType  = publicType;
            csMarshallable.MarshalType = marshalType ?? publicType;

            csMarshallable.Relations = RelationParser.ParseRelation(marshallable.GetMappingRule().Relation, logger);

            return(csMarshallable);
        }