private static void WriteNullFillers(SerializationState state, UInt32 nullCount) { if (nullCount > 0) { if (nullCount > 1) { var useByte = nullCount <= Byte.MaxValue; state.EnsureCapacity(useByte ? 2 : 5); state.array.WriteByteToBytes(ref state.idx, (Byte)(useByte ? RecordTypeEnumeration.ObjectNullMultiple256 : RecordTypeEnumeration.ObjectNullMultiple)); if (useByte) { state.array.WriteByteToBytes(ref state.idx, (Byte)nullCount); } else { state.array.WriteUInt32LEToBytes(ref state.idx, nullCount); } } else { // Just write one null state.EnsureCapacity(1); state.array.WriteByteToBytes(ref state.idx, (Byte)RecordTypeEnumeration.ObjectNull); } state.WriteArrayToStream(); } }
public static void WriteNRBFRecords(this IList <AbstractRecord> records, Stream stream) { var state = new SerializationState(stream); // Write header state.EnsureCapacity(17); // Header + header value state.array .WriteByteToBytes(ref state.idx, (Byte)RecordTypeEnumeration.SerializedStreamHeader) .WriteInt32LEToBytes(ref state.idx, 1) .WriteInt32LEToBytes(ref state.idx, -1) .WriteInt32LEToBytes(ref state.idx, 1) .WriteInt32LEToBytes(ref state.idx, 0); stream.Write(state.array); // Collect all assembly names foreach (var rec in records) { // Write used assembly names first WriteAssemblyNames(state, rec); // Write record structure WriteSingleRecord(state, rec, false); // Empty queue of reference objects while (state.recordQueue.Count > 0) { WriteSingleRecord(state, state.recordQueue.Dequeue(), true); } } // Write end state.EnsureCapacity(1); state.array.WriteByteToBytes(ref state.idx, (Byte)RecordTypeEnumeration.MessageEnd); stream.Write(state.array); }
private static void WriteSingleRecord(SerializationState state, AbstractRecord record, Boolean forceWrite) { Int32 id; if (state.TryAddRecord(record, out id) || forceWrite) { // If record hasn't been previously processed, or if we are told to write contents no matter what switch (record.Kind) { case RecordKind.String: var s = ((StringRecord)record).StringValue; var len = UTF8.GetByteCount(s); state.EnsureCapacity(10 + len); state.array .WriteByteToBytes(ref state.idx, (Byte)RecordTypeEnumeration.BinaryObjectString) .WriteInt32LEToBytes(ref state.idx, id) .WriteInt32Encoded7Bit(ref state.idx, len) .WriteStringToBytes(ref state.idx, UTF8, s); state.WriteArrayToStream(); break; case RecordKind.Class: WriteClassRecord(state, (ClassRecord)record, id); break; case RecordKind.Array: WriteArrayRecord(state, (ArrayRecord)record, id); break; case RecordKind.PrimitiveWrapper: // Write header state.EnsureCapacity(2); var p = ((PrimitiveWrapperRecord)record).Value; var pType = GetPrimitiveType(p); state.array .WriteByteToBytes(ref state.idx, (Byte)RecordTypeEnumeration.MemberPrimitiveTyped) .WriteByteToBytes(ref state.idx, (Byte)pType); state.WriteArrayToStream(); // Write primitive WritePrimitive(state, p, pType); break; } } else { // Record was already serialized, write member reference to it state.EnsureCapacity(5); state.array .WriteByteToBytes(ref state.idx, (Byte)RecordTypeEnumeration.MemberReference) .WriteInt32LEToBytes(ref state.idx, id); state.WriteArrayToStream(); } }
private static void WriteAssemblyName(SerializationState state, ElementWithTypeInfo element) { if (element != null) { var assName = element.AssemblyName; Int32 id; if (state.TryAddAssemblyName(assName, out id)) { var strByteCount = UTF8.GetByteCount(assName); state.EnsureCapacity(10 + strByteCount); state.array .WriteByteToBytes(ref state.idx, (Byte)RecordTypeEnumeration.BinaryLibrary) .WriteInt32LEToBytes(ref state.idx, id) .WriteInt32Encoded7Bit(ref state.idx, strByteCount) .WriteStringToBytes(ref state.idx, UTF8, assName); state.WriteArrayToStream(); } } }
private static void WritePrimitive(SerializationState state, Object primitive, PrimitiveTypeEnumeration pType) { String s; Int32 len; switch (pType) { case PrimitiveTypeEnumeration.Boolean: state.EnsureCapacity(1); state.array.WriteByteToBytes(ref state.idx, ((Boolean)primitive) == true ? (Byte)1 : (Byte)0); break; case PrimitiveTypeEnumeration.Byte: state.EnsureCapacity(1); state.array.WriteByteToBytes(ref state.idx, (Byte)primitive); break; case PrimitiveTypeEnumeration.Char: state.EnsureCapacity(4); state.idx = UTF8.GetBytes(new[] { (Char)primitive }, 0, 1, state.array, 0); break; case PrimitiveTypeEnumeration.Decimal: var d = (Decimal)primitive; s = d.ToString(); len = UTF8.GetByteCount(s); var ints = Decimal.GetBits(d); state.EnsureCapacity(5 + len + 16); state.array .WriteInt32Encoded7Bit(ref state.idx, len) .WriteStringToBytes(ref state.idx, UTF8, s) .WriteInt32LEToBytes(ref state.idx, ints[0]) .WriteInt32LEToBytes(ref state.idx, ints[1]) .WriteInt32LEToBytes(ref state.idx, ints[2]) .WriteInt32LEToBytes(ref state.idx, ints[3]); break; case PrimitiveTypeEnumeration.Double: state.EnsureCapacity(8); state.array.WriteDoubleLEToBytes(ref state.idx, (Double)primitive); break; case PrimitiveTypeEnumeration.Int16: state.EnsureCapacity(2); state.array.WriteInt16LEToBytes(ref state.idx, (Int16)primitive); break; case PrimitiveTypeEnumeration.Int32: state.EnsureCapacity(4); state.array.WriteInt32LEToBytes(ref state.idx, (Int32)primitive); break; case PrimitiveTypeEnumeration.Int64: state.EnsureCapacity(8); state.array.WriteInt64LEToBytes(ref state.idx, (Int64)primitive); break; case PrimitiveTypeEnumeration.SByte: state.EnsureCapacity(1); state.array.WriteSByteToBytes(ref state.idx, (SByte)primitive); break; case PrimitiveTypeEnumeration.Single: state.EnsureCapacity(4); state.array.WriteSingleLEToBytes(ref state.idx, (Single)primitive); break; case PrimitiveTypeEnumeration.TimeSpan: state.EnsureCapacity(8); state.array.WriteInt64LEToBytes(ref state.idx, ((TimeSpan)primitive).Ticks); break; case PrimitiveTypeEnumeration.DateTime: state.EnsureCapacity(8); state.array.WriteInt64LEToBytes(ref state.idx, ((DateTime)primitive).Ticks); break; case PrimitiveTypeEnumeration.UInt16: state.EnsureCapacity(2); state.array.WriteUInt16LEToBytes(ref state.idx, (UInt16)primitive); break; case PrimitiveTypeEnumeration.UInt32: state.EnsureCapacity(4); state.array.WriteUInt32LEToBytes(ref state.idx, (UInt32)primitive); break; case PrimitiveTypeEnumeration.UInt64: state.EnsureCapacity(8); state.array.WriteUInt64LEToBytes(ref state.idx, (UInt64)primitive); break; case PrimitiveTypeEnumeration.Null: state.EnsureCapacity(0); break; case PrimitiveTypeEnumeration.String: s = (String)primitive; len = UTF8.GetByteCount(s); state.EnsureCapacity(5 + len); state.array .WriteInt32Encoded7Bit(ref state.idx, len) .WriteStringToBytes(ref state.idx, UTF8, s); break; default: state.EnsureCapacity(0); break; } state.WriteArrayToStream(); }
private static void WriteArrayRecord(SerializationState state, ArrayRecord array, Int32 id) { var rank = Math.Max(1, array.Rank); Type pType = null; // Default for empty arrays and arrays with just nulls is ArraySinglePrimitive var recType = RecordTypeEnumeration.ArraySinglePrimitive; var nonNullEncountered = false; foreach (var val in array.ValuesAsVector) { if (val != null || (val is PrimitiveWrapperRecord && ((PrimitiveWrapperRecord)val).Value != null)) { var valType = (val is PrimitiveWrapperRecord ? ((PrimitiveWrapperRecord)val).Value : val).GetType(); if (nonNullEncountered) { if ( (recType == RecordTypeEnumeration.ArraySingleString && !(val is String || val is StringRecord)) || (recType == RecordTypeEnumeration.ArraySinglePrimitive && !Object.Equals(pType, valType)) ) { recType = RecordTypeEnumeration.ArraySingleObject; } } else { recType = (val is String || val is StringRecord) ? RecordTypeEnumeration.ArraySingleString : ((!(val is AbstractRecord) || val is PrimitiveWrapperRecord) ? RecordTypeEnumeration.ArraySinglePrimitive : RecordTypeEnumeration.ArraySingleObject); if (recType == RecordTypeEnumeration.ArraySinglePrimitive) { pType = valType; } nonNullEncountered = true; } } if (recType == RecordTypeEnumeration.ArraySingleObject) { break; } } var recTypeToUse = BinaryArrayTypeEnumeration.Single == array.ArrayKind ? recType : RecordTypeEnumeration.BinaryArray; // Write information common for all arrays state.EnsureCapacity(9); state.array .WriteByteToBytes(ref state.idx, (Byte)recTypeToUse) .WriteInt32LEToBytes(ref state.idx, id); if (RecordTypeEnumeration.BinaryArray != recTypeToUse) { state.array.WriteInt32LEToBytes(ref state.idx, array.ValuesAsVector.Count); } state.WriteArrayToStream(); PrimitiveTypeEnumeration pEnum; switch (recTypeToUse) { case RecordTypeEnumeration.BinaryArray: var ak = array.ArrayKind; var cap = 7 + 4 * rank; // array type (1), rank (4), rank lengths (4 each) + type info (1) + possible primitive info var hasOffset = false; switch (array.ArrayKind) { case BinaryArrayTypeEnumeration.SingleOffset: case BinaryArrayTypeEnumeration.JaggedOffset: case BinaryArrayTypeEnumeration.RectangularOffset: hasOffset = true; cap += 4 * rank; // rank offsets (4 each); break; } state.EnsureCapacity(cap); state.array .WriteByteToBytes(ref state.idx, (Byte)RecordTypeEnumeration.BinaryArray) .WriteInt32LEToBytes(ref state.idx, rank); for (var i = 0; i < rank; ++i) { state.array.WriteInt32LEToBytes(ref state.idx, array.Lengths[i]); } if (hasOffset) { for (var i = 0; i < rank; ++i) { state.array.WriteInt32LEToBytes(ref state.idx, array.LowerBounds[i]); } } BinaryTypeEnumeration typeEnum; switch (recType) { case RecordTypeEnumeration.ArraySinglePrimitive: typeEnum = BinaryTypeEnumeration.Primitive; break; case RecordTypeEnumeration.ArraySingleObject: typeEnum = BinaryTypeEnumeration.Object; break; case RecordTypeEnumeration.ArraySingleString: typeEnum = BinaryTypeEnumeration.String; break; default: throw new InvalidOperationException("The code to detect array type has changed and this switch clause wasn't adjusted appropriately."); } state.array.WriteByteToBytes(ref state.idx, (Byte)typeEnum); pEnum = GetPrimitiveTypeFromType(pType); if (BinaryTypeEnumeration.Primitive == typeEnum) { state.array.WriteByteToBytes(ref state.idx, (Byte)pEnum); } state.WriteArrayToStream(); WriteArrayValues(state, array.ValuesAsVector, obj => { if (BinaryTypeEnumeration.Primitive == typeEnum) { WritePrimitive(state, obj, pEnum); } else { var rec = obj as AbstractRecord; if (rec == null) { if (obj is String) { rec = new StringRecord(); ((StringRecord)rec).StringValue = (String)obj; } else { rec = new PrimitiveWrapperRecord(); ((PrimitiveWrapperRecord)rec).Value = obj; } } WriteSingleRecord(state, rec, false); } }); break; // Serialize all information about array case RecordTypeEnumeration.ArraySinglePrimitive: state.EnsureCapacity(1); pEnum = GetPrimitiveTypeFromType(pType); state.array.WriteByteToBytes(ref state.idx, (Byte)pEnum); state.WriteArrayToStream(); WriteArrayValues(state, array.ValuesAsVector, obj => WritePrimitive(state, obj is PrimitiveWrapperRecord ? ((PrimitiveWrapperRecord)obj).Value : obj, pEnum)); break; case RecordTypeEnumeration.ArraySingleObject: WriteArrayValues(state, array.ValuesAsVector, obj => { var objRec = obj as AbstractRecord; if (objRec == null) { objRec = new PrimitiveWrapperRecord(); ((PrimitiveWrapperRecord)objRec).Value = obj; } WriteSingleRecord(state, objRec, false); }); break; case RecordTypeEnumeration.ArraySingleString: WriteArrayValues(state, array.ValuesAsVector, obj => { var str = obj as StringRecord; if (str == null) { str = new StringRecord(); str.StringValue = (String)obj; } WriteSingleRecord(state, str, false); }); break; } }
private static void WriteClassRecord(SerializationState state, ClassRecord claas, Int32 id) { var metaDataKey = Tuple.Create(claas.AssemblyName, claas.TypeName); Int32 otherID; if (state.serializedObjects.TryGetValue(metaDataKey, out otherID)) { // Another record of the same type was serialized earlier, can use previous info state.EnsureCapacity(9); state.array .WriteByteToBytes(ref state.idx, (Byte)RecordTypeEnumeration.ClassWithID) .WriteInt32LEToBytes(ref state.idx, id) .WriteInt32LEToBytes(ref state.idx, otherID); state.WriteArrayToStream(); } else { var isSystem = claas.AssemblyName == null; var nameByteCount = SafeByteCount(claas.TypeName); state.EnsureCapacity(14 + nameByteCount); // class type (1), id (4), space for class name length (max 5), member count (4) state.array .WriteByteToBytes(ref state.idx, (Byte)(isSystem ? RecordTypeEnumeration.SystemClassWithMembersAndTypes : RecordTypeEnumeration.ClassWithMembersAndTypes)) .WriteInt32LEToBytes(ref state.idx, id) .WriteInt32Encoded7Bit(ref state.idx, nameByteCount) .WriteStringToBytes(ref state.idx, UTF8, claas.TypeName) .WriteInt32LEToBytes(ref state.idx, claas.Members.Count); state.WriteArrayToStream(); // Write member names foreach (var member in claas.Members) { nameByteCount = SafeByteCount(member.Name); state.EnsureCapacity(5 + nameByteCount); state.array .WriteInt32Encoded7Bit(ref state.idx, nameByteCount) .WriteStringToBytes(ref state.idx, UTF8, member.Name); state.WriteArrayToStream(); } // Write member type infos state.EnsureCapacity(claas.Members.Count); var mTypeCodes = new List <Tuple <BinaryTypeEnumeration, PrimitiveTypeEnumeration> >(claas.Members.Count); foreach (var member in claas.Members) { PrimitiveTypeEnumeration pType; var bt = GetTypeInfo(member.Value, out pType); mTypeCodes.Add(Tuple.Create(bt, pType)); state.array.WriteByteToBytes(ref state.idx, (Byte)bt); } state.WriteArrayToStream(); // Write additional type info where applicable for (var i = 0; i < mTypeCodes.Count; ++i) { var member = claas.Members[i]; var tuple = mTypeCodes[i]; switch (tuple.Item1) { case BinaryTypeEnumeration.Primitive: state.EnsureCapacity(1); state.array.WriteByteToBytes(ref state.idx, (Byte)tuple.Item2); break; case BinaryTypeEnumeration.SystemClass: nameByteCount = SafeByteCount(member.TypeName); state.EnsureCapacity(5 + nameByteCount); state.array .WriteInt32Encoded7Bit(ref state.idx, nameByteCount) .WriteStringToBytes(ref state.idx, UTF8, member.TypeName); break; case BinaryTypeEnumeration.Class: nameByteCount = SafeByteCount(member.TypeName); state.EnsureCapacity(9 + nameByteCount); state.array .WriteInt32Encoded7Bit(ref state.idx, nameByteCount) .WriteStringToBytes(ref state.idx, UTF8, member.TypeName) .WriteInt32LEToBytes(ref state.idx, state.assemblies[member.AssemblyName]); break; case BinaryTypeEnumeration.PrimitiveArray: state.EnsureCapacity(1); state.array .WriteByteToBytes(ref state.idx, (Byte)tuple.Item2); break; } state.WriteArrayToStream(); } // Write this class assembly name if needed if (!isSystem) { state.EnsureCapacity(4); state.array.WriteInt32LEToBytes(ref state.idx, state.assemblies[claas.AssemblyName]); state.WriteArrayToStream(); } // Write member values for (var i = 0; i < mTypeCodes.Count; ++i) { var member = claas.Members[i]; var val = member.Value; // Change raw string values to StringRecords to enable caching strings by id if (val is String) { var sRec = new StringRecord(); sRec.StringValue = (String)val; val = sRec; } var rec = val as AbstractRecord; if (rec != null) { // All arrays and non-structs are serialized afterwards. if (rec is ArrayRecord || (rec is ClassRecord && !((ClassRecord)rec).IsSerializedInPlace)) { // Add to mapping before calling recursively in order to create MemberReference if (state.TryAddRecord(rec, out id)) { // The record hasn't been serialized, add to queue state.recordQueue.Enqueue(rec); } } // Write the record WriteSingleRecord(state, rec, false); } else { // Write value as primitive WritePrimitive(state, val, mTypeCodes[i].Item2); } } } if (!state.serializedObjects.ContainsKey(metaDataKey)) { state.serializedObjects.Add(metaDataKey, id); } }