mirror of
https://github.com/SSCLI/sscli_20021101
synced 2026-06-08 12:28:57 +00:00
9fa3874800
Moved the original file to the archive subfolder.
1673 lines
71 KiB
C#
1673 lines
71 KiB
C#
// ==++==
|
|
//
|
|
//
|
|
// Copyright (c) 2002 Microsoft Corporation. All rights reserved.
|
|
//
|
|
// The use and distribution terms for this software are contained in the file
|
|
// named license.txt, which can be found in the root of this distribution.
|
|
// By using this software in any fashion, you are agreeing to be bound by the
|
|
// terms of this license.
|
|
//
|
|
// You must not remove this notice, or any other, from this software.
|
|
//
|
|
//
|
|
// ==--==
|
|
//============================================================
|
|
//
|
|
// Class: ObjectReader
|
|
// Purpose: DeSerializes XML in SOAP Format into an an object graph
|
|
//
|
|
// Date: June 10, 1999
|
|
//
|
|
//============================================================
|
|
|
|
namespace System.Runtime.Serialization.Formatters.Soap {
|
|
|
|
using System;
|
|
using System.IO;
|
|
using System.Reflection;
|
|
using System.Collections;
|
|
using System.Text;
|
|
using System.Runtime.Remoting;
|
|
using System.Runtime.Remoting.Metadata.W3cXsd2001;
|
|
using System.Runtime.Remoting.Messaging;
|
|
using System.Runtime.Serialization;
|
|
using System.Security;
|
|
using System.Security.Permissions;
|
|
using System.Diagnostics;
|
|
using System.Globalization;
|
|
|
|
internal sealed class ObjectReader
|
|
{
|
|
|
|
// System.Serializer information
|
|
internal ObjectIDGenerator m_idGenerator;
|
|
internal Stream m_stream;
|
|
internal ISurrogateSelector m_surrogates;
|
|
internal StreamingContext m_context;
|
|
internal ObjectManager m_objectManager;
|
|
internal InternalFE formatterEnums;
|
|
internal SerializationBinder m_binder;
|
|
|
|
internal SoapHandler soapHandler; //Set from SoapHandler
|
|
|
|
// Fake Top object and headers
|
|
internal long topId = 0;
|
|
internal SerStack topStack; // Stack for placing ProcessRecords if the top record cannot be serialized on the first pass.
|
|
internal bool isTopObjectSecondPass = false;
|
|
internal bool isTopObjectResolved = true;
|
|
internal bool isHeaderHandlerCalled = false;
|
|
internal Exception deserializationSecurityException = null;
|
|
internal Object handlerObject = null;
|
|
internal Object topObject;
|
|
internal long soapFaultId;
|
|
internal Header[] headers;
|
|
internal Header[] newheaders;
|
|
internal bool IsFakeTopObject = false;
|
|
internal HeaderHandler handler;
|
|
internal SerObjectInfoInit serObjectInfoInit = null;
|
|
internal IFormatterConverter m_formatterConverter = null;
|
|
|
|
// Stack of Object ParseRecords
|
|
internal SerStack stack = new SerStack("ObjectReader Object Stack");
|
|
|
|
// ValueType Fixup Stack
|
|
internal SerStack valueFixupStack = new SerStack("ValueType Fixup Stack");
|
|
|
|
// Generate Object Id's
|
|
internal Hashtable objectIdTable = new Hashtable(25); // holds the keyId value from the XML input and associated internal Id
|
|
internal long objectIds = 0;
|
|
|
|
internal int paramPosition = 0; //Position of parameter if soap top fake record.
|
|
|
|
internal int majorVersion = 0;
|
|
internal int minorVersion = 0;
|
|
|
|
internal String faultString = null;
|
|
|
|
// GetType - eliminate redundant Type.GetType()
|
|
//internal Hashtable typeTable = new Hashtable(10);
|
|
|
|
internal static SecurityPermission serializationPermission = new SecurityPermission(SecurityPermissionFlag.SerializationFormatter);
|
|
|
|
|
|
|
|
internal ObjectReader(Stream stream, ISurrogateSelector selector, StreamingContext context, InternalFE formatterEnums, SerializationBinder binder)
|
|
{
|
|
InternalST.Soap( this, "Constructor ISurrogateSelector ",((selector == null)?"null selector ":"selector present"));
|
|
|
|
if (stream==null)
|
|
{
|
|
throw new ArgumentNullException("stream", SoapUtil.GetResourceString("ArgumentNull_Stream"));
|
|
}
|
|
|
|
m_stream=stream;
|
|
m_surrogates = selector;
|
|
m_context = context;
|
|
m_binder = binder;
|
|
this.formatterEnums = formatterEnums;
|
|
|
|
InternalST.Soap( this, "Constructor formatterEnums.FEtopObject ",formatterEnums.FEtopObject);
|
|
if (formatterEnums.FEtopObject != null)
|
|
IsFakeTopObject = true;
|
|
else
|
|
IsFakeTopObject = false;
|
|
|
|
m_formatterConverter = new FormatterConverter();
|
|
}
|
|
|
|
|
|
private ObjectManager GetObjectManager() {
|
|
new SecurityPermission(SecurityPermissionFlag.SerializationFormatter).Assert();
|
|
return new ObjectManager(m_surrogates, m_context);
|
|
}
|
|
|
|
|
|
|
|
|
|
// Deserialize the stream into an object graph.
|
|
internal Object Deserialize(HeaderHandler handler, ISerParser serParser)
|
|
{
|
|
|
|
InternalST.Soap( this, "Deserialize Entry handler", handler);
|
|
|
|
if (serParser == null)
|
|
throw new ArgumentNullException("serParser", String.Format(SoapUtil.GetResourceString("ArgumentNull_WithParamName"), serParser));
|
|
|
|
|
|
deserializationSecurityException = null;
|
|
try {
|
|
serializationPermission.Demand();
|
|
} catch(Exception e ) {
|
|
deserializationSecurityException = e;
|
|
}
|
|
|
|
this.handler = handler;
|
|
isTopObjectSecondPass = false;
|
|
isHeaderHandlerCalled = false;
|
|
|
|
if (handler != null)
|
|
IsFakeTopObject = true;
|
|
|
|
m_idGenerator = new ObjectIDGenerator();
|
|
|
|
|
|
m_objectManager = GetObjectManager();
|
|
|
|
serObjectInfoInit = new SerObjectInfoInit();
|
|
objectIdTable.Clear();
|
|
objectIds = 0;
|
|
|
|
// Will call back to ParseObject, ParseHeader for each object found
|
|
serParser.Run();
|
|
|
|
if (handler != null)
|
|
{
|
|
InternalST.Soap( this, "Deserialize Fixup Before Delegate Invoke");
|
|
m_objectManager.DoFixups(); // Fixup for headers
|
|
|
|
// Header handler isn't invoked until method name is known from body fake record
|
|
// Except for SoapFault, in which case it is invoked below
|
|
if (handlerObject == null)
|
|
{
|
|
InternalST.Soap( this, "Deserialize Before SoapFault Delegate Invoke ");
|
|
handlerObject = handler(newheaders);
|
|
InternalST.Soap( this, "Deserialize after SoapFault Delegate Invoke");
|
|
}
|
|
|
|
|
|
// SoapFault creation Create a fake Pr for the handlerObject to use.
|
|
// Create a member for the fake pr with name __fault;
|
|
if ((soapFaultId > 0) && (handlerObject != null))
|
|
{
|
|
InternalST.Soap( this, "Deserialize SoapFault ");
|
|
topStack = new SerStack("Top ParseRecords");
|
|
ParseRecord pr = new ParseRecord();
|
|
pr.PRparseTypeEnum = InternalParseTypeE.Object;
|
|
pr.PRobjectPositionEnum = InternalObjectPositionE.Top;
|
|
pr.PRparseStateEnum = InternalParseStateE.Object;
|
|
pr.PRname = "Response";
|
|
topStack.Push(pr);
|
|
pr = new ParseRecord();
|
|
pr.PRparseTypeEnum = InternalParseTypeE.Member;
|
|
pr.PRobjectPositionEnum = InternalObjectPositionE.Child;
|
|
pr.PRmemberTypeEnum = InternalMemberTypeE.Field;
|
|
pr.PRmemberValueEnum = InternalMemberValueE.Reference;
|
|
pr.PRparseStateEnum = InternalParseStateE.Member;
|
|
pr.PRname = "__fault";
|
|
pr.PRidRef = soapFaultId;
|
|
topStack.Push(pr);
|
|
pr = new ParseRecord();
|
|
pr.PRparseTypeEnum = InternalParseTypeE.ObjectEnd;
|
|
pr.PRobjectPositionEnum = InternalObjectPositionE.Top;
|
|
pr.PRparseStateEnum = InternalParseStateE.Object;
|
|
pr.PRname = "Response";
|
|
topStack.Push(pr);
|
|
isTopObjectResolved = false;
|
|
}
|
|
}
|
|
|
|
|
|
// Resolve fake top object if necessary
|
|
if (!isTopObjectResolved)
|
|
{
|
|
//resolve top object
|
|
InternalST.Soap( this, "Deserialize TopObject Second Pass");
|
|
isTopObjectSecondPass = true;
|
|
topStack.Reverse();
|
|
// The top of the stack now contains the fake record
|
|
// When it is Parsed, the handler object will be substituted
|
|
// for it in ParseObject.
|
|
int topStackLength = topStack.Count();
|
|
ParseRecord pr = null;
|
|
for (int i=0; i<topStackLength; i++)
|
|
{
|
|
pr = (ParseRecord)topStack.Pop();
|
|
Parse(pr);
|
|
}
|
|
}
|
|
|
|
|
|
InternalST.Soap( this, "Deserialize Finished Parsing DoFixups");
|
|
|
|
m_objectManager.DoFixups();
|
|
|
|
if (topObject == null)
|
|
throw new SerializationException(SoapUtil.GetResourceString("Serialization_TopObject"));
|
|
|
|
if (topObject is IObjectReference) {
|
|
topObject = ((IObjectReference)topObject).GetRealObject(m_context);
|
|
}
|
|
|
|
InternalST.Soap( this, "Deserialize Exit ",topObject);
|
|
|
|
m_objectManager.RaiseDeserializationEvent();
|
|
|
|
if ((formatterEnums.FEtopObject != null) &&
|
|
(topObject is InternalSoapMessage))
|
|
|
|
|
|
{
|
|
// Convert InternalSoapMessage to SoapMessage
|
|
InternalST.Soap( this, "Deserialize SoapMessage Entry ");
|
|
|
|
InternalSoapMessage ismc = (InternalSoapMessage)topObject;
|
|
ISoapMessage smc = (ISoapMessage)formatterEnums.FEtopObject;
|
|
smc.MethodName = ismc.methodName;
|
|
smc.XmlNameSpace = ismc.xmlNameSpace;
|
|
smc.ParamNames = ismc.paramNames;
|
|
smc.ParamValues = ismc.paramValues;
|
|
smc.Headers = headers;
|
|
topObject = smc;
|
|
isTopObjectResolved = true;
|
|
InternalST.Soap( this, "Deserialize SoapMessage Exit topObject ",topObject," method name ",smc.MethodName);
|
|
}
|
|
|
|
return topObject;
|
|
}
|
|
|
|
internal ReadObjectInfo CreateReadObjectInfo(Type objectType, String assemblyName)
|
|
{
|
|
ReadObjectInfo objectInfo = ReadObjectInfo.Create(objectType, m_surrogates, m_context, m_objectManager, serObjectInfoInit, m_formatterConverter, assemblyName);
|
|
objectInfo.SetVersion(majorVersion, minorVersion);
|
|
return objectInfo;
|
|
}
|
|
|
|
internal ReadObjectInfo CreateReadObjectInfo(Type objectType, String[] memberNames, String assemblyName)
|
|
{
|
|
ReadObjectInfo objectInfo = ReadObjectInfo.Create(objectType, memberNames, null, m_surrogates, m_context, m_objectManager, serObjectInfoInit, m_formatterConverter, assemblyName);
|
|
objectInfo.SetVersion(majorVersion, minorVersion);
|
|
return objectInfo;
|
|
}
|
|
|
|
internal ReadObjectInfo CreateReadObjectInfo(Type objectType, String[] memberNames, Type[] memberTypes, String assemblyName)
|
|
{
|
|
ReadObjectInfo objectInfo = ReadObjectInfo.Create(objectType, memberNames, memberTypes, m_surrogates, m_context, m_objectManager, serObjectInfoInit, m_formatterConverter, assemblyName);
|
|
objectInfo.SetVersion(majorVersion, minorVersion);
|
|
return objectInfo;
|
|
}
|
|
|
|
|
|
// Main Parse routine, called by the XML Parse Handlers in XMLParser and also called internally to
|
|
// parse the fake top object.
|
|
internal void Parse(ParseRecord pr)
|
|
{
|
|
InternalST.Soap( this, "Parse Entry");
|
|
stack.Dump();
|
|
pr.Dump();
|
|
|
|
switch(pr.PRparseTypeEnum)
|
|
{
|
|
case InternalParseTypeE.SerializedStreamHeader:
|
|
ParseSerializedStreamHeader(pr);
|
|
break;
|
|
case InternalParseTypeE.SerializedStreamHeaderEnd:
|
|
ParseSerializedStreamHeaderEnd(pr);
|
|
break;
|
|
case InternalParseTypeE.Object:
|
|
ParseObject(pr);
|
|
break;
|
|
case InternalParseTypeE.ObjectEnd:
|
|
ParseObjectEnd(pr);
|
|
break;
|
|
case InternalParseTypeE.Member:
|
|
ParseMember(pr);
|
|
break;
|
|
case InternalParseTypeE.MemberEnd:
|
|
ParseMemberEnd(pr);
|
|
break;
|
|
case InternalParseTypeE.Body:
|
|
case InternalParseTypeE.BodyEnd:
|
|
case InternalParseTypeE.Envelope:
|
|
case InternalParseTypeE.EnvelopeEnd:
|
|
break;
|
|
case InternalParseTypeE.Empty:
|
|
default:
|
|
throw new SerializationException(String.Format(SoapUtil.GetResourceString("Serialization_XMLElement"), pr.PRname));
|
|
|
|
}
|
|
}
|
|
|
|
// Styled ParseError output
|
|
private void ParseError(ParseRecord processing, ParseRecord onStack)
|
|
{
|
|
InternalST.Soap( this, " ParseError ",processing," ",onStack);
|
|
throw new SerializationException(String.Format(SoapUtil.GetResourceString("Serialization_ParseError"),onStack.PRname+" "+((Enum)onStack.PRparseTypeEnum).ToString()+" "+processing.PRname+" "+((Enum)processing.PRparseTypeEnum).ToString()));
|
|
}
|
|
|
|
// Parse the SerializedStreamHeader element. This is the first element in the stream if present
|
|
private void ParseSerializedStreamHeader(ParseRecord pr)
|
|
{
|
|
InternalST.Soap( this, "SerializedHeader ",pr);
|
|
stack.Push(pr);
|
|
}
|
|
|
|
// Parse the SerializedStreamHeader end element. This is the last element in the stream if present
|
|
private void ParseSerializedStreamHeaderEnd(ParseRecord pr)
|
|
{
|
|
InternalST.Soap( this, "SerializedHeaderEnd ",pr);
|
|
stack.Pop();
|
|
}
|
|
|
|
|
|
private bool IsRemoting {
|
|
get {
|
|
//return (m_context.State & (StreamingContextStates.Persistence|StreamingContextStates.File|StreamingContextStates.Clone)) == 0;
|
|
return IsFakeTopObject;
|
|
}
|
|
}
|
|
|
|
private void CheckSecurity(ParseRecord pr)
|
|
{
|
|
InternalST.SoapAssert(pr!=null, "[BinaryObjectReader.CheckSecurity]pr!=null");
|
|
Type t = pr.PRdtType;
|
|
|
|
if (t != null && IsRemoting){
|
|
if (typeof(MarshalByRefObject).IsAssignableFrom(t))
|
|
throw new ArgumentException(String.Format(SoapUtil.GetResourceString("Serialization_MBRAsMBV"), t.FullName));
|
|
}
|
|
|
|
//If we passed the security check, they can do whatever they'd like,
|
|
//so we'll just short-circuit this.
|
|
if (deserializationSecurityException==null) {
|
|
return;
|
|
}
|
|
|
|
// BaseTypes and Array of basetypes allowed
|
|
|
|
if (t != null)
|
|
{
|
|
if (t.IsPrimitive || t == Converter.typeofString)
|
|
return;
|
|
|
|
if (typeof(Enum).IsAssignableFrom(t))
|
|
return;
|
|
|
|
if (t.IsArray)
|
|
{
|
|
Type type = t.GetElementType();
|
|
if (type.IsPrimitive || type == Converter.typeofString)
|
|
return;
|
|
}
|
|
}
|
|
|
|
throw deserializationSecurityException;
|
|
}
|
|
|
|
// New object encountered in stream
|
|
private void ParseObject(ParseRecord pr)
|
|
{
|
|
InternalST.Soap( this, "ParseObject Entry ");
|
|
|
|
if (pr.PRobjectPositionEnum == InternalObjectPositionE.Top)
|
|
topId = pr.PRobjectId;
|
|
|
|
if (pr.PRparseTypeEnum == InternalParseTypeE.Object)
|
|
{
|
|
InternalST.Soap( this, "ParseObject Push "+pr.PRname);
|
|
stack.Push(pr); // Nested objects member names are already on stack
|
|
}
|
|
|
|
if (pr.PRobjectTypeEnum == InternalObjectTypeE.Array)
|
|
{
|
|
ParseArray(pr);
|
|
InternalST.Soap( this, "ParseObject Exit, ParseArray ");
|
|
return;
|
|
}
|
|
|
|
if ((pr.PRdtType == null) && !IsFakeTopObject)
|
|
throw new SerializationException(String.Format(SoapUtil.GetResourceString("Serialization_TopObjectInstantiate"),pr.PRname));
|
|
|
|
|
|
if (pr.PRobjectPositionEnum == InternalObjectPositionE.Top && IsFakeTopObject && pr.PRdtType != Converter.typeofSoapFault)
|
|
{
|
|
|
|
// Soap fake top object
|
|
if (handler != null)
|
|
{
|
|
// Handler object will supply real top object
|
|
InternalST.Soap( this, "ParseObject FakeTopObject with handlerObject ");
|
|
|
|
// Now know the method name, can call header handler
|
|
//Create header for method name
|
|
if (!isHeaderHandlerCalled)
|
|
{
|
|
newheaders = null;
|
|
isHeaderHandlerCalled = true;
|
|
if (headers == null)
|
|
{
|
|
newheaders = new Header[1];
|
|
}
|
|
else
|
|
{
|
|
newheaders = new Header[headers.Length+1];
|
|
Array.Copy(headers, 0, newheaders, 1, headers.Length);
|
|
}
|
|
|
|
Header methodNameHeader = new Header("__methodName", pr.PRname, false, pr.PRnameXmlKey);
|
|
newheaders[0] = methodNameHeader;
|
|
InternalST.Soap( this, "Deserialize Before Delegate Invoke ");
|
|
handlerObject = handler(newheaders);
|
|
|
|
InternalST.Soap( this, "Deserialize after Delegate Invoke");
|
|
InternalST.Soap( this, "Deserialize delgate object ",((handlerObject == null)?"null":handlerObject));
|
|
}
|
|
|
|
if (isHeaderHandlerCalled)
|
|
{
|
|
// Handler object has supplied the real object for the fake object
|
|
// which is on top of the stack
|
|
pr.PRnewObj = handlerObject;
|
|
pr.PRdtType = handlerObject.GetType();
|
|
CheckSecurity(pr);
|
|
if (pr.PRnewObj is IFieldInfo)
|
|
{
|
|
IFieldInfo fi = (IFieldInfo)pr.PRnewObj;
|
|
if ((fi.FieldTypes != null) && (fi.FieldTypes.Length > 0))
|
|
{
|
|
pr.PRobjectInfo = CreateReadObjectInfo(pr.PRdtType, fi.FieldNames, fi.FieldTypes, pr.PRassemblyName);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Handler object has not yet been asked for the real object
|
|
// Stack the parse record until the second pass
|
|
isTopObjectResolved = false;
|
|
topStack = new SerStack("Top ParseRecords");
|
|
InternalST.Soap( this, "ParseObject Handler Push "+pr.PRname);
|
|
topStack.Push(pr.Copy());
|
|
return;
|
|
}
|
|
}
|
|
else if (formatterEnums.FEtopObject != null)
|
|
{
|
|
// SoapMessage will be used as the real object
|
|
InternalST.Soap( this, "ParseObject FakeTopObject with SoapMessage ");
|
|
if (isTopObjectSecondPass)
|
|
{
|
|
// This creates a the SoapMessage object as the real object, at this point it is an unitialized object.
|
|
pr.PRnewObj = new InternalSoapMessage();
|
|
pr.PRdtType = typeof(InternalSoapMessage);
|
|
CheckSecurity(pr);
|
|
if (formatterEnums.FEtopObject != null)
|
|
{
|
|
ISoapMessage soapMessage = (ISoapMessage)formatterEnums.FEtopObject;
|
|
pr.PRobjectInfo = CreateReadObjectInfo(pr.PRdtType, soapMessage.ParamNames, soapMessage.ParamTypes, pr.PRassemblyName);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Stack the parse record until the second pass
|
|
isTopObjectResolved = false;
|
|
topStack = new SerStack("Top ParseRecords");
|
|
topStack.Push(pr.Copy());
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
else if (pr.PRdtType == Converter.typeofString)
|
|
{
|
|
// String as a top level object
|
|
if (pr.PRvalue != null)
|
|
{
|
|
pr.PRnewObj = pr.PRvalue;
|
|
if (pr.PRobjectPositionEnum == InternalObjectPositionE.Top)
|
|
{
|
|
InternalST.Soap( this, "ParseObject String as top level, Top Object Resolved");
|
|
isTopObjectResolved = true;
|
|
topObject = pr.PRnewObj;
|
|
//stack.Pop();
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
InternalST.Soap( this, "ParseObject String as an object");
|
|
stack.Pop();
|
|
RegisterObject(pr.PRnewObj, pr, (ParseRecord)stack.Peek());
|
|
return;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// xml Doesn't have the value until later
|
|
return;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (pr.PRdtType == null)
|
|
{
|
|
ParseRecord objectPr = (ParseRecord)stack.Peek();
|
|
if (objectPr.PRdtType == Converter.typeofSoapFault)
|
|
{
|
|
InternalST.Soap( this, "ParseObject unknown SoapFault detail");
|
|
throw new ServerException(String.Format(SoapUtil.GetResourceString("Serialization_SoapFault"),faultString));
|
|
}
|
|
|
|
throw new SerializationException(String.Format(SoapUtil.GetResourceString("Serialization_TypeElement"),pr.PRname));
|
|
}
|
|
|
|
pr.PRnewObj = FormatterServices.GetUninitializedObject(pr.PRdtType);
|
|
CheckSecurity(pr);
|
|
}
|
|
|
|
if (pr.PRnewObj == null)
|
|
throw new SerializationException(String.Format(SoapUtil.GetResourceString("Serialization_TopObjectInstantiate"),pr.PRdtType));
|
|
|
|
long genId = pr.PRobjectId;
|
|
if (genId < 1)
|
|
pr.PRobjectId = GetId("GenId-"+objectIds);
|
|
|
|
|
|
if (IsFakeTopObject && pr.PRobjectPositionEnum == InternalObjectPositionE.Top)
|
|
{
|
|
InternalST.Soap( this, "ParseObject fake Top object resolved ",pr.PRnewObj);
|
|
isTopObjectResolved = true;
|
|
topObject = pr.PRnewObj;
|
|
}
|
|
|
|
if (pr.PRobjectInfo == null)
|
|
pr.PRobjectInfo = CreateReadObjectInfo(pr.PRdtType, pr.PRassemblyName);
|
|
pr.PRobjectInfo.obj = pr.PRnewObj;
|
|
|
|
if (IsFakeTopObject && pr.PRobjectPositionEnum == InternalObjectPositionE.Top)
|
|
{
|
|
InternalST.Soap( this, "ParseObject AddValue to fake object ",pr.PRobjectInfo.obj);
|
|
// Add the methodName to top object, either InternalSoapMessage or object returned by handler
|
|
pr.PRobjectInfo.AddValue("__methodName", pr.PRname);
|
|
pr.PRobjectInfo.AddValue("__keyToNamespaceTable", soapHandler.keyToNamespaceTable);
|
|
pr.PRobjectInfo.AddValue("__paramNameList", pr.PRobjectInfo.SetFakeObject());
|
|
if (formatterEnums.FEtopObject != null)
|
|
pr.PRobjectInfo.AddValue("__xmlNameSpace", pr.PRxmlNameSpace);
|
|
}
|
|
|
|
InternalST.Soap( this, "ParseObject Exit ");
|
|
}
|
|
|
|
|
|
private bool IsWhiteSpace(String value)
|
|
{
|
|
for (int i=0; i<value.Length; i++)
|
|
{
|
|
if (value[i] == ' ' || value[i] == '\n' || value[i] == '\r')
|
|
continue;
|
|
else
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
// End of object encountered in stream
|
|
|
|
private void ParseObjectEnd(ParseRecord pr)
|
|
{
|
|
InternalST.Soap( this, "ParseObjectEnd Entry ",pr.Trace());
|
|
ParseRecord objectPr = (ParseRecord)stack.Peek();
|
|
if (objectPr == null)
|
|
objectPr = pr;
|
|
|
|
|
|
//BCLDebug.Assert(objectPr != null, "[System.Runtime.Serialization.Formatters.ParseObjectEnd]objectPr != null");
|
|
|
|
InternalST.Soap( this, "ParseObjectEnd objectPr ",objectPr.Trace());
|
|
|
|
if (objectPr.PRobjectPositionEnum == InternalObjectPositionE.Top)
|
|
{
|
|
InternalST.Soap( this, "ParseObjectEnd Top Object dtType ",objectPr.PRdtType);
|
|
if (objectPr.PRdtType == Converter.typeofString)
|
|
{
|
|
InternalST.Soap( this, "ParseObjectEnd Top String");
|
|
if (objectPr.PRvalue == null)
|
|
objectPr.PRvalue = String.Empty; // Not a null object, but an empty string
|
|
|
|
objectPr.PRnewObj = objectPr.PRvalue;
|
|
CheckSecurity(objectPr);
|
|
isTopObjectResolved = true;
|
|
topObject = objectPr.PRnewObj;
|
|
return;
|
|
}
|
|
else if (objectPr.PRdtType != null && objectPr.PRvalue != null && !IsWhiteSpace(objectPr.PRvalue) && (objectPr.PRdtType.IsPrimitive || objectPr.PRdtType == Converter.typeofTimeSpan))
|
|
{
|
|
// When an xsd type is transmitted as a top level string <xsd:int>111</xsd:int>
|
|
objectPr.PRnewObj = Converter.FromString(objectPr.PRvalue, Converter.ToCode(objectPr.PRdtType));
|
|
CheckSecurity(objectPr);
|
|
isTopObjectResolved = true;
|
|
topObject = objectPr.PRnewObj;
|
|
return;
|
|
|
|
}
|
|
else if ((!isTopObjectResolved) && (objectPr.PRdtType != Converter.typeofSoapFault))
|
|
{
|
|
InternalST.Soap( this, "ParseObjectEnd Top but not String");
|
|
// Need to keep top record on object stack until finished building top stack
|
|
topStack.Push(pr.Copy());
|
|
// Note this is PRparseRecordId and not objectId
|
|
if (objectPr.PRparseRecordId == pr.PRparseRecordId)
|
|
{
|
|
// This handles the case of top stack containing nested objects and
|
|
// referenced objects. If nested objects the objects are not placed
|
|
// on stack, only topstack. If referenced objects they are placed on
|
|
// stack and need to be popped.
|
|
stack.Pop();
|
|
}
|
|
return;
|
|
}
|
|
}
|
|
|
|
stack.Pop();
|
|
|
|
ParseRecord parentPr = (ParseRecord)stack.Peek();
|
|
|
|
if (objectPr.PRobjectTypeEnum == InternalObjectTypeE.Array)
|
|
{
|
|
if (objectPr.PRobjectPositionEnum == InternalObjectPositionE.Top)
|
|
{
|
|
InternalST.Soap( this, "ParseObjectEnd Top Object (Array) Resolved");
|
|
isTopObjectResolved = true;
|
|
topObject = objectPr.PRnewObj;
|
|
}
|
|
|
|
InternalST.Soap( this, "ParseArray RegisterObject ",objectPr.PRobjectId," ",objectPr.PRnewObj.GetType());
|
|
RegisterObject(objectPr.PRnewObj, objectPr, parentPr);
|
|
|
|
return;
|
|
}
|
|
|
|
if (objectPr.PRobjectInfo != null)
|
|
{
|
|
objectPr.PRobjectInfo.PopulateObjectMembers();
|
|
}
|
|
|
|
if (objectPr.PRnewObj == null)
|
|
{
|
|
if (objectPr.PRdtType == Converter.typeofString)
|
|
{
|
|
InternalST.Soap( this, "ParseObjectEnd String ");
|
|
if (objectPr.PRvalue == null)
|
|
objectPr.PRvalue = String.Empty; // Not a null object, but an empty string
|
|
objectPr.PRnewObj = objectPr.PRvalue;
|
|
CheckSecurity(objectPr);
|
|
}
|
|
else
|
|
throw new SerializationException(String.Format(SoapUtil.GetResourceString("Serialization_ObjectMissing"),pr.PRname));
|
|
}
|
|
|
|
// Registration is after object is populated
|
|
if (!objectPr.PRisRegistered && objectPr.PRobjectId > 0)
|
|
{
|
|
InternalST.Soap( this, "ParseObjectEnd Register Object ",objectPr.PRobjectId," ",objectPr.PRnewObj.GetType());
|
|
RegisterObject(objectPr.PRnewObj, objectPr, parentPr);
|
|
}
|
|
|
|
if (objectPr.PRisValueTypeFixup)
|
|
{
|
|
InternalST.Soap( this, "ParseObjectEnd ValueTypeFixup ",objectPr.PRnewObj.GetType());
|
|
ValueFixup fixup = (ValueFixup)valueFixupStack.Pop(); //Value fixup
|
|
fixup.Fixup(objectPr, parentPr); // Value fixup
|
|
}
|
|
|
|
if (objectPr.PRobjectPositionEnum == InternalObjectPositionE.Top)
|
|
{
|
|
InternalST.Soap( this, "ParseObjectEnd Top Object Resolved ",objectPr.PRnewObj.GetType());
|
|
isTopObjectResolved = true;
|
|
topObject = objectPr.PRnewObj;
|
|
}
|
|
|
|
if (objectPr.PRnewObj is SoapFault)
|
|
soapFaultId = objectPr.PRobjectId;
|
|
|
|
if (objectPr.PRobjectInfo != null)
|
|
{
|
|
if (objectPr.PRobjectInfo.bfake && !objectPr.PRobjectInfo.bSoapFault)
|
|
objectPr.PRobjectInfo.AddValue("__fault", null); // need this because SerializationObjectInfo throws an exception if a name being referenced is missing
|
|
|
|
objectPr.PRobjectInfo.ObjectEnd();
|
|
}
|
|
|
|
InternalST.Soap( this, "ParseObjectEnd Exit ",objectPr.PRnewObj," id: ",objectPr.PRobjectId);
|
|
}
|
|
|
|
|
|
|
|
// Array object encountered in stream
|
|
private void ParseArray(ParseRecord pr)
|
|
{
|
|
InternalST.Soap( this, "ParseArray Entry");
|
|
pr.Dump();
|
|
|
|
long genId = pr.PRobjectId;
|
|
if (genId < 1)
|
|
pr.PRobjectId = GetId("GenId-"+objectIds);
|
|
|
|
if ((pr.PRarrayElementType != null) && (pr.PRarrayElementType.IsEnum))
|
|
pr.PRisEnum = true;
|
|
|
|
if (pr.PRarrayTypeEnum == InternalArrayTypeE.Base64)
|
|
{
|
|
if (pr.PRvalue == null)
|
|
{
|
|
pr.PRnewObj = new Byte[0];
|
|
CheckSecurity(pr);
|
|
}
|
|
else
|
|
{
|
|
// Used for arrays of Base64 and also for a parameter of Base64
|
|
InternalST.Soap( this, "ParseArray bin.base64 ",pr.PRvalue.Length," ",pr.PRvalue);
|
|
|
|
if (pr.PRdtType == Converter.typeofSoapBase64Binary)
|
|
{
|
|
// Parameter - Case where the return type is a SoapENC:base64 but the parameter type is xsd:base64Binary
|
|
pr.PRnewObj = SoapBase64Binary.Parse(pr.PRvalue);
|
|
CheckSecurity(pr);
|
|
}
|
|
else
|
|
{
|
|
// ByteArray
|
|
if (pr.PRvalue.Length > 0)
|
|
{
|
|
pr.PRnewObj = Convert.FromBase64String(FilterBin64(pr.PRvalue));
|
|
CheckSecurity(pr);
|
|
}
|
|
else
|
|
{
|
|
pr.PRnewObj = new Byte[0];
|
|
CheckSecurity(pr);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (stack.Peek() == pr)
|
|
{
|
|
InternalST.Soap( this, "ParseArray, bin.base64 has been stacked");
|
|
stack.Pop();
|
|
}
|
|
if (pr.PRobjectPositionEnum == InternalObjectPositionE.Top)
|
|
{
|
|
InternalST.Soap( this, "ParseArray, bin.base64 Top Object");
|
|
topObject = pr.PRnewObj;
|
|
isTopObjectResolved = true;
|
|
}
|
|
|
|
ParseRecord parentPr = (ParseRecord)stack.Peek();
|
|
|
|
// Base64 can be registered at this point because it is populated
|
|
InternalST.Soap( this, "ParseArray RegisterObject ",pr.PRobjectId," ",pr.PRnewObj.GetType());
|
|
RegisterObject(pr.PRnewObj, pr, parentPr);
|
|
|
|
}
|
|
else if ((pr.PRnewObj != null) && Converter.IsWriteAsByteArray(pr.PRarrayElementTypeCode))
|
|
{
|
|
// Primtive typed Array has already been read
|
|
if (pr.PRobjectPositionEnum == InternalObjectPositionE.Top)
|
|
{
|
|
topObject = pr.PRnewObj;
|
|
isTopObjectResolved = true;
|
|
}
|
|
|
|
ParseRecord parentPr = (ParseRecord)stack.Peek();
|
|
|
|
// Primitive typed array can be registered at this point because it is populated
|
|
InternalST.Soap( this, "ParseArray RegisterObject ",pr.PRobjectId," ",pr.PRnewObj.GetType());
|
|
RegisterObject(pr.PRnewObj, pr, parentPr);
|
|
}
|
|
else if ((pr.PRarrayTypeEnum == InternalArrayTypeE.Jagged) || (pr.PRarrayTypeEnum == InternalArrayTypeE.Single))
|
|
{
|
|
// Multidimensional jagged array or single array
|
|
InternalST.Soap( this, "ParseArray Before Jagged,Simple create ",pr.PRarrayElementType," ",(pr.PRrank >0?pr.PRlengthA[0].ToString():"0"));
|
|
if ((pr.PRlowerBoundA == null) || (pr.PRlowerBoundA[0] == 0))
|
|
{
|
|
pr.PRnewObj = Array.CreateInstance(pr.PRarrayElementType, (pr.PRrank>0?pr.PRlengthA[0]:0));
|
|
pr.PRisLowerBound = false;
|
|
}
|
|
else
|
|
{
|
|
pr.PRnewObj = Array.CreateInstance(pr.PRarrayElementType, pr.PRlengthA, pr.PRlowerBoundA);
|
|
pr.PRisLowerBound = true;
|
|
}
|
|
|
|
if (pr.PRarrayTypeEnum == InternalArrayTypeE.Single)
|
|
{
|
|
if (!pr.PRisLowerBound && (Converter.IsWriteAsByteArray(pr.PRarrayElementTypeCode)))
|
|
{
|
|
pr.PRprimitiveArray = new PrimitiveArray(pr.PRarrayElementTypeCode, (Array)pr.PRnewObj);
|
|
}
|
|
else if (!pr.PRarrayElementType.IsValueType)
|
|
pr.PRobjectA = (Object[])pr.PRnewObj;
|
|
}
|
|
CheckSecurity(pr);
|
|
|
|
InternalST.Soap( this, "ParseArray Jagged,Simple Array ",pr.PRnewObj.GetType());
|
|
|
|
// For binary, headers comes in as an array of header objects
|
|
if (pr.PRobjectPositionEnum == InternalObjectPositionE.Headers)
|
|
{
|
|
InternalST.Soap( this, "ParseArray header array");
|
|
headers = (Header[])pr.PRnewObj;
|
|
}
|
|
|
|
pr.PRindexMap = new int[1];
|
|
|
|
|
|
}
|
|
else if (pr.PRarrayTypeEnum == InternalArrayTypeE.Rectangular)
|
|
{
|
|
// Rectangle array
|
|
|
|
pr.PRisLowerBound = false;
|
|
if (pr.PRlowerBoundA != null)
|
|
{
|
|
for (int i=0; i<pr.PRrank; i++)
|
|
{
|
|
if (pr.PRlowerBoundA[i] != 0)
|
|
pr.PRisLowerBound = true;
|
|
}
|
|
}
|
|
|
|
|
|
if (!pr.PRisLowerBound)
|
|
pr.PRnewObj = Array.CreateInstance(pr.PRarrayElementType, pr.PRlengthA);
|
|
else
|
|
pr.PRnewObj = Array.CreateInstance(pr.PRarrayElementType, pr.PRlengthA, pr.PRlowerBoundA);
|
|
CheckSecurity(pr);
|
|
|
|
InternalST.Soap( this, "ParseArray Rectangle Array ",pr.PRnewObj.GetType()," lower Bound ",pr.PRisLowerBound);
|
|
|
|
// Calculate number of items
|
|
int sum = 1;
|
|
for (int i=0; i<pr.PRrank; i++)
|
|
{
|
|
sum = sum*pr.PRlengthA[i];
|
|
}
|
|
pr.PRindexMap = new int[pr.PRrank];
|
|
pr.PRrectangularMap = new int[pr.PRrank];
|
|
pr.PRlinearlength = sum;
|
|
}
|
|
else
|
|
throw new SerializationException(String.Format(SoapUtil.GetResourceString("Serialization_ArrayType"),((Enum)pr.PRarrayTypeEnum).ToString()));
|
|
|
|
InternalST.Soap( this, "ParseArray Exit");
|
|
}
|
|
|
|
|
|
// Builds a map for each item in an incoming rectangle array. The map specifies where the item is placed in the output Array Object
|
|
|
|
private void NextRectangleMap(ParseRecord pr)
|
|
{
|
|
// For each invocation, calculate the next rectangular array position
|
|
// example
|
|
// indexMap 0 [0,0,0]
|
|
// indexMap 1 [0,0,1]
|
|
// indexMap 2 [0,0,2]
|
|
// indexMap 3 [0,0,3]
|
|
// indexMap 4 [0,1,0]
|
|
for (int irank = pr.PRrank-1; irank>-1; irank--)
|
|
{
|
|
// Find the current or lower dimension which can be incremented.
|
|
if (pr.PRrectangularMap[irank] < pr.PRlengthA[irank]-1)
|
|
{
|
|
// The current dimension is at maximum. Increase the next lower dimension by 1
|
|
pr.PRrectangularMap[irank]++;
|
|
if (irank < pr.PRrank-1)
|
|
{
|
|
// The current dimension and higher dimensions are zeroed.
|
|
for (int i = irank+1; i<pr.PRrank; i++)
|
|
pr.PRrectangularMap[i] = 0;
|
|
}
|
|
Array.Copy(pr.PRrectangularMap, pr.PRindexMap, pr.PRrank);
|
|
break;
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
|
|
// Array object item encountered in stream
|
|
private void ParseArrayMember(ParseRecord pr)
|
|
{
|
|
InternalST.Soap( this, "ParseArrayMember Entry");
|
|
ParseRecord objectPr = (ParseRecord)stack.Peek();
|
|
|
|
// Set up for inserting value into correct array position
|
|
if (objectPr.PRarrayTypeEnum == InternalArrayTypeE.Rectangular)
|
|
{
|
|
|
|
if (objectPr.PRmemberIndex > 0)
|
|
NextRectangleMap(objectPr); // Rectangle array, calculate position in array
|
|
if (objectPr.PRisLowerBound)
|
|
{
|
|
for (int i=0; i<objectPr.PRrank; i++)
|
|
{
|
|
if (objectPr.PRpositionA == null)
|
|
objectPr.PRindexMap[i] = objectPr.PRrectangularMap[i] + objectPr.PRlowerBoundA[i];
|
|
else
|
|
objectPr.PRindexMap[i] = objectPr.PRpositionA[i];
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (!objectPr.PRisLowerBound)
|
|
{
|
|
if (objectPr.PRpositionA == null)
|
|
objectPr.PRindexMap[0] = objectPr.PRmemberIndex; // Zero based array
|
|
else
|
|
objectPr.PRindexMap[0] = objectPr.PRpositionA[0]; // item position specified in SOAP stream
|
|
}
|
|
else
|
|
objectPr.PRindexMap[0] = objectPr.PRlowerBoundA[0]+objectPr.PRmemberIndex; // Lower Bound based array
|
|
}
|
|
IndexTraceMessage("ParseArrayMember isLowerBound "+objectPr.PRisLowerBound+" indexMap ", objectPr.PRindexMap);
|
|
|
|
// Set Array element according to type of element
|
|
|
|
if (pr.PRmemberValueEnum == InternalMemberValueE.Reference)
|
|
{
|
|
// Object Reference
|
|
|
|
// See if object has already been instantiated
|
|
Object refObj = m_objectManager.GetObject(pr.PRidRef);
|
|
if (refObj == null)
|
|
{
|
|
// Object not instantiated
|
|
// Array fixup manager
|
|
IndexTraceMessage("ParseArrayMember Record Fixup "+objectPr.PRnewObj.GetType(), objectPr.PRindexMap);
|
|
int[] fixupIndex = new int[objectPr.PRrank];
|
|
Array.Copy(objectPr.PRindexMap, 0, fixupIndex, 0, objectPr.PRrank);
|
|
|
|
InternalST.Soap( this, "ParseArrayMember RecordArrayElementFixup objectId ",objectPr.PRobjectId," idRef ",pr.PRidRef);
|
|
m_objectManager.RecordArrayElementFixup(objectPr.PRobjectId, fixupIndex, pr.PRidRef);
|
|
}
|
|
else
|
|
{
|
|
IndexTraceMessage("ParseArrayMember SetValue ObjectReference "+objectPr.PRnewObj.GetType()+" "+refObj, objectPr.PRindexMap);
|
|
if (objectPr.PRobjectA != null)
|
|
objectPr.PRobjectA[objectPr.PRindexMap[0]] = refObj;
|
|
else
|
|
((Array)objectPr.PRnewObj).SetValue(refObj, objectPr.PRindexMap); // Object has been instantiated
|
|
}
|
|
}
|
|
else if (pr.PRmemberValueEnum == InternalMemberValueE.Nested)
|
|
{
|
|
//Set up dtType for ParseObject
|
|
InternalST.Soap( this, "ParseArrayMember Nested ");
|
|
if (pr.PRdtType == null)
|
|
{
|
|
pr.PRdtType = objectPr.PRarrayElementType;
|
|
}
|
|
|
|
ParseObject(pr);
|
|
|
|
InternalST.Soap( "ParseArrayMember Push object "+pr.PRname);
|
|
stack.Push(pr);
|
|
|
|
if ((objectPr.PRarrayElementType.IsValueType) && (pr.PRarrayElementTypeCode == InternalPrimitiveTypeE.Invalid))
|
|
{
|
|
InternalST.Soap( "ParseArrayMember ValueType ObjectPr ",objectPr.PRnewObj," index ",objectPr.PRmemberIndex);
|
|
pr.PRisValueTypeFixup = true; //Valuefixup
|
|
valueFixupStack.Push(new ValueFixup((Array)objectPr.PRnewObj, objectPr.PRindexMap)); //valuefixup
|
|
RegisterObject(pr.PRnewObj, pr, objectPr);
|
|
}
|
|
else
|
|
{
|
|
InternalST.Soap( "ParseArrayMember SetValue Nested, memberIndex ",objectPr.PRmemberIndex);
|
|
IndexTraceMessage("ParseArrayMember SetValue Nested ContainerObject "+objectPr.PRnewObj.GetType()+" "+objectPr.PRnewObj+" item Object "+pr.PRnewObj+" index ", objectPr.PRindexMap);
|
|
|
|
stack.Dump();
|
|
InternalST.Soap( "ParseArrayMember SetValue Nested ContainerObject objectPr ",objectPr.Trace());
|
|
InternalST.Soap( "ParseArrayMember SetValue Nested ContainerObject pr ",pr.Trace());
|
|
|
|
if (objectPr.PRobjectA != null)
|
|
objectPr.PRobjectA[objectPr.PRindexMap[0]] = pr.PRnewObj;
|
|
else
|
|
((Array)objectPr.PRnewObj).SetValue(pr.PRnewObj, objectPr.PRindexMap);
|
|
}
|
|
}
|
|
else if (pr.PRmemberValueEnum == InternalMemberValueE.InlineValue)
|
|
{
|
|
if (objectPr.PRarrayElementType == Converter.typeofString)
|
|
{
|
|
// String
|
|
ParseString(pr, objectPr);
|
|
IndexTraceMessage("ParseArrayMember SetValue String "+objectPr.PRnewObj.GetType()+" "+pr.PRvalue, objectPr.PRindexMap);
|
|
if (objectPr.PRobjectA != null)
|
|
objectPr.PRobjectA[objectPr.PRindexMap[0]] = (Object)pr.PRvalue;
|
|
else
|
|
((Array)objectPr.PRnewObj).SetValue((Object)pr.PRvalue, objectPr.PRindexMap);
|
|
}
|
|
else if (objectPr.PRisEnum)
|
|
{
|
|
// Soap sends Enums as strings
|
|
Object var = Enum.Parse(objectPr.PRarrayElementType, pr.PRvalue);
|
|
if (objectPr.PRobjectA != null)
|
|
objectPr.PRobjectA[objectPr.PRindexMap[0]] = (Enum)var;
|
|
else
|
|
((Array)objectPr.PRnewObj).SetValue((Enum)var, objectPr.PRindexMap);
|
|
InternalST.Soap( this, "ParseArrayMember Enum 1");
|
|
}
|
|
else if (objectPr.PRisArrayVariant)
|
|
{
|
|
// Array of type object
|
|
if (pr.PRdtType == null && pr.PRkeyDt == null)
|
|
throw new SerializationException(SoapUtil.GetResourceString("Serialization_ArrayTypeObject"));
|
|
|
|
Object var = null;
|
|
|
|
if (pr.PRdtType == Converter.typeofString)
|
|
{
|
|
ParseString(pr, objectPr);
|
|
var = pr.PRvalue;
|
|
}
|
|
else if (pr.PRdtType.IsEnum)
|
|
{
|
|
// Soap sends Enums as strings
|
|
var = Enum.Parse(pr.PRdtType, pr.PRvalue);
|
|
InternalST.Soap( this, "ParseArrayMember Enum 2");
|
|
}
|
|
else if (pr.PRdtTypeCode == InternalPrimitiveTypeE.Invalid)
|
|
{
|
|
// Not nested and invalid, so it is an empty object
|
|
var = FormatterServices.GetUninitializedObject(pr.PRdtType);
|
|
}
|
|
else
|
|
{
|
|
if (pr.PRvarValue != null)
|
|
var = pr.PRvarValue;
|
|
else
|
|
var = Converter.FromString(pr.PRvalue, pr.PRdtTypeCode);
|
|
}
|
|
IndexTraceMessage("ParseArrayMember SetValue variant or Object "+objectPr.PRnewObj.GetType()+" var "+var+" indexMap ", objectPr.PRindexMap);
|
|
if (objectPr.PRobjectA != null)
|
|
objectPr.PRobjectA[objectPr.PRindexMap[0]] = var;
|
|
else
|
|
((Array)objectPr.PRnewObj).SetValue(var, objectPr.PRindexMap); // Primitive type
|
|
}
|
|
else
|
|
{
|
|
// Primitive type
|
|
if (objectPr.PRprimitiveArray != null)
|
|
{
|
|
// Fast path for Soap primitive arrays. Binary was handled in the BinaryParser
|
|
objectPr.PRprimitiveArray.SetValue(pr.PRvalue, objectPr.PRindexMap[0]);
|
|
}
|
|
else
|
|
{
|
|
|
|
Object var = null;
|
|
if (pr.PRvarValue != null)
|
|
var = pr.PRvarValue;
|
|
else
|
|
var = Converter.FromString(pr.PRvalue, objectPr.PRarrayElementTypeCode);
|
|
|
|
if (objectPr.PRarrayElementTypeCode == InternalPrimitiveTypeE.QName)
|
|
{
|
|
InternalST.Soap( this, "ParseArrayMember Primitive QName");
|
|
SoapQName soapQName = (SoapQName)var;
|
|
if (soapQName.Key.Length == 0)
|
|
soapQName.Namespace = (String)soapHandler.keyToNamespaceTable["xmlns"];
|
|
else
|
|
soapQName.Namespace = (String)soapHandler.keyToNamespaceTable["xmlns"+":"+soapQName.Key];
|
|
}
|
|
|
|
InternalST.Soap( this, "ParseArrayMember SetValue Primitive pr.PRvalue "+var," elementTypeCode ",((Enum)objectPr.PRdtTypeCode).ToString());
|
|
IndexTraceMessage("ParseArrayMember SetValue Primitive "+objectPr.PRnewObj.GetType()+" var: "+var+" varType "+var.GetType(), objectPr.PRindexMap);
|
|
if (objectPr.PRobjectA != null)
|
|
objectPr.PRobjectA[objectPr.PRindexMap[0]] = var;
|
|
else
|
|
((Array)objectPr.PRnewObj).SetValue(var, objectPr.PRindexMap); // Primitive type
|
|
InternalST.Soap( this, "ParseArrayMember SetValue Primitive after");
|
|
}
|
|
}
|
|
}
|
|
else if (pr.PRmemberValueEnum == InternalMemberValueE.Null)
|
|
{
|
|
InternalST.Soap( "ParseArrayMember Null item ",pr.PRmemberIndex);
|
|
}
|
|
else
|
|
ParseError(pr, objectPr);
|
|
|
|
InternalST.Soap( "ParseArrayMember increment memberIndex ",objectPr.PRmemberIndex," ",objectPr.Trace());
|
|
objectPr.PRmemberIndex++;
|
|
InternalST.Soap( "ParseArrayMember Exit");
|
|
}
|
|
|
|
private void ParseArrayMemberEnd(ParseRecord pr)
|
|
{
|
|
InternalST.Soap( this, "ParseArrayMemberEnd");
|
|
// If this is a nested array object, then pop the stack
|
|
if (pr.PRmemberValueEnum == InternalMemberValueE.Nested)
|
|
{
|
|
ParseObjectEnd(pr);
|
|
}
|
|
}
|
|
|
|
|
|
// Object member encountered in stream
|
|
private void ParseMember(ParseRecord pr)
|
|
{
|
|
InternalST.Soap( this, "ParseMember Entry ");
|
|
|
|
|
|
ParseRecord objectPr = (ParseRecord)stack.Peek();
|
|
String objName = null;
|
|
if (objectPr != null)
|
|
objName = objectPr.PRname;
|
|
|
|
InternalST.Soap( this, "ParseMember ",objectPr.PRobjectId," ",pr.PRname);
|
|
InternalST.Soap( this, "ParseMember objectPr ",objectPr.Trace());
|
|
InternalST.Soap( this, "ParseMember pr ",pr.Trace());
|
|
|
|
if (objectPr.PRdtType == Converter.typeofSoapFault && pr.PRname.ToLower(CultureInfo.InvariantCulture) == "faultstring")
|
|
faultString = pr.PRvalue; // Save fault string in case rest of SoapFault cannot be parsed
|
|
|
|
|
|
if ((objectPr.PRobjectPositionEnum == InternalObjectPositionE.Top) && !isTopObjectResolved)
|
|
{
|
|
InternalST.Soap( this, "ParseMember Top not resolved");
|
|
if (pr.PRdtType == Converter.typeofString)
|
|
{
|
|
ParseString(pr, objectPr);
|
|
}
|
|
topStack.Push(pr.Copy());
|
|
return;
|
|
}
|
|
|
|
switch(pr.PRmemberTypeEnum)
|
|
{
|
|
case InternalMemberTypeE.Item:
|
|
ParseArrayMember(pr);
|
|
return;
|
|
case InternalMemberTypeE.Field:
|
|
break;
|
|
}
|
|
|
|
|
|
if (objectPr.PRobjectInfo != null)
|
|
objectPr.PRobjectInfo.AddMemberSeen();
|
|
|
|
bool bParams = (IsFakeTopObject &&
|
|
objectPr.PRobjectPositionEnum == InternalObjectPositionE.Top &&
|
|
objectPr.PRobjectInfo != null && objectPr.PRdtType != Converter.typeofSoapFault);
|
|
|
|
if ((pr.PRdtType == null) && objectPr.PRobjectInfo.isTyped)
|
|
{
|
|
InternalST.Soap( this, "ParseMember pr.PRdtType null and not isSi");
|
|
|
|
if (bParams)
|
|
{
|
|
// Get type of parameters
|
|
InternalST.Soap( this, "ParseMember pr.PRdtType Get Param Type position "+paramPosition+" name "+pr.PRname);
|
|
pr.PRdtType = objectPr.PRobjectInfo.GetType(paramPosition++);
|
|
InternalST.Soap( this, "ParseMember pr.PRdtType Get Param Type Type "+pr.PRdtType);
|
|
}
|
|
else
|
|
pr.PRdtType = objectPr.PRobjectInfo.GetType(pr.PRname);
|
|
|
|
if (pr.PRdtType == null)
|
|
throw new SerializationException(String.Format(SoapUtil.GetResourceString("Serialization_TypeResolved"), objectPr.PRnewObj+" "+pr.PRname));
|
|
|
|
pr.PRdtTypeCode = Converter.ToCode(pr.PRdtType);
|
|
}
|
|
else
|
|
{
|
|
if (bParams)
|
|
{
|
|
paramPosition++;
|
|
}
|
|
}
|
|
|
|
|
|
if (pr.PRmemberValueEnum == InternalMemberValueE.Null)
|
|
{
|
|
// Value is Null
|
|
InternalST.Soap( this, "ParseMember null member: ",pr.PRname);
|
|
InternalST.Soap( this, "AddValue 1");
|
|
objectPr.PRobjectInfo.AddValue(pr.PRname, null);
|
|
}
|
|
else if (pr.PRmemberValueEnum == InternalMemberValueE.Nested)
|
|
{
|
|
InternalST.Soap( this, "ParseMember Nested Type member: ",pr.PRname," objectPr.PRnewObj ",objectPr.PRnewObj);
|
|
ParseObject(pr);
|
|
InternalST.Soap( "ParseMember Push object "+pr.PRname);
|
|
stack.Push(pr);
|
|
InternalST.Soap( this, "AddValue 2 ",pr.PRnewObj," is value type ",pr.PRnewObj.GetType().IsValueType);
|
|
|
|
if ((pr.PRobjectInfo != null) && (pr.PRobjectInfo.objectType.IsValueType))
|
|
{
|
|
InternalST.Soap( "ParseMember ValueType ObjectPr ",objectPr.PRnewObj," memberName ",pr.PRname," nested object ",pr.PRnewObj);
|
|
if (IsFakeTopObject)
|
|
objectPr.PRobjectInfo.AddParamName(pr.PRname);
|
|
|
|
pr.PRisValueTypeFixup = true; //Valuefixup
|
|
valueFixupStack.Push(new ValueFixup(objectPr.PRnewObj, pr.PRname, objectPr.PRobjectInfo));//valuefixup
|
|
}
|
|
else
|
|
{
|
|
InternalST.Soap( this, "AddValue 2A ");
|
|
objectPr.PRobjectInfo.AddValue(pr.PRname, pr.PRnewObj);
|
|
}
|
|
}
|
|
else if (pr.PRmemberValueEnum == InternalMemberValueE.Reference)
|
|
{
|
|
InternalST.Soap( this, "ParseMember Reference Type member: ",pr.PRname);
|
|
// See if object has already been instantiated
|
|
Object refObj = m_objectManager.GetObject(pr.PRidRef);
|
|
if (refObj == null)
|
|
{
|
|
InternalST.Soap( this, "ParseMember RecordFixup: ",pr.PRname);
|
|
InternalST.Soap( this, "AddValue 3");
|
|
objectPr.PRobjectInfo.AddValue(pr.PRname, null);
|
|
objectPr.PRobjectInfo.RecordFixup(objectPr.PRobjectId, pr.PRname, pr.PRidRef); // Object not instantiated
|
|
}
|
|
else
|
|
{
|
|
InternalST.Soap( this, "ParseMember Referenced Object Known ",pr.PRname," ",refObj);
|
|
InternalST.Soap( this, "AddValue 5");
|
|
objectPr.PRobjectInfo.AddValue(pr.PRname, refObj);
|
|
}
|
|
}
|
|
|
|
else if (pr.PRmemberValueEnum == InternalMemberValueE.InlineValue)
|
|
{
|
|
// Primitive type or String
|
|
InternalST.Soap( this, "ParseMember primitive or String member: ",pr.PRname);
|
|
|
|
if (pr.PRdtType == Converter.typeofString)
|
|
{
|
|
ParseString(pr, objectPr);
|
|
InternalST.Soap( this, "AddValue 6");
|
|
objectPr.PRobjectInfo.AddValue(pr.PRname, pr.PRvalue);
|
|
}
|
|
else if (pr.PRdtTypeCode == InternalPrimitiveTypeE.Invalid)
|
|
{
|
|
// The member field was an object put the value is Inline either bin.Base64 or invalid
|
|
if (pr.PRarrayTypeEnum == InternalArrayTypeE.Base64)
|
|
{
|
|
InternalST.Soap( this, "AddValue 7");
|
|
objectPr.PRobjectInfo.AddValue(pr.PRname, Convert.FromBase64String(FilterBin64(pr.PRvalue)));
|
|
}
|
|
else if (pr.PRdtType == Converter.typeofObject && pr.PRvalue != null)
|
|
{
|
|
if (objectPr != null && objectPr.PRdtType == Converter.typeofHeader)
|
|
{
|
|
// assume the type is a string for a header
|
|
pr.PRdtType = Converter.typeofString;
|
|
ParseString(pr, objectPr);
|
|
InternalST.Soap( this, "AddValue 6");
|
|
objectPr.PRobjectInfo.AddValue(pr.PRname, pr.PRvalue);
|
|
}
|
|
else
|
|
throw new SerializationException(String.Format(SoapUtil.GetResourceString("Serialization_TypeMissing"), pr.PRname));
|
|
}
|
|
else
|
|
{
|
|
InternalST.Soap( this, "Object Class with no memberInfo data Member "+pr.PRname+" type "+pr.PRdtType);
|
|
|
|
if (pr.PRdtType != null && pr.PRdtType.IsEnum)
|
|
{
|
|
// Soap sends Enums as strings
|
|
Object obj = Enum.Parse(pr.PRdtType, pr.PRvalue);
|
|
InternalST.Soap( this, "AddValue 8");
|
|
objectPr.PRobjectInfo.AddValue(pr.PRname, obj);
|
|
}
|
|
else if (pr.PRdtType != null && pr.PRdtType == Converter.typeofTypeArray)
|
|
{
|
|
// Soap sends MethodSignature as an array of types
|
|
InternalST.Soap( this, "AddValue 8A");
|
|
objectPr.PRobjectInfo.AddValue(pr.PRname, pr.PRvarValue);
|
|
}
|
|
else
|
|
{
|
|
if ((!pr.PRisRegistered) && (pr.PRobjectId > 0))
|
|
{
|
|
if (pr.PRvalue == null)
|
|
pr.PRvalue = ""; //can't register null value, this must be a string so set to empty string.
|
|
|
|
InternalST.Soap( this, "ParseMember RegisterObject ",pr.PRvalue," ",pr.PRobjectId);
|
|
RegisterObject(pr.PRvalue, pr, objectPr);
|
|
}
|
|
|
|
// Object Class with no memberInfo data
|
|
if (pr.PRdtType == Converter.typeofSystemVoid)
|
|
{
|
|
InternalST.Soap( this, "AddValue 9");
|
|
objectPr.PRobjectInfo.AddValue(pr.PRname, pr.PRdtType);
|
|
}
|
|
else if (objectPr.PRobjectInfo.isSi)
|
|
{
|
|
// ISerializable are added as strings, the conversion to type is done by the
|
|
// ISerializable object
|
|
InternalST.Soap( this, "AddValue 10");
|
|
objectPr.PRobjectInfo.AddValue(pr.PRname, pr.PRvalue);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Object var = null;
|
|
if (pr.PRvarValue != null)
|
|
var = pr.PRvarValue;
|
|
else
|
|
var = Converter.FromString(pr.PRvalue, pr.PRdtTypeCode);
|
|
// Not a string, convert the value
|
|
InternalST.Soap( this, "ParseMember Converting primitive and storing");
|
|
stack.Dump();
|
|
InternalST.Soap( this, "ParseMember pr "+pr.Trace());
|
|
InternalST.Soap( this, "ParseMember objectPr ",objectPr.Trace());
|
|
|
|
InternalST.Soap( this, "AddValue 11");
|
|
if (pr.PRdtTypeCode == InternalPrimitiveTypeE.QName && var != null)
|
|
{
|
|
SoapQName soapQName = (SoapQName)var;
|
|
if (soapQName.Key != null)
|
|
{
|
|
if (soapQName.Key.Length == 0)
|
|
soapQName.Namespace = (String)soapHandler.keyToNamespaceTable["xmlns"];
|
|
else
|
|
soapQName.Namespace = (String)soapHandler.keyToNamespaceTable["xmlns"+":"+soapQName.Key];
|
|
}
|
|
}
|
|
objectPr.PRobjectInfo.AddValue(pr.PRname, var);
|
|
}
|
|
}
|
|
else
|
|
ParseError(pr, objectPr);
|
|
}
|
|
|
|
// Object member end encountered in stream
|
|
private void ParseMemberEnd(ParseRecord pr)
|
|
{
|
|
InternalST.Soap( this, "ParseMemberEnd");
|
|
switch(pr.PRmemberTypeEnum)
|
|
{
|
|
case InternalMemberTypeE.Item:
|
|
ParseArrayMemberEnd(pr);
|
|
return;
|
|
case InternalMemberTypeE.Field:
|
|
if (pr.PRmemberValueEnum == InternalMemberValueE.Nested)
|
|
ParseObjectEnd(pr);
|
|
break;
|
|
default:
|
|
if (pr.PRmemberValueEnum == InternalMemberValueE.Nested)
|
|
ParseObjectEnd(pr);
|
|
else
|
|
ParseError(pr, (ParseRecord)stack.Peek());
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Processes a string object by getting an internal ID for it and registering it with the objectManager
|
|
private void ParseString(ParseRecord pr, ParseRecord parentPr)
|
|
{
|
|
InternalST.Soap( this, "ParseString Entry ",pr.PRobjectId," ",pr.PRvalue," ",pr.PRisRegistered);
|
|
|
|
// If there is a string and it wasn't marked as a null object, then it is an empty string
|
|
if (pr.PRvalue == null)
|
|
pr.PRvalue = "";
|
|
|
|
// Process String class
|
|
if ((!pr.PRisRegistered) && (pr.PRobjectId > 0))
|
|
{
|
|
InternalST.Soap( this, "ParseString RegisterObject ",pr.PRvalue," ",pr.PRobjectId);
|
|
// String is treated as an object if it has an id
|
|
//m_objectManager.RegisterObject(pr.PRvalue, pr.PRobjectId);
|
|
RegisterObject(pr.PRvalue, pr, parentPr);
|
|
}
|
|
}
|
|
|
|
|
|
private void RegisterObject(Object obj, ParseRecord pr, ParseRecord objectPr)
|
|
{
|
|
if (!pr.PRisRegistered)
|
|
{
|
|
pr.PRisRegistered = true;
|
|
|
|
SerializationInfo si = null;
|
|
long parentId = 0;
|
|
MemberInfo memberInfo = null;
|
|
int[] indexMap = null;
|
|
|
|
if (objectPr != null)
|
|
{
|
|
indexMap = objectPr.PRindexMap;
|
|
parentId = objectPr.PRobjectId;
|
|
|
|
if (objectPr.PRobjectInfo != null)
|
|
{
|
|
if (!objectPr.PRobjectInfo.isSi)
|
|
{
|
|
// ParentId is only used if there is a memberInfo
|
|
InternalST.Soap( this, "RegisterObject GetMemberInfo parent ",objectPr.PRobjectInfo.objectType," name looking for ", pr.PRname," field obj "+obj);
|
|
memberInfo = objectPr.PRobjectInfo.GetMemberInfo(pr.PRname);
|
|
}
|
|
}
|
|
}
|
|
if (pr.PRobjectInfo != null)
|
|
{
|
|
// SerializationInfo is always needed for ISerialization
|
|
si = pr.PRobjectInfo.si;
|
|
}
|
|
|
|
InternalST.Soap( this, "RegisterObject 0bj ",obj," objectId ",pr.PRobjectId," si ", si," parentId ",parentId," memberInfo ",memberInfo, " indexMap "+indexMap);
|
|
m_objectManager.RegisterObject(obj, pr.PRobjectId, si, parentId, memberInfo, indexMap);
|
|
}
|
|
}
|
|
|
|
|
|
internal void SetVersion(int major, int minor)
|
|
{
|
|
// Don't do version checking if property is set to Simple
|
|
if (formatterEnums.FEassemblyFormat != FormatterAssemblyStyle.Simple)
|
|
{
|
|
this.majorVersion = major;
|
|
this.minorVersion = minor;
|
|
}
|
|
}
|
|
|
|
|
|
// Assigns an internal ID associated with the xml id attribute
|
|
|
|
String inKeyId = null;
|
|
long outKeyId = 0;
|
|
internal long GetId(String keyId)
|
|
{
|
|
if (keyId == null)
|
|
throw new ArgumentNullException("keyId", String.Format(SoapUtil.GetResourceString("ArgumentNull_WithParamName"), "keyId"));
|
|
|
|
if (keyId != inKeyId)
|
|
{
|
|
inKeyId = keyId;
|
|
String idString = null;
|
|
InternalST.Soap( this, "GetId Entry ",keyId);
|
|
if (keyId[0] == '#')
|
|
idString = keyId.Substring(1);
|
|
else
|
|
idString = keyId;
|
|
|
|
Object idObj = objectIdTable[idString];
|
|
if (idObj == null)
|
|
{
|
|
outKeyId = ++objectIds;
|
|
objectIdTable[idString] = outKeyId;
|
|
InternalST.Soap( this, "GetId Exit new ID ",outKeyId);
|
|
}
|
|
else
|
|
{
|
|
InternalST.Soap( this, "GetId Exit oldId ",(Int64)idObj);
|
|
outKeyId = (Int64)idObj;
|
|
}
|
|
}
|
|
InternalST.Soap( this, "GetId in id ",keyId, " out id ", outKeyId);
|
|
return outKeyId;
|
|
}
|
|
|
|
// Assigns an internal ID associated with the binary id number
|
|
|
|
long inId = 0;
|
|
long outId = 0;
|
|
internal long GetId(long objectId)
|
|
{
|
|
if (inId != objectId)
|
|
{
|
|
|
|
inId = objectId;
|
|
Object idObj = null;
|
|
if (objectId > 0)
|
|
idObj = objectIdTable[objectId];
|
|
if (idObj == null)
|
|
{
|
|
outId = ++objectIds;
|
|
objectIdTable[objectId] = outId;
|
|
InternalST.Soap( this, "GetId Exit new ID ",outId);
|
|
}
|
|
else
|
|
{
|
|
InternalST.Soap( this, "GetId Exit oldId ",(Int64)idObj);
|
|
outId = (Int64)idObj;
|
|
}
|
|
}
|
|
return outId;
|
|
}
|
|
|
|
|
|
// Trace which includes a single dimensional int array
|
|
[Conditional("SER_LOGGING")]
|
|
private void IndexTraceMessage(String message, int[] index)
|
|
{
|
|
StringBuilder sb = new StringBuilder(10);
|
|
sb.Append("[");
|
|
for (int i=0; i<index.Length; i++)
|
|
{
|
|
sb.Append(index[i]);
|
|
if (i != index.Length -1)
|
|
sb.Append(",");
|
|
}
|
|
sb.Append("]");
|
|
InternalST.Soap( this, message," ",sb.ToString());
|
|
}
|
|
|
|
internal Assembly LoadAssemblyFromString(String assemblyString)
|
|
{
|
|
Assembly assm = null;
|
|
if(formatterEnums.FEassemblyFormat == FormatterAssemblyStyle.Simple) {
|
|
assm = Assembly.LoadWithPartialName(assemblyString);
|
|
}
|
|
else {
|
|
try
|
|
{
|
|
assm = Assembly.Load(assemblyString);
|
|
}
|
|
catch (Exception)
|
|
{
|
|
}
|
|
}
|
|
|
|
return assm;
|
|
}
|
|
|
|
internal Type Bind(String assemblyString, String typeString)
|
|
{
|
|
Type type = null;
|
|
if (m_binder != null)
|
|
type = m_binder.BindToType(assemblyString, typeString);
|
|
return type;
|
|
}
|
|
|
|
internal class TypeNAssembly
|
|
{
|
|
public Type type;
|
|
public String assemblyName;
|
|
}
|
|
|
|
NameCache typeCache = new NameCache();
|
|
internal Type FastBindToType(String assemblyName, String typeName)
|
|
{
|
|
Type type = null;
|
|
|
|
TypeNAssembly entry = (TypeNAssembly)typeCache.GetCachedValue(typeName);
|
|
|
|
if (entry == null || entry.assemblyName != assemblyName)
|
|
{
|
|
Assembly assm = LoadAssemblyFromString(assemblyName);
|
|
if (assm == null)
|
|
return null;
|
|
|
|
type = FormatterServices.GetTypeFromAssembly(assm, typeName);
|
|
|
|
if (type == null)
|
|
return null;
|
|
|
|
entry = new TypeNAssembly();
|
|
entry.type = type;
|
|
entry.assemblyName = assemblyName;
|
|
typeCache.SetCachedValue(entry);
|
|
}
|
|
return entry.type;
|
|
}
|
|
|
|
/*
|
|
static Hashtable typeNames = new Hashtable();
|
|
static int s_numEntries = 0;
|
|
private const int MAX_CACHE_ENTRIES = 128; // No data gathered to arrive at this number !
|
|
|
|
internal Type FastBindToType(String assemblyName, String typeName)
|
|
{
|
|
TypeNAssembly match = (TypeNAssembly)typeNames[typeName];
|
|
if (match == null)
|
|
{
|
|
match = new TypeNAssembly();
|
|
Assembly assm = null;
|
|
try
|
|
{
|
|
assm = Assembly.Load(assemblyName);
|
|
}
|
|
catch (Exception)
|
|
{
|
|
return null;
|
|
}
|
|
|
|
if (assm == null)
|
|
return null;
|
|
|
|
match.type = FormatterServices.GetTypeFromAssembly(assm, typeName);
|
|
if (match.type == null)
|
|
return null;
|
|
|
|
match.assemblyName = assemblyName;
|
|
lock (typeNames)
|
|
{
|
|
if (s_numEntries == MAX_CACHE_ENTRIES)
|
|
{
|
|
typeNames.Clear();
|
|
s_numEntries = 0;
|
|
}
|
|
typeNames[typeName] = match;
|
|
s_numEntries ++;
|
|
}
|
|
|
|
return match.type;
|
|
}
|
|
if (match.assemblyName.Equals(assemblyName))
|
|
return match.type;
|
|
|
|
// So if same type name occurs in 2 assemblies, the second guy loses
|
|
return null;
|
|
}
|
|
*/
|
|
|
|
StringBuilder sbf = new StringBuilder();
|
|
internal String FilterBin64(String value)
|
|
{
|
|
sbf.Length = 0;
|
|
for (int i=0; i<value.Length; i++)
|
|
{
|
|
if (!(value[i] == ' '|| value[i] == '\n' || value[i] == '\r'))
|
|
sbf.Append(value[i]);
|
|
}
|
|
return sbf.ToString();
|
|
}
|
|
|
|
}
|
|
}
|