private void Validate(NamingRules value, NamingRules option1, NamingRules option2) { if ((value & option1) == option1 && (value & option2) == option2) { throw new ArgumentException(string.Format(Strings.ExOptionXIsMutuallyExclusiveWithOptionY, option1, option2)); } }
private Domain BuildDomain(DomainUpgradeMode upgradeMode, NamingRules namingRules, Type sampleType) { var configuration = DomainConfigurationFactory.Create(); configuration.UpgradeMode = upgradeMode; configuration.NamingConvention.NamingRules = namingRules; configuration.Types.Register(sampleType.Assembly, sampleType.Namespace); return(Domain.Build(configuration)); }
private void UpdateNamingRules(ConfigFile file) { foreach (var namingRule in file.Naming) { if (namingRule is NamingRuleShort) { NamingRules.AddShortNameRule(namingRule.Name, namingRule.Value); } } }
/// <summary> /// Adds a list of constant gathered from macros/guids to a C# type. /// </summary> /// <param name="elementFinder">The C++ module to search.</param> /// <param name="macroRegexp">The macro regexp.</param> /// <param name="fullNameCSharpType">Full type of the name C sharp.</param> /// <param name="type">The type.</param> /// <param name="fieldName">Name of the field.</param> /// <param name="valueMap">The value map.</param> /// <param name="visibility">The visibility.</param> /// <param name="nameSpace">The current namespace.</param> public void AddConstantFromMacroToCSharpType(CppElementFinder elementFinder, string macroRegexp, string fullNameCSharpType, string type, string fieldName, string valueMap, Visibility?visibility, string nameSpace) { var constantDefinitions = elementFinder.Find <CppConstant>(macroRegexp); var regex = new Regex(macroRegexp); // $0: Name of the C++ macro // $1: Value of the C++ macro // $2: Name of the C# // $3: Name of current namespace if (valueMap != null) { valueMap = valueMap.Replace("{", "{{"); valueMap = valueMap.Replace("}", "}}"); valueMap = valueMap.Replace("$0", "{0}"); valueMap = valueMap.Replace("$1", "{1}"); valueMap = valueMap.Replace("$2", "{2}"); valueMap = valueMap.Replace("$3", "{3}"); } foreach (var macroDef in constantDefinitions) { var finalFieldName = fieldName == null ? macroDef.Name : NamingRules.ConvertToPascalCase( regex.Replace(macroDef.Name, fieldName), NamingFlags.Default); var finalValue = valueMap == null ? macroDef.Value : string.Format(valueMap, macroDef.Name, macroDef.Value, finalFieldName, nameSpace); var constant = AddConstantToCSharpType(macroDef, fullNameCSharpType, type, finalFieldName, finalValue); constant.Visibility = visibility ?? Visibility.Public | Visibility.Const; } var guidDefinitions = elementFinder.Find <CppGuid>(macroRegexp); foreach (var guidDef in guidDefinitions) { var finalFieldName = fieldName == null ? guidDef.Name : NamingRules.ConvertToPascalCase( regex.Replace(guidDef.Name, fieldName), NamingFlags.Default); var finalValue = valueMap == null? guidDef.Guid.ToString() : string.Format(valueMap, guidDef.Name, guidDef.Guid.ToString(), finalFieldName, nameSpace); var constant = AddConstantToCSharpType(guidDef, fullNameCSharpType, type, finalFieldName, finalValue); constant.Visibility = visibility ?? Visibility.Public | Visibility.Static | Visibility.Readonly; } }
public void DotsAndHypensExclusiveOptionsTest() { var configuration = new DomainConfiguration(); const NamingRules invalidRules1 = NamingRules.UnderscoreDots | NamingRules.UnderscoreHyphens | NamingRules.RemoveDots; const NamingRules invalidRules2 = NamingRules.RemoveDots | NamingRules.RemoveHyphens | NamingRules.UnderscoreHyphens; const NamingRules validRules1 = NamingRules.UnderscoreHyphens | NamingRules.UnderscoreDots; const NamingRules validRules2 = NamingRules.RemoveDots | NamingRules.RemoveHyphens; var convention = configuration.NamingConvention; AssertEx.ThrowsArgumentException(() => convention.NamingRules = invalidRules1); AssertEx.ThrowsArgumentException(() => convention.NamingRules = invalidRules2); convention.NamingRules = validRules1; convention.NamingRules = validRules2; }
/// <summary> /// Prepares C++ struct for mapping. This method is creating the associated C# struct. /// </summary> /// <param name="cppStruct">The c++ struct.</param> /// <returns></returns> public override CsStruct Prepare(CppStruct cppStruct) { // Create a new C# struct var nameSpace = namespaceRegistry.ResolveNamespace(cppStruct); var csStruct = new CsStruct(cppStruct) { Name = NamingRules.Rename(cppStruct), // IsFullyMapped to false => The structure is being mapped IsFullyMapped = false }; // Add the C# struct to its namespace nameSpace.Add(csStruct); // Map the C++ name to the C# struct typeRegistry.BindType(cppStruct.Name, csStruct); return(csStruct); }
/// <summary> /// Prepares the specified C++ element to a C# element. /// </summary> /// <param name="cppElement">The C++ element.</param> /// <returns>The C# element created and registered to the <see cref="TransformManager"/></returns> public override CsBase Prepare(CppElement cppElement) { var cppInterface = (CppInterface)cppElement; // IsFullyMapped to false => The structure is being mapped var cSharpInterface = new CsInterface(cppInterface) { IsFullyMapped = false }; CsNamespace nameSpace = Manager.ResolveNamespace(cppInterface); cSharpInterface.Name = NamingRules.Rename(cppInterface); nameSpace.Add(cSharpInterface); Manager.BindType(cppInterface.Name, cSharpInterface); return(cSharpInterface); }
/// <summary> /// Processes the specified method. /// </summary> /// <param name="method">The method.</param> private void ProcessMethod(CsCallable method) { var cppMethod = (CppCallable)method.CppElement; method.Name = NamingRules.Rename(cppMethod); // For methods, the tag "type" is only used for return type // So we are overriding the return type here var methodRule = cppMethod.GetMappingRule(); if (methodRule.MappingType != null) { cppMethod.ReturnValue.Rule = new MappingRule { MappingType = methodRule.MappingType } } ; // Get the inferred return type method.ReturnValue = factory.Create(cppMethod.ReturnValue); if (method.ReturnValue.PublicType is CsInterface iface && iface.IsCallback) { method.ReturnValue.PublicType = iface.GetNativeImplementationOrThis(); } // Hide return type only if it is a HRESULT and AlwaysReturnHResult is false if (method.CheckReturnType && method.ReturnValue.PublicType != null && method.ReturnValue.PublicType.QualifiedName == globalNamespace.GetTypeName(WellKnownName.Result)) { method.HideReturnType = !method.AlwaysReturnHResult; } // Iterates on parameters to convert them to C# parameters foreach (var cppParameter in cppMethod.Parameters) { var paramMethod = factory.Create(cppParameter); paramMethod.Name = NamingRules.Rename(cppParameter); method.Add(paramMethod); } }
/// <summary> /// Prepares the specified C++ element to a C# element. /// </summary> /// <param name="cppEnum">The C++ element.</param> /// <returns>The C# element created and registered to the <see cref="TransformManager"/></returns> public override CsEnum Prepare(CppEnum cppEnum) { // Create C# enum var newEnum = new CsEnum { Name = NamingRules.Rename(cppEnum), CppElement = cppEnum, UnderlyingType = typeRegistry.ImportType(typeof(int)) }; // Get the namespace for this particular include and enum var nameSpace = namespaceRegistry.ResolveNamespace(cppEnum); nameSpace.Add(newEnum); // Bind C++ enum to C# enum typeRegistry.BindType(cppEnum.Name, newEnum); return(newEnum); }
/// <summary> /// Prepares C++ struct for mapping. This method is creating the associated C# struct. /// </summary> /// <param name="cppElement">The c++ struct.</param> /// <returns></returns> public override CsBase Prepare(CppElement cppElement) { var cppStruct = (CppStruct)cppElement; // Create a new C# struct var nameSpace = Manager.ResolveNamespace(cppStruct); var csStruct = new CsStruct(cppStruct) { Name = NamingRules.Rename(cppStruct), // IsFullyMapped to false => The structure is being mapped IsFullyMapped = false }; // Add the C# struct to its namespace nameSpace.Add(csStruct); // Map the C++ name to the C# struct Manager.BindType(cppStruct.Name, csStruct); return(csStruct); }
/// <summary> /// Prepares the specified C++ element to a C# element. /// </summary> /// <param name="cppInterface">The C++ element.</param> /// <returns>The C# element created and registered to the <see cref="TransformManager"/></returns> public override CsInterface Prepare(CppInterface cppInterface) { // IsFullyMapped to false => The structure is being mapped var cSharpInterface = new CsInterface(cppInterface) { IsFullyMapped = false }; var nameSpace = namespaceRegistry.ResolveNamespace(cppInterface); cSharpInterface.Name = NamingRules.Rename(cppInterface); nameSpace.Add(cSharpInterface); typeRegistry.BindType(cppInterface.Name, cSharpInterface); foreach (var cppMethod in cppInterface.Methods) { cSharpInterface.Add(MethodPreparer.Prepare(cppMethod)); } return(cSharpInterface); }
/// <summary> /// Prepares the specified C++ element to a C# element. /// </summary> /// <param name="cppElement">The C++ element.</param> /// <returns>The C# element created and registered to the <see cref="TransformManager"/></returns> public override CsBase Prepare(CppElement cppElement) { var cppEnum = (CppEnum)cppElement; // Create C# enum var newEnum = new CsEnum { Name = NamingRules.Rename(cppEnum), CppElement = cppEnum }; // Get the namespace for this particular include and enum var nameSpace = Manager.ResolveNamespace(cppEnum); nameSpace.Add(newEnum); // Bind C++ enum to C# enum Manager.BindType(cppEnum.Name, newEnum); return(newEnum); }
private void BuildDomain(string version, DomainUpgradeMode upgradeMode, NamingRules namingRules) { if (domain != null) { domain.DisposeSafely(); } string ns = typeof(M1.Person).Namespace; string nsPrefix = ns.Substring(0, ns.Length - 1); var configuration = DomainConfigurationFactory.Create(); configuration.UpgradeMode = upgradeMode; configuration.Types.Register(Assembly.GetExecutingAssembly(), nsPrefix + version); configuration.Types.Register(typeof(Upgrader)); configuration.NamingConvention.NamingRules = namingRules; using (Upgrader.Enable(version)) { domain = Domain.Build(configuration); } }
private void RunTest(NamingRules namingRules) { int myEntityTypeId; int myChildEntityTypeId; using (var domain = BuildInitialDomain(namingRules)) using (var session = domain.OpenSession()) using (var tx = session.OpenTransaction()) { var types = domain.Model.Types; myEntityTypeId = types[typeof(MyEntity)].TypeId; myChildEntityTypeId = types[typeof(V1.MyChildEntity)].TypeId; new MyEntity(); new V1.MyChildEntity(); tx.Complete(); } using (var domain = BuildUpgradedDomain(namingRules)) using (var session = domain.OpenSession()) using (var tx = session.OpenTransaction()) { var types = domain.Model.Types; Assert.That(types[typeof(MyEntity)].TypeId, Is.EqualTo(myEntityTypeId)); Assert.That(types[typeof(V2.MyChildEntity)].TypeId, Is.EqualTo(myChildEntityTypeId)); var allItems = session.Query.All <MyEntity>().ToList(); Assert.That(allItems.Count, Is.EqualTo(2)); Assert.That(allItems.Count(item => item is V2.MyChildEntity), Is.EqualTo(1)); Assert.That(allItems.Count(item => !(item is V2.MyChildEntity)), Is.EqualTo(1)); var myChildEntity = session.Query.All <V2.MyChildEntity>().Single(); Assert.That(myChildEntity.Name, Is.EqualTo("MyChildEntity")); var myEntity = session.Query.All <MyEntity>().Single(e => e != myChildEntity); Assert.That(myEntity.Name, Is.EqualTo("MyEntity")); tx.Complete(); } }
private void RunTest(NamingRules namingRules) { BuildDomain("1", DomainUpgradeMode.Recreate, namingRules); using (var session = domain.OpenSession()) { using (var tx = session.OpenTransaction()) { var person = new M1.Person { Name = "Vasya", Weight = 80, Age = 20, Phone = new M1.Phone(), }; tx.Complete(); } } BuildDomain("2", DomainUpgradeMode.PerformSafely, namingRules); using (var session = domain.OpenSession()) { using (var tx = session.OpenTransaction()) { var vasya = session.Query.All <Model.Version2.Person>().Single(); Assert.AreEqual("Vasya", vasya.Name); Assert.AreEqual(80, vasya.Weight); Assert.IsNotNull(vasya.Phone); } } }
private Task <Domain> BuildUpgradedDomainAsync(NamingRules namingRules) => BuildDomainAsync(DomainUpgradeMode.PerformSafely, namingRules, typeof(V2.MyChildEntity));
/// <summary> /// Processes the specified method. /// </summary> /// <param name="method">The method.</param> private void Process(CsMethod method) { var cppMethod = (CppMethod)method.CppElement; method.Name = NamingRules.Rename(cppMethod); method.Offset = cppMethod.Offset; // For methods, the tag "type" is only used for return type // So we are overriding the return type here var tag = cppMethod.GetTagOrDefault <MappingRule>(); if (tag.MappingType != null) { cppMethod.ReturnType.Tag = new MappingRule { MappingType = tag.MappingType } } ; // Apply any offset to the method's vtable method.Offset += tag.LayoutOffsetTranslate; // Get the inferred return type method.ReturnType = Manager.GetCsType <CsMarshalBase>(cppMethod.ReturnType); // Hide return type only if it is a HRESULT and AlwaysReturnHResult is false if (method.CheckReturnType && method.ReturnType.PublicType != null && method.ReturnType.PublicType.QualifiedName == Manager.GlobalNamespace.GetTypeName("Result")) { method.HideReturnType = !method.AlwaysReturnHResult; } // Iterates on parameters to convert them to C# parameters foreach (var cppParameter in cppMethod.Parameters) { var cppAttribute = cppParameter.Attribute; var paramTag = cppParameter.GetTagOrDefault <MappingRule>(); bool hasArray = cppParameter.IsArray || ((cppAttribute & ParamAttribute.Buffer) != 0); bool hasParams = (cppAttribute & ParamAttribute.Params) == ParamAttribute.Params; bool isOptional = (cppAttribute & ParamAttribute.Optional) != 0; var paramMethod = Manager.GetCsType <CsParameter>(cppParameter); paramMethod.Name = NamingRules.Rename(cppParameter); bool hasPointer = paramMethod.HasPointer; var publicType = paramMethod.PublicType; var marshalType = paramMethod.MarshalType; CsParameterAttribute parameterAttribute = CsParameterAttribute.In; if (hasArray) { hasPointer = true; } // -------------------------------------------------------------------------------- // Pointer - Handle special cases // -------------------------------------------------------------------------------- if (hasPointer) { marshalType = Manager.ImportType(typeof(IntPtr)); // -------------------------------------------------------------------------------- // Handling Parameter Interface // -------------------------------------------------------------------------------- if (publicType is CsInterface) { // Force Interface** to be ParamAttribute.Out when None if (cppAttribute == ParamAttribute.In) { if (cppParameter.Pointer == "**") { cppAttribute = ParamAttribute.Out; } } if ((cppAttribute & ParamAttribute.In) != 0 || (cppAttribute & ParamAttribute.InOut) != 0) { parameterAttribute = CsParameterAttribute.In; // Force all array of interface to support null if (hasArray) { isOptional = true; } // If Interface is a callback, use IntPtr as a public marshalling type CsInterface publicCsInterface = (CsInterface)publicType; if (publicCsInterface.IsCallback) { publicType = Manager.ImportType(typeof(IntPtr)); // By default, set the Visibility to internal for methods using callbacks // as we need to provide user method. Don't do this on functions as they // are already hidden by the container if (!(method is CsFunction)) { method.Visibility = Visibility.Internal; method.Name = method.Name + "_"; } } } //else if ((cppParameter.Attribute & ParamAttribute.InOut) != 0) // parameterAttribute = method.ParameterAttribute.Ref; else if ((cppAttribute & ParamAttribute.Out) != 0) { parameterAttribute = CsParameterAttribute.Out; } } else { // If a pointer to array of bool are handle as array of int if (paramMethod.IsBoolToInt && (cppAttribute & ParamAttribute.Buffer) != 0) { publicType = Manager.ImportType(typeof(int)); } // -------------------------------------------------------------------------------- // Handling Parameter Interface // -------------------------------------------------------------------------------- if ((cppAttribute & ParamAttribute.In) != 0) { parameterAttribute = publicType.Type == typeof(IntPtr) || publicType.Name == Manager.GlobalNamespace.GetTypeName("FunctionCallback") || publicType.Type == typeof(string) ? CsParameterAttribute.In : CsParameterAttribute.RefIn; } else if ((cppAttribute & ParamAttribute.InOut) != 0) { if ((cppAttribute & ParamAttribute.Optional) != 0) { publicType = Manager.ImportType(typeof(IntPtr)); parameterAttribute = CsParameterAttribute.In; } else { parameterAttribute = CsParameterAttribute.Ref; } } else if ((cppAttribute & ParamAttribute.Out) != 0) { parameterAttribute = CsParameterAttribute.Out; } // Handle void* with Buffer attribute if (cppParameter.TypeName == "void" && (cppAttribute & ParamAttribute.Buffer) != 0) { hasArray = false; parameterAttribute = CsParameterAttribute.In; } else if (publicType.Type == typeof(string) && (cppAttribute & ParamAttribute.Out) != 0) { publicType = Manager.ImportType(typeof(IntPtr)); parameterAttribute = CsParameterAttribute.In; hasArray = false; } else if (publicType is CsStruct && (parameterAttribute == CsParameterAttribute.Out || hasArray || parameterAttribute == CsParameterAttribute.RefIn || parameterAttribute == CsParameterAttribute.Ref)) { // Set IsOut on structure to generate proper marshalling (publicType as CsStruct).IsOut = true; } } } paramMethod.HasPointer = hasPointer; paramMethod.Attribute = parameterAttribute; paramMethod.IsArray = hasArray; paramMethod.HasParams = hasParams; paramMethod.HasPointer = hasPointer; paramMethod.PublicType = publicType ?? throw new ArgumentException("Public type cannot be null"); paramMethod.MarshalType = marshalType; paramMethod.IsOptional = isOptional; // Force IsString to be only string (due to Buffer attribute) if (paramMethod.IsString) { paramMethod.IsArray = false; } method.Add(paramMethod); } } }
/// <summary> /// Maps the C++ struct to C# struct. /// </summary> /// <param name="csStruct">The c sharp struct.</param> private 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)Manager.FindBindType(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 isInUnion = false; int cumulatedBitOffset = 0; var inheritedStructs = new Stack <CppStruct>(); var currentStruct = cppStruct; while (currentStruct != null && currentStruct.ParentName != currentStruct.Name) { inheritedStructs.Push(currentStruct); currentStruct = Manager.FindBindType(currentStruct.ParentName)?.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 fieldStruct = Manager.GetCsType <CsField>(cppField, true); csStruct.Add(fieldStruct); // Get name fieldStruct.Name = NamingRules.Rename(cppField); // BoolToInt doesn't generate native Marshaling although they have a different marshaller if (!fieldStruct.IsBoolToInt && fieldStruct.HasMarshalType) { hasMarshalType = true; } // If last field has same offset, then it's a union // CurrentOffset is not moved if (isInUnion && previousFieldOffsetIndex != cppField.Offset) { previousFieldSize = maxSizeOfField; maxSizeOfField = 0; isInUnion = false; } currentFieldAbsoluteOffset += previousFieldSize; var fieldAlignment = (fieldStruct.MarshalType ?? fieldStruct.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) fieldStruct.Offset = currentFieldAbsoluteOffset; fieldStruct.IsBitField = cppField.IsBitField; // 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; fieldStruct.BitMask = ((1 << cppField.BitOffset) - 1); // &~((1 << (lastCumulatedBitOffset + 1)) - 1); fieldStruct.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 = fieldStruct.SizeOf > maxSizeOfField ? fieldStruct.SizeOf : maxSizeOfField; isInUnion = true; csStruct.ExplicitLayout = true; previousFieldSize = 0; } else { previousFieldSize = fieldStruct.SizeOf; } previousFieldOffsetIndex = cppField.Offset; }); } } // In case of explicit layout, check that we can safely generate it on both x86 and x64 (in case of an union // using pointers, we can't) if (csStruct.ExplicitLayout) { var fieldList = csStruct.Fields.ToList(); for (int i = 0; i < fieldList.Count; i++) { var field = fieldList[i]; var fieldAlignment = (field.MarshalType ?? field.PublicType).CalculateAlignment(); if (fieldAlignment < 0) { // If pointer field is not the last one, than we can't handle it if ((i + 1) < fieldList.Count) { Logger.Error( "The field [{0}] in structure [{1}] has pointer alignment within a structure that contains an union. An explicit layout cannot be handled on both x86/x64. This structure needs manual layout (remove fields from definition) and write them manually in xml mapping files", field.CppElementName, csStruct.CppElementName); break; } } } } csStruct.SizeOf = currentFieldAbsoluteOffset + previousFieldSize; csStruct.HasMarshalType = hasMarshalType; }
private Task <Domain> BuildDomainAsync(DomainUpgradeMode upgradeMode, NamingRules namingRules, Type sampleType) { var configuration = BuildDomainConfiguration(upgradeMode, namingRules, sampleType); return(Domain.BuildAsync(configuration)); }
private Domain BuildInitialDomain(NamingRules namingRules) => BuildDomain(DomainUpgradeMode.Recreate, namingRules, typeof(V1.MyChildEntity));
/// <summary> /// Maps the C++ struct to C# struct. /// </summary> /// <param name="csStruct">The c sharp struct.</param> private void Process(CsStruct csStruct) { // TODO: this mapping must be robust. Current caculation for field offset is not always accurate for union. // TODO: need to handle align/packing correctly. // If a struct was already mapped, then return immediatly // The method MapStruct can be called recursivelly 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 anoter 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)Manager.FindBindType(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 currentOffset = 0; int fieldCount = cppStruct.IsEmpty ? 0 : cppStruct.Items.Count; // Offset stored for each field int[] offsetOfFields = new int[fieldCount]; // Last field offset int lastCppFieldOffset = -1; // Size of the last field int lastFieldSize = 0; // int maxSizeOfField = 0; bool isInUnion = false; int cumulatedBitOffset = 0; // ------------------------------------------------------------------------------- // Iterate on all fields and perform mapping // ------------------------------------------------------------------------------- for (int fieldIndex = 0; fieldIndex < fieldCount; fieldIndex++) { var cppField = (CppField)cppStruct.Items[fieldIndex]; Logger.RunInContext(cppField.ToString(), () => { var fieldStruct = Manager.GetCsType <CsField>(cppField, true); // Get name fieldStruct.Name = NamingRules.Rename(cppField); // BoolToInt doesn't generate native Marshaling although they have a different marshaller if (!fieldStruct.IsBoolToInt && fieldStruct.HasMarshalType) { hasMarshalType = true; } // If last field has same offset, then it's a union // CurrentOffset is not moved if (isInUnion && lastCppFieldOffset != cppField.Offset) { lastFieldSize = maxSizeOfField; maxSizeOfField = 0; isInUnion = false; } currentOffset += lastFieldSize; offsetOfFields[cppField.Offset] = currentOffset; // Get correct offset (for handling union) fieldStruct.Offset = offsetOfFields[cppField.Offset]; fieldStruct.IsBitField = cppField.IsBitField; // Handle bit fields : calculate BitOffset and BitMask for this field if (lastCppFieldOffset != cppField.Offset) { cumulatedBitOffset = 0; } if (cppField.IsBitField) { int lastCumulatedBitOffset = cumulatedBitOffset; cumulatedBitOffset += cppField.BitOffset; fieldStruct.BitMask = ((1 << cppField.BitOffset) - 1); // &~((1 << (lastCumulatedBitOffset + 1)) - 1); //fieldStruct.BitMask2 = ((1 << cppField.BitOffset) - 1); // &~((1 << (lastCumulatedBitOffset + 1)) - 1); fieldStruct.BitOffset = lastCumulatedBitOffset; } csStruct.Add(fieldStruct); // TODO : handle packing rules here!!!!! // If last field has same offset, then it's a union // CurrentOffset is not moved if (lastCppFieldOffset == cppField.Offset || ((fieldIndex + 1) < fieldCount && (cppStruct.Items[fieldIndex + 1] as CppField).Offset == cppField.Offset)) { isInUnion = true; csStruct.ExplicitLayout = true; maxSizeOfField = fieldStruct.SizeOf > maxSizeOfField ? fieldStruct.SizeOf : maxSizeOfField; lastFieldSize = 0; } else { lastFieldSize = fieldStruct.SizeOf; } lastCppFieldOffset = cppField.Offset; }); } csStruct.SizeOf = currentOffset + lastFieldSize; csStruct.HasMarshalType = hasMarshalType; }
/// <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; });
private Domain BuildUpgradedDomain(NamingRules namingRules) => BuildDomain(DomainUpgradeMode.PerformSafely, namingRules, typeof(V2.MyChildEntity));
/// <summary> /// Maps a C++ Enum to a C# enum. /// </summary> /// <param name="newEnum">the C# enum.</param> private void Process(CsEnum newEnum) { var cppEnum = (CppEnum)newEnum.CppElement; // Get tag from C++ enum var tag = cppEnum.GetTagOrDefault <MappingRule>(); // Determine enum type. Default is int string typeName = cppEnum.GetTypeNameWithMapping(); switch (typeName) { case "byte": newEnum.Type = typeof(byte); newEnum.SizeOf = 1; break; case "short": newEnum.Type = typeof(short); newEnum.SizeOf = 1; break; case "int": newEnum.Type = typeof(int); newEnum.SizeOf = 4; break; default: Logger.Error("Invalid type [{0}] for enum [{1}]. Types supported are : int, byte, short", typeName, cppEnum); break; } // Find Root Name of this enum // All enum items should start with the same root name and the root name should be at least 4 chars string rootName = cppEnum.Name; string rootNameFound = null; bool isRootNameFound = false; for (int i = rootName.Length; i >= 4 && !isRootNameFound; i--) { rootNameFound = rootName.Substring(0, i); isRootNameFound = true; foreach (var cppEnumItem in cppEnum.EnumItems) { if (!cppEnumItem.Name.StartsWith(rootNameFound)) { isRootNameFound = false; break; } } } if (isRootNameFound) { rootName = rootNameFound; } // Create enum items for enum foreach (var cppEnumItem in cppEnum.EnumItems) { string enumName = NamingRules.Rename(cppEnumItem, rootName); string enumValue = cppEnumItem.Value; var csharpEnumItem = new CsEnumItem(enumName, enumValue) { CppElement = cppEnumItem }; newEnum.Add(csharpEnumItem); if (cppEnumItem.Name != "None") { Manager.BindType(cppEnumItem.Name, csharpEnumItem); } } bool tryToAddNone = tag.EnumHasNone.HasValue ? tag.EnumHasNone.Value : false; // If C++ enum name is ending with FLAG OR FLAGS // Then tag this enum as flags and add None if necessary if (cppEnum.Name.EndsWith("FLAG") || cppEnum.Name.EndsWith("FLAGS")) { newEnum.IsFlag = true; if (!tag.EnumHasNone.HasValue) { tryToAddNone = !newEnum.Items.Cast <CsEnumItem>().Any(item => item.Name == "None"); } } // Add None value if (tryToAddNone) { var csharpEnumItem = new CsEnumItem("None", "0"); csharpEnumItem.CppElement = new CppElement { Description = "None." }; newEnum.Add(csharpEnumItem); } }
/// <summary> /// Maps a C++ Enum to a C# enum. /// </summary> /// <param name="newEnum">the C# enum.</param> public override void Process(CsEnum newEnum) { var cppEnum = (CppEnum)newEnum.CppElement; // Determine enum type. Default is int var typeName = cppEnum.GetTypeNameWithMapping(); switch (typeName) { case "byte": newEnum.UnderlyingType = typeRegistry.ImportType(typeof(byte)); break; case "short": newEnum.UnderlyingType = typeRegistry.ImportType(typeof(short)); break; case "ushort": newEnum.UnderlyingType = typeRegistry.ImportType(typeof(ushort)); break; case "int": newEnum.UnderlyingType = typeRegistry.ImportType(typeof(int)); break; case "uint": newEnum.UnderlyingType = typeRegistry.ImportType(typeof(uint)); break; default: Logger.Error(LoggingCodes.InvalidUnderlyingType, "Invalid type [{0}] for enum [{1}]. Types supported are : int, byte, short", typeName, cppEnum); break; } // Find Root Name of this enum // All enum items should start with the same root name and the root name should be at least 4 chars string rootName = cppEnum.Name; string rootNameFound = null; bool isRootNameFound = false; for (int i = rootName.Length; i >= 4 && !isRootNameFound; i--) { rootNameFound = rootName.Substring(0, i); isRootNameFound = true; foreach (var cppEnumItem in cppEnum.EnumItems) { if (!cppEnumItem.Name.StartsWith(rootNameFound)) { isRootNameFound = false; break; } } } if (isRootNameFound) { rootName = rootNameFound; } // Create enum items for enum foreach (var cppEnumItem in cppEnum.EnumItems) { string enumName = NamingRules.Rename(cppEnumItem, rootName); string enumValue = cppEnumItem.Value; var csharpEnumItem = new CsEnumItem(enumName, enumValue) { CppElement = cppEnumItem }; newEnum.Add(csharpEnumItem); } var rule = cppEnum.GetMappingRule(); bool tryToAddNone = rule.EnumHasNone ?? false; // If C++ enum name is ending with FLAG OR FLAGS // Then tag this enum as flags and add None if necessary if (cppEnum.Name.EndsWith("FLAG") || cppEnum.Name.EndsWith("FLAGS")) { newEnum.IsFlag = true; if (!rule.EnumHasNone.HasValue) { tryToAddNone = !newEnum.EnumItems.Any(item => item.Name == "None"); } } // Add None value if (tryToAddNone) { var csharpEnumItem = new CsEnumItem("None", "0") { CppElementName = "None", Description = "None" }; newEnum.Add(csharpEnumItem); } }
private Domain BuildDomain(DomainUpgradeMode upgradeMode, NamingRules namingRules, Type sampleType) { var configuration = BuildDomainConfiguration(upgradeMode, namingRules, sampleType); return(Domain.Build(configuration)); }