private (int, Encoding)? GetLengthAttributeValues(MemberAttributeInfo fieldAttributes, ValueStorage storage) { var fixedLengthAttribute = fieldAttributes?.FixedLengthAttribute; var variableLengthAttribute = fieldAttributes?.VariableLengthAttribute; var calculatedLengthAttribute = fieldAttributes?.CalculatedLengthAttribute; Encoding stringEncoding; int length; if (fixedLengthAttribute != null) { stringEncoding = Tools.RetrieveEncoding(fixedLengthAttribute.StringEncoding); length = fixedLengthAttribute.Length; } else if (variableLengthAttribute != null) { stringEncoding = Tools.RetrieveEncoding(variableLengthAttribute.StringEncoding); length = Convert.ToInt32(storage.Get(variableLengthAttribute.FieldName)) + variableLengthAttribute.Offset; } else if (calculatedLengthAttribute != null) { stringEncoding = Tools.RetrieveEncoding(calculatedLengthAttribute.StringEncoding); length = calculatedLengthAttribute.CalculationAction(storage); } else { return(null); } return(length, stringEncoding); }
private object ReadTypeInternal(BinaryReaderX br, Type readType, ValueStorage storage, FieldInfo fieldInfo = null, bool isTypeChosen = false) { var typeAttributes = new MemberAttributeInfo(readType); var fieldAttributes = fieldInfo == null ? null : new MemberAttributeInfo(fieldInfo); var bkByteOrder = br.ByteOrder; var bkBitOrder = br.BitOrder; var bkBlockSize = br.BlockSize; br.ByteOrder = fieldAttributes?.EndiannessAttribute?.ByteOrder ?? typeAttributes.EndiannessAttribute?.ByteOrder ?? br.ByteOrder; object returnValue; if (IsTypeChoice(fieldAttributes) && !isTypeChosen) { var chosenType = ChooseType(readType, fieldAttributes, storage); returnValue = ReadTypeInternal(br, chosenType, storage, fieldInfo, true); } else if (readType.IsPrimitive) { returnValue = ReadTypePrimitive(br, readType); } else if (readType == typeof(string)) { returnValue = ReadTypeString(br, fieldAttributes, storage); } else if (readType == typeof(decimal)) { returnValue = br.ReadDecimal(); } else if (Tools.IsList(readType)) { returnValue = ReadTypeList(br, readType, fieldAttributes, storage, fieldInfo?.Name); } else if (readType.IsClass || Tools.IsStruct(readType)) { returnValue = ReadTypeClass(br, readType, storage.CreateScope(fieldInfo?.Name)); } else if (readType.IsEnum) { returnValue = ReadTypeInternal(br, readType.GetEnumUnderlyingType(), storage); } else { throw new UnsupportedTypeException(readType); } br.ByteOrder = bkByteOrder; br.BitOrder = bkBitOrder; br.BlockSize = bkBlockSize; return(returnValue); }
private object ReadTypeClass(BinaryReaderX br, Type readType, ValueStorage storage) { var typeAttributes = new MemberAttributeInfo(readType); var bitFieldInfoAttribute = typeAttributes.BitFieldInfoAttribute; var alignmentAttribute = typeAttributes.AlignmentAttribute; if (bitFieldInfoAttribute != null) { br.ResetBitBuffer(); } br.BitOrder = (bitFieldInfoAttribute?.BitOrder != BitOrder.Default ? bitFieldInfoAttribute?.BitOrder : br.BitOrder) ?? br.BitOrder; br.BlockSize = bitFieldInfoAttribute?.BlockSize ?? br.BlockSize; if (br.BlockSize != 8 && br.BlockSize != 4 && br.BlockSize != 2 && br.BlockSize != 1) { throw new InvalidBitFieldInfoException(br.BlockSize); } var item = Activator.CreateInstance(readType); var fields = readType.GetFields().OrderBy(fi => fi.MetadataToken); foreach (var field in fields) { // If field condition is false, read no value and leave field to default var conditionAttribute = field.GetCustomAttribute <ConditionAttribute>(); if (!ResolveCondition(conditionAttribute, storage)) { continue; } var bitInfo = field.GetCustomAttribute <BitFieldAttribute>(); object fieldValue; if (bitInfo != null) { fieldValue = Convert.ChangeType(br.ReadBits(bitInfo.BitLength), field.FieldType); } else { fieldValue = ReadTypeInternal(br, field.FieldType, storage, field); } storage.Add(field.Name, fieldValue); field.SetValue(item, fieldValue); } if (alignmentAttribute != null) { br.SeekAlignment(alignmentAttribute.Alignment); } return(item); }
private object ReadTypeString(BinaryReaderX br, MemberAttributeInfo fieldAttributes, ValueStorage storage) { var attributeValues = GetLengthAttributeValues(fieldAttributes, storage); if (attributeValues.HasValue) { var(length, encoding) = attributeValues.Value; return(br.ReadString(length, encoding)); } return(null); }
private void WriteTypeClass(BinaryWriterX bw, object writeValue, Type writeType, ValueStorage storage) { var typeAttributes = new MemberAttributeInfo(writeType); var bitFieldInfoAttribute = typeAttributes.BitFieldInfoAttribute; var alignmentAttribute = typeAttributes.AlignmentAttribute; if (bitFieldInfoAttribute != null) { bw.Flush(); } bw.BitOrder = (bitFieldInfoAttribute?.BitOrder != BitOrder.Default ? bitFieldInfoAttribute?.BitOrder : bw.BitOrder) ?? bw.BitOrder; bw.BlockSize = bitFieldInfoAttribute?.BlockSize ?? bw.BlockSize; if (bw.BlockSize != 8 && bw.BlockSize != 4 && bw.BlockSize != 2 && bw.BlockSize != 1) { throw new InvalidBitFieldInfoException(bw.BlockSize); } var fields = writeType.GetFields().OrderBy(fi => fi.MetadataToken); foreach (var field in fields) { // If field condition is false, write no value and ignore field var conditionAttribute = field.GetCustomAttribute <ConditionAttribute>(); if (!ResolveCondition(conditionAttribute, storage)) { continue; } var fieldValue = field.GetValue(writeValue); storage.Add(field.Name, fieldValue); var bitInfo = field.GetCustomAttribute <BitFieldAttribute>(); if (bitInfo != null) { bw.WriteBits(Convert.ToInt64(fieldValue), bitInfo.BitLength); } else { WriteTypeInternal(bw, fieldValue, storage, field); } } bw.Flush(); // Apply alignment if (alignmentAttribute != null) { bw.WriteAlignment(alignmentAttribute.Alignment); } }
private object ReadTypeString(BinaryReaderX br, MemberAttributeInfo fieldAttributes, ValueStorage storage) { var attributeValues = GetLengthAttributeValues(fieldAttributes, storage); // If no length attributes are given, assume string with 7bit-encoded int length prefixing the string if (!attributeValues.HasValue) { return(br.ReadString()); } var(length, encoding) = attributeValues.Value; return(br.ReadString(length, encoding)); }
private void WriteTypeString(BinaryWriterX bw, string writeValue, MemberAttributeInfo fieldAttributes, ValueStorage storage) { var attributeValues = GetLengthAttributeValues(fieldAttributes, storage); // If no length attributes are given, assume string with 7bit-encoded int length prefixing the string if (!attributeValues.HasValue) { bw.Write(writeValue); return; } var(length, encoding) = attributeValues.Value; bw.Write(ConvertStringValue(writeValue, encoding, length)); }
private void WriteTypeInternal(BinaryWriterX bw, object writeValue, ValueStorage storage, FieldInfo fieldInfo = null, bool isTypeChose = false) { var writeType = writeValue.GetType(); var typeAttributes = new MemberAttributeInfo(writeType); var fieldAttributes = fieldInfo == null ? null : new MemberAttributeInfo(fieldInfo); var bkByteOrder = bw.ByteOrder; var bkBitOrder = bw.BitOrder; var bkBlockSize = bw.BlockSize; bw.ByteOrder = fieldAttributes?.EndiannessAttribute?.ByteOrder ?? typeAttributes.EndiannessAttribute?.ByteOrder ?? bw.ByteOrder; if (writeType.IsPrimitive) { WriteTypePrimitive(bw, writeValue, writeType); } else if (writeType == typeof(string)) { WriteTypeString(bw, (string)writeValue, fieldAttributes, storage); } else if (writeType == typeof(decimal)) { bw.Write((decimal)writeValue); } else if (Tools.IsList(writeType)) { WriteTypeList(bw, (IList)writeValue, fieldAttributes, storage); } else if (writeType.IsClass || Tools.IsStruct(writeType)) { WriteTypeClass(bw, writeValue, writeType, storage.CreateScope(fieldInfo?.Name)); } else if (writeType.IsEnum) { var underlyingType = (writeType as TypeInfo)?.DeclaredFields.ToList()[0]; WriteTypeInternal(bw, underlyingType?.GetValue(writeValue), storage); } else { throw new UnsupportedTypeException(writeType); } bw.ByteOrder = bkByteOrder; bw.BitOrder = bkBitOrder; bw.BlockSize = bkBlockSize; }
private void WriteTypeString(BinaryWriterX bw, string writeValue, MemberAttributeInfo fieldAttributes, ValueStorage storage) { var attributeValues = GetLengthAttributeValues(fieldAttributes, storage); if (!attributeValues.HasValue) { return; } var(length, encoding) = attributeValues.Value; if (encoding.GetByteCount(writeValue) != length) { throw new FieldLengthMismatchException(encoding.GetByteCount(writeValue), length); } bw.WriteString(writeValue, encoding, false, false); }
private object ReadTypeList(BinaryReaderX br, Type readType, MemberAttributeInfo fieldAttributes, ValueStorage storage, string listFieldName) { var attributeValues = GetLengthAttributeValues(fieldAttributes, storage); if (!attributeValues.HasValue) { return(null); } var(length, _) = attributeValues.Value; IList list; Type elementType; if (readType.IsArray) { elementType = readType.GetElementType(); list = Array.CreateInstance(elementType, length); } else { elementType = readType.GetGenericArguments()[0]; list = (IList)Activator.CreateInstance(readType); } for (var i = 0; i < length; i++) { var elementValue = ReadTypeInternal(br, elementType, storage.CreateScope($"{listFieldName}[{i}]")); if (list.IsFixedSize) { list[i] = elementValue; } else { list.Add(elementValue); } } return(list); }
private void WriteTypeList(BinaryWriterX bw, IList writeValue, MemberAttributeInfo fieldAttributes, ValueStorage storage) { var attributeValues = GetLengthAttributeValues(fieldAttributes, storage); if (!attributeValues.HasValue) { return; } var(length, _) = attributeValues.Value; if (writeValue.Count != length) { throw new FieldLengthMismatchException(writeValue.Count, length); } var listCounter = 0; foreach (var element in writeValue) { WriteTypeInternal(bw, element, storage.CreateScope($"[{listCounter++}]")); } }
private Type ChooseType(Type readType, MemberAttributeInfo fieldAttributes, ValueStorage storage) { var typeChoices = fieldAttributes.TypeChoiceAttributes.ToArray(); if (readType != typeof(object) && typeChoices.Any(x => !readType.IsAssignableFrom(x.InjectionType))) { throw new InvalidOperationException($"Not all type choices are injectable to '{readType.Name}'."); } Type chosenType = null; foreach (var typeChoice in typeChoices) { if (!storage.Exists(typeChoice.FieldName)) { throw new InvalidOperationException($"Field '{typeChoice.FieldName}' could not be found."); } var value = storage.Get(typeChoice.FieldName); switch (typeChoice.Comparer) { case TypeChoiceComparer.Equal: if (Convert.ToUInt64(value) == Convert.ToUInt64(typeChoice.Value)) { chosenType = typeChoice.InjectionType; } break; case TypeChoiceComparer.Greater: if (Convert.ToUInt64(value) > Convert.ToUInt64(typeChoice.Value)) { chosenType = typeChoice.InjectionType; } break; case TypeChoiceComparer.Smaller: if (Convert.ToUInt64(value) < Convert.ToUInt64(typeChoice.Value)) { chosenType = typeChoice.InjectionType; } break; case TypeChoiceComparer.GEqual: if (Convert.ToUInt64(value) >= Convert.ToUInt64(typeChoice.Value)) { chosenType = typeChoice.InjectionType; } break; case TypeChoiceComparer.SEqual: if (Convert.ToUInt64(value) <= Convert.ToUInt64(typeChoice.Value)) { chosenType = typeChoice.InjectionType; } break; default: throw new InvalidOperationException($"Unknown comparer {typeChoice.Comparer}."); } if (chosenType != null) { break; } } if (chosenType == null) { throw new InvalidOperationException($"No choice matched the criteria for injection"); } return(chosenType); }
private bool IsTypeChoice(MemberAttributeInfo fieldAttributes) { return(fieldAttributes?.TypeChoiceAttributes?.Any() ?? false); }