in SharpGen/Transform/StructTransform.cs [89:251]
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;
// 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
uint currentFieldAbsoluteOffset = 0;
// Last field offset
int previousFieldOffsetIndex = -1;
// Size of the last field
uint previousFieldSize = 0;
uint 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();
var fields = currentStruct.Fields.ToArray();
int fieldCount = fields.Length;
var fieldNames = NamingRules.Rename(fields);
// -------------------------------------------------------------------------------
// Iterate on all fields and perform mapping
// -------------------------------------------------------------------------------
for (int fieldIndex = 0; fieldIndex < fieldCount; fieldIndex++)
{
var cppField = fields[fieldIndex];
var fieldName = fieldNames[fieldIndex];
Logger.RunInContext(
cppField.ToString(),
() =>
{
var csField = factory.Create(cppField, fieldName);
csStruct.Add(csField);
// 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;
// If field alignment is null, then we have a pointer somewhere so we can't align
if (csField.MarshalType.Alignment is { } fieldAlignment)
{
// otherwise, align the field on the alignment requirement of the field
var 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)
{
var lastCumulatedBitOffset = cumulatedBitOffset;
cumulatedBitOffset += cppField.BitOffset;
csField.BitMask = (1 << cppField.BitOffset) - 1;
csField.BitOffset = lastCumulatedBitOffset;
}
var nextFieldIndex = fieldIndex + 1;
if (previousFieldOffsetIndex == cppField.Offset
|| nextFieldIndex < fieldCount && fields[nextFieldIndex].Offset == cppField.Offset)
{
if (previousFieldOffsetIndex != cppField.Offset)
maxSizeOfField = 0;
maxSizeOfField = Math.Max(csField.Size, maxSizeOfField);
isNonSequential = true;
csStruct.ExplicitLayout = true;
previousFieldSize = 0;
}
else
{
previousFieldSize = csField.Size;
}
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.HasCustomMarshal && csStruct.ExplicitLayout && !cppStruct.IsUnion)
{
var fieldList = csStruct.Fields;
for (var i = 0; i < fieldList.Count; i++)
{
var field = fieldList[i];
var fieldAlignment = field.MarshalType.Alignment;
if (fieldAlignment.HasValue)
continue;
// If pointer field is not the last one, than we can't handle it
if (i + 1 >= fieldList.Count)
continue;
Logger.Error(
LoggingCodes.NonPortableAlignment,
"The field [{0}] in structure [{1}] has pointer alignment within a structure that requires explicit layout. This situation cannot be handled on both 32-bit and 64-bit architectures. This structure needs manual layout (remove fields from definition) and write them manually in xml mapping files",
field.CppElementName,
csStruct.CppElementName
);
break;
}
}
csStruct.StructSize = currentFieldAbsoluteOffset + previousFieldSize;
}