object CreateValueInternal( BitStreamReader reader, IContract contract, DsdlProperty member, ContainerContract containerContract, DsdlProperty containerMember, object existingValue, DsdlType scheme, Type objectType, bool tailArrayOptimization = false) { switch (scheme) { case VoidDsdlType t: ReadAlignment(reader, t); return(null); case PrimitiveDsdlType t: var primitive = ReadPrimitiveType(reader, t); return(EnsureType(reader, primitive, CultureInfo.InvariantCulture, contract, objectType)); case ArrayDsdlType t when t.IsStringLike && contract.UnderlyingType == typeof(string): var list = CreateList(reader, StringContract, member, null, t, tailArrayOptimization) as IEnumerable <byte>; return(_encoding.GetString(list.ToArray())); case ArrayDsdlType t: return(CreateList(reader, contract, member, existingValue, t, tailArrayOptimization)); case CompositeDsdlTypeBase t: return(CreateObject(reader, contract, member, containerContract, containerMember, existingValue, objectType, t, tailArrayOptimization)); default: throw new ArgumentOutOfRangeException(nameof(scheme)); } }
object PopulateList( IList list, BitStreamReader reader, ArrayContract contract, DsdlProperty containerProperty, ArrayDsdlType scheme, bool tailArrayOptimization) { object underlyingList = list is IWrappedCollection wrappedCollection ? wrappedCollection.UnderlyingCollection : list; if (contract.ItemContract == null) { contract.ItemContract = GetContractSafe(contract.CollectionItemType); } object ReadArrayItem(bool tao = false) { return(CreateValueInternal(reader, contract.ItemContract, null, contract, containerProperty, null, scheme.ElementType, contract.CollectionItemType, tao)); } switch (scheme.Mode) { case ArrayDsdlTypeMode.Static: { for (int i = 0; i < scheme.MaxSize; i++) { list.Add(ReadArrayItem()); } break; } case ArrayDsdlTypeMode.Dynamic: { if (tailArrayOptimization && scheme.ElementType.MinBitlen >= 8) { while (reader.LengthInBytes - reader.CurrentIndex > 1) { list.Add(ReadArrayItem()); } } else { var arraySize = ReadDynamicArraySize(reader, scheme); for (int i = 0; i < arraySize; i++) { var tao = i == arraySize - 1 ? tailArrayOptimization : false; list.Add(ReadArrayItem(tao)); } } break; } default: throw new ArgumentOutOfRangeException(nameof(ArrayDsdlTypeMode)); } return(underlyingList); }
private bool ShouldSetPropertyValue(DsdlProperty property, ObjectContract contract, object value) { if (!property.Writable) { return(false); } return(true); }
object PopulateDictionary( IDictionary dictionary, BitStreamReader reader, DictionaryContract contract, DsdlProperty containerProperty, CompositeDsdlTypeBase scheme, bool tailArrayOptimization) { object underlyingDictionary = dictionary is IWrappedDictionary wrappedDictionary ? wrappedDictionary.UnderlyingDictionary : dictionary; if (contract.KeyContract == null) { contract.KeyContract = GetContractSafe(contract.DictionaryKeyType); } if (contract.ItemContract == null) { contract.ItemContract = GetContractSafe(contract.DictionaryValueType); } foreach (var(field, tao) in EnumerateSchemeFields(reader, scheme, tailArrayOptimization)) { if (field.Type is VoidDsdlType t) { ReadAlignment(reader, t); continue; } var keyValue = EnsureType(reader, field.Name, CultureInfo.InvariantCulture, contract.KeyContract, contract.DictionaryKeyType); var itemValue = CreateValueInternal(reader, contract.ItemContract, null, contract, containerProperty, null, field.Type, null, tao); dictionary[keyValue] = itemValue; } return(underlyingDictionary); }
bool CheckForCircularReference(object value, DsdlProperty property, IContract contract) { if (value == null || contract is PrimitiveContract) { return(true); } if (_serializeStack.Contains(value)) { string message = "Self referencing loop detected"; if (property != null) { message += " for property '{0}'".FormatWith(CultureInfo.InvariantCulture, property.PropertyName); } message += " with type '{0}'.".FormatWith(CultureInfo.InvariantCulture, value.GetType()); throw new SerializationException(message); } return(true); }
bool CalculatePropertyValues(object value, ContainerContract contract, DsdlProperty property, out IContract memberContract, out object memberValue) { memberContract = null; memberValue = null; if (property.Ignored || !property.Readable) { return(false); } memberValue = property.ValueProvider.GetValue(value); if (memberValue == null) { return(false); } if (property.PropertyContract == null) { property.PropertyContract = _serializer.ContractResolver.ResolveContract(property.PropertyType); } memberContract = (property.PropertyContract.IsSealed) ? property.PropertyContract : _serializer.ContractResolver.ResolveContract(memberValue.GetType()); if (!CheckForCircularReference(memberValue, property, memberContract)) { return(false); } if (!CheckDsdlTypeCompatibility(property.DsdlType, memberContract)) { throw new InvalidOperationException( $"DSDL type mismatch for property '{contract.UnderlyingType.FullName}.{property.UnderlyingName}'."); } return(true); }
private object PopulateObject( object newObject, BitStreamReader reader, ObjectContract contract, DsdlProperty member, CompositeDsdlTypeBase scheme, bool tailArrayOptimization) { foreach (var(field, tao) in EnumerateSchemeFields(reader, scheme, tailArrayOptimization)) { if (field.Type is VoidDsdlType t) { ReadAlignment(reader, t); continue; } // attempt exact case match first // then try match ignoring case DsdlProperty property = contract.Properties.GetClosestMatchProperty(field.Name); if (property == null) { throw new SerializationException($"Could not find member '{field.Name}' on object of type '{contract.UnderlyingType.FullName}'"); } if (property.PropertyContract == null) { property.PropertyContract = GetContractSafe(property.PropertyType); } SetPropertyValue(property, contract, member, reader, newObject, field.Type, tao); } return(newObject); }
public object CreateNewObject(BitStreamReader reader, ObjectContract objectContract, DsdlProperty containerMember, DsdlProperty containerProperty, out bool createdFromNonDefaultCreator) { object newObject = null; if (objectContract.DefaultCreator != null && !objectContract.DefaultCreatorNonPublic) { // use the default constructor if it is... // public // non-public and the user has change constructor handling settings // non-public and there is no other creator newObject = objectContract.DefaultCreator(); } if (newObject == null) { if (!objectContract.IsInstantiable) { throw new SerializationException("Could not create an instance of type {0}. Type is an interface or abstract class and cannot be instantiated.".FormatWith(CultureInfo.InvariantCulture, objectContract.UnderlyingType)); } throw new SerializationException("Unable to find a constructor to use for type {0}. A class should either have a default constructor, one constructor with arguments or a constructor marked with the JsonConstructor attribute.".FormatWith(CultureInfo.InvariantCulture, objectContract.UnderlyingType)); } createdFromNonDefaultCreator = false; return(newObject); }
bool SetPropertyValue( DsdlProperty property, ContainerContract containerContract, DsdlProperty containerProperty, BitStreamReader reader, object target, DsdlType scheme, bool tailArrayOptimization) { if (property.Ignored) { return(true); } if (property.PropertyContract == null) { property.PropertyContract = GetContractSafe(property.PropertyType); } bool useExistingValue = false; object currentValue = null; if (property.Readable) { currentValue = property.ValueProvider.GetValue(target); } IContract propertyContract; if (currentValue == null) { propertyContract = property.PropertyContract; } else { propertyContract = GetContractSafe(currentValue.GetType()); useExistingValue = (!propertyContract.IsReadOnlyOrFixedSize && !propertyContract.UnderlyingType.IsValueType()); } var value = CreateValueInternal( reader, propertyContract, property, containerContract, containerProperty, (useExistingValue) ? currentValue : null, scheme, property.PropertyType, tailArrayOptimization); // always set the value if useExistingValue is false, // otherwise also set it if CreateValue returns a new value compared to the currentValue // this could happen because of a JsonConverter against the type if ((!useExistingValue || value != currentValue) && ShouldSetPropertyValue(property, containerContract as ObjectContract, value)) { property.ValueProvider.SetValue(target, value); return(true); } // the value wasn't set be JSON was populated onto the existing value return(useExistingValue); }
object CreateList( BitStreamReader reader, IContract contract, DsdlProperty member, object existingValue, ArrayDsdlType scheme, bool tailArrayOptimization) { if (HasNoDefinedType(contract)) { return(CreateUnknownObject(reader, scheme, tailArrayOptimization)); } if (!(contract is ArrayContract arrayContract)) { throw new SerializationException("Could not resolve type to IContract."); } if (existingValue == null) { var list = CreateNewList(reader, arrayContract, out bool createdFromNonDefaultCreator); if (createdFromNonDefaultCreator && !arrayContract.HasParameterizedCreatorInternal && !arrayContract.IsArray) { throw new SerializationException($"Cannot deserialize readonly or fixed size list: {contract.UnderlyingType}."); } if (arrayContract.IsMultidimensionalArray) { throw new NotSupportedException("Multidimensional arrays are not supported."); } PopulateList(list, reader, arrayContract, member, scheme, tailArrayOptimization); if (createdFromNonDefaultCreator) { if (arrayContract.IsArray) { Array a = Array.CreateInstance(arrayContract.CollectionItemType, list.Count); list.CopyTo(a, 0); list = a; } else { ObjectConstructor <object> creator = arrayContract.OverrideCreator ?? arrayContract.ParameterizedCreator; return(creator(list)); } } else if (list is IWrappedCollection wrappedCollection) { return(wrappedCollection.UnderlyingCollection); } return(list); } else { if (!arrayContract.CanDeserialize) { throw new SerializationException($"Cannot populate list type {contract.CreatedType}."); } return(PopulateList( (arrayContract.ShouldCreateWrapper || !(existingValue is IList list)) ? arrayContract.CreateWrapper(existingValue) : list, reader, arrayContract, member, scheme, tailArrayOptimization)); } }
object CreateObject( BitStreamReader reader, IContract contract, DsdlProperty member, ContainerContract containerContract, DsdlProperty containerMember, object existingValue, Type objectType, CompositeDsdlTypeBase scheme, bool tailArrayOptimization) { if (HasNoDefinedType(contract)) { return(CreateUnknownObject(reader, scheme)); } switch (contract) { case ObjectContract objectContract: { bool createdFromNonDefaultCreator = false; object targetObject; // check that if type name handling is being used that the existing value is compatible with the specified type if (existingValue != null && objectType != null && objectType.IsAssignableFrom(existingValue.GetType())) { targetObject = existingValue; } else { targetObject = CreateNewObject(reader, objectContract, member, containerMember, out createdFromNonDefaultCreator); } // don't populate if read from non-default creator because the object has already been read if (createdFromNonDefaultCreator) { return(targetObject); } return(PopulateObject(targetObject, reader, objectContract, member, scheme, tailArrayOptimization)); } case DictionaryContract dictionaryContract: { object targetDictionary; if (existingValue == null) { var dictionary = CreateNewDictionary(reader, dictionaryContract, out bool createdFromNonDefaultCreator); if (createdFromNonDefaultCreator && !dictionaryContract.HasParameterizedCreatorInternal) { throw new SerializationException("Cannot deserialize readonly or fixed size dictionary: {0}.".FormatWith(CultureInfo.InvariantCulture, contract.UnderlyingType)); } PopulateDictionary(dictionary, reader, dictionaryContract, member, scheme, tailArrayOptimization); if (createdFromNonDefaultCreator) { ObjectConstructor <object> creator = dictionaryContract.OverrideCreator ?? dictionaryContract.ParameterizedCreator; return(creator(dictionary)); } else if (dictionary is IWrappedDictionary wrappedDictionary) { return(wrappedDictionary.UnderlyingDictionary); } targetDictionary = dictionary; } else { targetDictionary = PopulateDictionary( dictionaryContract.ShouldCreateWrapper || !(existingValue is IDictionary) ? dictionaryContract.CreateWrapper(existingValue) : (IDictionary)existingValue, reader, dictionaryContract, member, scheme, tailArrayOptimization); } return(targetDictionary); } } throw new SerializationException($"Cannot deserialize the current object."); }