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 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); } }