// ==++== // // Copyright (c) Microsoft Corporation. All rights reserved. // // ==--== /*============================================================ ** ** Class: BinaryWriter ** ** ** Purpose: Writes primitive values to a stream ** ** ===========================================================*/ namespace System.Runtime.Serialization.Formatters.Binary { using System; using System.Collections; using System.IO; using System.Reflection; using System.Text; using System.Globalization; using System.Runtime.Serialization.Formatters; using System.Configuration.Assemblies; using System.Threading; using System.Runtime.Remoting; using System.Runtime.Serialization; internal sealed class __BinaryWriter { internal Stream sout; internal FormatterTypeStyle formatterTypeStyle; internal Hashtable objectMapTable; internal ObjectWriter objectWriter = null; internal BinaryWriter dataWriter = null; // disable csharp compiler warning #0414: field assigned unused value #pragma warning disable 0414 internal int m_nestedObjectCount; #pragma warning restore 0414 private int nullCount = 0; //Count of consecutive array nulls // Constructor internal __BinaryWriter(Stream sout, ObjectWriter objectWriter, FormatterTypeStyle formatterTypeStyle) { SerTrace.Log( this, "BinaryWriter "); this.sout = sout; this.formatterTypeStyle = formatterTypeStyle; this.objectWriter = objectWriter; m_nestedObjectCount = 0; dataWriter = new BinaryWriter(sout, Encoding.UTF8); } internal void WriteBegin() { BCLDebug.Trace("BINARY", "\n%%%%%BinaryWriterBegin%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n"); } internal void WriteEnd() { BCLDebug.Trace("BINARY", "\n%%%%%BinaryWriterEnd%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n"); dataWriter.Flush(); } // Methods to write a value onto the stream internal void WriteBoolean(Boolean value) { dataWriter.Write(value); } internal void WriteByte(Byte value) { dataWriter.Write(value); } private void WriteBytes(Byte[] value) { dataWriter.Write(value); } private void WriteBytes(byte[] byteA, int offset, int size) { dataWriter.Write(byteA, offset, size); } internal void WriteChar(Char value) { dataWriter.Write(value); } internal void WriteChars(Char[] value) { dataWriter.Write(value); } internal void WriteDecimal(Decimal value) { WriteString(value.ToString(CultureInfo.InvariantCulture)); } internal void WriteSingle(Single value) { dataWriter.Write(value); } internal void WriteDouble(Double value) { dataWriter.Write(value); } internal void WriteInt16(Int16 value) { dataWriter.Write(value); } internal void WriteInt32(Int32 value) { dataWriter.Write(value); } internal void WriteInt64(Int64 value) { dataWriter.Write(value); } internal void WriteSByte(SByte value) { WriteByte((Byte)value); } internal void WriteString(String value) { dataWriter.Write(value); } internal void WriteTimeSpan(TimeSpan value) { WriteInt64(value.Ticks); } internal void WriteDateTime(DateTime value) { WriteInt64(value.ToBinaryRaw()); } internal void WriteUInt16(UInt16 value) { dataWriter.Write(value); } internal void WriteUInt32(UInt32 value) { dataWriter.Write(value); } internal void WriteUInt64(UInt64 value) { dataWriter.Write(value); } internal void WriteObjectEnd(NameInfo memberNameInfo, NameInfo typeNameInfo) { } internal void WriteSerializationHeaderEnd() { MessageEnd record = new MessageEnd(); record.Dump(sout); record.Write(this); } // Methods to write Binary Serialization Record onto the stream, a record is composed of primitive types internal void WriteSerializationHeader(int topId, int headerId, int minorVersion, int majorVersion) { SerializationHeaderRecord record = new SerializationHeaderRecord(BinaryHeaderEnum.SerializedStreamHeader, topId, headerId, minorVersion, majorVersion); record.Dump(); record.Write(this); } internal BinaryMethodCall binaryMethodCall; internal void WriteMethodCall() { if (binaryMethodCall == null) binaryMethodCall = new BinaryMethodCall(); binaryMethodCall.Dump(); binaryMethodCall.Write(this); } internal Object[] WriteCallArray(String uri, String methodName, String typeName, Type[] instArgs, Object[] args, Object methodSignature, Object callContext, Object[] properties) { if (binaryMethodCall == null) binaryMethodCall = new BinaryMethodCall(); return binaryMethodCall.WriteArray(uri, methodName, typeName, instArgs, args, methodSignature, callContext, properties); } internal BinaryMethodReturn binaryMethodReturn; internal void WriteMethodReturn() { if (binaryMethodReturn == null) binaryMethodReturn = new BinaryMethodReturn(); binaryMethodReturn.Dump(); binaryMethodReturn.Write(this); } internal Object[] WriteReturnArray(Object returnValue, Object[] args, Exception exception, Object callContext, Object[] properties) { if (binaryMethodReturn == null) binaryMethodReturn = new BinaryMethodReturn(); return binaryMethodReturn.WriteArray(returnValue, args, exception, callContext, properties); } internal BinaryObject binaryObject; internal BinaryObjectWithMap binaryObjectWithMap; internal BinaryObjectWithMapTyped binaryObjectWithMapTyped; //internal BinaryCrossAppDomainMap crossAppDomainMap; internal void WriteObject(NameInfo nameInfo, NameInfo typeNameInfo, int numMembers, String[] memberNames, Type[] memberTypes, WriteObjectInfo[] memberObjectInfos) { InternalWriteItemNull(); int assemId; #if _DEBUG nameInfo.Dump("WriteObject nameInfo"); typeNameInfo.Dump("WriteObject typeNameInfo"); #endif int objectId = (int)nameInfo.NIobjectId; //if (objectId < 0) // objectId = --m_nestedObjectCount; if (objectId > 0) { BCLDebug.Trace("BINARY", "-----Top Level Object-----"); } String objectName = null; if (objectId < 0) { // Nested Object objectName = typeNameInfo.NIname; } else { // Non-Nested objectName = nameInfo.NIname; } SerTrace.Log( this, "WriteObject objectName ",objectName); if (objectMapTable == null) { objectMapTable = new Hashtable(); } ObjectMapInfo objectMapInfo = (ObjectMapInfo)objectMapTable[objectName]; if (objectMapInfo != null && objectMapInfo.isCompatible(numMembers, memberNames, memberTypes)) { // Object if (binaryObject == null) binaryObject = new BinaryObject(); binaryObject.Set(objectId, objectMapInfo.objectId); #if _DEBUG binaryObject.Dump(); #endif binaryObject.Write(this); } else if (!typeNameInfo.NItransmitTypeOnObject) { // ObjectWithMap if (binaryObjectWithMap == null) binaryObjectWithMap = new BinaryObjectWithMap(); // BCL types are not placed into table assemId = (int)typeNameInfo.NIassemId; binaryObjectWithMap.Set(objectId, objectName, numMembers, memberNames, assemId); binaryObjectWithMap.Dump(); binaryObjectWithMap.Write(this); if (objectMapInfo == null) objectMapTable.Add(objectName, new ObjectMapInfo(objectId, numMembers, memberNames, memberTypes)); } else { // ObjectWithMapTyped BinaryTypeEnum[] binaryTypeEnumA = new BinaryTypeEnum[numMembers]; Object[] typeInformationA = new Object[numMembers]; int[] assemIdA = new int[numMembers]; for (int i=0; i0) { BCLDebug.Trace("BINARY", "-----Top Level Object-----"); } #if _DEBUG binaryArray.Dump(); #endif binaryArray.Write(this); if (Converter.IsWriteAsByteArray(arrayElemTypeNameInfo.NIprimitiveTypeEnum) && (lowerBound == 0)) { //array is written out as an array of bytes if (arrayElemTypeNameInfo.NIprimitiveTypeEnum == InternalPrimitiveTypeE.Byte) WriteBytes((Byte[])array); else if (arrayElemTypeNameInfo.NIprimitiveTypeEnum == InternalPrimitiveTypeE.Char) WriteChars((char[])array); else WriteArrayAsBytes(array, Converter.TypeLength(arrayElemTypeNameInfo.NIprimitiveTypeEnum)); } } byte[] byteBuffer = null; int chunkSize = 4096; [System.Security.SecurityCritical] // auto-generated private void WriteArrayAsBytes(Array array, int typeLength) { InternalWriteItemNull(); int byteLength = array.Length*typeLength; int arrayOffset = 0; if (byteBuffer == null) byteBuffer = new byte[chunkSize]; while (arrayOffset < array.Length) { int numArrayItems = Math.Min(chunkSize/typeLength, array.Length-arrayOffset); int bufferUsed = numArrayItems*typeLength; Buffer.InternalBlockCopy(array, arrayOffset*typeLength, byteBuffer, 0, bufferUsed); if (!BitConverter.IsLittleEndian) { // we know that we are writing a primitive type, so just do a simple swap for (int i = 0; i < bufferUsed; i += typeLength) { for (int j = 0; j < typeLength / 2; j++) { byte tmp = byteBuffer[i + j]; byteBuffer[i + j] = byteBuffer[i + typeLength-1 - j]; byteBuffer[i + typeLength-1 - j] = tmp; } } } WriteBytes(byteBuffer, 0, bufferUsed); arrayOffset += numArrayItems; } } internal void WriteJaggedArray(NameInfo memberNameInfo, NameInfo arrayNameInfo, WriteObjectInfo objectInfo, NameInfo arrayElemTypeNameInfo, int length, int lowerBound) { #if _DEBUG arrayNameInfo.Dump("WriteRectangleArray arrayNameInfo"); arrayElemTypeNameInfo.Dump("WriteRectangleArray arrayElemTypeNameInfo"); #endif InternalWriteItemNull(); BinaryArrayTypeEnum binaryArrayTypeEnum; Int32[] lengthA = new Int32[1]; lengthA[0] = length; Int32[] lowerBoundA = null; Object typeInformation = null; int assemId = 0; if (lowerBound == 0) { binaryArrayTypeEnum = BinaryArrayTypeEnum.Jagged; } else { binaryArrayTypeEnum = BinaryArrayTypeEnum.JaggedOffset; lowerBoundA = new Int32[1]; lowerBoundA[0] = lowerBound; } BinaryTypeEnum binaryTypeEnum = BinaryConverter.GetBinaryTypeInfo(arrayElemTypeNameInfo.NItype, objectInfo, arrayElemTypeNameInfo.NIname, objectWriter, out typeInformation, out assemId); if (binaryArray == null) binaryArray = new BinaryArray(); binaryArray.Set((int)arrayNameInfo.NIobjectId, (int)1, lengthA, lowerBoundA, binaryTypeEnum, typeInformation, binaryArrayTypeEnum, assemId); if (arrayNameInfo.NIobjectId >0) { BCLDebug.Trace("BINARY", "-----Top Level Object-----"); } #if _DEBUG binaryArray.Dump(); #endif binaryArray.Write(this); } internal void WriteRectangleArray(NameInfo memberNameInfo, NameInfo arrayNameInfo, WriteObjectInfo objectInfo, NameInfo arrayElemTypeNameInfo, int rank, int[] lengthA, int[] lowerBoundA) { #if _DEBUG arrayNameInfo.Dump("WriteRectangleArray arrayNameInfo"); arrayElemTypeNameInfo.Dump("WriteRectangleArray arrayElemTypeNameInfo"); #endif InternalWriteItemNull(); BinaryArrayTypeEnum binaryArrayTypeEnum = BinaryArrayTypeEnum.Rectangular; Object typeInformation = null; int assemId = 0; BinaryTypeEnum binaryTypeEnum = BinaryConverter.GetBinaryTypeInfo(arrayElemTypeNameInfo.NItype, objectInfo, arrayElemTypeNameInfo.NIname, objectWriter, out typeInformation, out assemId); if (binaryArray == null) binaryArray = new BinaryArray(); for (int i=0; i0) { BCLDebug.Trace("BINARY", "-----Top Level Object-----"); } #if _DEBUG binaryArray.Dump(); #endif binaryArray.Write(this); } [System.Security.SecurityCritical] // auto-generated internal void WriteObjectByteArray(NameInfo memberNameInfo, NameInfo arrayNameInfo, WriteObjectInfo objectInfo, NameInfo arrayElemTypeNameInfo, int length, int lowerBound, Byte[] byteA) { #if _DEBUG arrayNameInfo.Dump("WriteObjectByteArray arrayNameInfo"); arrayElemTypeNameInfo.Dump("WriteObjectByteArray arrayElemTypeNameInfo"); #endif InternalWriteItemNull(); WriteSingleArray(memberNameInfo, arrayNameInfo, objectInfo, arrayElemTypeNameInfo, length, lowerBound, byteA); } internal MemberPrimitiveUnTyped memberPrimitiveUnTyped; internal MemberPrimitiveTyped memberPrimitiveTyped; internal void WriteMember(NameInfo memberNameInfo, NameInfo typeNameInfo, Object value) { #if _DEBUG SerTrace.Log("BinaryWriter", "Write Member memberName ",memberNameInfo.NIname,", value ",value); memberNameInfo.Dump("WriteMember memberNameInfo"); typeNameInfo.Dump("WriteMember typeNameInfo"); #endif InternalWriteItemNull(); InternalPrimitiveTypeE typeInformation = typeNameInfo.NIprimitiveTypeEnum; // Writes Members with primitive values if (memberNameInfo.NItransmitTypeOnMember) { if (memberPrimitiveTyped == null) memberPrimitiveTyped = new MemberPrimitiveTyped(); memberPrimitiveTyped.Set((InternalPrimitiveTypeE)typeInformation, value); if (memberNameInfo.NIisArrayItem) { BCLDebug.Trace("BINARY", "-----item-----"); } else { BCLDebug.Trace("BINARY","-----",memberNameInfo.NIname,"-----"); } memberPrimitiveTyped.Dump(); memberPrimitiveTyped.Write(this); } else { if (memberPrimitiveUnTyped == null) memberPrimitiveUnTyped = new MemberPrimitiveUnTyped(); memberPrimitiveUnTyped.Set(typeInformation, value); if (memberNameInfo.NIisArrayItem) { BCLDebug.Trace("BINARY", "-----item-----"); } else { BCLDebug.Trace("BINARY", "-----",memberNameInfo.NIname,"-----"); } memberPrimitiveUnTyped.Dump(); memberPrimitiveUnTyped.Write(this); } } internal ObjectNull objectNull; internal void WriteNullMember(NameInfo memberNameInfo, NameInfo typeNameInfo) { #if _DEBUG typeNameInfo.Dump("WriteNullMember typeNameInfo"); #endif InternalWriteItemNull(); if (objectNull == null) objectNull = new ObjectNull(); if (memberNameInfo.NIisArrayItem) { BCLDebug.Trace("BINARY", "-----item-----"); } else { objectNull.SetNullCount(1); BCLDebug.Trace("BINARY", "-----",memberNameInfo.NIname,"-----"); objectNull.Dump(); objectNull.Write(this); nullCount = 0; } } internal MemberReference memberReference; internal void WriteMemberObjectRef(NameInfo memberNameInfo, int idRef) { InternalWriteItemNull(); if (memberReference == null) memberReference = new MemberReference(); memberReference.Set(idRef); if (memberNameInfo.NIisArrayItem) { BCLDebug.Trace("BINARY", "-----item-----"); } else { BCLDebug.Trace("BINARY", "-----",memberNameInfo.NIname,"-----"); } memberReference.Dump(); memberReference.Write(this); } internal void WriteMemberNested(NameInfo memberNameInfo) { InternalWriteItemNull(); if (memberNameInfo.NIisArrayItem) { BCLDebug.Trace("BINARY", "-----item-----"); } else { BCLDebug.Trace("BINARY", "-----",memberNameInfo.NIname,"-----"); } } internal void WriteMemberString(NameInfo memberNameInfo, NameInfo typeNameInfo, String value) { InternalWriteItemNull(); if (memberNameInfo.NIisArrayItem) { BCLDebug.Trace("BINARY", "-----item-----"); } else { BCLDebug.Trace("BINARY", "-----",memberNameInfo.NIname,"-----"); } WriteObjectString((int)typeNameInfo.NIobjectId, value); } internal void WriteItem(NameInfo itemNameInfo, NameInfo typeNameInfo, Object value) { InternalWriteItemNull(); WriteMember(itemNameInfo, typeNameInfo, value); } internal void WriteNullItem(NameInfo itemNameInfo, NameInfo typeNameInfo) { nullCount++; InternalWriteItemNull(); } internal void WriteDelayedNullItem() { nullCount++; } internal void WriteItemEnd() { InternalWriteItemNull(); } private void InternalWriteItemNull() { if (nullCount > 0) { if (objectNull == null) objectNull = new ObjectNull(); objectNull.SetNullCount(nullCount); BCLDebug.Trace("BINARY", "-----item-----"); objectNull.Dump(); objectNull.Write(this); nullCount = 0; } } internal void WriteItemObjectRef(NameInfo nameInfo, int idRef) { InternalWriteItemNull(); WriteMemberObjectRef(nameInfo, idRef); } internal BinaryAssembly binaryAssembly; internal BinaryCrossAppDomainAssembly crossAppDomainAssembly; internal void WriteAssembly(Type type, String assemblyString, int assemId, bool isNew) { SerTrace.Log( this,"WriteAssembly type ",type,", id ",assemId,", name ", assemblyString,", isNew ",isNew); //If the file being tested wasn't built as an assembly, then we're going to get null back //for the assembly name. This is very unfortunate. InternalWriteItemNull(); if (assemblyString==null) { assemblyString=String.Empty; } if (isNew) { if (binaryAssembly == null) binaryAssembly = new BinaryAssembly(); binaryAssembly.Set(assemId, assemblyString); binaryAssembly.Dump(); binaryAssembly.Write(this); } } // Method to write a value onto a stream given its primitive type code internal void WriteValue(InternalPrimitiveTypeE code, Object value) { SerTrace.Log( this, "WriteValue Entry ",((Enum)code).ToString()," " , ((value==null)?"":value.GetType().ToString()) , " ",value); switch (code) { case InternalPrimitiveTypeE.Boolean: WriteBoolean(Convert.ToBoolean(value, CultureInfo.InvariantCulture)); break; case InternalPrimitiveTypeE.Byte: WriteByte(Convert.ToByte(value, CultureInfo.InvariantCulture)); break; case InternalPrimitiveTypeE.Char: WriteChar(Convert.ToChar(value, CultureInfo.InvariantCulture)); break; case InternalPrimitiveTypeE.Double: WriteDouble(Convert.ToDouble(value, CultureInfo.InvariantCulture)); break; case InternalPrimitiveTypeE.Int16: WriteInt16(Convert.ToInt16(value, CultureInfo.InvariantCulture)); break; case InternalPrimitiveTypeE.Int32: WriteInt32(Convert.ToInt32(value, CultureInfo.InvariantCulture)); break; case InternalPrimitiveTypeE.Int64: WriteInt64(Convert.ToInt64(value, CultureInfo.InvariantCulture)); break; case InternalPrimitiveTypeE.SByte: WriteSByte(Convert.ToSByte(value, CultureInfo.InvariantCulture)); break; case InternalPrimitiveTypeE.Single: WriteSingle(Convert.ToSingle(value, CultureInfo.InvariantCulture)); break; case InternalPrimitiveTypeE.UInt16: WriteUInt16(Convert.ToUInt16(value, CultureInfo.InvariantCulture)); break; case InternalPrimitiveTypeE.UInt32: WriteUInt32(Convert.ToUInt32(value, CultureInfo.InvariantCulture)); break; case InternalPrimitiveTypeE.UInt64: WriteUInt64(Convert.ToUInt64(value, CultureInfo.InvariantCulture)); break; case InternalPrimitiveTypeE.Decimal: WriteDecimal(Convert.ToDecimal(value, CultureInfo.InvariantCulture)); break; case InternalPrimitiveTypeE.TimeSpan: WriteTimeSpan((TimeSpan)value); break; case InternalPrimitiveTypeE.DateTime: WriteDateTime((DateTime)value); break; default: throw new SerializationException(Environment.GetResourceString("Serialization_TypeCode",((Enum)code).ToString())); } SerTrace.Log( this, "Write Exit "); } } internal sealed class ObjectMapInfo { internal int objectId; int numMembers; String[] memberNames; Type[] memberTypes; internal ObjectMapInfo(int objectId, int numMembers, String[] memberNames, Type[] memberTypes) { this.objectId = objectId; this.numMembers = numMembers; this.memberNames = memberNames; this.memberTypes = memberTypes; } internal bool isCompatible(int numMembers, String[] memberNames, Type[] memberTypes) { bool result = true; if (this.numMembers == numMembers) { for (int i=0; i