public bool TryGetFormatter(Type type, FormatterLocationStep step, ISerializationPolicy policy, out IFormatter formatter) { if (!type.IsArray) { formatter = null; return(false); } if (type.GetArrayRank() == 1) { if (FormatterUtilities.IsPrimitiveArrayType(type.GetElementType())) { formatter = (IFormatter)Activator.CreateInstance(typeof(PrimitiveArrayFormatter <>).MakeGenericType(type.GetElementType())); } else { formatter = (IFormatter)Activator.CreateInstance(typeof(ArrayFormatter <>).MakeGenericType(type.GetElementType())); } } else { formatter = (IFormatter)Activator.CreateInstance(typeof(MultiDimensionalArrayFormatter <,>).MakeGenericType(type, type.GetElementType())); } return(true); }
/// <summary> /// Reads a primitive array value. This call will succeed if the next entry is an <see cref="EntryType.PrimitiveArray" />. /// <para /> /// If the call fails (and returns <c>false</c>), it will skip the current entry value, unless that entry is an <see cref="EntryType.EndOfNode" /> or an <see cref="EntryType.EndOfArray" />. /// </summary> /// <typeparam name="T">The element type of the primitive array. Valid element types can be determined using <see cref="FormatterUtilities.IsPrimitiveArrayType(Type)" />.</typeparam> /// <param name="array">The resulting primitive array.</param> /// <returns> /// <c>true</c> if reading a primitive array succeeded, otherwise <c>false</c> /// </returns> /// <exception cref="System.ArgumentException">Type + typeof(T).Name + is not a valid primitive array type.</exception> public override bool ReadPrimitiveArray <T>(out T[] array) { if (FormatterUtilities.IsPrimitiveArrayType(typeof(T)) == false) { throw new ArgumentException("Type " + typeof(T).Name + " is not a valid primitive array type."); } this.PeekEntry(); if (this.peekedEntryType == EntryType.PrimitiveArray) { this.PushArray(); if (this.peekedEntryName != JsonConfig.PRIMITIVE_ARRAY_LENGTH_SIG) { this.Context.Config.DebugContext.LogError("Array entry wasn't preceded by an array length entry!"); array = null; // No array content for you! return(false); } else { int intLength; if (int.TryParse(this.peekedEntryContent, NumberStyles.Any, CultureInfo.InvariantCulture, out intLength) == false) { this.Context.Config.DebugContext.LogError("Failed to parse array length: " + this.peekedEntryContent); array = null; // No array content for you! return(false); } this.ReadToNextEntry(); if (this.peekedEntryName != JsonConfig.PRIMITIVE_ARRAY_CONTENT_SIG) { this.Context.Config.DebugContext.LogError("Failed to find primitive array content entry after array length entry!"); array = null; // No array content for you! return(false); } this.peekedEntryType = null; Func <T> reader = (Func <T>) this.primitiveArrayReaders[typeof(T)]; array = new T[intLength]; for (int i = 0; i < intLength; i++) { array[i] = reader(); } this.ExitArray(); return(true); } } else { this.SkipEntry(); array = null; return(false); } }
/// <summary> /// Writes a primitive array to the stream. /// </summary> /// <typeparam name="T">The element type of the primitive array. Valid element types can be determined using <see cref="FormatterUtilities.IsPrimitiveArrayType(Type)" />.</typeparam> /// <param name="array">The primitive array to write.</param> /// <exception cref="System.ArgumentException">Type + typeof(T).Name + is not a valid primitive array type.</exception> /// <exception cref="System.ArgumentNullException">array</exception> public override void WritePrimitiveArray <T>(T[] array) { if (FormatterUtilities.IsPrimitiveArrayType(typeof(T)) == false) { throw new ArgumentException("Type " + typeof(T).Name + " is not a valid primitive array type."); } if (array == null) { throw new ArgumentNullException("array"); } Action <string, T> writer = (Action <string, T>) this.primitiveTypeWriters[typeof(T)]; this.WriteInt64(JsonConfig.PRIMITIVE_ARRAY_LENGTH_SIG, array.Length); this.WriteEntry(JsonConfig.PRIMITIVE_ARRAY_CONTENT_SIG, "["); this.forceNoSeparatorNextLine = true; this.PushArray(); for (int i = 0; i < array.Length; i++) { writer(null, array[i]); } this.PopArray(); this.StartNewLine(true); this.writer.Write("]"); }
/// <summary> /// Reads a primitive array value. This call will succeed if the next entry is an <see cref="EntryType.PrimitiveArray" />. /// <para /> /// If the call fails (and returns <c>false</c>), it will skip the current entry value, unless that entry is an <see cref="EntryType.EndOfNode" /> or an <see cref="EntryType.EndOfArray" />. /// </summary> /// <typeparam name="T">The element type of the primitive array. Valid element types can be determined using <see cref="FormatterUtilities.IsPrimitiveArrayType(Type)" />.</typeparam> /// <param name="array">The resulting primitive array.</param> /// <returns> /// <c>true</c> if reading a primitive array succeeded, otherwise <c>false</c> /// </returns> /// <exception cref="System.ArgumentException">Type + typeof(T).Name + is not a valid primitive array type.</exception> public override bool ReadPrimitiveArray <T>(out T[] array) { if (FormatterUtilities.IsPrimitiveArrayType(typeof(T)) == false) { throw new ArgumentException("Type " + typeof(T).Name + " is not a valid primitive array type."); } if (this.peekedEntryType != EntryType.PrimitiveArray) { this.SkipEntry(); array = null; return(false); } if (typeof(T) == typeof(byte)) { array = (T[])(object)ProperBitConverter.HexStringToBytes(this.peekedEntryData); return(true); } else { this.PeekEntry(); long length; if (this.peekedEntryType != EntryType.PrimitiveArray) { this.Context.Config.DebugContext.LogError("Expected entry of type '" + EntryType.StartOfArray + "' when reading primitive array but got entry of type '" + this.peekedEntryType + "'."); this.SkipEntry(); array = new T[0]; return(false); } if (!long.TryParse(this.peekedEntryData, NumberStyles.Any, CultureInfo.InvariantCulture, out length)) { this.Context.Config.DebugContext.LogError("Failed to parse primitive array length from entry data '" + this.peekedEntryData + "'."); this.SkipEntry(); array = new T[0]; return(false); } this.ConsumeCurrentEntry(); this.PushArray(); array = new T[length]; Func <T> reader = (Func <T>) this.primitiveTypeReaders[typeof(T)]; for (int i = 0; i < length; i++) { array[i] = reader(); } this.ExitArray(); return(true); } }
/// <summary> /// Writes a primitive array to the stream. /// </summary> /// <typeparam name="T">The element type of the primitive array. Valid element types can be determined using <see cref="FormatterUtilities.IsPrimitiveArrayType(Type)" />.</typeparam> /// <param name="array">The primitive array to write.</param> /// <exception cref="System.ArgumentException">Type + typeof(T).Name + is not a valid primitive array type.</exception> public override void WritePrimitiveArray <T>(T[] array) { if (FormatterUtilities.IsPrimitiveArrayType(typeof(T)) == false) { throw new ArgumentException("Type " + typeof(T).Name + " is not a valid primitive array type."); } int bytesPerElement = PrimitiveSizes[typeof(T)]; int byteCount = array.Length * bytesPerElement; // Write entry flag this.Stream.WriteByte((byte)BinaryEntryType.PrimitiveArray); // Write array length ProperBitConverter.GetBytes(this.buffer, 0, array.Length); this.Stream.Write(this.buffer, 0, 4); // Write size of an element in bytes ProperBitConverter.GetBytes(this.buffer, 0, bytesPerElement); this.Stream.Write(this.buffer, 0, 4); // Write the actual array content if (typeof(T) == typeof(byte)) { // We can include a special case for byte arrays, as there's no need to copy that to a buffer var byteArray = (byte[])(object)array; this.Stream.Write(byteArray, 0, byteCount); } else { // Otherwise we copy to a buffer in order to write the entire array into the stream with one call using (var tempBuffer = Buffer <byte> .Claim(byteCount)) { if (BitConverter.IsLittleEndian) { // We always store in little endian, so we can do a direct memory mapping, which is a lot faster UnsafeUtilities.MemoryCopy(array, tempBuffer.Array, byteCount, 0, 0); } else { // We have to convert each individual element to bytes, since the byte order has to be reversed Action <byte[], int, T> toBytes = (Action <byte[], int, T>)PrimitiveGetBytesMethods[typeof(T)]; var b = tempBuffer.Array; for (int i = 0; i < array.Length; i++) { toBytes(b, i * bytesPerElement, array[i]); } } this.Stream.Write(tempBuffer.Array, 0, byteCount); } } }
/// <summary> /// Not yet documented. /// </summary> public override void WritePrimitiveArray <T>(T[] array) { if (FormatterUtilities.IsPrimitiveArrayType(typeof(T)) == false) { throw new ArgumentException("Type " + typeof(T).Name + " is not a valid primitive array type."); } if (typeof(T) == typeof(byte)) { string hex = ProperBitConverter.BytesToHexString((byte[])(object)array); this.Nodes.Add(new SerializationNode() { Name = string.Empty, Entry = EntryType.PrimitiveArray, Data = hex }); } else { this.Nodes.Add(new SerializationNode() { Name = string.Empty, Entry = EntryType.PrimitiveArray, Data = array.LongLength.ToString(CultureInfo.InvariantCulture) }); this.PushArray(); Action <string, T> writer = (Action <string, T>) this.primitiveTypeWriters[typeof(T)]; for (int i = 0; i < array.Length; i++) { writer(string.Empty, array[i]); } this.EndArrayNode(); } }