2020-03-24 11:08:37 -07:00
// Copyright (c) Microsoft Corporation.
2018-02-13 09:23:53 -08:00
// Licensed under the MIT License.
2016-03-30 14:20:52 -07:00
using System ;
using System.Collections ;
using System.Collections.Generic ;
using System.Collections.ObjectModel ;
using System.Diagnostics.CodeAnalysis ;
using System.Globalization ;
using System.IO ;
using System.Linq ;
using System.Management.Automation.Internal ;
using System.Management.Automation.Language ;
2019-04-30 10:25:11 +05:00
using System.Management.Automation.Remoting ;
2016-03-30 14:20:52 -07:00
using System.Management.Automation.Runspaces ;
using System.Management.Automation.Tracing ;
2017-04-17 11:52:38 -07:00
using System.Net.Mail ;
2016-03-30 14:20:52 -07:00
using System.Reflection ;
using System.Runtime.CompilerServices ;
using System.Security ;
using System.Text ;
using System.Xml ;
2019-04-30 10:25:11 +05:00
2016-03-30 14:20:52 -07:00
using Microsoft.Management.Infrastructure ;
using Microsoft.Management.Infrastructure.Serialization ;
using Microsoft.PowerShell.Commands ;
2019-04-30 10:25:11 +05:00
2016-03-30 14:20:52 -07:00
using Dbg = System . Management . Automation . Diagnostics ;
namespace System.Management.Automation
{
2016-07-29 13:02:49 -07:00
[Flags]
internal enum SerializationOptions
{
None = 0 ,
UseDepthFromTypes = 1 ,
NoRootElement = 2 ,
NoNamespace = 4 ,
NoObjectRefIds = 8 ,
PreserveSerializationSettingOfOriginal = 16 ,
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
RemotingOptions = UseDepthFromTypes | NoRootElement | NoNamespace | PreserveSerializationSettingOfOriginal ,
}
2016-03-30 14:20:52 -07:00
internal class SerializationContext
{
private const int DefaultSerializationDepth = 2 ;
internal SerializationContext ()
: this ( DefaultSerializationDepth , true )
{
}
internal SerializationContext ( int depth , bool useDepthFromTypes )
: this (
2016-07-29 13:02:49 -07:00
depth ,
2016-03-30 14:20:52 -07:00
( useDepthFromTypes ? SerializationOptions . UseDepthFromTypes : SerializationOptions . None ) |
2016-07-29 13:02:49 -07:00
SerializationOptions . PreserveSerializationSettingOfOriginal ,
2016-03-30 14:20:52 -07:00
null )
{
}
internal SerializationContext ( int depth , SerializationOptions options , PSRemotingCryptoHelper cryptoHelper )
{
if ( depth < 1 )
{
throw PSTraceSource . NewArgumentException ( "writer" , Serialization . DepthOfOneRequired );
}
this . depth = depth ;
this . options = options ;
this . cryptoHelper = cryptoHelper ;
}
2016-07-29 13:02:49 -07:00
2016-03-30 14:20:52 -07:00
internal readonly int depth ;
internal readonly SerializationOptions options ;
internal readonly PSRemotingCryptoHelper cryptoHelper ;
internal readonly CimClassSerializationCache < CimClassSerializationId > cimClassSerializationIdCache = new CimClassSerializationCache < CimClassSerializationId >();
}
2016-07-29 13:02:49 -07:00
/// <summary>
2019-01-06 04:40:24 +05:00
/// This class provides public functionality for serializing a PSObject.
2016-07-29 13:02:49 -07:00
/// </summary>
public class PSSerializer
{
internal PSSerializer () { }
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
/// <summary>
2019-01-06 04:40:24 +05:00
/// Serializes an object into PowerShell CliXml.
2016-07-29 13:02:49 -07:00
/// </summary>
2018-12-28 16:39:06 +05:00
/// <param name="source">The input object to serialize. Serializes to a default depth of 1.</param>
2018-12-25 21:43:03 +05:00
/// <returns>The serialized object, as CliXml.</returns>
2019-11-06 08:47:32 +05:00
public static string Serialize ( object source )
2016-07-29 13:02:49 -07:00
{
return Serialize ( source , s_mshDefaultSerializationDepth );
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
/// <summary>
2019-01-06 04:40:24 +05:00
/// Serializes an object into PowerShell CliXml.
2016-07-29 13:02:49 -07:00
/// </summary>
2018-12-28 16:39:06 +05:00
/// <param name="source">The input object to serialize.</param>
/// <param name="depth">The depth of the members to serialize.</param>
2018-12-25 21:43:03 +05:00
/// <returns>The serialized object, as CliXml.</returns>
2019-11-06 08:47:32 +05:00
public static string Serialize ( object source , int depth )
2016-07-29 13:02:49 -07:00
{
// Create an xml writer
StringBuilder sb = new StringBuilder ();
XmlWriterSettings xmlSettings = new XmlWriterSettings ();
xmlSettings . CloseOutput = true ;
xmlSettings . Encoding = System . Text . Encoding . Unicode ;
xmlSettings . Indent = true ;
xmlSettings . OmitXmlDeclaration = true ;
XmlWriter xw = XmlWriter . Create ( sb , xmlSettings );
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
// Serialize the objects
Serializer serializer = new Serializer ( xw , depth , true );
serializer . Serialize ( source );
serializer . Done ();
serializer = null ;
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
// Return the output
return sb . ToString ();
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
/// <summary>
/// Deserializes PowerShell CliXml into an object.
/// </summary>
/// <param name="source">The CliXml the represents the object to deserialize.</param>
2018-12-25 21:43:03 +05:00
/// <returns>An object that represents the serialized content.</returns>
2016-07-29 13:02:49 -07:00
public static object Deserialize ( string source )
{
2018-12-24 12:32:38 +05:00
object [] results = DeserializeAsList ( source );
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
// Return the results
if ( results . Length == 0 )
{
return null ;
}
else if ( results . Length == 1 )
{
return results [ 0 ];
}
else
{
return results ;
}
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
/// <summary>
/// Deserializes PowerShell CliXml into a list of objects.
/// </summary>
/// <param name="source">The CliXml the represents the object to deserialize.</param>
2018-12-25 21:43:03 +05:00
/// <returns>An object array represents the serialized content.</returns>
2016-07-29 13:02:49 -07:00
public static object [] DeserializeAsList ( string source )
{
2016-03-30 14:20:52 -07:00
List < object > results = new List < object >();
2016-07-29 13:02:49 -07:00
// Create the text reader to hold the content
TextReader textReader = new StringReader ( source );
XmlReader xmlReader = XmlReader . Create ( textReader , InternalDeserializer . XmlReaderSettingsForCliXml );
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
// Deserialize the content
Deserializer deserializer = new Deserializer ( xmlReader );
while (! deserializer . Done ())
{
object result = deserializer . Deserialize ();
results . Add ( result );
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
return results . ToArray ();
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
/// <summary>
2019-01-06 04:40:24 +05:00
/// Default depth of serialization.
2016-07-29 13:02:49 -07:00
/// </summary>
2020-11-05 03:36:23 +00:00
private static readonly int s_mshDefaultSerializationDepth = 1 ;
2016-07-29 13:02:49 -07:00
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
/// <summary>
2019-01-06 04:40:24 +05:00
/// This class provides functionality for serializing a PSObject.
2016-07-29 13:02:49 -07:00
/// </summary>
internal class Serializer
{
#region constructor
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
private readonly InternalSerializer _serializer ;
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
/// <summary>
2019-01-06 04:40:24 +05:00
/// Creates a Serializer using default serialization context.
2016-07-29 13:02:49 -07:00
/// </summary>
2018-12-29 08:25:49 +05:00
/// <param name="writer">Writer to be used for serialization.</param>
2016-07-29 13:02:49 -07:00
internal Serializer ( XmlWriter writer )
: this ( writer , new SerializationContext ())
{
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
/// <summary>
2019-01-06 04:40:24 +05:00
/// Creates a Serializer using specified serialization context.
2016-07-29 13:02:49 -07:00
/// </summary>
2018-12-29 08:25:49 +05:00
/// <param name="writer">Writer to be used for serialization.</param>
/// <param name="depth">Depth of serialization.</param>
2016-07-29 13:02:49 -07:00
/// <param name="useDepthFromTypes">
2020-11-24 04:35:46 +00:00
/// if <see langword="true"/> then types.ps1xml can override depth
2016-07-29 13:02:49 -07:00
/// for a particular types (using SerializationDepth property)
/// </param>
internal Serializer ( XmlWriter writer , int depth , bool useDepthFromTypes )
: this ( writer , new SerializationContext ( depth , useDepthFromTypes ))
{
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
/// <summary>
2019-01-06 04:40:24 +05:00
/// Creates a Serializer using specified serialization context.
2016-07-29 13:02:49 -07:00
/// </summary>
2018-12-29 08:25:49 +05:00
/// <param name="writer">Writer to be used for serialization.</param>
/// <param name="context">Serialization context.</param>
2016-07-29 13:02:49 -07:00
internal Serializer ( XmlWriter writer , SerializationContext context )
{
2020-07-30 16:06:38 -07:00
if ( writer == null )
2016-07-29 13:02:49 -07:00
{
2020-05-19 19:57:52 +01:00
throw PSTraceSource . NewArgumentException ( nameof ( writer ));
2016-07-29 13:02:49 -07:00
}
2018-12-23 22:20:06 -08:00
2020-07-30 16:06:38 -07:00
if ( context == null )
2016-07-29 13:02:49 -07:00
{
2020-05-19 19:57:52 +01:00
throw PSTraceSource . NewArgumentException ( nameof ( context ));
2016-07-29 13:02:49 -07:00
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
_serializer = new InternalSerializer ( writer , context );
_serializer . Start ();
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
#endregion constructor
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
#region public methods / properties
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
/// <summary>
/// Used by Remoting infrastructure. This TypeTable instance
/// will be used by Serializer if ExecutionContext is not
2016-08-28 05:44:55 +00:00
/// available (to get the ExecutionContext's TypeTable)
2016-07-29 13:02:49 -07:00
/// </summary>
internal TypeTable TypeTable
{
get { return _serializer . TypeTable ; }
2018-12-23 22:20:06 -08:00
2016-07-29 13:02:49 -07:00
set { _serializer . TypeTable = value ; }
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
/// <summary>
2019-01-06 04:40:24 +05:00
/// Serializes the object.
2016-07-29 13:02:49 -07:00
/// </summary>
2018-12-29 08:25:49 +05:00
/// <param name="source">Object to be serialized.</param>
2016-07-29 13:02:49 -07:00
/// <remarks>
2017-01-16 13:31:14 -08:00
/// Please note that this method shouldn't throw any exceptions.
2016-07-29 13:02:49 -07:00
/// If it throws - please open a bug.
/// </remarks>
internal void Serialize ( object source )
{
Serialize ( source , null );
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
/// <summary>
2019-01-06 04:40:24 +05:00
/// Serializes passed in object.
2016-07-29 13:02:49 -07:00
/// </summary>
/// <param name="source">
/// object to be serialized
/// </param>
/// <param name="streamName">
/// Stream to which this object belong. Ex: Output, Error etc.
/// </param>
/// <remarks>
2017-01-16 13:31:14 -08:00
/// Please note that this method shouldn't throw any exceptions.
2016-07-29 13:02:49 -07:00
/// If it throws - please open a bug.
/// </remarks>
internal void Serialize ( object source , string streamName )
{
_serializer . WriteOneTopLevelObject ( source , streamName );
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
/// <summary>
2019-01-06 04:40:24 +05:00
/// Write the end of root element.
2016-07-29 13:02:49 -07:00
/// </summary>
internal void Done ()
{
_serializer . End ();
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
internal void Stop ()
{
_serializer . Stop ();
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
#endregion
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
[Flags]
internal enum DeserializationOptions
{
None = 0 ,
2017-01-16 13:31:14 -08:00
NoRootElement = 256 , // I start at 256 to try not to overlap
2016-07-29 13:02:49 -07:00
NoNamespace = 512 , // with SerializationOptions and to catch bugs early
DeserializeScriptBlocks = 1024 ,
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
RemotingOptions = NoRootElement | NoNamespace ,
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
internal class DeserializationContext
{
internal DeserializationContext ()
: this ( DeserializationOptions . None , null )
{
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
internal DeserializationContext ( DeserializationOptions options , PSRemotingCryptoHelper cryptoHelper )
{
this . options = options ;
this . cryptoHelper = cryptoHelper ;
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
/// <summary>
/// Limits the total data processed by the deserialization context. Deserialization context
/// is used by PriorityReceivedDataCollection (remoting) to process incoming data from the
/// remote end. A value of Null means that the max memory is unlimited.
/// </summary>
2020-11-05 05:05:50 +00:00
internal int? MaximumAllowedMemory { get ; set ; }
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
/// <summary>
/// Logs that memory used by deserialized objects is not related to the size of input xml.
/// Used mainly to account for memory usage of cloned TypeNames when calculating memory quota usage.
/// </summary>
/// <param name="amountOfExtraMemory"></param>
internal void LogExtraMemoryUsage ( int amountOfExtraMemory )
{
if ( amountOfExtraMemory < 0 )
{
return ;
}
2016-03-30 14:20:52 -07:00
2016-08-02 13:29:09 -07:00
if ( MaximumAllowedMemory . HasValue )
2016-07-29 13:02:49 -07:00
{
2016-08-02 13:29:09 -07:00
if ( amountOfExtraMemory > ( MaximumAllowedMemory . Value - _totalDataProcessedSoFar ))
2016-07-29 13:02:49 -07:00
{
2016-08-02 13:29:09 -07:00
string message = StringUtil . Format ( Serialization . DeserializationMemoryQuota , (( double ) MaximumAllowedMemory . Value ) / ( 1 << 20 ),
2016-07-29 13:02:49 -07:00
ConfigurationDataFromXML . MAXRCVDOBJSIZETOKEN_CamelCase ,
ConfigurationDataFromXML . MAXRCVDCMDSIZETOKEN_CamelCase );
throw new XmlException ( message );
}
2016-03-30 14:20:52 -07:00
2020-11-05 04:48:13 +00:00
_totalDataProcessedSoFar += amountOfExtraMemory ;
2016-07-29 13:02:49 -07:00
}
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
private int _totalDataProcessedSoFar ;
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
internal readonly DeserializationOptions options ;
internal readonly PSRemotingCryptoHelper cryptoHelper ;
2016-03-30 14:20:52 -07:00
2020-05-31 06:10:22 +01:00
internal static readonly int MaxItemsInCimClassCache = 100 ;
2016-07-29 13:02:49 -07:00
internal readonly CimClassDeserializationCache < CimClassSerializationId > cimClassSerializationIdCache = new CimClassDeserializationCache < CimClassSerializationId >();
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
internal class CimClassDeserializationCache < TKey >
{
private readonly Dictionary < TKey , CimClass > _cimClassIdToClass = new Dictionary < TKey , CimClass >();
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
internal void AddCimClassToCache ( TKey key , CimClass cimClass )
{
if ( _cimClassIdToClass . Count >= DeserializationContext . MaxItemsInCimClassCache )
{
_cimClassIdToClass . Clear ();
}
2018-12-23 22:20:06 -08:00
2016-07-29 13:02:49 -07:00
_cimClassIdToClass . Add ( key , cimClass );
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
/* PRINTF DEBUG
2017-09-04 19:45:51 -07:00
Console.WriteLine("Contents of deserialization cache (after a call to AddCimClassToCache ({0})):", key);
2017-04-14 00:45:46 +04:00
Console.WriteLine(" Count = {0}", this._cimClassIdToClass.Count);
foreach (var t in this._cimClassIdToClass.Keys)
{
Console.WriteLine(" {0}", t);
}
*/
2016-07-29 13:02:49 -07:00
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
internal CimClass GetCimClassFromCache ( TKey key )
{
CimClass cimClass ;
if ( _cimClassIdToClass . TryGetValue ( key , out cimClass ))
{
/* PRINTF DEBUG
2017-04-14 00:45:46 +04:00
Console.WriteLine("GetCimClassFromCache - class found: {0}", key);
*/
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
return cimClass ;
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
/* PRINTF DEBUG
2017-04-14 00:45:46 +04:00
Console.WriteLine("GetCimClassFromCache - class NOT found: {0}", key);
*/
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
return null ;
}
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
internal class CimClassSerializationCache < TKey >
{
private readonly HashSet < TKey > _cimClassesHeldByDeserializer = new HashSet < TKey >( EqualityComparer < TKey >. Default );
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
internal bool DoesDeserializerAlreadyHaveCimClass ( TKey key )
{
return _cimClassesHeldByDeserializer . Contains ( key );
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
internal void AddClassToCache ( TKey key )
{
Dbg . Assert (! _cimClassesHeldByDeserializer . Contains ( key ), "This method should not be called for classes already in the cache" );
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
if ( _cimClassesHeldByDeserializer . Count >= DeserializationContext . MaxItemsInCimClassCache )
{
_cimClassesHeldByDeserializer . Clear ();
}
2018-12-23 22:20:06 -08:00
2016-07-29 13:02:49 -07:00
_cimClassesHeldByDeserializer . Add ( key );
/* PRINTF DEBUG
2017-04-14 00:45:46 +04:00
Console.WriteLine("Contents of serialization cache (after adding {0}):", key);
Console.WriteLine(" Count = {0}", this._cimClassesHeldByDeserializer.Count);
foreach (var t in _cimClassesHeldByDeserializer)
{
Console.WriteLine(" {0}", t);
}
*/
2016-07-29 13:02:49 -07:00
}
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
internal class CimClassSerializationId : Tuple < string , string , string , int >
{
public CimClassSerializationId ( string className , string namespaceName , string computerName , int hashCode )
: base ( className , namespaceName , computerName , hashCode )
{
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
public string ClassName { get { return this . Item1 ; } }
2018-12-23 22:20:06 -08:00
2016-07-29 13:02:49 -07:00
public string NamespaceName { get { return this . Item2 ; } }
2018-12-23 22:20:06 -08:00
2016-07-29 13:02:49 -07:00
public string ComputerName { get { return this . Item3 ; } }
2018-12-23 22:20:06 -08:00
2016-07-29 13:02:49 -07:00
public int ClassHashCode { get { return this . Item4 ; } }
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
/// <summary>
2019-01-06 04:40:24 +05:00
/// This class provides functionality for deserializing a PSObject.
2016-07-29 13:02:49 -07:00
/// </summary>
internal class Deserializer
{
#region constructor
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
private readonly XmlReader _reader ;
private readonly InternalDeserializer _deserializer ;
private readonly DeserializationContext _context ;
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
/// <summary>
2019-01-06 04:40:24 +05:00
/// Creates a Deserializer using default deserialization context.
2016-07-29 13:02:49 -07:00
/// </summary>
2018-12-29 08:25:49 +05:00
/// <param name="reader">Reader to be used for deserialization.</param>
2016-07-29 13:02:49 -07:00
/// <exception cref="XmlException">
/// Thrown when the xml is in an incorrect format
/// </exception>
internal Deserializer ( XmlReader reader )
: this ( reader , new DeserializationContext ())
{
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
/// <summary>
2019-01-06 04:40:24 +05:00
/// Creates a Deserializer using specified serialization context.
2016-07-29 13:02:49 -07:00
/// </summary>
2018-12-29 08:25:49 +05:00
/// <param name="reader">Reader to be used for deserialization.</param>
/// <param name="context">Serialization context.</param>
2016-07-29 13:02:49 -07:00
/// <exception cref="XmlException">
/// Thrown when the xml is in an incorrect format
/// </exception>
internal Deserializer ( XmlReader reader , DeserializationContext context )
{
2020-07-30 16:06:38 -07:00
if ( reader == null )
2016-07-29 13:02:49 -07:00
{
2020-05-19 19:57:52 +01:00
throw PSTraceSource . NewArgumentNullException ( nameof ( reader ));
2016-07-29 13:02:49 -07:00
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
_reader = reader ;
_context = context ;
_deserializer = new InternalDeserializer ( _reader , _context );
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
try
{
Start ();
}
catch ( XmlException exception )
{
ReportExceptionForETW ( exception );
throw ;
}
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
#endregion constructor
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
#region public method / properties
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
private static void ReportExceptionForETW ( XmlException exception )
{
PSEtwLog . LogAnalyticError (
PSEventId . Serializer_XmlExceptionWhenDeserializing , PSOpcode . Exception , PSTask . Serialization ,
PSKeyword . Serializer | PSKeyword . UseAlwaysAnalytic ,
exception . LineNumber , exception . LinePosition , exception . ToString ());
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
private bool _done = false ;
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
/// <summary>
/// Used by Remoting infrastructure. This TypeTable instance
/// will be used by Deserializer if ExecutionContext is not
2016-08-28 05:44:55 +00:00
/// available (to get the ExecutionContext's TypeTable)
2016-07-29 13:02:49 -07:00
/// </summary>
internal TypeTable TypeTable
{
get { return _deserializer . TypeTable ; }
2018-12-23 22:20:06 -08:00
2016-07-29 13:02:49 -07:00
set { _deserializer . TypeTable = value ; }
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
/// <summary>
2017-01-16 13:31:14 -08:00
/// Read the root element tag and set the cursor to start tag of
2016-07-29 13:02:49 -07:00
/// first object.
/// </summary>
private void Start ()
{
Dbg . Assert ( _reader . ReadState == ReadState . Initial , "When deserialization starts we should have XmlReader.ReadState == Initial" );
Dbg . Assert ( _reader . NodeType == XmlNodeType . None , "When deserialization starts we should have XmlReader.NodeType == None" );
_reader . Read ();
2016-03-30 14:20:52 -07:00
2019-01-06 06:51:20 +05:00
// If version is not provided, we assume it is the default
2016-07-29 13:02:49 -07:00
string version = InternalSerializer . DefaultVersion ;
2020-11-20 12:26:46 +00:00
if (( _context . options & DeserializationOptions . NoRootElement ) == DeserializationOptions . NoRootElement )
2016-07-29 13:02:49 -07:00
{
_done = _reader . EOF ;
}
else
{
// Make sure the reader is positioned on the root ( <Objs> ) element (not on XmlDeclaration for example)
_reader . MoveToContent ();
Dbg . Assert ( _reader . EOF || ( _reader . NodeType == XmlNodeType . Element ), "When deserialization starts reading we should have XmlReader.NodeType == Element" );
2016-03-30 14:20:52 -07:00
2019-01-06 06:51:20 +05:00
// Read version attribute and validate it.
2016-07-29 13:02:49 -07:00
string versionAttribute = _reader . GetAttribute ( SerializationStrings . VersionAttribute );
if ( versionAttribute != null )
{
version = versionAttribute ;
}
2016-03-30 14:20:52 -07:00
2019-01-06 06:51:20 +05:00
// If the root element tag is empty, there are no objects to read.
2016-07-29 13:02:49 -07:00
if (! _deserializer . ReadStartElementAndHandleEmpty ( SerializationStrings . RootElementTag ))
{
_done = true ;
}
}
2018-12-23 22:20:06 -08:00
2016-07-29 13:02:49 -07:00
_deserializer . ValidateVersion ( version );
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
internal bool Done ()
{
2020-11-13 04:39:25 +00:00
if (! _done )
2016-07-29 13:02:49 -07:00
{
2020-11-20 12:26:46 +00:00
if (( _context . options & DeserializationOptions . NoRootElement ) == DeserializationOptions . NoRootElement )
2016-07-29 13:02:49 -07:00
{
_done = _reader . EOF ;
}
else
{
if ( _reader . NodeType == XmlNodeType . EndElement )
{
try
{
_reader . ReadEndElement ();
}
catch ( XmlException exception )
{
ReportExceptionForETW ( exception );
throw ;
}
2018-12-23 22:20:06 -08:00
2016-07-29 13:02:49 -07:00
_done = true ;
}
}
}
2018-12-23 22:20:06 -08:00
2016-07-29 13:02:49 -07:00
return _done ;
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
internal void Stop ()
{
_deserializer . Stop ();
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
/// <summary>
/// Deserializes next object.
/// </summary>
/// <exception cref="XmlException">
/// Thrown when the xml is in an incorrect format
/// </exception>
internal object Deserialize ()
{
string ignore ;
return Deserialize ( out ignore );
}
2016-03-30 14:20:52 -07:00
/// <summary>
/// Deserializes next object.
/// </summary>
2018-12-29 08:25:49 +05:00
/// <param name="streamName">Stream the object belongs to (i.e. "Error", "Output", etc.).</param>
2016-03-30 14:20:52 -07:00
/// <exception cref="XmlException">
/// Thrown when the xml is in an incorrect format
/// </exception>
internal object Deserialize ( out string streamName )
{
if ( Done ())
{
throw PSTraceSource . NewInvalidOperationException ( Serialization . ReadCalledAfterDone );
}
try
{
return _deserializer . ReadOneObject ( out streamName );
}
catch ( XmlException exception )
{
ReportExceptionForETW ( exception );
throw ;
}
}
2016-07-29 13:02:49 -07:00
#endregion public methods
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
#region Helper methods for dealing with "Deserialized." prefix
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
/// <summary>
2019-01-06 04:40:24 +05:00
/// Adds "Deserialized." prefix to passed in argument if not already present.
2016-07-29 13:02:49 -07:00
/// </summary>
/// <param name="type"></param>
internal static void AddDeserializationPrefix ( ref string type )
{
Dbg . Assert ( type != null , "caller should validate the parameter" );
if (! type . StartsWith ( Deserializer . DeserializationTypeNamePrefix , StringComparison . OrdinalIgnoreCase ))
{
type = type . Insert ( 0 , Deserializer . DeserializationTypeNamePrefix );
}
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
/// <summary>
/// Checks if an object <paramref name="o"/> is either a live or deserialized instance of class <paramref name="type"/> or one of its subclasses.
/// </summary>
/// <param name="o"></param>
/// <param name="type"></param>
2020-11-24 04:35:46 +00:00
/// <returns><see langword="true"/> if <paramref name="o"/> is either a live or deserialized instance of class <paramref name="type"/> or one of its subclasses; <see langword="false"/> otherwise.</returns>
2016-07-29 13:02:49 -07:00
internal static bool IsInstanceOfType ( object o , Type type )
{
2020-07-30 16:06:38 -07:00
if ( type == null )
2016-07-29 13:02:49 -07:00
{
2020-05-19 19:57:52 +01:00
throw PSTraceSource . NewArgumentNullException ( nameof ( type ));
2016-07-29 13:02:49 -07:00
}
2018-12-23 22:20:06 -08:00
2020-07-30 16:06:38 -07:00
if ( o == null )
2016-07-29 13:02:49 -07:00
{
return false ;
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
return type . IsInstanceOfType ( PSObject . Base ( o )) || IsDeserializedInstanceOfType ( o , type );
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
/// <summary>
/// Checks if an object <paramref name="o"/> is a deserialized instance of class <paramref name="type"/> or one of its subclasses.
/// </summary>
/// <param name="o"></param>
/// <param name="type"></param>
2020-11-24 04:35:46 +00:00
/// <returns><see langword="true"/> if <paramref name="o"/> is a deserialized instance of class <paramref name="type"/> or one of its subclasses; <see langword="false"/> otherwise.</returns>
2016-07-29 13:02:49 -07:00
internal static bool IsDeserializedInstanceOfType ( object o , Type type )
{
2020-07-30 16:06:38 -07:00
if ( type == null )
2016-07-29 13:02:49 -07:00
{
2020-05-19 19:57:52 +01:00
throw PSTraceSource . NewArgumentNullException ( nameof ( type ));
2016-07-29 13:02:49 -07:00
}
2018-12-23 22:20:06 -08:00
2020-07-30 16:06:38 -07:00
if ( o == null )
2016-07-29 13:02:49 -07:00
{
return false ;
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
PSObject pso = o as PSObject ;
if ( pso != null )
{
IEnumerable < string > typeNames = pso . InternalTypeNames ;
if ( typeNames != null )
{
foreach ( string typeName in typeNames )
{
if ( typeName . Length == Deserializer . DeserializationTypeNamePrefix . Length + type . FullName . Length &&
typeName . StartsWith ( Deserializer . DeserializationTypeNamePrefix , StringComparison . OrdinalIgnoreCase ) &&
typeName . EndsWith ( type . FullName , StringComparison . OrdinalIgnoreCase ))
{
return true ;
}
}
}
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
// not the right type
return false ;
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
internal static string MaskDeserializationPrefix ( string typeName )
{
2020-07-30 16:06:38 -07:00
if ( typeName == null )
2016-07-29 13:02:49 -07:00
{
return null ;
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
if ( typeName . StartsWith ( Deserializer . DeserializationTypeNamePrefix , StringComparison . OrdinalIgnoreCase ))
{
typeName = typeName . Substring ( Deserializer . DeserializationTypeNamePrefix . Length );
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
return typeName ;
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
/// <summary>
/// Gets a new collection of typenames without "Deserialization." prefix
2017-01-16 13:31:14 -08:00
/// in the typename. This will allow to map type info/format info of the orignal type
2016-07-29 13:02:49 -07:00
/// for deserialized objects.
/// </summary>
/// <param name="typeNames"></param>
/// <returns>
/// Null if no type with "Deserialized." prefix is found.
/// Otherwise <paramref name="typeNames"/> with the prefix removed if any.
/// </returns>
internal static Collection < string > MaskDeserializationPrefix ( Collection < string > typeNames )
{
2018-06-26 02:37:09 +05:00
Dbg . Assert ( typeNames != null , "typeNames cannot be null" );
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
bool atleastOneDeserializedTypeFound = false ;
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
Collection < string > typesWithoutPrefix = new Collection < string >();
foreach ( string type in typeNames )
{
if ( type . StartsWith ( Deserializer . DeserializationTypeNamePrefix ,
StringComparison . OrdinalIgnoreCase ))
{
atleastOneDeserializedTypeFound = true ;
// remove *only* the prefix
typesWithoutPrefix . Add ( type . Substring ( Deserializer . DeserializationTypeNamePrefix . Length ));
}
else
{
typesWithoutPrefix . Add ( type );
}
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
if ( atleastOneDeserializedTypeFound )
{
return typesWithoutPrefix ;
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
return null ;
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
/// <summary>
/// Used to prefix a typename for deserialization.
/// </summary>
private const string DeserializationTypeNamePrefix = "Deserialized." ;
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
#endregion
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
/// <summary>
2019-01-06 04:40:24 +05:00
/// Types of known type container supported by monad.
2016-07-29 13:02:49 -07:00
/// </summary>
internal enum ContainerType
{
Dictionary ,
Queue ,
Stack ,
List ,
Enumerable ,
None
2020-11-21 14:26:44 +00:00
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
/// <summary>
/// This internal helper class provides methods for serializing mshObject.
/// </summary>
internal class InternalSerializer
{
#region constructor
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
internal const string DefaultVersion = "1.1.0.1" ;
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
/// <summary>
2019-01-06 04:40:24 +05:00
/// Xml writer to be used.
2016-07-29 13:02:49 -07:00
/// </summary>
private readonly XmlWriter _writer ;
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
/// <summary>
2019-01-06 04:40:24 +05:00
/// Serialization context.
2016-07-29 13:02:49 -07:00
/// </summary>
private readonly SerializationContext _context ;
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
/// Used by Remoting infrastructure. This TypeTable instance
/// will be used by Serializer if ExecutionContext is not
2016-08-28 05:44:55 +00:00
/// available (to get the ExecutionContext's TypeTable)
2016-07-29 13:02:49 -07:00
private TypeTable _typeTable ;
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
/// <summary>
/// Depth below top level - used to prevent infinitely deep serialization
/// (without this protection it would be possible i.e. with SerializationDepth and recursion)
/// </summary>
private int _depthBelowTopLevel ;
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
private const int MaxDepthBelowTopLevel = 50 ;
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
private readonly ReferenceIdHandlerForSerializer < object > _objectRefIdHandler ;
private readonly ReferenceIdHandlerForSerializer < ConsolidatedString > _typeRefIdHandler ;
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
internal InternalSerializer ( XmlWriter writer , SerializationContext context )
{
Dbg . Assert ( writer != null , "caller should validate the parameter" );
Dbg . Assert ( context != null , "caller should validate the parameter" );
_writer = writer ;
_context = context ;
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
IDictionary < object , ulong > objectRefIdDictionary = null ;
if (( _context . options & SerializationOptions . NoObjectRefIds ) == 0 )
{
objectRefIdDictionary = new WeakReferenceDictionary < UInt64 >();
}
2018-12-23 22:20:06 -08:00
2016-07-29 13:02:49 -07:00
_objectRefIdHandler = new ReferenceIdHandlerForSerializer < object >( objectRefIdDictionary );
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
_typeRefIdHandler = new ReferenceIdHandlerForSerializer < ConsolidatedString >(
new Dictionary < ConsolidatedString , UInt64 >( ConsolidatedString . EqualityComparer ));
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
#endregion
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
/// <summary>
/// Used by Remoting infrastructure. This TypeTable instance
/// will be used by Serializer if ExecutionContext is not
2016-08-28 05:44:55 +00:00
/// available (to get the ExecutionContext's TypeTable)
2016-07-29 13:02:49 -07:00
/// </summary>
internal TypeTable TypeTable
{
get { return _typeTable ; }
2018-12-23 22:20:06 -08:00
2016-07-29 13:02:49 -07:00
set { _typeTable = value ; }
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
/// <summary>
2019-01-06 04:40:24 +05:00
/// Writes the start of root element.
2016-07-29 13:02:49 -07:00
/// </summary>
internal void Start ()
{
2020-11-20 12:26:46 +00:00
if (( _context . options & SerializationOptions . NoRootElement ) != SerializationOptions . NoRootElement )
2016-07-29 13:02:49 -07:00
{
this . WriteStartElement ( SerializationStrings . RootElementTag );
this . WriteAttribute ( SerializationStrings . VersionAttribute , InternalSerializer . DefaultVersion );
}
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
/// <summary>
2019-01-06 04:40:24 +05:00
/// Writes the end of root element.
2016-07-29 13:02:49 -07:00
/// </summary>
internal void End ()
{
2020-11-20 12:26:46 +00:00
if (( _context . options & SerializationOptions . NoRootElement ) != SerializationOptions . NoRootElement )
2016-07-29 13:02:49 -07:00
{
_writer . WriteEndElement ();
}
2018-12-23 22:20:06 -08:00
2016-07-29 13:02:49 -07:00
_writer . Flush ();
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
private bool _isStopping = false ;
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
/// <summary>
2019-01-06 04:40:24 +05:00
/// Called from a separate thread will stop the serialization process.
2016-07-29 13:02:49 -07:00
/// </summary>
internal void Stop ()
{
_isStopping = true ;
}
2016-03-30 14:20:52 -07:00
private void CheckIfStopping ()
{
2016-07-29 13:02:49 -07:00
if ( _isStopping )
2016-03-30 14:20:52 -07:00
{
throw PSTraceSource . NewInvalidOperationException ( Serialization . Stopping );
}
}
2016-07-29 13:02:49 -07:00
internal static bool IsPrimitiveKnownType ( Type input )
{
2019-01-06 06:51:20 +05:00
// Check if source is of primitive known type
2016-07-29 13:02:49 -07:00
TypeSerializationInfo pktInfo = KnownTypes . GetTypeSerializationInfo ( input );
return ( pktInfo != null );
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
/// <summary>
/// This writes one object.
/// </summary>
/// <param name="source">
/// source to be serialized.
/// </param>
/// <param name="streamName">
/// Stream to which source belongs
/// </param>
internal void WriteOneTopLevelObject
(
object source ,
string streamName
)
{
Dbg . Assert ( _depthBelowTopLevel == 0 , "InternalSerializer.depthBelowTopLevel should be 0 at top-level" );
WriteOneObject ( source , streamName , null , _context . depth );
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
private void WriteOneObject
(
object source ,
string streamName ,
string property ,
int depth
)
{
Dbg . Assert ( depth >= 0 , "depth should always be greater or equal to zero" );
this . CheckIfStopping ();
2016-03-30 14:20:52 -07:00
2020-07-30 16:06:38 -07:00
if ( source == null )
2016-07-29 13:02:49 -07:00
{
WriteNull ( streamName , property );
return ;
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
try
{
_depthBelowTopLevel ++;
Dbg . Assert ( _depthBelowTopLevel <= MaxDepthBelowTopLevel , "depthBelowTopLevel should be <= MaxDepthBelowTopLevel" );
if ( HandleMaxDepth ( source , streamName , property ))
{
return ;
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
depth = GetDepthOfSerialization ( source , depth );
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
if ( HandlePrimitiveKnownTypeByConvertingToPSObject ( source , streamName , property , depth ))
{
return ;
}
2016-03-30 14:20:52 -07:00
2019-01-06 06:51:20 +05:00
// Object is not of primitive known type. Check if this has
// already been serialized.
2016-07-29 13:02:49 -07:00
string refId = _objectRefIdHandler . GetRefId ( source );
if ( refId != null )
{
WritePSObjectReference ( streamName , property , refId );
return ;
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
if ( HandlePrimitiveKnownTypePSObject ( source , streamName , property , depth ))
{
return ;
}
2016-03-30 14:20:52 -07:00
2019-01-06 06:51:20 +05:00
// Note: We do not use containers in depth calculation. i.e even if the
// current depth is zero, we serialize the container. All contained items will
// get serialized with depth zero.
2016-07-29 13:02:49 -07:00
if ( HandleKnownContainerTypes ( source , streamName , property , depth ))
{
return ;
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
PSObject mshSource = PSObject . AsPSObject ( source );
2019-01-06 06:51:20 +05:00
// If depth is zero, complex type should be serialized as string.
2016-07-29 13:02:49 -07:00
if ( depth == 0 || SerializeAsString ( mshSource ))
{
HandlePSObjectAsString ( mshSource , streamName , property , depth );
return ;
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
HandleComplexTypePSObject ( source , streamName , property , depth );
return ;
}
finally
{
_depthBelowTopLevel --;
Dbg . Assert ( _depthBelowTopLevel >= 0 , "depthBelowTopLevel should be >= 0" );
}
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
private bool HandleMaxDepth ( object source , string streamName , string property )
{
if ( _depthBelowTopLevel == MaxDepthBelowTopLevel )
{
// assert commented out because of clashes with Wei's tests
// Dbg.Assert(false, "We should never reach MaxDepthBelowTopLevel with non-malicious input");
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
PSEtwLog . LogAnalyticError ( PSEventId . Serializer_MaxDepthWhenSerializing , PSOpcode . Exception ,
PSTask . Serialization , PSKeyword . Serializer , source . GetType (). AssemblyQualifiedName , property , _depthBelowTopLevel );
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
string content = Serialization . DeserializationTooDeep ;
HandlePrimitiveKnownType ( content , streamName , property );
return true ;
}
else
{
return false ;
}
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
/// <summary>
/// Serializes Primitive Known Types.
/// </summary>
/// <returns>
/// true if source is handled, else false.
/// </returns>
private bool HandlePrimitiveKnownType
(
object source ,
string streamName ,
string property
)
{
Dbg . Assert ( source != null , "caller should validate the parameter" );
2019-01-06 06:51:20 +05:00
// Check if source is of primitive known type
2016-07-29 13:02:49 -07:00
TypeSerializationInfo pktInfo = KnownTypes . GetTypeSerializationInfo ( source . GetType ());
if ( pktInfo != null )
{
WriteOnePrimitiveKnownType ( this , streamName , property , source , pktInfo );
return true ;
}
2018-12-23 22:20:06 -08:00
2016-07-29 13:02:49 -07:00
return false ;
}
/// <summary>
/// Handles primitive known type by first converting it to a PSObject.In W8, extended
2016-08-28 05:44:55 +00:00
/// property data is stored external to PSObject. By converting to PSObject, we will
2016-07-29 13:02:49 -07:00
/// be able to retrieve and serialize the extended properties. This is tracked by
2019-01-06 04:40:24 +05:00
/// Win8: 414042.
2016-07-29 13:02:49 -07:00
/// </summary>
/// <param name="source"></param>
/// <param name="streamName"></param>
/// <param name="property"></param>
/// <param name="depth"></param>
/// <returns></returns>
private bool HandlePrimitiveKnownTypeByConvertingToPSObject (
object source ,
string streamName ,
string property ,
int depth
)
{
Dbg . Assert ( source != null , "caller should validate the parameter" );
2019-01-06 06:51:20 +05:00
// Check if source is of primitive known type
2016-07-29 13:02:49 -07:00
TypeSerializationInfo pktInfo = KnownTypes . GetTypeSerializationInfo ( source . GetType ());
if ( pktInfo != null )
{
PSObject pktInfoPSObject = PSObject . AsPSObject ( source );
return HandlePrimitiveKnownTypePSObject ( pktInfoPSObject , streamName , property , depth );
}
2018-12-23 22:20:06 -08:00
2016-07-29 13:02:49 -07:00
return false ;
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
/// <summary>
/// </summary>
/// <param name="source"></param>
/// <param name="streamName"></param>
/// <param name="property"></param>
/// <returns></returns>
private bool HandleSecureString ( object source , string streamName , string property )
{
Dbg . Assert ( source != null , "caller should validate the parameter" );
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
SecureString secureString = null ;
secureString = source as SecureString ;
PSObject moSource ;
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
if ( secureString != null )
{
moSource = PSObject . AsPSObject ( secureString );
}
else
{
moSource = source as PSObject ;
}
2016-03-30 14:20:52 -07:00
2019-03-21 02:43:52 +01:00
if ( moSource != null && ! moSource . ImmediateBaseObjectIsEmpty )
2016-07-29 13:02:49 -07:00
{
// check if source is of type secure string
2016-03-30 14:20:52 -07:00
secureString = moSource . ImmediateBaseObject as SecureString ;
if ( secureString != null )
2016-07-29 13:02:49 -07:00
{
// the principle used in serialization is that serialization
// never throws, and if something can't be serialized nothing
2019-02-07 15:36:13 -08:00
// is written. So we write the elements only if encryption succeeds.
// However, in the case for non-Windows where secure string encryption
// is not yet supported, a PSCryptoException will be thrown.
string encryptedString ;
if ( _context . cryptoHelper != null )
2016-07-29 13:02:49 -07:00
{
2019-02-07 15:36:13 -08:00
encryptedString = _context . cryptoHelper . EncryptSecureString ( secureString );
2016-07-29 13:02:49 -07:00
}
2019-02-07 15:36:13 -08:00
else
2016-07-29 13:02:49 -07:00
{
2019-02-07 15:36:13 -08:00
encryptedString = Microsoft . PowerShell . SecureStringHelper . Protect ( secureString );
2016-07-29 13:02:49 -07:00
}
2019-02-07 15:36:13 -08:00
if ( property != null )
{
WriteStartElement ( SerializationStrings . SecureStringTag );
WriteNameAttribute ( property );
}
else
{
WriteStartElement ( SerializationStrings . SecureStringTag );
}
if ( streamName != null )
{
WriteAttribute ( SerializationStrings . StreamNameAttribute , streamName );
}
// Note: We do not use WriteRaw for serializing secure string. WriteString
// does necessary escaping which may be needed for certain
// characters.
_writer . WriteString ( encryptedString );
_writer . WriteEndElement ();
return true ;
2018-12-08 18:53:30 +02:00
}
2016-07-29 13:02:49 -07:00
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
return false ;
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
/// <summary>
2019-01-06 04:40:24 +05:00
/// Serializes PSObject whose base objects are of primitive known type.
2016-07-29 13:02:49 -07:00
/// </summary>
/// <param name="source"></param>
/// <param name="streamName"></param>
/// <param name="property"></param>
/// <param name="depth"></param>
/// <returns>
/// true if source is handled, else false.
/// </returns>
private bool HandlePrimitiveKnownTypePSObject
(
object source ,
string streamName ,
string property ,
int depth
)
{
Dbg . Assert ( source != null , "caller should validate the parameter" );
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
bool sourceHandled = false ;
PSObject moSource = source as PSObject ;
2019-03-21 02:43:52 +01:00
if ( moSource != null && ! moSource . ImmediateBaseObjectIsEmpty )
2016-07-29 13:02:49 -07:00
{
2019-01-06 06:51:20 +05:00
// Check if baseObject is primitive known type
2016-07-29 13:02:49 -07:00
object baseObject = moSource . ImmediateBaseObject ;
TypeSerializationInfo pktInfo = KnownTypes . GetTypeSerializationInfo ( baseObject . GetType ());
if ( pktInfo != null )
{
WritePrimitiveTypePSObject ( moSource , baseObject , pktInfo , streamName , property , depth );
sourceHandled = true ;
}
}
2018-12-23 22:20:06 -08:00
2016-07-29 13:02:49 -07:00
return sourceHandled ;
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
private bool HandleKnownContainerTypes
(
object source ,
string streamName ,
string property ,
int depth
)
{
Dbg . Assert ( source != null , "caller should validate the parameter" );
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
ContainerType ct = ContainerType . None ;
PSObject mshSource = source as PSObject ;
IEnumerable enumerable = null ;
IDictionary dictionary = null ;
2016-03-30 14:20:52 -07:00
2019-01-06 06:51:20 +05:00
// If passed in object is PSObject with no baseobject, return false.
2019-03-21 02:43:52 +01:00
if ( mshSource != null && mshSource . ImmediateBaseObjectIsEmpty )
2016-07-29 13:02:49 -07:00
{
return false ;
}
2016-03-30 14:20:52 -07:00
2019-01-06 06:51:20 +05:00
// Check if source (or baseobject in mshSource) is known container type
2016-07-29 13:02:49 -07:00
SerializationUtilities . GetKnownContainerTypeInfo ( mshSource != null ? mshSource . ImmediateBaseObject : source , out ct ,
out dictionary , out enumerable );
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
if ( ct == ContainerType . None )
return false ;
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
string refId = _objectRefIdHandler . SetRefId ( source );
WriteStartOfPSObject (
mshSource ?? PSObject . AsPSObject ( source ),
streamName ,
property ,
refId ,
true , // always write TypeNames information for known container types
null ); // never write ToString information for known container types
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
switch ( ct )
{
case ContainerType . Dictionary :
WriteDictionary ( dictionary , SerializationStrings . DictionaryTag , depth );
break ;
case ContainerType . Stack :
WriteEnumerable ( enumerable , SerializationStrings . StackTag , depth );
break ;
case ContainerType . Queue :
WriteEnumerable ( enumerable , SerializationStrings . QueueTag , depth );
break ;
case ContainerType . List :
WriteEnumerable ( enumerable , SerializationStrings . ListTag , depth );
break ;
case ContainerType . Enumerable :
WriteEnumerable ( enumerable , SerializationStrings . CollectionTag , depth );
break ;
default :
Dbg . Assert ( false , "All containers should be handled in the switch" );
break ;
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
if ( depth != 0 )
{
2017-01-16 13:31:14 -08:00
// An object which is original enumerable becomes an PSObject with ArrayList on deserialization.
2016-03-30 14:20:52 -07:00
// So on roundtrip it will show up as List.
2017-01-16 13:31:14 -08:00
// We serialize properties of enumerable and on deserialization mark the object as Deserialized.
2016-03-30 14:20:52 -07:00
// So if object is marked deserialized, we should write properties.
2019-03-21 02:43:52 +01:00
if ( ct == ContainerType . Enumerable || ( mshSource != null && mshSource . IsDeserialized ))
2016-07-29 13:02:49 -07:00
{
PSObject sourceAsPSObject = PSObject . AsPSObject ( source );
2016-03-30 14:20:52 -07:00
PSMemberInfoInternalCollection < PSPropertyInfo > specificPropertiesToSerialize = SerializationUtilities . GetSpecificPropertiesToSerialize ( sourceAsPSObject , AllPropertiesCollection , _typeTable );
2016-07-29 13:02:49 -07:00
WritePSObjectProperties ( sourceAsPSObject , depth , specificPropertiesToSerialize );
SerializeExtendedProperties ( sourceAsPSObject , depth , specificPropertiesToSerialize );
}
// always serialize instance properties if there are any
else if ( mshSource != null )
{
SerializeInstanceProperties ( mshSource , depth );
}
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
_writer . WriteEndElement ();
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
return true ;
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
#region Write PSObject
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
/// <summary>
2019-01-06 04:40:24 +05:00
/// Writes PSObject Reference Element.
2016-07-29 13:02:49 -07:00
/// </summary>
private void WritePSObjectReference
(
string streamName ,
string property ,
string refId
)
{
Dbg . Assert (! string . IsNullOrEmpty ( refId ), "caller should validate the parameter" );
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
WriteStartElement ( SerializationStrings . ReferenceTag );
if ( streamName != null )
{
WriteAttribute ( SerializationStrings . StreamNameAttribute , streamName );
}
2018-12-23 22:20:06 -08:00
2016-07-29 13:02:49 -07:00
if ( property != null )
{
WriteNameAttribute ( property );
}
2018-12-23 22:20:06 -08:00
2016-07-29 13:02:49 -07:00
WriteAttribute ( SerializationStrings . ReferenceIdAttribute , refId );
_writer . WriteEndElement ();
}
2016-03-30 14:20:52 -07:00
2016-08-02 19:00:50 -07:00
private static bool PSObjectHasModifiedTypesCollection ( PSObject pso )
2016-07-29 13:02:49 -07:00
{
ConsolidatedString currentTypes = pso . InternalTypeNames ;
Collection < string > originalTypes = pso . InternalAdapter . BaseGetTypeNameHierarchy ( pso . ImmediateBaseObject );
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
if ( currentTypes . Count != originalTypes . Count )
{
return true ;
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
IEnumerator < string > currentEnumerator = currentTypes . GetEnumerator ();
IEnumerator < string > originalEnumerator = originalTypes . GetEnumerator ();
while ( currentEnumerator . MoveNext () && originalEnumerator . MoveNext ())
{
if (! currentEnumerator . Current . Equals ( originalEnumerator . Current , StringComparison . OrdinalIgnoreCase ))
{
return true ;
}
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
return false ;
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
/// <summary>
/// Serializes an PSObject whose baseobject is of primitive type.
/// </summary>
/// <param name="source">
/// source from which notes are written
/// </param>
/// <param name="primitive">
/// primitive object which is written as base object. In most cases it
/// is same source.ImmediateBaseObject. When PSObject is serialized as string,
/// it can be different. <see cref="HandlePSObjectAsString"/> for more info.
/// </param>
/// <param name="pktInfo">
2017-01-16 13:31:14 -08:00
/// TypeSerializationInfo for the primitive.
2016-07-29 13:02:49 -07:00
/// </param>
/// <param name="streamName"></param>
/// <param name="property"></param>
/// <param name="depth"></param>
private void WritePrimitiveTypePSObject
(
PSObject source ,
object primitive ,
TypeSerializationInfo pktInfo ,
string streamName ,
string property ,
int depth
)
{
Dbg . Assert ( source != null , "Caller should validate source != null" );
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
string toStringValue = SerializationUtilities . GetToStringForPrimitiveObject ( source );
bool hasModifiedTypesCollection = PSObjectHasModifiedTypesCollection ( source );
bool hasNotes = PSObjectHasNotes ( source );
bool hasModifiedToString = ( toStringValue != null );
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
if ( hasNotes || hasModifiedTypesCollection || hasModifiedToString )
{
WritePrimitiveTypePSObjectWithNotes (
source ,
primitive ,
hasModifiedTypesCollection ,
toStringValue ,
pktInfo ,
streamName ,
property ,
depth );
return ;
}
else
{
if ( primitive != null )
{
WriteOnePrimitiveKnownType ( this , streamName , property , primitive , pktInfo );
return ;
}
else
{
WriteNull ( streamName , property );
return ;
}
}
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
/// <summary>
/// Serializes an PSObject whose baseobject is of primitive type
/// and which has notes.
/// </summary>
/// <param name="source">
/// source from which notes are written
/// </param>
/// <param name="primitive">
/// primitive object which is written as base object. In most cases it
/// is same source.ImmediateBaseObject. When PSObject is serialized as string,
/// it can be different. <see cref="HandlePSObjectAsString"/> for more info.
/// </param>
/// <param name="hasModifiedTypesCollection"></param>
/// <param name="toStringValue"></param>
/// <param name="pktInfo">
2017-01-16 13:31:14 -08:00
/// TypeSerializationInfo for the primitive.
2016-07-29 13:02:49 -07:00
/// </param>
/// <param name="streamName"></param>
/// <param name="property"></param>
/// <param name="depth"></param>
private void WritePrimitiveTypePSObjectWithNotes
(
PSObject source ,
object primitive ,
bool hasModifiedTypesCollection ,
string toStringValue ,
TypeSerializationInfo pktInfo ,
string streamName ,
string property ,
int depth
)
{
Dbg . Assert ( source != null , "caller should validate the parameter" );
Dbg . Assert ( pktInfo != null , "Caller should validate pktInfo != null" );
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
string refId = _objectRefIdHandler . SetRefId ( source );
WriteStartOfPSObject (
source ,
streamName ,
property ,
refId ,
hasModifiedTypesCollection , // preserve TypeNames information if different from the primitive type
toStringValue ); // preserve ToString information only if got it from deserialization or overridden by PSObject
// (example where preservation of TypeNames and ToString is needed: enums serialized as ints, help string with custom type names (HelpInfoShort))
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
if ( pktInfo != null )
{
WriteOnePrimitiveKnownType ( this , streamName , null , primitive , pktInfo );
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
// serialize only instance properties - members from type table are
// always going to be available for known primitive types
SerializeInstanceProperties ( source , depth );
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
_writer . WriteEndElement ();
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
private void HandleComplexTypePSObject
(
object source ,
string streamName ,
string property ,
int depth
)
{
Dbg . Assert ( source != null , "caller should validate the parameter" );
PSObject mshSource = PSObject . AsPSObject ( source );
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
// Figure out what kind of object we are dealing with
bool isErrorRecord = false ;
bool isInformationalRecord = false ;
bool isEnum = false ;
bool isPSObject = false ;
bool isCimInstance = false ;
2016-03-30 14:20:52 -07:00
2019-03-21 02:43:52 +01:00
if (! mshSource . ImmediateBaseObjectIsEmpty )
2016-07-29 13:02:49 -07:00
{
do // false loop
{
CimInstance cimInstance = mshSource . ImmediateBaseObject as CimInstance ;
if ( cimInstance != null )
{
isCimInstance = true ;
break ;
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
ErrorRecord errorRecord = mshSource . ImmediateBaseObject as ErrorRecord ;
if ( errorRecord != null )
{
errorRecord . ToPSObjectForRemoting ( mshSource );
isErrorRecord = true ;
break ;
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
InformationalRecord informationalRecord = mshSource . ImmediateBaseObject as InformationalRecord ;
if ( informationalRecord != null )
{
informationalRecord . ToPSObjectForRemoting ( mshSource );
isInformationalRecord = true ;
break ;
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
isEnum = mshSource . ImmediateBaseObject is Enum ;
isPSObject = mshSource . ImmediateBaseObject is PSObject ;
} while ( false );
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
bool writeToString = true ;
2020-07-30 16:06:38 -07:00
if ( mshSource . ToStringFromDeserialization == null ) // continue to write ToString from deserialized objects, but...
2016-07-29 13:02:49 -07:00
{
2019-03-21 02:43:52 +01:00
if ( mshSource . ImmediateBaseObjectIsEmpty ) // ... don't write ToString for property bags
2016-07-29 13:02:49 -07:00
{
writeToString = false ;
}
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
string refId = _objectRefIdHandler . SetRefId ( source );
WriteStartOfPSObject (
mshSource ,
streamName ,
property ,
refId ,
true , // always write TypeNames for complex objects
writeToString ? SerializationUtilities . GetToString ( mshSource ) : null );
2016-03-30 14:20:52 -07:00
PSMemberInfoInternalCollection < PSPropertyInfo > specificPropertiesToSerialize = SerializationUtilities . GetSpecificPropertiesToSerialize ( mshSource , AllPropertiesCollection , _typeTable );
2016-07-29 13:02:49 -07:00
if ( isEnum )
{
object baseObject = mshSource . ImmediateBaseObject ;
WriteOneObject ( System . Convert . ChangeType ( baseObject , Enum . GetUnderlyingType ( baseObject . GetType ()), System . Globalization . CultureInfo . InvariantCulture ), null , null , depth );
}
else if ( isPSObject )
{
WriteOneObject ( mshSource . ImmediateBaseObject , null , null , depth );
}
else if ( isErrorRecord || isInformationalRecord )
{
// nothing to do
}
else
{
WritePSObjectProperties ( mshSource , depth , specificPropertiesToSerialize );
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
if ( isCimInstance )
{
CimInstance cimInstance = mshSource . ImmediateBaseObject as CimInstance ;
PrepareCimInstanceForSerialization ( mshSource , cimInstance );
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
SerializeExtendedProperties ( mshSource , depth , specificPropertiesToSerialize );
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
_writer . WriteEndElement ();
}
2016-03-30 14:20:52 -07:00
2020-11-05 03:36:23 +00:00
private static readonly Lazy < CimSerializer > s_cimSerializer = new Lazy < CimSerializer >( CimSerializer . Create );
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
private void PrepareCimInstanceForSerialization ( PSObject psObject , CimInstance cimInstance )
{
Queue < CimClassSerializationId > serializedClasses = new Queue < CimClassSerializationId >();
2016-03-30 14:20:52 -07:00
2017-01-16 13:31:14 -08:00
//
2016-07-29 13:02:49 -07:00
// CREATE SERIALIZED FORM OF THE CLASS METADATA
//
2016-03-30 14:20:52 -07:00
ArrayList psoClasses = new ArrayList ();
2016-07-29 13:02:49 -07:00
for ( CimClass cimClass = cimInstance . CimClass ; cimClass != null ; cimClass = cimClass . CimSuperClass )
{
PSObject psoClass = new PSObject ();
psoClass . TypeNames . Clear ();
psoClasses . Add ( psoClass );
psoClass . Properties . Add ( new PSNoteProperty ( InternalDeserializer . CimClassNameProperty , cimClass . CimSystemProperties . ClassName ));
psoClass . Properties . Add ( new PSNoteProperty ( InternalDeserializer . CimNamespaceProperty , cimClass . CimSystemProperties . Namespace ));
psoClass . Properties . Add ( new PSNoteProperty ( InternalDeserializer . CimServerNameProperty , cimClass . CimSystemProperties . ServerName ));
psoClass . Properties . Add ( new PSNoteProperty ( InternalDeserializer . CimHashCodeProperty , cimClass . GetHashCode ()));
CimClassSerializationId cimClassSerializationId = new CimClassSerializationId (
cimClass . CimSystemProperties . ClassName ,
cimClass . CimSystemProperties . Namespace ,
cimClass . CimSystemProperties . ServerName ,
cimClass . GetHashCode ());
if ( _context . cimClassSerializationIdCache . DoesDeserializerAlreadyHaveCimClass ( cimClassSerializationId ))
{
break ;
}
serializedClasses . Enqueue ( cimClassSerializationId );
byte [] miXmlBytes = s_cimSerializer . Value . Serialize ( cimClass , ClassSerializationOptions . None );
string miXmlString = Encoding . Unicode . GetString ( miXmlBytes , 0 , miXmlBytes . Length );
psoClass . Properties . Add ( new PSNoteProperty ( InternalDeserializer . CimMiXmlProperty , miXmlString ));
}
2018-12-23 22:20:06 -08:00
2016-07-29 13:02:49 -07:00
psoClasses . Reverse ();
//
// UPDATE CLASSDECL CACHE
//
foreach ( CimClassSerializationId serializedClassId in serializedClasses )
{
_context . cimClassSerializationIdCache . AddClassToCache ( serializedClassId );
}
//
// ATTACH CLASS METADATA TO THE OBJECT BEING SERIALIZED
//
PSPropertyInfo classMetadataProperty = psObject . Properties [ InternalDeserializer . CimClassMetadataProperty ];
if ( classMetadataProperty != null )
{
classMetadataProperty . Value = psoClasses ;
}
else
{
PSNoteProperty classMetadataNote = new PSNoteProperty (
InternalDeserializer . CimClassMetadataProperty ,
psoClasses );
classMetadataNote . IsHidden = true ;
psObject . Properties . Add ( classMetadataNote );
}
// ATTACH INSTANCE METADATA TO THE OBJECT BEING SERIALIZED
List < string > namesOfModifiedProperties = cimInstance
. CimInstanceProperties
. Where ( p => p . IsValueModified )
. Select ( p => p . Name )
. ToList ();
if ( namesOfModifiedProperties . Count != 0 )
{
PSObject instanceMetadata = new PSObject ();
PSPropertyInfo instanceMetadataProperty = psObject . Properties [ InternalDeserializer . CimInstanceMetadataProperty ];
if ( instanceMetadataProperty != null )
{
instanceMetadataProperty . Value = instanceMetadata ;
}
else
{
PSNoteProperty instanceMetadataNote = new PSNoteProperty ( InternalDeserializer . CimInstanceMetadataProperty , instanceMetadata );
instanceMetadataNote . IsHidden = true ;
psObject . Properties . Add ( instanceMetadataNote );
}
instanceMetadata . InternalTypeNames = ConsolidatedString . Empty ;
instanceMetadata . Properties . Add (
new PSNoteProperty (
InternalDeserializer . CimModifiedProperties ,
string . Join ( " " , namesOfModifiedProperties )));
}
}
/// <summary>
/// Writes start element, attributes and typeNames for PSObject.
/// </summary>
/// <param name="mshObject"></param>
/// <param name="streamName"></param>
/// <param name="property"></param>
/// <param name="refId"></param>
2018-12-29 08:25:49 +05:00
/// <param name="writeTypeNames">If true, TypeName information is written, else not.</param>
/// <param name="toStringValue">If not null then ToString information is written.</param>
2016-07-29 13:02:49 -07:00
private void WriteStartOfPSObject
(
PSObject mshObject ,
string streamName ,
string property ,
string refId ,
bool writeTypeNames ,
string toStringValue
)
{
Dbg . Assert ( mshObject != null , "caller should validate the parameter" );
2019-01-06 06:51:20 +05:00
// Write PSObject start element.
2016-07-29 13:02:49 -07:00
WriteStartElement ( SerializationStrings . PSObjectTag );
if ( streamName != null )
{
WriteAttribute ( SerializationStrings . StreamNameAttribute , streamName );
}
if ( property != null )
{
WriteNameAttribute ( property );
}
if ( refId != null )
{
WriteAttribute ( SerializationStrings . ReferenceIdAttribute , refId );
}
if ( writeTypeNames )
{
2019-01-06 06:51:20 +05:00
// Write TypeNames
2016-07-29 13:02:49 -07:00
ConsolidatedString typeNames = mshObject . InternalTypeNames ;
if ( typeNames . Count > 0 )
{
string typeNameHierarchyReferenceId = _typeRefIdHandler . GetRefId ( typeNames );
2020-07-30 16:06:38 -07:00
if ( typeNameHierarchyReferenceId == null )
2016-07-29 13:02:49 -07:00
{
WriteStartElement ( SerializationStrings . TypeNamesTag );
2019-01-06 06:51:20 +05:00
// Create a new refId and write it as attribute
2016-07-29 13:02:49 -07:00
string tnRefId = _typeRefIdHandler . SetRefId ( typeNames );
Dbg . Assert ( tnRefId != null , "SetRefId should always succeed for strings" );
WriteAttribute ( SerializationStrings . ReferenceIdAttribute , tnRefId );
foreach ( string type in typeNames )
{
WriteEncodedElementString ( SerializationStrings . TypeNamesItemTag , type );
}
2018-12-23 22:20:06 -08:00
2016-07-29 13:02:49 -07:00
_writer . WriteEndElement ();
}
else
{
WriteStartElement ( SerializationStrings . TypeNamesReferenceTag );
WriteAttribute ( SerializationStrings . ReferenceIdAttribute , typeNameHierarchyReferenceId );
_writer . WriteEndElement ();
}
}
}
if ( toStringValue != null )
{
WriteEncodedElementString ( SerializationStrings . ToStringElementTag , toStringValue );
}
}
#region membersets
/// <summary>
2017-01-16 13:31:14 -08:00
/// Returns true if PSObject has notes.
2016-07-29 13:02:49 -07:00
/// </summary>
/// <param name="source"></param>
/// <returns>
/// </returns>
private static bool PSObjectHasNotes ( PSObject source )
{
Dbg . Assert ( source != null , "Caller should validate the parameter" );
if ( source . InstanceMembers != null && source . InstanceMembers . Count > 0 )
{
return true ;
}
2018-12-23 22:20:06 -08:00
2016-07-29 13:02:49 -07:00
return false ;
}
private bool? _canUseDefaultRunspaceInThreadSafeManner ;
private bool CanUseDefaultRunspaceInThreadSafeManner
{
get
{
if (! _canUseDefaultRunspaceInThreadSafeManner . HasValue )
{
_canUseDefaultRunspaceInThreadSafeManner = Runspace . CanUseDefaultRunspace ;
}
return _canUseDefaultRunspaceInThreadSafeManner . Value ;
}
}
/// <summary>
2017-01-16 13:31:14 -08:00
/// Serialize member set. This method serializes without writing
2016-07-29 13:02:49 -07:00
/// enclosing tags and attributes.
/// </summary>
/// <param name="me">
/// enumerable containing members
/// </param>
/// <param name="depth"></param>
/// <param name="writeEnclosingMemberSetElementTag">
/// if this is true, write an enclosing "<memberset></memberset>" tag.
/// </param>
/// <returns></returns>
private void WriteMemberInfoCollection
(
IEnumerable < PSMemberInfo > me ,
int depth ,
bool writeEnclosingMemberSetElementTag
)
{
Dbg . Assert ( me != null , "caller should validate the parameter" );
bool enclosingTagWritten = false ;
foreach ( PSMemberInfo info in me )
{
if (! info . ShouldSerialize )
{
continue ;
}
2018-12-23 22:20:06 -08:00
2016-07-29 13:02:49 -07:00
int depthOfMember = info . IsInstance ? depth : depth - 1 ;
if ( info . MemberType == ( info . MemberType & PSMemberTypes . Properties ))
{
bool gotValue ;
object value = SerializationUtilities . GetPropertyValueInThreadSafeManner (( PSPropertyInfo ) info , this . CanUseDefaultRunspaceInThreadSafeManner , out gotValue );
if ( gotValue )
{
if ( writeEnclosingMemberSetElementTag && ! enclosingTagWritten )
{
enclosingTagWritten = true ;
WriteStartElement ( SerializationStrings . MemberSet );
}
WriteOneObject ( value , null , info . Name , depthOfMember );
}
}
else if ( info . MemberType == PSMemberTypes . MemberSet )
{
if ( writeEnclosingMemberSetElementTag && ! enclosingTagWritten )
{
enclosingTagWritten = true ;
WriteStartElement ( SerializationStrings . MemberSet );
}
2018-12-23 22:20:06 -08:00
2016-07-29 13:02:49 -07:00
WriteMemberSet (( PSMemberSet ) info , depthOfMember );
}
}
2018-12-23 22:20:06 -08:00
2016-07-29 13:02:49 -07:00
if ( enclosingTagWritten )
{
_writer . WriteEndElement ();
}
}
/// <summary>
/// Serializes MemberSet.
/// </summary>
private void WriteMemberSet
(
PSMemberSet set ,
int depth
)
{
Dbg . Assert ( set != null , "Caller should validate the parameter" );
if (! set . ShouldSerialize )
{
return ;
}
2018-12-23 22:20:06 -08:00
2016-07-29 13:02:49 -07:00
WriteStartElement ( SerializationStrings . MemberSet );
WriteNameAttribute ( set . Name );
WriteMemberInfoCollection ( set . Members , depth , false );
_writer . WriteEndElement ();
}
#endregion membersets
#region properties
/// <summary>
2019-01-06 04:40:24 +05:00
/// Serializes properties of PSObject.
2016-07-29 13:02:49 -07:00
/// </summary>
private void WritePSObjectProperties
(
PSObject source ,
int depth ,
IEnumerable < PSPropertyInfo > specificPropertiesToSerialize
)
{
Dbg . Assert ( source != null , "caller should validate the information" );
2019-01-06 06:51:20 +05:00
// Depth available for each property is one less
2016-07-29 13:02:49 -07:00
-- depth ;
Dbg . Assert ( depth >= 0 , "depth should be greater or equal to zero" );
if ( specificPropertiesToSerialize != null )
{
SerializeProperties ( specificPropertiesToSerialize , SerializationStrings . AdapterProperties , depth );
}
else
{
if ( source . ShouldSerializeAdapter ())
{
IEnumerable < PSPropertyInfo > adapterCollection = null ;
adapterCollection = source . GetAdaptedProperties ();
if ( adapterCollection != null )
{
SerializeProperties ( adapterCollection , SerializationStrings . AdapterProperties , depth );
}
}
}
}
private void SerializeInstanceProperties
(
PSObject source ,
int depth
)
{
2019-01-06 06:51:20 +05:00
// Serialize instanceMembers
2016-07-29 13:02:49 -07:00
Dbg . Assert ( source != null , "caller should validate the information" );
PSMemberInfoCollection < PSMemberInfo > instanceMembers = source . InstanceMembers ;
if ( instanceMembers != null )
{
WriteMemberInfoCollection ( instanceMembers , depth , true );
}
}
private Collection < CollectionEntry < PSMemberInfo >> _extendedMembersCollection ;
2020-05-29 05:56:33 +01:00
2016-07-29 13:02:49 -07:00
private Collection < CollectionEntry < PSMemberInfo >> ExtendedMembersCollection
{
2019-04-24 19:27:22 +05:00
get
{
2020-11-25 12:37:01 +00:00
return _extendedMembersCollection ??=
PSObject . GetMemberCollection ( PSMemberViewTypes . Extended , _typeTable );
2016-07-29 13:02:49 -07:00
}
}
private Collection < CollectionEntry < PSPropertyInfo >> _allPropertiesCollection ;
2020-05-29 05:56:33 +01:00
2016-07-29 13:02:49 -07:00
private Collection < CollectionEntry < PSPropertyInfo >> AllPropertiesCollection
{
2019-04-24 19:27:22 +05:00
get
{
2020-11-25 12:37:01 +00:00
return _allPropertiesCollection ??= PSObject . GetPropertyCollection ( PSMemberViewTypes . All , _typeTable );
2016-07-29 13:02:49 -07:00
}
}
private void SerializeExtendedProperties
(
PSObject source ,
int depth ,
IEnumerable < PSPropertyInfo > specificPropertiesToSerialize
)
{
Dbg . Assert ( source != null , "caller should validate the information" );
IEnumerable < PSMemberInfo > extendedMembersEnumerable = null ;
2020-07-30 16:06:38 -07:00
if ( specificPropertiesToSerialize == null )
2016-07-29 13:02:49 -07:00
{
// Get only extended members including hidden members from the psobect source.
PSMemberInfoIntegratingCollection < PSMemberInfo > membersToSearch =
new PSMemberInfoIntegratingCollection < PSMemberInfo >( source , ExtendedMembersCollection );
extendedMembersEnumerable = membersToSearch . Match (
"*" ,
PSMemberTypes . Properties | PSMemberTypes . PropertySet | PSMemberTypes . MemberSet ,
MshMemberMatchOptions . IncludeHidden | MshMemberMatchOptions . OnlySerializable );
}
else
{
List < PSMemberInfo > extendedMembersList = new List < PSMemberInfo >( source . InstanceMembers );
extendedMembersEnumerable = extendedMembersList ;
foreach ( PSMemberInfo member in specificPropertiesToSerialize )
{
if ( member . IsInstance )
{
continue ;
}
if ( member is PSProperty )
{
continue ;
}
extendedMembersList . Add ( member );
}
}
if ( extendedMembersEnumerable != null )
{
WriteMemberInfoCollection ( extendedMembersEnumerable , depth , true );
}
}
/// <summary>
2019-01-06 04:40:24 +05:00
/// Serializes properties from collection.
2016-07-29 13:02:49 -07:00
/// </summary>
/// <param name="propertyCollection">
/// Collection of properties to serialize
/// </param>
/// <param name="name">
/// Name for enclosing element tag
/// </param>
/// <param name="depth">
2017-01-16 13:31:14 -08:00
/// depth to which each property should be
2016-07-29 13:02:49 -07:00
/// serialized
/// </param>
private void SerializeProperties
(
IEnumerable < PSPropertyInfo > propertyCollection ,
string name ,
int depth
)
{
Dbg . Assert ( propertyCollection != null , "caller should validate the parameter" );
bool startElementWritten = false ;
foreach ( PSMemberInfo info in propertyCollection )
{
2020-11-05 16:58:48 +00:00
if (!( info is PSProperty prop ))
2016-07-29 13:02:49 -07:00
{
continue ;
}
if (! startElementWritten )
{
WriteStartElement ( name );
startElementWritten = true ;
}
bool success ;
object value = SerializationUtilities . GetPropertyValueInThreadSafeManner ( prop , this . CanUseDefaultRunspaceInThreadSafeManner , out success );
if ( success )
{
WriteOneObject ( value , null , prop . Name , depth );
}
}
if ( startElementWritten )
{
_writer . WriteEndElement ();
}
}
#endregion base properties
#endregion WritePSObject
#region enumerable and dictionary
/// <summary>
2019-01-06 04:40:24 +05:00
/// Serializes IEnumerable.
2016-07-29 13:02:49 -07:00
/// </summary>
/// <param name="enumerable">
/// enumerable which is serialized
/// </param>
/// <param name="tag">
/// </param>
/// <param name="depth"></param>
private void WriteEnumerable
(
IEnumerable enumerable ,
string tag ,
int depth
)
{
Dbg . Assert ( enumerable != null , "caller should validate the parameter" );
Dbg . Assert (! string . IsNullOrEmpty ( tag ), "caller should validate the parameter" );
2019-01-06 06:51:20 +05:00
// Start element
2016-07-29 13:02:49 -07:00
WriteStartElement ( tag );
IEnumerator enumerator = null ;
try
{
enumerator = enumerable . GetEnumerator ();
try
{
enumerator . Reset ();
}
catch ( System . NotSupportedException )
{
2019-01-06 06:51:20 +05:00
// ignore exceptions thrown when the enumerator doesn't support Reset() method as in win8:948569
2016-07-29 13:02:49 -07:00
}
}
catch ( Exception exception )
{
// Catch-all OK. This is a third-party call-out.
PSEtwLog . LogAnalyticWarning (
PSEventId . Serializer_EnumerationFailed , PSOpcode . Exception , PSTask . Serialization ,
PSKeyword . Serializer | PSKeyword . UseAlwaysAnalytic ,
enumerable . GetType (). AssemblyQualifiedName ,
exception . ToString ());
enumerator = null ;
}
2019-01-06 06:51:20 +05:00
// AD has incorrect implementation of IEnumerable where they returned null
// for GetEnumerator instead of empty enumerator
2016-07-29 13:02:49 -07:00
if ( enumerator != null )
{
while ( true )
{
object item = null ;
try
{
if (! enumerator . MoveNext ())
{
break ;
}
else
{
item = enumerator . Current ;
}
}
catch ( Exception exception )
{
// Catch-all OK. This is a third-party call-out.
PSEtwLog . LogAnalyticWarning (
PSEventId . Serializer_EnumerationFailed , PSOpcode . Exception , PSTask . Serialization ,
PSKeyword . Serializer | PSKeyword . UseAlwaysAnalytic ,
enumerable . GetType (). AssemblyQualifiedName ,
exception . ToString ());
break ;
}
2018-12-23 22:20:06 -08:00
2016-07-29 13:02:49 -07:00
WriteOneObject ( item , null , null , depth );
}
}
2019-01-06 06:51:20 +05:00
// End element
2016-07-29 13:02:49 -07:00
_writer . WriteEndElement ();
}
/// <summary>
2019-01-06 04:40:24 +05:00
/// Serializes IDictionary.
2016-07-29 13:02:49 -07:00
/// </summary>
2018-12-29 08:25:49 +05:00
/// <param name="dictionary">Dictionary which is serialized.</param>
2016-07-29 13:02:49 -07:00
/// <param name="tag"></param>
/// <param name="depth"></param>
private void WriteDictionary
(
IDictionary dictionary ,
string tag ,
int depth
)
{
Dbg . Assert ( dictionary != null , "caller should validate the parameter" );
Dbg . Assert (! string . IsNullOrEmpty ( tag ), "caller should validate the parameter" );
2019-01-06 06:51:20 +05:00
// Start element
2016-07-29 13:02:49 -07:00
WriteStartElement ( tag );
IDictionaryEnumerator dictionaryEnum = null ;
try
{
dictionaryEnum = dictionary . GetEnumerator ();
}
catch ( Exception exception ) // ignore non-severe exceptions
{
// Catch-all OK. This is a third-party call-out.
PSEtwLog . LogAnalyticWarning (
PSEventId . Serializer_EnumerationFailed , PSOpcode . Exception , PSTask . Serialization ,
PSKeyword . Serializer | PSKeyword . UseAlwaysAnalytic ,
dictionary . GetType (). AssemblyQualifiedName ,
exception . ToString ());
}
if ( dictionaryEnum != null )
{
while ( true )
{
object key = null ;
object value = null ;
try
{
if (! dictionaryEnum . MoveNext ())
{
break ;
}
else
{
key = dictionaryEnum . Key ;
value = dictionaryEnum . Value ;
}
}
catch ( Exception exception )
{
// Catch-all OK. This is a third-party call-out.
PSEtwLog . LogAnalyticWarning (
PSEventId . Serializer_EnumerationFailed , PSOpcode . Exception , PSTask . Serialization ,
PSKeyword . Serializer | PSKeyword . UseAlwaysAnalytic ,
dictionary . GetType (). AssemblyQualifiedName ,
exception . ToString ());
break ;
}
Dbg . Assert ( key != null , "Dictionary keys should never be null" );
2020-07-30 16:06:38 -07:00
if ( key == null ) break ;
2016-07-29 13:02:49 -07:00
WriteStartElement ( SerializationStrings . DictionaryEntryTag );
WriteOneObject ( key , null , SerializationStrings . DictionaryKey , depth );
WriteOneObject ( value , null , SerializationStrings . DictionaryValue , depth );
_writer . WriteEndElement ();
}
}
2019-01-06 06:51:20 +05:00
// End element
2016-07-29 13:02:49 -07:00
_writer . WriteEndElement ();
}
#endregion enumerable and dictionary
#region serialize as string
private void HandlePSObjectAsString (
PSObject source ,
string streamName ,
string property ,
int depth )
{
Dbg . Assert ( source != null , "caller should validate the information" );
string value = GetSerializationString ( source );
TypeSerializationInfo pktInfo = null ;
if ( value != null )
{
pktInfo = KnownTypes . GetTypeSerializationInfo ( value . GetType ());
}
WritePrimitiveTypePSObject ( source , value , pktInfo , streamName , property , depth );
}
2016-03-30 14:20:52 -07:00
/// <summary>
/// Gets the string from PSObject using the information from
2017-01-16 13:31:14 -08:00
/// types.ps1xml.
/// This string is used for serializing the PSObject at depth 0
2016-03-30 14:20:52 -07:00
/// or when pso.SerializationMethod == SerializationMethod.String.
/// </summary>
/// <param name="source">
/// PSObject to be converted to string
/// </param>
/// <returns>
/// string value to use for serializing this PSObject.
/// </returns>
private string GetSerializationString ( PSObject source )
{
Dbg . Assert ( source != null , "caller should have validated the information" );
PSPropertyInfo serializationProperty = null ;
try
{
serializationProperty = source . GetStringSerializationSource ( _typeTable );
}
catch ( ExtendedTypeSystemException e )
{
PSEtwLog . LogAnalyticWarning (
PSEventId . Serializer_ToStringFailed , PSOpcode . Exception , PSTask . Serialization ,
PSKeyword . Serializer | PSKeyword . UseAlwaysAnalytic ,
source . GetType (). AssemblyQualifiedName ,
e . InnerException != null ? e . InnerException . ToString () : e . ToString ());
}
string result = null ;
if ( serializationProperty != null )
{
bool success ;
object val = SerializationUtilities . GetPropertyValueInThreadSafeManner ( serializationProperty , this . CanUseDefaultRunspaceInThreadSafeManner , out success );
if ( success && ( val != null ))
{
result = SerializationUtilities . GetToString ( val );
}
}
else
{
result = SerializationUtilities . GetToString ( source );
}
return result ;
}
/// <summary>
/// Reads the information the PSObject
/// and returns true if this object should be serialized as
2019-01-06 04:40:24 +05:00
/// string.
2016-03-30 14:20:52 -07:00
/// </summary>
2018-12-28 16:39:06 +05:00
/// <param name="source">PSObject to be serialized.</param>
2018-12-25 21:43:03 +05:00
/// <returns>True if the object needs to be serialized as a string.</returns>
2016-03-30 14:20:52 -07:00
private bool SerializeAsString ( PSObject source )
{
SerializationMethod method = source . GetSerializationMethod ( _typeTable );
if ( method == SerializationMethod . String )
{
PSEtwLog . LogAnalyticVerbose (
PSEventId . Serializer_ModeOverride , PSOpcode . SerializationSettings , PSTask . Serialization ,
PSKeyword . Serializer | PSKeyword . UseAlwaysAnalytic ,
source . InternalTypeNames . Key ,
( UInt32 )( SerializationMethod . String ));
return true ;
}
else
{
return false ;
}
}
2016-07-29 13:02:49 -07:00
#endregion serialize as string
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
/// <summary>
2019-01-10 02:07:41 +05:00
/// Compute the serialization depth for an PSObject instance subtree.
2016-07-29 13:02:49 -07:00
/// </summary>
2018-12-28 16:39:06 +05:00
/// <param name="source">PSObject whose serialization depth has to be computed.</param>
2018-12-29 08:25:49 +05:00
/// <param name="depth">Current depth.</param>
2016-07-29 13:02:49 -07:00
/// <returns></returns>
private int GetDepthOfSerialization ( object source , int depth )
{
Dbg . Assert ( source != null , "Caller should verify source != null" );
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
PSObject pso = PSObject . AsPSObject ( source );
2020-07-30 16:06:38 -07:00
if ( pso == null )
2016-07-29 13:02:49 -07:00
{
return depth ;
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
if ( pso . BaseObject is CimInstance )
{
return 1 ;
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
if ( pso . BaseObject is PSCredential )
{
return 1 ;
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
if ( pso . BaseObject is PSSenderInfo )
{
return 4 ;
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
if ( pso . BaseObject is SwitchParameter )
{
return 1 ;
}
2016-03-30 14:20:52 -07:00
2020-11-05 04:13:12 +00:00
if (( _context . options & SerializationOptions . UseDepthFromTypes ) != 0 )
2016-07-29 13:02:49 -07:00
{
// get the depth from the PSObject
// NOTE: we assume that the depth out of the PSObject is > 0
// else we consider it not set in types.ps1xml
int typesPs1xmlDepth = pso . GetSerializationDepth ( _typeTable );
if ( typesPs1xmlDepth > 0 )
{
if ( typesPs1xmlDepth != depth )
{
PSEtwLog . LogAnalyticVerbose (
PSEventId . Serializer_DepthOverride , PSOpcode . SerializationSettings , PSTask . Serialization ,
PSKeyword . Serializer | PSKeyword . UseAlwaysAnalytic ,
pso . InternalTypeNames . Key , depth , typesPs1xmlDepth , _depthBelowTopLevel );
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
return typesPs1xmlDepth ;
}
}
}
2016-03-30 14:20:52 -07:00
2020-11-05 04:13:12 +00:00
if (( _context . options & SerializationOptions . PreserveSerializationSettingOfOriginal ) != 0 )
2016-07-29 13:02:49 -07:00
{
2019-03-21 02:43:52 +01:00
if (( pso . IsDeserialized ) && ( depth <= 0 ))
2016-07-29 13:02:49 -07:00
{
return 1 ;
}
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
return depth ;
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
/// <summary>
2019-01-06 04:40:24 +05:00
/// Writes null.
2016-07-29 13:02:49 -07:00
/// </summary>
/// <param name="streamName"></param>
/// <param name="property"></param>
private void WriteNull ( string streamName , string property )
{
WriteStartElement ( SerializationStrings . NilTag );
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
if ( streamName != null )
{
WriteAttribute ( SerializationStrings . StreamNameAttribute , streamName );
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
if ( property != null )
{
WriteNameAttribute ( property );
}
2018-12-23 22:20:06 -08:00
2016-07-29 13:02:49 -07:00
_writer . WriteEndElement ();
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
#region known type serialization
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
/// <summary>
2019-01-06 04:40:24 +05:00
/// Writes raw string as item or property in Monad namespace.
2016-07-29 13:02:49 -07:00
/// </summary>
/// <param name="serializer">The serializer to which the object is serialized.</param>
2018-12-29 08:25:49 +05:00
/// <param name="streamName">Name of the stream to write. Do not write if null.</param>
/// <param name="property">Name of property. Pass null for item.</param>
/// <param name="raw">String to write.</param>
/// <param name="entry">Serialization information.</param>
2016-07-29 13:02:49 -07:00
private static void WriteRawString
(
InternalSerializer serializer ,
string streamName ,
string property ,
string raw ,
TypeSerializationInfo entry
)
{
Dbg . Assert ( serializer != null , "caller should have validated the information" );
Dbg . Assert ( raw != null , "caller should have validated the information" );
Dbg . Assert ( entry != null , "caller should have validated the information" );
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
if ( property != null )
{
serializer . WriteStartElement ( entry . PropertyTag );
serializer . WriteNameAttribute ( property );
}
else
{
serializer . WriteStartElement ( entry . ItemTag );
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
if ( streamName != null )
{
serializer . WriteAttribute ( SerializationStrings . StreamNameAttribute , streamName );
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
serializer . _writer . WriteRaw ( raw );
serializer . _writer . WriteEndElement ();
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
/// <summary>
2019-01-06 04:40:24 +05:00
/// Writes an item or property in Monad namespace.
2016-07-29 13:02:49 -07:00
/// </summary>
/// <param name="serializer">The serializer to which the object is serialized.</param>
/// <param name="streamName"></param>
2018-12-29 08:25:49 +05:00
/// <param name="property">Name of property. Pass null for item.</param>
/// <param name="source">Object to be written.</param>
/// <param name="entry">Serialization information about source.</param>
2016-07-29 13:02:49 -07:00
private static void WriteOnePrimitiveKnownType
(
InternalSerializer serializer ,
string streamName ,
string property ,
object source ,
TypeSerializationInfo entry
)
{
Dbg . Assert ( serializer != null , "caller should have validated the information" );
Dbg . Assert ( source != null , "caller should have validated the information" );
Dbg . Assert ( entry != null , "caller should have validated the information" );
2016-03-30 14:20:52 -07:00
2020-07-30 16:06:38 -07:00
if ( entry . Serializer == null )
2016-07-29 13:02:49 -07:00
{
// we are not using GetToString, because we assume that
// ToString() for primitive types never throws
string value = Convert . ToString ( source , CultureInfo . InvariantCulture );
Dbg . Assert ( value != null , "ToString shouldn't return null for primitive types" );
WriteRawString ( serializer , streamName , property , value , entry );
}
else
{
entry . Serializer ( serializer , streamName , property , source , entry );
}
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
/// <summary>
2019-01-06 04:40:24 +05:00
/// Writes DateTime as item or property.
2016-07-29 13:02:49 -07:00
/// </summary>
/// <param name="serializer">The serializer to which the object is serialized.</param>
/// <param name="streamName"></param>
2018-12-29 08:25:49 +05:00
/// <param name="property">Name of property. pass null for item.</param>
2018-12-28 16:39:06 +05:00
/// <param name="source">DateTime to write.</param>
2018-12-29 08:25:49 +05:00
/// <param name="entry">Serialization information about source.</param>
2016-07-29 13:02:49 -07:00
internal static void WriteDateTime ( InternalSerializer serializer , string streamName , string property , object source , TypeSerializationInfo entry )
{
Dbg . Assert ( serializer != null , "caller should have validated the information" );
Dbg . Assert ( source != null , "caller should have validated the information" );
Dbg . Assert ( entry != null , "caller should have validated the information" );
2016-03-30 14:20:52 -07:00
WriteRawString ( serializer , streamName , property , XmlConvert . ToString (( DateTime ) source , XmlDateTimeSerializationMode . RoundtripKind ), entry );
2016-07-29 13:02:49 -07:00
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
/// <summary>
2019-01-06 04:40:24 +05:00
/// Writes Version.
2016-07-29 13:02:49 -07:00
/// </summary>
/// <param name="serializer">The serializer to which the object is serialized.</param>
/// <param name="streamName"></param>
2018-12-29 08:25:49 +05:00
/// <param name="property">Name of property. pass null for item.</param>
2018-12-28 16:39:06 +05:00
/// <param name="source">Version to write.</param>
2018-12-29 08:25:49 +05:00
/// <param name="entry">Serialization information about source.</param>
2016-07-29 13:02:49 -07:00
internal static void WriteVersion ( InternalSerializer serializer , string streamName , string property , object source , TypeSerializationInfo entry )
{
Dbg . Assert ( serializer != null , "caller should have validated the information" );
Dbg . Assert ( source != null , "caller should have validated the information" );
Dbg . Assert ( source is Version , "Caller should verify that typeof(source) is Version" );
Dbg . Assert ( entry != null , "caller should have validated the information" );
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
WriteRawString ( serializer , streamName , property , Convert . ToString ( source , CultureInfo . InvariantCulture ), entry );
}
2016-03-30 14:20:52 -07:00
2016-08-01 13:57:57 -07:00
/// <summary>
2019-01-06 04:40:24 +05:00
/// Writes SemanticVersion.
2016-08-01 13:57:57 -07:00
/// </summary>
/// <param name="serializer">The serializer to which the object is serialized.</param>
/// <param name="streamName"></param>
2018-12-29 08:25:49 +05:00
/// <param name="property">Name of property. pass null for item.</param>
2018-12-28 16:39:06 +05:00
/// <param name="source">Version to write.</param>
2018-12-29 08:25:49 +05:00
/// <param name="entry">Serialization information about source.</param>
2016-08-01 13:57:57 -07:00
internal static void WriteSemanticVersion ( InternalSerializer serializer , string streamName , string property , object source , TypeSerializationInfo entry )
{
Dbg . Assert ( serializer != null , "caller should have validated the information" );
Dbg . Assert ( source != null , "caller should have validated the information" );
Dbg . Assert ( source is SemanticVersion , "Caller should verify that typeof(source) is Version" );
Dbg . Assert ( entry != null , "caller should have validated the information" );
WriteRawString ( serializer , streamName , property , Convert . ToString ( source , CultureInfo . InvariantCulture ), entry );
}
2016-07-29 13:02:49 -07:00
/// <summary>
2019-01-06 04:40:24 +05:00
/// Serialize scriptblock as item or property.
2016-07-29 13:02:49 -07:00
/// </summary>
/// <param name="serializer">The serializer to which the object is serialized.</param>
/// <param name="streamName"></param>
2018-12-29 08:25:49 +05:00
/// <param name="property">Name of property. pass null for item.</param>
/// <param name="source">Scriptblock to write.</param>
/// <param name="entry">Serialization information about source.</param>
2016-07-29 13:02:49 -07:00
internal static void WriteScriptBlock ( InternalSerializer serializer , string streamName , string property , object source , TypeSerializationInfo entry )
{
Dbg . Assert ( serializer != null , "caller should have validated the information" );
Dbg . Assert ( source != null , "caller should have validated the information" );
Dbg . Assert ( source is ScriptBlock , "Caller should verify that typeof(source) is ScriptBlock" );
Dbg . Assert ( entry != null , "caller should have validated the information" );
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
WriteEncodedString ( serializer , streamName , property , Convert . ToString ( source , CultureInfo . InvariantCulture ), entry );
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
/// <summary>
2019-01-06 04:40:24 +05:00
/// Serialize URI as item or property.
2016-07-29 13:02:49 -07:00
/// </summary>
/// <param name="serializer">The serializer to which the object is serialized.</param>
/// <param name="streamName"></param>
2018-12-29 08:25:49 +05:00
/// <param name="property">Name of property. pass null for item.</param>
2018-12-28 16:39:06 +05:00
/// <param name="source">URI to write.</param>
2018-12-29 08:25:49 +05:00
/// <param name="entry">Serialization information about source.</param>
2016-07-29 13:02:49 -07:00
internal static void WriteUri ( InternalSerializer serializer , string streamName , string property , object source , TypeSerializationInfo entry )
{
Dbg . Assert ( serializer != null , "caller should have validated the information" );
Dbg . Assert ( source != null , "caller should have validated the information" );
Dbg . Assert ( source is Uri , "Caller should verify that typeof(source) is Uri" );
Dbg . Assert ( entry != null , "caller should have validated the information" );
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
WriteEncodedString ( serializer , streamName , property , Convert . ToString ( source , CultureInfo . InvariantCulture ), entry );
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
/// <summary>
2019-01-06 04:40:24 +05:00
/// Serialize string as item or property.
2016-07-29 13:02:49 -07:00
/// </summary>
/// <param name="serializer">The serializer to which the object is serialized.</param>
/// <param name="streamName"></param>
2018-12-29 08:25:49 +05:00
/// <param name="property">Name of property. pass null for item.</param>
/// <param name="source">String to write.</param>
/// <param name="entry">Serialization information about source.</param>
2016-07-29 13:02:49 -07:00
internal static void WriteEncodedString ( InternalSerializer serializer , string streamName , string property , object source , TypeSerializationInfo entry )
{
Dbg . Assert ( serializer != null , "caller should have validated the information" );
Dbg . Assert ( source != null , "caller should have validated the information" );
Dbg . Assert ( source is string , "caller should have validated the information" );
Dbg . Assert ( entry != null , "caller should have validated the information" );
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
if ( property != null )
{
serializer . WriteStartElement ( entry . PropertyTag );
serializer . WriteNameAttribute ( property );
}
else
{
serializer . WriteStartElement ( entry . ItemTag );
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
if ( streamName != null )
{
serializer . WriteAttribute ( SerializationStrings . StreamNameAttribute , streamName );
}
2016-03-30 14:20:52 -07:00
2019-01-06 06:51:20 +05:00
// Note: We do not use WriteRaw for serializing string. WriteString
// does necessary escaping which may be needed for certain
// characters.
2016-07-29 13:02:49 -07:00
Dbg . Assert ( source is string , "Caller should verify that typeof(source) is String" );
string s = ( string ) source ;
string encoded = EncodeString ( s );
serializer . _writer . WriteString ( encoded );
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
serializer . _writer . WriteEndElement ();
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
/// <summary>
2019-01-06 04:40:24 +05:00
/// Writes Double as item or property.
2016-07-29 13:02:49 -07:00
/// </summary>
/// <param name="serializer">The serializer to which the object is serialized.</param>
/// <param name="streamName"></param>
2018-12-29 08:25:49 +05:00
/// <param name="property">Name of property. pass null for item.</param>
2018-12-28 16:39:06 +05:00
/// <param name="source">Double to write.</param>
2018-12-29 08:25:49 +05:00
/// <param name="entry">Serialization information about source.</param>
2016-07-29 13:02:49 -07:00
internal static void WriteDouble ( InternalSerializer serializer , string streamName , string property , object source , TypeSerializationInfo entry )
{
Dbg . Assert ( serializer != null , "caller should have validated the information" );
Dbg . Assert ( source != null , "caller should have validated the information" );
Dbg . Assert ( entry != null , "caller should have validated the information" );
2016-03-30 14:20:52 -07:00
2019-11-06 08:47:32 +05:00
WriteRawString ( serializer , streamName , property , XmlConvert . ToString (( double ) source ), entry );
2016-07-29 13:02:49 -07:00
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
/// <summary>
2019-01-06 04:40:24 +05:00
/// Writes Char as item or property.
2016-07-29 13:02:49 -07:00
/// </summary>
/// <param name="serializer">The serializer to which the object is serialized.</param>
/// <param name="streamName"></param>
2018-12-29 08:25:49 +05:00
/// <param name="property">Name of property. pass null for item.</param>
2018-12-28 16:39:06 +05:00
/// <param name="source">Char to write.</param>
2018-12-29 08:25:49 +05:00
/// <param name="entry">Serialization information about source.</param>
2016-07-29 13:02:49 -07:00
internal static void WriteChar ( InternalSerializer serializer , string streamName , string property , object source , TypeSerializationInfo entry )
{
Dbg . Assert ( serializer != null , "caller should have validated the information" );
Dbg . Assert ( source != null , "caller should have validated the information" );
Dbg . Assert ( entry != null , "caller should have validated the information" );
2016-03-30 14:20:52 -07:00
2019-01-06 06:51:20 +05:00
// Char is defined as unsigned short in schema
2019-01-08 00:40:07 +05:00
WriteRawString ( serializer , streamName , property , XmlConvert . ToString (( UInt16 )( char ) source ), entry );
2016-07-29 13:02:49 -07:00
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
/// <summary>
2019-01-06 04:40:24 +05:00
/// Writes Boolean as item or property.
2016-07-29 13:02:49 -07:00
/// </summary>
/// <param name="serializer">The serializer to which the object is serialized.</param>
/// <param name="streamName"></param>
2018-12-29 08:25:49 +05:00
/// <param name="property">Name of property. pass null for item.</param>
2018-12-28 16:39:06 +05:00
/// <param name="source">Boolean to write.</param>
2018-12-29 08:25:49 +05:00
/// <param name="entry">Serialization information about source.</param>
2016-07-29 13:02:49 -07:00
internal static void WriteBoolean ( InternalSerializer serializer , string streamName , string property , object source , TypeSerializationInfo entry )
{
Dbg . Assert ( serializer != null , "caller should have validated the information" );
Dbg . Assert ( source != null , "caller should have validated the information" );
Dbg . Assert ( entry != null , "caller should have validated the information" );
2016-03-30 14:20:52 -07:00
2019-01-08 00:40:07 +05:00
WriteRawString ( serializer , streamName , property , XmlConvert . ToString (( bool ) source ), entry );
2016-07-29 13:02:49 -07:00
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
/// <summary>
2019-01-06 04:40:24 +05:00
/// Writes Single as item or property.
2016-07-29 13:02:49 -07:00
/// </summary>
/// <param name="serializer">The serializer to which the object is serialized.</param>
/// <param name="streamName"></param>
2018-12-29 08:25:49 +05:00
/// <param name="property">Name of property. pass null for item.</param>
/// <param name="source">Single to write.</param>
/// <param name="entry">Serialization information about source.</param>
2016-07-29 13:02:49 -07:00
internal static void WriteSingle ( InternalSerializer serializer , string streamName , string property , object source , TypeSerializationInfo entry )
{
Dbg . Assert ( serializer != null , "caller should have validated the information" );
Dbg . Assert ( source != null , "caller should have validated the information" );
Dbg . Assert ( entry != null , "caller should have validated the information" );
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
WriteRawString ( serializer , streamName , property , XmlConvert . ToString (( Single ) source ), entry );
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
/// <summary>
2019-01-06 04:40:24 +05:00
/// Writes TimeSpan as item or property.
2016-07-29 13:02:49 -07:00
/// </summary>
/// <param name="serializer">The serializer to which the object is serialized.</param>
/// <param name="streamName"></param>
2018-12-29 08:25:49 +05:00
/// <param name="property">Name of property. pass null for item.</param>
2018-12-28 16:39:06 +05:00
/// <param name="source">DateTime to write.</param>
2018-12-29 08:25:49 +05:00
/// <param name="entry">Serialization information about source.</param>
2016-07-29 13:02:49 -07:00
internal static void WriteTimeSpan ( InternalSerializer serializer , string streamName , string property , object source , TypeSerializationInfo entry )
{
Dbg . Assert ( serializer != null , "caller should have validated the information" );
Dbg . Assert ( source != null , "caller should have validated the information" );
Dbg . Assert ( entry != null , "caller should have validated the information" );
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
WriteRawString ( serializer , streamName , property , XmlConvert . ToString (( TimeSpan ) source ), entry );
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
/// <summary>
2019-01-06 04:40:24 +05:00
/// Writes Single as item or property.
2016-07-29 13:02:49 -07:00
/// </summary>
/// <param name="serializer">The serializer to which the object is serialized.</param>
/// <param name="streamName"></param>
2018-12-29 08:25:49 +05:00
/// <param name="property">Name of property. pass null for item.</param>
/// <param name="source">Bytearray to write.</param>
/// <param name="entry">Serialization information about source.</param>
2016-07-29 13:02:49 -07:00
internal static void WriteByteArray ( InternalSerializer serializer , string streamName , string property , object source , TypeSerializationInfo entry )
{
Dbg . Assert ( serializer != null , "caller should have validated the information" );
Dbg . Assert ( source != null , "caller should have validated the information" );
Dbg . Assert ( entry != null , "caller should have validated the information" );
2016-03-30 14:20:52 -07:00
2018-12-24 11:23:18 +05:00
byte [] bytes = ( byte []) source ;
2016-07-29 13:02:49 -07:00
if ( property != null )
{
serializer . WriteStartElement ( entry . PropertyTag );
serializer . WriteNameAttribute ( property );
}
else
{
serializer . WriteStartElement ( entry . ItemTag );
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
if ( streamName != null )
{
serializer . WriteAttribute ( SerializationStrings . StreamNameAttribute , streamName );
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
serializer . _writer . WriteBase64 ( bytes , 0 , bytes . Length );
serializer . _writer . WriteEndElement ();
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
internal static void WriteXmlDocument ( InternalSerializer serializer , string streamName , string property , object source , TypeSerializationInfo entry )
{
Dbg . Assert ( serializer != null , "caller should have validated the information" );
Dbg . Assert ( source != null , "caller should have validated the information" );
Dbg . Assert ( entry != null , "caller should have validated the information" );
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
string xml = (( XmlDocument ) source ). OuterXml ;
WriteEncodedString ( serializer , streamName , property , xml , entry );
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
internal static void WriteProgressRecord ( InternalSerializer serializer , string streamName , string property , object source , TypeSerializationInfo entry )
{
Dbg . Assert ( serializer != null , "caller should have validated the information" );
Dbg . Assert ( source != null , "caller should have validated the information" );
Dbg . Assert ( entry != null , "caller should have validated the information" );
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
ProgressRecord rec = ( ProgressRecord ) source ;
serializer . WriteStartElement ( entry . PropertyTag );
if ( property != null )
{
serializer . WriteNameAttribute ( property );
}
2018-12-23 22:20:06 -08:00
2016-07-29 13:02:49 -07:00
if ( streamName != null )
{
serializer . WriteAttribute ( SerializationStrings . StreamNameAttribute , streamName );
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
serializer . WriteEncodedElementString ( SerializationStrings . ProgressRecordActivity , rec . Activity );
serializer . WriteEncodedElementString ( SerializationStrings . ProgressRecordActivityId , rec . ActivityId . ToString ( CultureInfo . InvariantCulture ));
serializer . WriteOneObject ( rec . CurrentOperation , null , null , 1 );
serializer . WriteEncodedElementString ( SerializationStrings . ProgressRecordParentActivityId , rec . ParentActivityId . ToString ( CultureInfo . InvariantCulture ));
serializer . WriteEncodedElementString ( SerializationStrings . ProgressRecordPercentComplete , rec . PercentComplete . ToString ( CultureInfo . InvariantCulture ));
serializer . WriteEncodedElementString ( SerializationStrings . ProgressRecordType , rec . RecordType . ToString ());
serializer . WriteEncodedElementString ( SerializationStrings . ProgressRecordSecondsRemaining , rec . SecondsRemaining . ToString ( CultureInfo . InvariantCulture ));
serializer . WriteEncodedElementString ( SerializationStrings . ProgressRecordStatusDescription , rec . StatusDescription );
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
serializer . _writer . WriteEndElement ();
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
internal static void WriteSecureString ( InternalSerializer serializer , string streamName , string property , object source , TypeSerializationInfo entry )
{
Dbg . Assert ( serializer != null , "caller should have validated the information" );
Dbg . Assert ( source != null , "caller should have validated the information" );
Dbg . Assert ( entry != null , "caller should have validated the information" );
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
serializer . HandleSecureString ( source , streamName , property );
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
#endregion known type serialization
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
#region misc
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
/// <summary>
2019-01-06 04:40:24 +05:00
/// Writes start element in Monad namespace.
2016-07-29 13:02:49 -07:00
/// </summary>
2018-12-29 08:25:49 +05:00
/// <param name="elementTag">Tag of element.</param>
2016-07-29 13:02:49 -07:00
private void WriteStartElement ( string elementTag )
{
Dbg . Assert (! string . IsNullOrEmpty ( elementTag ), "Caller should validate the parameter" );
2020-11-20 12:26:46 +00:00
if (( _context . options & SerializationOptions . NoNamespace ) == SerializationOptions . NoNamespace )
2016-07-29 13:02:49 -07:00
{
_writer . WriteStartElement ( elementTag );
}
else
{
_writer . WriteStartElement ( elementTag , SerializationStrings . MonadNamespace );
}
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
/// <summary>
2019-01-06 04:40:24 +05:00
/// Writes attribute in monad namespace.
2016-07-29 13:02:49 -07:00
/// </summary>
2018-12-29 08:25:49 +05:00
/// <param name="name">Name of attribute.</param>
/// <param name="value">Value of attribute.</param>
2016-07-29 13:02:49 -07:00
private void WriteAttribute ( string name , string value )
{
Dbg . Assert (! string . IsNullOrEmpty ( name ), "Caller should validate the parameter" );
Dbg . Assert ( value != null , "Caller should validate the parameter" );
_writer . WriteAttributeString ( name , value );
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
private void WriteNameAttribute ( string value )
{
Dbg . Assert (! string . IsNullOrEmpty ( value ), "Caller should validate the parameter" );
WriteAttribute (
SerializationStrings . NameAttribute ,
EncodeString ( value ));
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
/// <summary>
/// Encodes the string to escape characters which would make XmlWriter.WriteString throw an exception.
/// </summary>
2018-12-29 08:25:49 +05:00
/// <param name="s">String to encode.</param>
2018-12-25 21:43:03 +05:00
/// <returns>Encoded string.</returns>
2016-07-29 13:02:49 -07:00
/// <remarks>
/// Output from this method can be reverted using XmlConvert.DecodeName method
/// (or InternalDeserializer.DecodeString).
/// This method has been introduced to produce shorter output than XmlConvert.EncodeName
/// (which escapes everything that can't be part of an xml name - whitespace, punctuation).
2017-01-16 13:31:14 -08:00
///
2016-07-29 13:02:49 -07:00
/// This method has been split into 2 parts to optimize its performance:
2017-01-16 13:31:14 -08:00
/// 1) part1 (this method) checks if there are any encodable characters and
2016-07-29 13:02:49 -07:00
/// if there aren't it simply (and efficiently) returns the original string
2017-01-16 13:31:14 -08:00
/// 2) part2 (EncodeString(string, int)) picks up when part1 detects the first encodable
2016-07-29 13:02:49 -07:00
/// character. It avoids looking at the characters already verified by part1
2017-01-16 13:31:14 -08:00
/// and copies those already verified characters and then starts encoding
2016-07-29 13:02:49 -07:00
/// the rest of the string.
/// </remarks>
internal static string EncodeString ( string s )
{
Dbg . Assert ( s != null , "Caller should validate the parameter" );
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
int slen = s . Length ;
for ( int i = 0 ; i < slen ; ++ i )
{
char c = s [ i ];
// A control character is in ranges 0x00-0x1F or 0x7F-0x9F
// The escape character is 0x5F ('_') if followed by an 'x'
// A surrogate character is in range 0xD800-0xDFFF
if ( c <= 0x1F
|| ( c >= 0x7F && c <= 0x9F )
|| ( c >= 0xD800 && c <= 0xDFFF )
|| ( c == 0x5F && ( i + 1 < slen ) &&
(( s [ i + 1 ] == 'x' ) || ( s [ i + 1 ] == 'X' ))
))
{
return EncodeString ( s , i );
}
}
// No encodable characters were found above - simply return the original string
return s ;
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
private static readonly char [] s_hexlookup = { '0' , '1' , '2' , '3' , '4' , '5' , '6' , '7' , '8' , '9' , 'A' , 'B' , 'C' , 'D' , 'E' , 'F' };
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
/// <summary>
/// This is the real workhorse that encodes strings.
2020-11-25 17:58:52 +00:00
/// See <see cref="EncodeString(string)"/> for more information.
2016-07-29 13:02:49 -07:00
/// </summary>
2018-12-29 08:25:49 +05:00
/// <param name="s">String to encode.</param>
/// <param name="indexOfFirstEncodableCharacter">IndexOfFirstEncodableCharacter.</param>
2018-12-25 21:43:03 +05:00
/// <returns>Encoded string.</returns>
2016-07-29 13:02:49 -07:00
private static string EncodeString ( string s , int indexOfFirstEncodableCharacter )
{
Dbg . Assert ( s != null , "Caller should validate the 's' parameter" );
Dbg . Assert ( indexOfFirstEncodableCharacter >= 0 , "Caller should verify validity of indexOfFirstEncodableCharacter" );
Dbg . Assert ( indexOfFirstEncodableCharacter < s . Length , "Caller should verify validity of indexOfFirstEncodableCharacter" );
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
int slen = s . Length ;
char [] result = new char [ indexOfFirstEncodableCharacter + ( slen - indexOfFirstEncodableCharacter ) * 7 ];
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
s . CopyTo ( 0 , result , 0 , indexOfFirstEncodableCharacter );
int rlen = indexOfFirstEncodableCharacter ;
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
for ( int i = indexOfFirstEncodableCharacter ; i < slen ; ++ i )
{
char c = s [ i ];
// A control character is in ranges 0x00-0x1F or 0x7F-0x9F
// The escape character is 0x5F ('_') if followed by an 'x'
// A surrogate character is in range 0xD800-0xDFFF
if ( c > 0x1F
&& ( c < 0x7F || c > 0x9F )
&& ( c < 0xD800 || c > 0xDFFF )
&& ( c != 0x5F || (( i + 1 >= slen ) ||
(( s [ i + 1 ] != 'x' ) && ( s [ i + 1 ] != 'X' ))
)))
{
result [ rlen ++] = c ;
}
else if ( c == 0x5F )
{
// Special case the escape character, encode _
result [ rlen + 0 ] = '_' ;
result [ rlen + 1 ] = 'x' ;
result [ rlen + 2 ] = '0' ;
result [ rlen + 3 ] = '0' ;
result [ rlen + 4 ] = '5' ;
result [ rlen + 5 ] = 'F' ;
result [ rlen + 6 ] = '_' ;
rlen += 7 ;
}
else
{
// It is a control character or a unicode surrogate
result [ rlen + 0 ] = '_' ;
result [ rlen + 1 ] = 'x' ;
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
result [ rlen + 2 + 3 ] = s_hexlookup [ c & 0x0F ];
c >>= 4 ;
result [ rlen + 2 + 2 ] = s_hexlookup [ c & 0x0F ];
c >>= 4 ;
result [ rlen + 2 + 1 ] = s_hexlookup [ c & 0x0F ];
c >>= 4 ;
result [ rlen + 2 + 0 ] = s_hexlookup [ c & 0x0F ];
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
result [ rlen + 6 ] = '_' ;
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
rlen += 7 ;
}
}
2018-12-23 22:20:06 -08:00
2019-11-06 08:47:32 +05:00
return new string ( result , 0 , rlen );
2016-07-29 13:02:49 -07:00
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
/// <summary>
2019-01-06 04:40:24 +05:00
/// Writes element string in monad namespace.
2016-07-29 13:02:49 -07:00
/// </summary>
/// <param name="name"></param>
/// <param name="value"></param>
private void WriteEncodedElementString ( string name , string value )
{
Dbg . Assert (! string . IsNullOrEmpty ( name ), "Caller should validate the parameter" );
Dbg . Assert ( value != null , "Caller should validate the parameter" );
this . CheckIfStopping ();
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
value = EncodeString ( value );
2016-03-30 14:20:52 -07:00
2020-11-20 12:26:46 +00:00
if (( _context . options & SerializationOptions . NoNamespace ) == SerializationOptions . NoNamespace )
2016-07-29 13:02:49 -07:00
{
_writer . WriteElementString ( name , value );
}
else
{
_writer . WriteElementString ( name , SerializationStrings . MonadNamespace , value );
}
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
#endregion misc
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
/// <summary>
/// This internal class provides methods for de-serializing mshObject.
/// </summary>
internal class InternalDeserializer
{
#region constructor
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
/// <summary>
2019-01-06 04:40:24 +05:00
/// XmlReader from which object is deserialized.
2016-07-29 13:02:49 -07:00
/// </summary>
private readonly XmlReader _reader ;
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
/// <summary>
2019-01-06 04:40:24 +05:00
/// Deserialization context.
2016-07-29 13:02:49 -07:00
/// </summary>
private readonly DeserializationContext _context ;
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
/// Used by Remoting infrastructure. This TypeTable instance
/// will be used by Serializer if ExecutionContext is not
2016-08-28 05:44:55 +00:00
/// available (to get the ExecutionContext's TypeTable)
2016-07-29 13:02:49 -07:00
private TypeTable _typeTable ;
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
/// <summary>
2019-01-06 04:40:24 +05:00
/// If true, unknowntags are allowed inside PSObject.
2016-07-29 13:02:49 -07:00
/// </summary>
private bool UnknownTagsAllowed
{
get
{
Dbg . Assert ( _version . Major <= 1 , "Deserializer assumes clixml version is <= 1.1" );
2019-01-06 06:51:20 +05:00
// If minor version is greater than 1, it means that there can be
// some unknown tags in xml. Deserialization should ignore such element.
2016-07-29 13:02:49 -07:00
return ( _version . Minor > 1 );
}
}
2016-03-30 14:20:52 -07:00
2020-11-27 08:10:43 +00:00
[SuppressMessage(
"Performance",
"CA1822:Mark members as static",
Justification = "Accesses instance members in preprocessor branch.")]
2016-07-29 13:02:49 -07:00
private bool DuplicateRefIdsAllowed
{
get
{
2016-03-30 14:20:52 -07:00
#if DEBUG
2016-07-29 13:02:49 -07:00
Dbg . Assert ( _version . Major <= 1 , "Deserializer assumes clixml version is <= 1.1" );
Version boundaryVersion = new Version ( 1 , 1 , 0 , 1 );
return ( _version < boundaryVersion );
2016-03-30 14:20:52 -07:00
#else
2016-07-29 13:02:49 -07:00
return true ; // handle v1 stuff gracefully
2016-03-30 14:20:52 -07:00
#endif
2016-07-29 13:02:49 -07:00
}
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
/// <summary>
2019-01-06 04:40:24 +05:00
/// Depth below top level - used to prevent stack overflow during deserialization.
2016-07-29 13:02:49 -07:00
/// </summary>
private int _depthBelowTopLevel ;
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
/// <summary>
2019-01-06 04:40:24 +05:00
/// Version declared by the clixml being read.
2016-07-29 13:02:49 -07:00
/// </summary>
private Version _version ;
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
private const int MaxDepthBelowTopLevel = 50 ;
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
private readonly ReferenceIdHandlerForDeserializer < object > _objectRefIdHandler ;
private readonly ReferenceIdHandlerForDeserializer < ConsolidatedString > _typeRefIdHandler ;
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
/// <summary>
/// </summary>
/// <param name="reader"></param>
/// <param name="context"></param>
internal InternalDeserializer ( XmlReader reader , DeserializationContext context )
{
Dbg . Assert ( reader != null , "caller should validate the parameter" );
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
_reader = reader ;
_context = context ;
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
_objectRefIdHandler = new ReferenceIdHandlerForDeserializer < object >();
_typeRefIdHandler = new ReferenceIdHandlerForDeserializer < ConsolidatedString >();
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
#endregion constructor
2016-03-30 14:20:52 -07:00
2017-07-14 09:52:24 -07:00
#region Known CIMTypes
2020-11-05 03:36:23 +00:00
private static readonly Lazy < HashSet < Type >> s_knownCimArrayTypes = new Lazy < HashSet < Type >>(
2017-07-14 09:52:24 -07:00
() =>
new HashSet < Type >
{
2019-01-08 00:40:07 +05:00
typeof ( bool ),
2017-07-14 09:52:24 -07:00
typeof ( byte ),
typeof ( char ),
typeof ( DateTime ),
2019-11-06 08:47:32 +05:00
typeof ( decimal ),
typeof ( double ),
2017-07-14 09:52:24 -07:00
typeof ( Int16 ),
typeof ( Int32 ),
typeof ( Int64 ),
2019-11-06 08:47:32 +05:00
typeof ( sbyte ),
2017-07-14 09:52:24 -07:00
typeof ( Single ),
2019-11-06 08:47:32 +05:00
typeof ( string ),
2017-07-14 09:52:24 -07:00
typeof ( TimeSpan ),
typeof ( UInt16 ),
typeof ( UInt32 ),
typeof ( UInt64 ),
typeof ( object ),
typeof ( CimInstance )
}
);
#endregion
2016-07-29 13:02:49 -07:00
#region deserialization
/// <summary>
/// Used by Remoting infrastructure. This TypeTable instance
/// will be used by Deserializer if ExecutionContext is not
2016-08-28 05:44:55 +00:00
/// available (to get the ExecutionContext's TypeTable)
2016-07-29 13:02:49 -07:00
/// </summary>
internal TypeTable TypeTable
{
get { return _typeTable ; }
2018-12-23 22:20:06 -08:00
2016-07-29 13:02:49 -07:00
set { _typeTable = value ; }
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
/// <summary>
/// Validates the version for correctness. Also validates that deserializer
/// can deserialize this version.
/// </summary>
/// <param name="version">
/// version in string format
/// </param>
internal void ValidateVersion ( string version )
{
Dbg . Assert ( version != null , "Caller should validate the parameter" );
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
_version = null ;
Exception exceptionToRethrow = null ;
try
{
_version = new Version ( version );
}
catch ( ArgumentException e )
{
exceptionToRethrow = e ;
}
catch ( FormatException e )
{
exceptionToRethrow = e ;
}
2018-12-23 22:20:06 -08:00
2016-07-29 13:02:49 -07:00
if ( exceptionToRethrow != null )
{
throw NewXmlException ( Serialization . InvalidVersion , exceptionToRethrow );
}
2016-03-30 14:20:52 -07:00
2019-01-06 06:51:20 +05:00
// Versioning Note:Future version of serialization can add new known types.
// This version will ignore those known types, if they are base object.
// It is expected that future version will still put information in base
// and adapter properties which this serializer can read and use.
// For example, assume the version 2 serialization engine supports a new known
// type IPAddress. The version 1 deserializer doesn't know IPAddress as known
// type and it must retrieve it as an PSObject. The version 2 serializer
// can serialize this as follows:
// <PSObject Version=1.2 Was=Deserialized.IPAddress >
2016-07-29 13:02:49 -07:00
// <TypeNames>...</TypeNames>
// <BaseObject>
2016-08-28 05:44:55 +00:00
// <IPAddress>120.23.35.53</IPAddress>
2016-07-29 13:02:49 -07:00
// </BaseObject>
// <Properties>
// <string name=Address>120.23.34.53</string>
// <string name=class>A</string>
// </Properties>
2019-01-06 06:51:20 +05:00
// </PSObject>
2016-08-28 05:44:55 +00:00
// In above example, V1 serializer will ignore <IPAddress> element and read
2016-07-29 13:02:49 -07:00
// properties from <Properties>
// V2 serializer can read <IPAddress> tag and ignore properties.
2016-08-28 05:44:55 +00:00
// Read serialization note doc for information.
2016-03-30 14:20:52 -07:00
2019-01-06 06:51:20 +05:00
// Now validate the major version number is 1
2016-07-29 13:02:49 -07:00
if ( _version . Major != 1 )
{
throw NewXmlException ( Serialization . UnexpectedVersion , null , _version . Major );
}
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
private object ReadOneDeserializedObject ( out string streamName , out bool isKnownPrimitiveType )
{
if ( _reader . NodeType != XmlNodeType . Element )
{
throw NewXmlException ( Serialization . InvalidNodeType , null ,
2020-05-19 19:57:52 +01:00
_reader . NodeType . ToString (), nameof ( XmlNodeType . Element ));
2016-07-29 13:02:49 -07:00
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
s_trace . WriteLine ( "Processing start node {0}" , _reader . LocalName );
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
streamName = _reader . GetAttribute ( SerializationStrings . StreamNameAttribute );
isKnownPrimitiveType = false ;
2016-03-30 14:20:52 -07:00
2019-01-06 06:51:20 +05:00
// handle nil node
2016-07-29 13:02:49 -07:00
if ( IsNextElement ( SerializationStrings . NilTag ))
{
Skip ();
return null ;
}
2016-03-30 14:20:52 -07:00
2019-01-06 06:51:20 +05:00
// Handle reference to previous deserialized object.
2016-07-29 13:02:49 -07:00
if ( IsNextElement ( SerializationStrings . ReferenceTag ))
{
string refId = _reader . GetAttribute ( SerializationStrings . ReferenceIdAttribute );
2016-03-30 14:20:52 -07:00
2020-07-30 16:06:38 -07:00
if ( refId == null )
2016-07-29 13:02:49 -07:00
{
throw NewXmlException ( Serialization . AttributeExpected , null , SerializationStrings . ReferenceIdAttribute );
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
object duplicate = _objectRefIdHandler . GetReferencedObject ( refId );
2020-07-30 16:06:38 -07:00
if ( duplicate == null )
2016-07-29 13:02:49 -07:00
{
throw NewXmlException ( Serialization . InvalidReferenceId , null , refId );
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
Skip ();
return duplicate ;
}
2016-03-30 14:20:52 -07:00
2019-01-06 06:51:20 +05:00
// Handle primitive known types
2016-07-29 13:02:49 -07:00
TypeSerializationInfo pktInfo = KnownTypes . GetTypeSerializationInfoFromItemTag ( _reader . LocalName );
if ( pktInfo != null )
{
s_trace . WriteLine ( "Primitive Knowntype Element {0}" , pktInfo . ItemTag );
isKnownPrimitiveType = true ;
return ReadPrimaryKnownType ( pktInfo );
}
2016-03-30 14:20:52 -07:00
2019-01-06 06:51:20 +05:00
// Handle PSObject
2016-07-29 13:02:49 -07:00
if ( IsNextElement ( SerializationStrings . PSObjectTag ))
{
s_trace . WriteLine ( "PSObject Element" );
return ReadPSObject ();
}
2016-03-30 14:20:52 -07:00
2019-01-06 06:51:20 +05:00
// If we are here, we have an unknown node. Unknown nodes may
// be allowed inside PSObject. We do not allow them at top level.
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
s_trace . TraceError ( "Invalid element {0} tag found" , _reader . LocalName );
throw NewXmlException ( Serialization . InvalidElementTag , null , _reader . LocalName );
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
private bool _isStopping = false ;
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
/// <summary>
2019-01-06 04:40:24 +05:00
/// Called from a separate thread will stop the serialization process.
2016-07-29 13:02:49 -07:00
/// </summary>
internal void Stop ()
{
_isStopping = true ;
}
2016-03-30 14:20:52 -07:00
private void CheckIfStopping ()
{
2016-07-29 13:02:49 -07:00
if ( _isStopping )
2016-03-30 14:20:52 -07:00
{
throw PSTraceSource . NewInvalidOperationException ( Serialization . Stopping );
}
}
2016-07-29 13:02:49 -07:00
internal const string CimInstanceMetadataProperty = "__InstanceMetadata" ;
internal const string CimModifiedProperties = "Modified" ;
internal const string CimClassMetadataProperty = "__ClassMetadata" ;
internal const string CimClassNameProperty = "ClassName" ;
internal const string CimNamespaceProperty = "Namespace" ;
internal const string CimServerNameProperty = "ServerName" ;
internal const string CimHashCodeProperty = "Hash" ;
internal const string CimMiXmlProperty = "MiXml" ;
2016-03-30 14:20:52 -07:00
2020-11-27 08:10:43 +00:00
private static bool RehydrateCimInstanceProperty (
2016-07-29 13:02:49 -07:00
CimInstance cimInstance ,
PSPropertyInfo deserializedProperty ,
HashSet < string > namesOfModifiedProperties )
{
Dbg . Assert ( cimInstance != null , "Caller should make sure cimInstance != null" );
Dbg . Assert ( deserializedProperty != null , "Caller should make sure deserializedProperty != null" );
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
if ( deserializedProperty . Name . Equals ( RemotingConstants . ComputerNameNoteProperty , StringComparison . OrdinalIgnoreCase ))
{
string psComputerNameValue = deserializedProperty . Value as string ;
if ( psComputerNameValue != null )
{
cimInstance . SetCimSessionComputerName ( psComputerNameValue );
}
2018-12-23 22:20:06 -08:00
2016-07-29 13:02:49 -07:00
return true ;
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
CimProperty cimProperty = cimInstance . CimInstanceProperties [ deserializedProperty . Name ];
2020-07-30 16:06:38 -07:00
if ( cimProperty == null )
2016-07-29 13:02:49 -07:00
{
return false ;
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
// TODO/FIXME - think if it is possible to do the array handling in a more efficient way
object propertyValue = deserializedProperty . Value ;
if ( propertyValue != null )
{
PSObject psoPropertyValue = PSObject . AsPSObject ( propertyValue );
if ( psoPropertyValue . BaseObject is ArrayList )
{
2020-07-30 16:06:38 -07:00
if (( psoPropertyValue . InternalTypeNames == null ) || ( psoPropertyValue . InternalTypeNames . Count == 0 ))
2016-07-29 13:02:49 -07:00
{
return false ;
}
2018-12-23 22:20:06 -08:00
2016-07-29 13:02:49 -07:00
string originalArrayTypeName = Deserializer . MaskDeserializationPrefix ( psoPropertyValue . InternalTypeNames [ 0 ]);
2020-07-30 16:06:38 -07:00
if ( originalArrayTypeName == null )
2016-07-29 13:02:49 -07:00
{
return false ;
}
2018-12-23 22:20:06 -08:00
2016-07-29 13:02:49 -07:00
Type originalArrayType ;
if (! LanguagePrimitives . TryConvertTo ( originalArrayTypeName , CultureInfo . InvariantCulture , out originalArrayType ))
{
return false ;
}
2018-12-23 22:20:06 -08:00
2017-07-14 09:52:24 -07:00
if (! originalArrayType . IsArray || ! s_knownCimArrayTypes . Value . Contains ( originalArrayType . GetElementType ()))
2016-07-29 13:02:49 -07:00
{
return false ;
}
2018-12-23 22:20:06 -08:00
2016-07-29 13:02:49 -07:00
object newPropertyValue ;
if (! LanguagePrimitives . TryConvertTo ( propertyValue , originalArrayType , CultureInfo . InvariantCulture , out newPropertyValue ))
{
return false ;
}
2018-12-23 22:20:06 -08:00
2016-07-29 13:02:49 -07:00
psoPropertyValue = PSObject . AsPSObject ( newPropertyValue );
}
2018-12-23 22:20:06 -08:00
2016-07-29 13:02:49 -07:00
propertyValue = psoPropertyValue . BaseObject ;
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
try
{
cimProperty . Value = propertyValue ;
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
if (! namesOfModifiedProperties . Contains ( deserializedProperty . Name ))
{
cimProperty . IsValueModified = false ;
}
2016-03-30 14:20:52 -07:00
#if DEBUG
2016-07-29 13:02:49 -07:00
else
{
Dbg . Assert ( cimProperty . IsValueModified , "Deserialized CIM properties should by default be marked as 'modified' " );
}
2016-03-30 14:20:52 -07:00
#endif
2016-07-29 13:02:49 -07:00
}
catch ( FormatException )
{
return false ;
}
catch ( InvalidCastException )
{
return false ;
}
catch ( ArgumentException )
{
return false ;
}
catch ( CimException )
{
return false ;
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
return true ;
}
2016-03-30 14:20:52 -07:00
2020-11-05 03:36:23 +00:00
private static readonly Lazy < CimDeserializer > s_cimDeserializer = new Lazy < CimDeserializer >( CimDeserializer . Create );
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
private CimClass RehydrateCimClass ( PSPropertyInfo classMetadataProperty )
{
2020-07-30 16:06:38 -07:00
if (( classMetadataProperty == null ) || ( classMetadataProperty . Value == null ))
2016-07-29 13:02:49 -07:00
{
return null ;
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
IEnumerable deserializedClasses = LanguagePrimitives . GetEnumerable ( classMetadataProperty . Value );
2020-07-30 16:06:38 -07:00
if ( deserializedClasses == null )
2016-07-29 13:02:49 -07:00
{
return null ;
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
Stack < KeyValuePair < CimClassSerializationId , CimClass >> cimClassesToAddToCache = new Stack < KeyValuePair < CimClassSerializationId , CimClass >>();
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
//
// REHYDRATE CLASS METADATA
//
CimClass parentClass = null ;
CimClass currentClass = null ;
foreach ( var deserializedClass in deserializedClasses )
{
parentClass = currentClass ;
2016-03-30 14:20:52 -07:00
2020-07-30 16:06:38 -07:00
if ( deserializedClass == null )
2016-07-29 13:02:49 -07:00
{
return null ;
}
2018-12-23 22:20:06 -08:00
2016-07-29 13:02:49 -07:00
PSObject psoDeserializedClass = PSObject . AsPSObject ( deserializedClass );
2016-03-30 14:20:52 -07:00
2020-11-05 16:58:48 +00:00
if (!( psoDeserializedClass . InstanceMembers [ InternalDeserializer . CimNamespaceProperty ] is PSPropertyInfo namespaceProperty ))
2016-07-29 13:02:49 -07:00
{
return null ;
}
2018-12-23 22:20:06 -08:00
2016-07-29 13:02:49 -07:00
string cimNamespace = namespaceProperty . Value as string ;
2016-03-30 14:20:52 -07:00
2020-11-05 16:58:48 +00:00
if (!( psoDeserializedClass . InstanceMembers [ InternalDeserializer . CimClassNameProperty ] is PSPropertyInfo classNameProperty ))
2016-07-29 13:02:49 -07:00
{
return null ;
}
2018-12-23 22:20:06 -08:00
2016-07-29 13:02:49 -07:00
string cimClassName = classNameProperty . Value as string ;
2016-03-30 14:20:52 -07:00
2020-11-05 16:58:48 +00:00
if (!( psoDeserializedClass . InstanceMembers [ InternalDeserializer . CimServerNameProperty ] is PSPropertyInfo computerNameProperty ))
2016-07-29 13:02:49 -07:00
{
return null ;
}
2018-12-23 22:20:06 -08:00
2016-07-29 13:02:49 -07:00
string computerName = computerNameProperty . Value as string ;
2016-03-30 14:20:52 -07:00
2020-11-05 16:58:48 +00:00
if (!( psoDeserializedClass . InstanceMembers [ InternalDeserializer . CimHashCodeProperty ] is PSPropertyInfo hashCodeProperty ))
2016-07-29 13:02:49 -07:00
{
return null ;
}
2018-12-23 22:20:06 -08:00
2016-07-29 13:02:49 -07:00
var hashCodeObject = hashCodeProperty . Value ;
2020-07-30 16:06:38 -07:00
if ( hashCodeObject == null )
2016-07-29 13:02:49 -07:00
{
return null ;
}
2018-12-23 22:20:06 -08:00
2016-07-29 13:02:49 -07:00
if ( hashCodeObject is PSObject )
{
hashCodeObject = (( PSObject ) hashCodeObject ). BaseObject ;
}
2018-12-23 22:20:06 -08:00
2020-08-01 00:41:59 +01:00
if ( hashCodeObject is not int )
2016-07-29 13:02:49 -07:00
{
return null ;
}
2018-12-23 22:20:06 -08:00
2016-07-29 13:02:49 -07:00
int hashCode = ( int ) hashCodeObject ;
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
CimClassSerializationId cimClassSerializationId = new CimClassSerializationId ( cimClassName , cimNamespace , computerName , hashCode );
currentClass = _context . cimClassSerializationIdCache . GetCimClassFromCache ( cimClassSerializationId );
if ( currentClass != null )
{
continue ;
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
PSPropertyInfo miXmlProperty = psoDeserializedClass . InstanceMembers [ InternalDeserializer . CimMiXmlProperty ] as PSPropertyInfo ;
2020-07-30 16:06:38 -07:00
if (( miXmlProperty == null ) || ( miXmlProperty . Value == null ))
2016-07-29 13:02:49 -07:00
{
return null ;
}
2018-12-23 22:20:06 -08:00
2016-07-29 13:02:49 -07:00
string miXmlString = miXmlProperty . Value . ToString ();
byte [] miXmlBytes = Encoding . Unicode . GetBytes ( miXmlString );
uint offset = 0 ;
try
{
currentClass = s_cimDeserializer . Value . DeserializeClass (
miXmlBytes ,
ref offset ,
parentClass ,
computerName : computerName ,
namespaceName : cimNamespace );
cimClassesToAddToCache . Push ( new KeyValuePair < CimClassSerializationId , CimClass >( cimClassSerializationId , currentClass ));
}
catch ( CimException )
{
return null ;
}
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
//
// UPDATE CLASSDECL DACHE
//
foreach ( var cacheEntry in cimClassesToAddToCache )
{
_context . cimClassSerializationIdCache . AddCimClassToCache ( cacheEntry . Key , cacheEntry . Value );
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
return currentClass ;
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
// NOTE: Win7 change for refid-s that span multiple xml documents: ADMIN: changelist #226414
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
private PSObject RehydrateCimInstance ( PSObject deserializedObject )
{
2020-08-01 00:41:59 +01:00
if ( deserializedObject . BaseObject is not PSCustomObject )
2016-07-29 13:02:49 -07:00
{
return deserializedObject ;
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
PSPropertyInfo classMetadataProperty = deserializedObject . InstanceMembers [ CimClassMetadataProperty ] as PSPropertyInfo ;
CimClass cimClass = RehydrateCimClass ( classMetadataProperty );
2020-07-30 16:06:38 -07:00
if ( cimClass == null )
2016-07-29 13:02:49 -07:00
{
return deserializedObject ;
}
2018-12-23 22:20:06 -08:00
2016-07-29 13:02:49 -07:00
CimInstance cimInstance ;
try
{
cimInstance = new CimInstance ( cimClass );
}
catch ( CimException )
{
return deserializedObject ;
}
2018-12-23 22:20:06 -08:00
2016-07-29 13:02:49 -07:00
PSObject psoCimInstance = PSObject . AsPSObject ( cimInstance );
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
// process __InstanceMetadata
HashSet < string > namesOfModifiedProperties = new HashSet < string >( StringComparer . OrdinalIgnoreCase );
PSPropertyInfo instanceMetadataProperty = deserializedObject . InstanceMembers [ CimInstanceMetadataProperty ] as PSPropertyInfo ;
if (( instanceMetadataProperty != null ) && ( instanceMetadataProperty . Value != null ))
{
PSObject instanceMetadata = PSObject . AsPSObject ( instanceMetadataProperty . Value );
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
PSPropertyInfo modifiedPropertiesProperty = instanceMetadata . InstanceMembers [ CimModifiedProperties ] as PSPropertyInfo ;
if (( modifiedPropertiesProperty != null ) && ( modifiedPropertiesProperty . Value != null ))
{
string modifiedPropertiesString = modifiedPropertiesProperty . Value . ToString ();
foreach ( string nameOfModifiedProperty in modifiedPropertiesString . Split ( Utils . Separators . Space ))
{
namesOfModifiedProperties . Add ( nameOfModifiedProperty );
}
}
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
// process properties that were originally "adapted" properties
2019-03-21 02:43:52 +01:00
if ( deserializedObject . AdaptedMembers != null )
2016-07-29 13:02:49 -07:00
{
2019-03-21 02:43:52 +01:00
foreach ( PSMemberInfo deserializedMemberInfo in deserializedObject . AdaptedMembers )
2016-07-29 13:02:49 -07:00
{
2020-11-05 16:58:48 +00:00
if (!( deserializedMemberInfo is PSPropertyInfo deserializedProperty ))
2016-07-29 13:02:49 -07:00
{
continue ;
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
bool propertyHandledSuccessfully = RehydrateCimInstanceProperty (
cimInstance ,
deserializedProperty ,
namesOfModifiedProperties );
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
if (! propertyHandledSuccessfully )
{
return deserializedObject ;
}
}
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
// process properties that were originally "extended" properties
foreach ( PSMemberInfo deserializedMemberInfo in deserializedObject . InstanceMembers )
{
2020-11-05 16:58:48 +00:00
if (!( deserializedMemberInfo is PSPropertyInfo deserializedProperty ))
2016-07-29 13:02:49 -07:00
{
continue ;
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
// skip adapted properties
2019-03-21 02:43:52 +01:00
if (( deserializedObject . AdaptedMembers != null ) && ( deserializedObject . AdaptedMembers [ deserializedProperty . Name ] != null ))
2016-07-29 13:02:49 -07:00
{
continue ;
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
// skip metadata introduced by CliXml/CimInstance serialization
if ( deserializedProperty . Name . Equals ( CimClassMetadataProperty , StringComparison . OrdinalIgnoreCase ))
{
continue ;
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
// skip properties re-added by the client (i.e. through types.ps1xml)
if ( psoCimInstance . Properties [ deserializedProperty . Name ] != null )
{
continue ;
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
PSNoteProperty noteProperty = new PSNoteProperty ( deserializedProperty . Name , deserializedProperty . Value );
psoCimInstance . Properties . Add ( noteProperty );
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
return psoCimInstance ;
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
/// <summary>
/// Reads one object. At this point reader should be positioned
/// at the start tag of object.
/// </summary>
/// <returns>
/// Deserialized Object.
/// </returns>
internal object ReadOneObject ( out string streamName )
{
this . CheckIfStopping ();
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
try
{
_depthBelowTopLevel ++;
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
Dbg . Assert ( _depthBelowTopLevel <= MaxDepthBelowTopLevel , "depthBelowTopLevel should be <= MaxDepthBelowTopLevel" );
if ( _depthBelowTopLevel == MaxDepthBelowTopLevel )
{
throw NewXmlException ( Serialization . DeserializationTooDeep , null );
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
bool isKnownPrimitiveType ;
object result = ReadOneDeserializedObject ( out streamName , out isKnownPrimitiveType );
2020-07-30 16:06:38 -07:00
if ( result == null )
2016-07-29 13:02:49 -07:00
{
return null ;
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
if (! isKnownPrimitiveType )
{
PSObject mshSource = PSObject . AsPSObject ( result );
if ( Deserializer . IsDeserializedInstanceOfType ( mshSource , typeof ( CimInstance )))
{
return RehydrateCimInstance ( mshSource );
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
// Convert deserialized object to a user-defined type (specified in a types.ps1xml file)
Type targetType = mshSource . GetTargetTypeForDeserialization ( _typeTable );
2018-06-26 02:37:09 +05:00
if ( targetType != null )
2016-07-29 13:02:49 -07:00
{
Exception rehydrationException = null ;
try
{
object rehydratedResult = LanguagePrimitives . ConvertTo (
result , targetType , true /* recurse */ , CultureInfo . InvariantCulture , _typeTable );
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
PSEtwLog . LogAnalyticVerbose ( PSEventId . Serializer_RehydrationSuccess ,
PSOpcode . Rehydration , PSTask . Serialization , PSKeyword . Serializer ,
mshSource . InternalTypeNames . Key , targetType . FullName ,
rehydratedResult . GetType (). FullName );
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
return rehydratedResult ;
}
catch ( InvalidCastException e )
{
rehydrationException = e ;
}
catch ( ArgumentException e )
{
rehydrationException = e ;
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
Dbg . Assert ( rehydrationException != null ,
"The only way to get here is with rehydrationException != null" );
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
PSEtwLog . LogAnalyticError ( PSEventId . Serializer_RehydrationFailure ,
PSOpcode . Rehydration , PSTask . Serialization , PSKeyword . Serializer ,
mshSource . InternalTypeNames . Key ,
targetType . FullName ,
rehydrationException . ToString (),
2020-07-30 16:06:38 -07:00
rehydrationException . InnerException == null
2016-07-29 13:02:49 -07:00
? string . Empty
: rehydrationException . InnerException . ToString ());
}
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
return result ;
}
finally
{
_depthBelowTopLevel --;
Dbg . Assert ( _depthBelowTopLevel >= 0 , "depthBelowTopLevel should be >= 0" );
}
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
private object ReadOneObject ()
{
string ignore ;
return ReadOneObject ( out ignore );
}
2016-03-30 14:20:52 -07:00
2019-01-06 06:51:20 +05:00
// Reads one PSObject
2016-07-29 13:02:49 -07:00
private PSObject ReadPSObject ()
{
PSObject dso = ReadAttributeAndCreatePSObject ();
2016-03-30 14:20:52 -07:00
2019-01-06 06:51:20 +05:00
// Read start element tag
2020-11-13 04:39:25 +00:00
if (! ReadStartElementAndHandleEmpty ( SerializationStrings . PSObjectTag ))
2016-07-29 13:02:49 -07:00
{
2019-01-06 06:51:20 +05:00
// Empty element.
2016-07-29 13:02:49 -07:00
return dso ;
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
bool overrideTypeInfo = true ;
2019-01-06 06:51:20 +05:00
// Process all the child nodes
2016-07-29 13:02:49 -07:00
while ( _reader . NodeType == XmlNodeType . Element )
{
if ( IsNextElement ( SerializationStrings . TypeNamesTag ) ||
IsNextElement ( SerializationStrings . TypeNamesReferenceTag ))
{
ReadTypeNames ( dso );
overrideTypeInfo = false ;
}
else if ( IsNextElement ( SerializationStrings . AdapterProperties ))
{
ReadProperties ( dso );
}
else if ( IsNextElement ( SerializationStrings . MemberSet ))
{
ReadMemberSet ( dso . InstanceMembers );
}
else if ( IsNextElement ( SerializationStrings . ToStringElementTag ))
{
dso . ToStringFromDeserialization = ReadDecodedElementString ( SerializationStrings . ToStringElementTag );
2019-03-21 02:43:52 +01:00
dso . InstanceMembers . Add ( PSObject . DotNetInstanceAdapter . GetDotNetMethod < PSMemberInfo >( dso , "ToString" ));
2016-07-29 13:02:49 -07:00
PSGetMemberBinder . SetHasInstanceMember ( "ToString" );
// Fix for Win8:75437
// The TokenText property is used in type conversion and it is not being populated during deserialization
// As a result, parameter binding fails in the following case on a remote session
2017-01-16 13:31:14 -08:00
// register-psssessionconfiguration -Name foo -psversion 3.0
// The value "3.0" is treated as a double and since the TokenText property holds null, the type converter tries to convert
2016-07-29 13:02:49 -07:00
// from System.Double to System.Version using Parse method of System.Version and fails
dso . TokenText = dso . ToStringFromDeserialization ;
}
else
{
2019-01-06 06:51:20 +05:00
// Handle BaseObject
2016-07-29 13:02:49 -07:00
object baseObject = null ;
ContainerType ct = ContainerType . None ;
2016-03-30 14:20:52 -07:00
2019-01-06 06:51:20 +05:00
// Check if tag is PrimaryKnownType.
2016-07-29 13:02:49 -07:00
TypeSerializationInfo pktInfo = KnownTypes . GetTypeSerializationInfoFromItemTag ( _reader . LocalName );
if ( pktInfo != null )
{
s_trace . WriteLine ( "Primitive Knowntype Element {0}" , pktInfo . ItemTag );
baseObject = ReadPrimaryKnownType ( pktInfo );
}
else if ( IsKnownContainerTag ( out ct ))
{
s_trace . WriteLine ( "Found container node {0}" , ct );
baseObject = ReadKnownContainer ( ct );
}
else if ( IsNextElement ( SerializationStrings . PSObjectTag ))
{
s_trace . WriteLine ( "Found PSObject node" );
baseObject = ReadOneObject ();
}
else
{
2019-01-06 06:51:20 +05:00
// We have an unknown tag
2016-09-07 21:27:57 +00:00
s_trace . WriteLine ( "Unknown tag {0} encountered" , _reader . LocalName );
2016-07-29 13:02:49 -07:00
if ( UnknownTagsAllowed )
{
Skip ();
}
else
{
throw NewXmlException ( Serialization . InvalidElementTag , null , _reader . LocalName );
}
}
2018-12-23 22:20:06 -08:00
2016-07-29 13:02:49 -07:00
if ( baseObject != null )
{
dso . SetCoreOnDeserialization ( baseObject , overrideTypeInfo );
}
}
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
ReadEndElement ();
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
PSObject immediateBasePso = dso . ImmediateBaseObject as PSObject ;
if ( immediateBasePso != null )
{
PSObject . CopyDeserializerFields ( source : immediateBasePso , target : dso );
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
return dso ;
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
/// <summary>
2017-01-16 13:31:14 -08:00
/// This function reads the refId attribute and creates a
2019-01-06 04:40:24 +05:00
/// mshObject for that attribute.
2016-07-29 13:02:49 -07:00
/// </summary>
2018-12-25 21:43:03 +05:00
/// <returns>MshObject which is created for refId.</returns>
2016-07-29 13:02:49 -07:00
private PSObject ReadAttributeAndCreatePSObject ()
{
string refId = _reader . GetAttribute ( SerializationStrings . ReferenceIdAttribute );
PSObject sh = new PSObject ();
2016-03-30 14:20:52 -07:00
2019-01-06 06:51:20 +05:00
// RefId is not mandatory attribute
2016-07-29 13:02:49 -07:00
if ( refId != null )
{
s_trace . WriteLine ( "Read PSObject with refId: {0}" , refId );
_objectRefIdHandler . SetRefId ( sh , refId , this . DuplicateRefIdsAllowed );
}
2018-12-23 22:20:06 -08:00
2016-07-29 13:02:49 -07:00
return sh ;
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
/// <summary>
2019-01-06 04:40:24 +05:00
/// Read type names.
2016-07-29 13:02:49 -07:00
/// </summary>
/// <param name="dso">
/// PSObject to which TypeNames are added
/// </param>
private void ReadTypeNames ( PSObject dso )
{
Dbg . Assert ( dso != null , "caller should validate the parameter" );
Dbg . Assert ( _reader . NodeType == XmlNodeType . Element , "NodeType should be Element" );
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
if ( IsNextElement ( SerializationStrings . TypeNamesTag ))
{
Collection < string > typeNames = new Collection < string >();
2016-03-30 14:20:52 -07:00
2019-01-06 06:51:20 +05:00
// Read refId attribute if available
2016-07-29 13:02:49 -07:00
string refId = _reader . GetAttribute ( SerializationStrings . ReferenceIdAttribute );
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
s_trace . WriteLine ( "Processing TypeNamesTag with refId {0}" , refId );
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
if ( ReadStartElementAndHandleEmpty ( SerializationStrings . TypeNamesTag ))
{
while ( _reader . NodeType == XmlNodeType . Element )
{
if ( IsNextElement ( SerializationStrings . TypeNamesItemTag ))
{
string item = ReadDecodedElementString ( SerializationStrings . TypeNamesItemTag );
if (! string . IsNullOrEmpty ( item ))
{
Deserializer . AddDeserializationPrefix ( ref item );
typeNames . Add ( item );
}
}
else
{
throw NewXmlException ( Serialization . InvalidElementTag , null , _reader . LocalName );
}
}
2018-12-23 22:20:06 -08:00
2016-07-29 13:02:49 -07:00
ReadEndElement ();
}
2018-12-23 22:20:06 -08:00
2016-07-29 13:02:49 -07:00
dso . InternalTypeNames = new ConsolidatedString ( typeNames );
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
if ( refId != null )
{
_typeRefIdHandler . SetRefId ( dso . InternalTypeNames , refId , this . DuplicateRefIdsAllowed );
}
}
else if ( IsNextElement ( SerializationStrings . TypeNamesReferenceTag ))
{
string refId = _reader . GetAttribute ( SerializationStrings . ReferenceIdAttribute );
s_trace . WriteLine ( "Processing TypeNamesReferenceTag with refId {0}" , refId );
2020-07-30 16:06:38 -07:00
if ( refId == null )
2016-07-29 13:02:49 -07:00
{
throw NewXmlException ( Serialization . AttributeExpected , null , SerializationStrings . ReferenceIdAttribute );
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
ConsolidatedString typeNames = _typeRefIdHandler . GetReferencedObject ( refId );
2020-07-30 16:06:38 -07:00
if ( typeNames == null )
2016-07-29 13:02:49 -07:00
{
throw NewXmlException ( Serialization . InvalidTypeHierarchyReferenceId , null , refId );
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
// At this point we know that we will clone the ConsolidatedString object, so we might end up
// allocating much more memory than the length of the xml string
// We have to account for that to limit that to remoting quota and protect against OOM.
_context . LogExtraMemoryUsage (
typeNames . Key . Length * sizeof ( char ) // Key is shared among the cloned and original object
// but the list of strings isn't. The expression to the left
// is roughly the size of memory the list of strings occupies
- 29 // size of <Obj><TNRef RefId="0"/></Obj> in UTF8 encoding
);
dso . InternalTypeNames = new ConsolidatedString ( typeNames );
2016-03-30 14:20:52 -07:00
2019-01-06 06:51:20 +05:00
// Skip the node
2016-07-29 13:02:49 -07:00
Skip ();
}
else
{
Dbg . Assert ( false , "caller should validate that we do no reach here" );
}
}
2016-03-30 14:20:52 -07:00
/// <summary>
2019-01-06 04:40:24 +05:00
/// Read properties.
2016-03-30 14:20:52 -07:00
/// </summary>
private void ReadProperties ( PSObject dso )
{
Dbg . Assert ( dso != null , "caller should validate the parameter" );
Dbg . Assert ( _reader . NodeType == XmlNodeType . Element , "NodeType should be Element" );
2019-01-06 06:51:20 +05:00
// Since we are adding baseobject properties as propertybag,
// mark the object as deserialized.
2019-03-21 02:43:52 +01:00
dso . IsDeserialized = true ;
dso . AdaptedMembers = new PSMemberInfoInternalCollection < PSPropertyInfo >();
2016-03-30 14:20:52 -07:00
2019-01-06 06:51:20 +05:00
// Add the GetType method to the instance members, so that it works on deserialized psobjects
2019-03-21 02:43:52 +01:00
dso . InstanceMembers . Add ( PSObject . DotNetInstanceAdapter . GetDotNetMethod < PSMemberInfo >( dso , "GetType" ));
2016-03-30 14:20:52 -07:00
PSGetMemberBinder . SetHasInstanceMember ( "GetType" );
2019-01-06 06:51:20 +05:00
// Set Clr members to a collection which is empty
2019-03-21 02:43:52 +01:00
dso . ClrMembers = new PSMemberInfoInternalCollection < PSPropertyInfo >();
2016-03-30 14:20:52 -07:00
if ( ReadStartElementAndHandleEmpty ( SerializationStrings . AdapterProperties ))
{
2019-01-06 06:51:20 +05:00
// Read one or more property elements
2016-03-30 14:20:52 -07:00
while ( _reader . NodeType == XmlNodeType . Element )
{
string property = ReadNameAttribute ();
object value = ReadOneObject ();
PSProperty prop = new PSProperty ( property , value );
2019-03-21 02:43:52 +01:00
dso . AdaptedMembers . Add ( prop );
2016-03-30 14:20:52 -07:00
}
2018-12-23 22:20:06 -08:00
2016-03-30 14:20:52 -07:00
ReadEndElement ();
}
}
2016-07-29 13:02:49 -07:00
#region memberset
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
/// <summary>
2017-01-16 13:31:14 -08:00
/// Read memberset.
2016-07-29 13:02:49 -07:00
/// </summary>
/// <param name="collection">
/// collection to which members are added
/// </param>
private void ReadMemberSet ( PSMemberInfoCollection < PSMemberInfo > collection )
{
Dbg . Assert ( collection != null , "caller should validate the value" );
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
if ( ReadStartElementAndHandleEmpty ( SerializationStrings . MemberSet ))
{
while ( _reader . NodeType == XmlNodeType . Element )
{
if ( IsNextElement ( SerializationStrings . MemberSet ))
{
string name = ReadNameAttribute ();
PSMemberSet set = new PSMemberSet ( name );
collection . Add ( set );
ReadMemberSet ( set . Members );
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
PSGetMemberBinder . SetHasInstanceMember ( name );
}
else
{
PSNoteProperty note = ReadNoteProperty ();
collection . Add ( note );
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
PSGetMemberBinder . SetHasInstanceMember ( note . Name );
}
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
ReadEndElement ();
}
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
/// <summary>
2019-01-10 02:07:41 +05:00
/// Read note.
2016-07-29 13:02:49 -07:00
/// </summary>
/// <returns></returns>
private PSNoteProperty ReadNoteProperty ()
{
string name = ReadNameAttribute ();
object value = ReadOneObject ();
PSNoteProperty note = new PSNoteProperty ( name , value );
return note ;
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
#endregion memberset
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
#region known container
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
private bool IsKnownContainerTag ( out ContainerType ct )
{
Dbg . Assert ( _reader . NodeType == XmlNodeType . Element , "Expected node type is element" );
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
if ( IsNextElement ( SerializationStrings . DictionaryTag ))
{
ct = ContainerType . Dictionary ;
}
else if ( IsNextElement ( SerializationStrings . QueueTag ))
{
ct = ContainerType . Queue ;
}
else if ( IsNextElement ( SerializationStrings . StackTag ))
{
ct = ContainerType . Stack ;
}
else if ( IsNextElement ( SerializationStrings . ListTag ))
{
ct = ContainerType . List ;
}
else if ( IsNextElement ( SerializationStrings . CollectionTag ))
{
ct = ContainerType . Enumerable ;
}
else
{
ct = ContainerType . None ;
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
return ct != ContainerType . None ;
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
private object ReadKnownContainer ( ContainerType ct )
{
switch ( ct )
{
case ContainerType . Dictionary :
return ReadDictionary ( ct );
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
case ContainerType . Enumerable :
case ContainerType . List :
case ContainerType . Queue :
case ContainerType . Stack :
return ReadListContainer ( ct );
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
default :
Dbg . Assert ( false , "Unrecognized ContainerType enum" );
return null ;
}
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
/// <summary>
2019-01-06 04:40:24 +05:00
/// Read List Containers.
2016-07-29 13:02:49 -07:00
/// </summary>
/// <returns></returns>
private object ReadListContainer ( ContainerType ct )
{
Dbg . Assert ( ct == ContainerType . Enumerable ||
ct == ContainerType . List ||
ct == ContainerType . Queue ||
2016-09-07 21:27:57 +00:00
ct == ContainerType . Stack , "ct should be queue, stack, enumerable or list" );
2016-03-30 14:20:52 -07:00
ArrayList list = new ArrayList ();
2016-07-29 13:02:49 -07:00
if ( ReadStartElementAndHandleEmpty ( _reader . LocalName ))
{
while ( _reader . NodeType == XmlNodeType . Element )
{
list . Add ( ReadOneObject ());
}
2018-12-23 22:20:06 -08:00
2016-07-29 13:02:49 -07:00
ReadEndElement ();
}
2018-12-23 22:20:06 -08:00
2016-07-29 13:02:49 -07:00
if ( ct == ContainerType . Stack )
{
list . Reverse ();
return new Stack ( list );
}
else if ( ct == ContainerType . Queue )
{
2016-03-30 14:20:52 -07:00
return new Queue ( list );
2016-07-29 13:02:49 -07:00
}
2018-12-23 22:20:06 -08:00
2016-07-29 13:02:49 -07:00
return list ;
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
/// <summary>
2019-01-06 04:40:24 +05:00
/// Deserialize Dictionary.
2016-07-29 13:02:49 -07:00
/// </summary>
/// <returns></returns>
private object ReadDictionary ( ContainerType ct )
{
Dbg . Assert ( ct == ContainerType . Dictionary , "Unrecognized ContainerType enum" );
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
// We assume the hash table is a PowerShell hash table and hence uses
// a case insensitive string comparer. If we discover a key collision,
// we'll revert back to the default comparer.
Hashtable table = new Hashtable ( StringComparer . CurrentCultureIgnoreCase );
int keyClashFoundIteration = 0 ;
if ( ReadStartElementAndHandleEmpty ( SerializationStrings . DictionaryTag ))
{
while ( _reader . NodeType == XmlNodeType . Element )
{
ReadStartElement ( SerializationStrings . DictionaryEntryTag );
2016-03-30 14:20:52 -07:00
2019-01-06 06:51:20 +05:00
// Read Key
2016-07-29 13:02:49 -07:00
if ( _reader . NodeType != XmlNodeType . Element )
{
throw NewXmlException ( Serialization . DictionaryKeyNotSpecified , null );
}
2018-12-23 22:20:06 -08:00
2016-07-29 13:02:49 -07:00
string name = ReadNameAttribute ();
2020-06-25 07:30:40 +01:00
if (! string . Equals ( name , SerializationStrings . DictionaryKey , StringComparison . OrdinalIgnoreCase ))
2016-07-29 13:02:49 -07:00
{
throw NewXmlException ( Serialization . InvalidDictionaryKeyName , null );
}
2018-12-23 22:20:06 -08:00
2016-07-29 13:02:49 -07:00
object key = ReadOneObject ();
2016-03-30 14:20:52 -07:00
2020-07-30 16:06:38 -07:00
if ( key == null )
2016-07-29 13:02:49 -07:00
{
throw NewXmlException ( Serialization . NullAsDictionaryKey , null );
}
2019-01-06 06:51:20 +05:00
// Read Value
2016-07-29 13:02:49 -07:00
if ( _reader . NodeType != XmlNodeType . Element )
{
throw NewXmlException ( Serialization . DictionaryValueNotSpecified , null );
}
2018-12-23 22:20:06 -08:00
2016-07-29 13:02:49 -07:00
name = ReadNameAttribute ();
2020-06-25 07:30:40 +01:00
if (! string . Equals ( name , SerializationStrings . DictionaryValue , StringComparison . OrdinalIgnoreCase ))
2016-07-29 13:02:49 -07:00
{
throw NewXmlException ( Serialization . InvalidDictionaryValueName , null );
}
2018-12-23 22:20:06 -08:00
2016-07-29 13:02:49 -07:00
object value = ReadOneObject ();
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
// On the first collision, copy the hash table to one that uses the default comparer.
if ( table . ContainsKey ( key ) && ( keyClashFoundIteration == 0 ))
{
keyClashFoundIteration ++;
Hashtable newHashTable = new Hashtable ();
foreach ( DictionaryEntry entry in table )
{
newHashTable . Add ( entry . Key , entry . Value );
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
table = newHashTable ;
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
// win8: 389060. If there are still collisions even with case-sensitive default comparer,
// use an IEqualityComparer that does object ref equality.
if ( table . ContainsKey ( key ) && ( keyClashFoundIteration == 1 ))
{
keyClashFoundIteration ++;
IEqualityComparer equalityComparer = new ReferenceEqualityComparer ();
Hashtable newHashTable = new Hashtable ( equalityComparer );
foreach ( DictionaryEntry entry in table )
{
newHashTable . Add ( entry . Key , entry . Value );
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
table = newHashTable ;
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
try
{
2019-01-06 06:51:20 +05:00
// Add entry to hashtable
2016-07-29 13:02:49 -07:00
table . Add ( key , value );
}
catch ( ArgumentException e )
{
throw this . NewXmlException ( Serialization . InvalidPrimitiveType , e , typeof ( Hashtable ));
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
ReadEndElement ();
}
2018-12-23 22:20:06 -08:00
2016-07-29 13:02:49 -07:00
ReadEndElement ();
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
return table ;
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
#endregion known containers
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
#endregion deserialization
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
#region Getting XmlReaderSettings
2016-03-30 14:20:52 -07:00
2016-08-02 19:00:50 -07:00
internal static XmlReaderSettings XmlReaderSettingsForCliXml { get ; } = GetXmlReaderSettingsForCliXml ();
2016-03-30 14:20:52 -07:00
2016-08-02 19:00:50 -07:00
private static XmlReaderSettings GetXmlReaderSettingsForCliXml ()
2016-07-29 13:02:49 -07:00
{
XmlReaderSettings xrs = new XmlReaderSettings ();
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
xrs . CheckCharacters = false ;
xrs . CloseInput = false ;
2016-03-30 14:20:52 -07:00
2019-01-06 06:51:20 +05:00
// The XML data needs to be in conformance to the rules for a well-formed XML 1.0 document.
2016-07-29 13:02:49 -07:00
xrs . ConformanceLevel = ConformanceLevel . Document ;
xrs . IgnoreComments = true ;
xrs . IgnoreProcessingInstructions = true ;
xrs . IgnoreWhitespace = false ;
xrs . MaxCharactersFromEntities = 1024 ;
2017-07-06 09:09:57 -07:00
xrs . XmlResolver = null ;
xrs . DtdProcessing = DtdProcessing . Prohibit ;
2016-07-29 13:02:49 -07:00
xrs . Schemas = null ;
xrs . ValidationFlags = System . Xml . Schema . XmlSchemaValidationFlags . None ;
xrs . ValidationType = ValidationType . None ;
return xrs ;
}
2016-03-30 14:20:52 -07:00
2016-08-02 19:00:50 -07:00
internal static XmlReaderSettings XmlReaderSettingsForUntrustedXmlDocument { get ; } = GetXmlReaderSettingsForUntrustedXmlDocument ();
2016-03-30 14:20:52 -07:00
2016-08-02 19:00:50 -07:00
private static XmlReaderSettings GetXmlReaderSettingsForUntrustedXmlDocument ()
2016-07-29 13:02:49 -07:00
{
XmlReaderSettings settings = new XmlReaderSettings ();
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
settings . CheckCharacters = false ;
settings . ConformanceLevel = ConformanceLevel . Auto ;
settings . IgnoreComments = true ;
settings . IgnoreProcessingInstructions = true ;
settings . IgnoreWhitespace = true ;
settings . MaxCharactersFromEntities = 1024 ;
settings . MaxCharactersInDocument = 512 * 1024 * 1024 ; // 512M characters = 1GB
2017-07-06 09:09:57 -07:00
settings . XmlResolver = null ;
2016-03-30 14:20:52 -07:00
settings . DtdProcessing = DtdProcessing . Parse ; // Allowing DTD parsing with limits of MaxCharactersFromEntities/MaxCharactersInDocument
2016-07-29 13:02:49 -07:00
settings . ValidationFlags = System . Xml . Schema . XmlSchemaValidationFlags . None ;
settings . ValidationType = ValidationType . None ;
return settings ;
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
#endregion
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
#region known type deserialization
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
internal static object DeserializeBoolean ( InternalDeserializer deserializer )
{
Dbg . Assert ( deserializer != null , "Caller should validate the parameter" );
try
{
2016-03-30 14:20:52 -07:00
return XmlConvert . ToBoolean ( deserializer . _reader . ReadElementContentAsString ());
2016-07-29 13:02:49 -07:00
}
catch ( FormatException e )
{
throw deserializer . NewXmlException ( Serialization . InvalidPrimitiveType , e , typeof ( bool ). FullName );
}
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
internal static object DeserializeByte ( InternalDeserializer deserializer )
{
Dbg . Assert ( deserializer != null , "Caller should validate the parameter" );
Exception recognizedException = null ;
try
{
2016-03-30 14:20:52 -07:00
return XmlConvert . ToByte ( deserializer . _reader . ReadElementContentAsString ());
2016-07-29 13:02:49 -07:00
}
catch ( FormatException e )
{
recognizedException = e ;
}
catch ( OverflowException e )
{
recognizedException = e ;
}
2018-12-23 22:20:06 -08:00
2016-07-29 13:02:49 -07:00
throw deserializer . NewXmlException ( Serialization . InvalidPrimitiveType , recognizedException , typeof ( byte ). FullName );
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
internal static object DeserializeChar ( InternalDeserializer deserializer )
{
Dbg . Assert ( deserializer != null , "Caller should validate the parameter" );
Exception recognizedException = null ;
try
{
2019-01-08 00:40:07 +05:00
return ( char ) XmlConvert . ToUInt16 ( deserializer . _reader . ReadElementContentAsString ());
2016-07-29 13:02:49 -07:00
}
catch ( FormatException e )
{
recognizedException = e ;
}
catch ( OverflowException e )
{
recognizedException = e ;
}
2018-12-23 22:20:06 -08:00
2016-07-29 13:02:49 -07:00
throw deserializer . NewXmlException ( Serialization . InvalidPrimitiveType , recognizedException , typeof ( char ). FullName );
}
2016-03-30 14:20:52 -07:00
internal static object DeserializeDateTime ( InternalDeserializer deserializer )
{
Dbg . Assert ( deserializer != null , "Caller should validate the parameter" );
try
{
return XmlConvert . ToDateTime ( deserializer . _reader . ReadElementContentAsString (), XmlDateTimeSerializationMode . RoundtripKind );
}
catch ( FormatException e )
{
throw deserializer . NewXmlException ( Serialization . InvalidPrimitiveType , e , typeof ( DateTime ). FullName );
}
}
2016-07-29 13:02:49 -07:00
internal static object DeserializeDecimal ( InternalDeserializer deserializer )
{
Dbg . Assert ( deserializer != null , "Caller should validate the parameter" );
Exception recognizedException = null ;
try
{
2016-03-30 14:20:52 -07:00
return XmlConvert . ToDecimal ( deserializer . _reader . ReadElementContentAsString ());
2016-07-29 13:02:49 -07:00
}
catch ( FormatException e )
{
recognizedException = e ;
}
catch ( OverflowException e )
{
recognizedException = e ;
}
2018-12-23 22:20:06 -08:00
2016-07-29 13:02:49 -07:00
throw deserializer . NewXmlException ( Serialization . InvalidPrimitiveType , recognizedException , typeof ( decimal ). FullName );
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
internal static object DeserializeDouble ( InternalDeserializer deserializer )
{
Dbg . Assert ( deserializer != null , "Caller should validate the parameter" );
Exception recognizedException = null ;
try
{
2016-03-30 14:20:52 -07:00
return XmlConvert . ToDouble ( deserializer . _reader . ReadElementContentAsString ());
2016-07-29 13:02:49 -07:00
}
catch ( FormatException e )
{
recognizedException = e ;
}
catch ( OverflowException e )
{
recognizedException = e ;
}
2018-12-23 22:20:06 -08:00
2016-07-29 13:02:49 -07:00
throw deserializer . NewXmlException ( Serialization . InvalidPrimitiveType , recognizedException , typeof ( double ). FullName );
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
internal static object DeserializeGuid ( InternalDeserializer deserializer )
{
Dbg . Assert ( deserializer != null , "Caller should validate the parameter" );
Exception recognizedException = null ;
try
{
2016-03-30 14:20:52 -07:00
return XmlConvert . ToGuid ( deserializer . _reader . ReadElementContentAsString ());
2016-07-29 13:02:49 -07:00
}
// MSDN for XmlConvert.ToGuid doesn't list any exceptions, but
// Reflector shows that this just calls to new Guid(string)
// which MSDN documents can throw Format/OverflowException
catch ( FormatException e )
{
recognizedException = e ;
}
catch ( OverflowException e )
{
recognizedException = e ;
}
2018-12-23 22:20:06 -08:00
2016-07-29 13:02:49 -07:00
throw deserializer . NewXmlException ( Serialization . InvalidPrimitiveType , recognizedException , typeof ( Guid ). FullName );
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
internal static object DeserializeVersion ( InternalDeserializer deserializer )
{
Dbg . Assert ( deserializer != null , "Caller should validate the parameter" );
Exception recognizedException = null ;
try
{
2016-03-30 14:20:52 -07:00
return new Version ( deserializer . _reader . ReadElementContentAsString ());
2016-07-29 13:02:49 -07:00
}
catch ( ArgumentException e )
{
recognizedException = e ;
}
catch ( FormatException e )
{
recognizedException = e ;
}
catch ( OverflowException e )
{
recognizedException = e ;
}
2018-12-23 22:20:06 -08:00
2016-07-29 13:02:49 -07:00
throw deserializer . NewXmlException ( Serialization . InvalidPrimitiveType , recognizedException , typeof ( Version ). FullName );
}
2016-03-30 14:20:52 -07:00
2016-08-01 13:57:57 -07:00
internal static object DeserializeSemanticVersion ( InternalDeserializer deserializer )
{
Dbg . Assert ( deserializer != null , "Caller should validate the parameter" );
Exception recognizedException = null ;
try
{
return new SemanticVersion ( deserializer . _reader . ReadElementContentAsString ());
}
catch ( ArgumentException e )
{
recognizedException = e ;
}
catch ( FormatException e )
{
recognizedException = e ;
}
catch ( OverflowException e )
{
recognizedException = e ;
}
2018-12-23 22:20:06 -08:00
2016-08-01 13:57:57 -07:00
throw deserializer . NewXmlException ( Serialization . InvalidPrimitiveType , recognizedException , typeof ( Version ). FullName );
}
2016-07-29 13:02:49 -07:00
internal static object DeserializeInt16 ( InternalDeserializer deserializer )
{
Dbg . Assert ( deserializer != null , "Caller should validate the parameter" );
Exception recognizedException = null ;
try
{
2016-03-30 14:20:52 -07:00
return XmlConvert . ToInt16 ( deserializer . _reader . ReadElementContentAsString ());
2016-07-29 13:02:49 -07:00
}
catch ( FormatException e )
{
recognizedException = e ;
}
catch ( OverflowException e )
{
recognizedException = e ;
}
2018-12-23 22:20:06 -08:00
2016-07-29 13:02:49 -07:00
throw deserializer . NewXmlException ( Serialization . InvalidPrimitiveType , recognizedException , typeof ( Int16 ). FullName );
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
internal static object DeserializeInt32 ( InternalDeserializer deserializer )
{
Dbg . Assert ( deserializer != null , "Caller should validate the parameter" );
Exception recognizedException = null ;
try
{
2016-03-30 14:20:52 -07:00
return XmlConvert . ToInt32 ( deserializer . _reader . ReadElementContentAsString ());
2016-07-29 13:02:49 -07:00
}
catch ( FormatException e )
{
recognizedException = e ;
}
catch ( OverflowException e )
{
recognizedException = e ;
}
2018-12-23 22:20:06 -08:00
2016-07-29 13:02:49 -07:00
throw deserializer . NewXmlException ( Serialization . InvalidPrimitiveType , recognizedException , typeof ( Int32 ). FullName );
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
internal static object DeserializeInt64 ( InternalDeserializer deserializer )
{
Dbg . Assert ( deserializer != null , "Caller should validate the parameter" );
Exception recognizedException = null ;
try
{
2016-03-30 14:20:52 -07:00
return XmlConvert . ToInt64 ( deserializer . _reader . ReadElementContentAsString ());
2016-07-29 13:02:49 -07:00
}
catch ( FormatException e )
{
recognizedException = e ;
}
catch ( OverflowException e )
{
recognizedException = e ;
}
2018-12-23 22:20:06 -08:00
2016-07-29 13:02:49 -07:00
throw deserializer . NewXmlException ( Serialization . InvalidPrimitiveType , recognizedException , typeof ( Int64 ). FullName );
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
internal static object DeserializeSByte ( InternalDeserializer deserializer )
{
Dbg . Assert ( deserializer != null , "Caller should validate the parameter" );
Exception recognizedException = null ;
try
{
2016-03-30 14:20:52 -07:00
return XmlConvert . ToSByte ( deserializer . _reader . ReadElementContentAsString ());
2016-07-29 13:02:49 -07:00
}
catch ( FormatException e )
{
recognizedException = e ;
}
catch ( OverflowException e )
{
recognizedException = e ;
}
2018-12-23 22:20:06 -08:00
2016-07-29 13:02:49 -07:00
throw deserializer . NewXmlException ( Serialization . InvalidPrimitiveType , recognizedException , typeof ( sbyte ). FullName );
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
internal static object DeserializeSingle ( InternalDeserializer deserializer )
{
Dbg . Assert ( deserializer != null , "Caller should validate the parameter" );
Exception recognizedException = null ;
try
{
2016-03-30 14:20:52 -07:00
return XmlConvert . ToSingle ( deserializer . _reader . ReadElementContentAsString ());
2016-07-29 13:02:49 -07:00
}
catch ( FormatException e )
{
recognizedException = e ;
}
catch ( OverflowException e )
{
recognizedException = e ;
}
2018-12-23 22:20:06 -08:00
2016-07-29 13:02:49 -07:00
throw deserializer . NewXmlException ( Serialization . InvalidPrimitiveType , recognizedException , typeof ( float ). FullName );
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
internal static object DeserializeScriptBlock ( InternalDeserializer deserializer )
{
Dbg . Assert ( deserializer != null , "Caller should validate the parameter" );
string scriptBlockBody = deserializer . ReadDecodedElementString ( SerializationStrings . ScriptBlockTag );
2020-11-20 12:26:46 +00:00
if (( deserializer . _context . options & DeserializationOptions . DeserializeScriptBlocks ) == DeserializationOptions . DeserializeScriptBlocks )
2016-07-29 13:02:49 -07:00
{
return ScriptBlock . Create ( scriptBlockBody );
}
else
{
2019-01-06 06:51:20 +05:00
// Scriptblock is deserialized as string
2016-07-29 13:02:49 -07:00
return scriptBlockBody ;
}
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
internal static object DeserializeString ( InternalDeserializer deserializer )
{
Dbg . Assert ( deserializer != null , "Caller should validate the parameter" );
return deserializer . ReadDecodedElementString ( SerializationStrings . StringTag );
}
2016-03-30 14:20:52 -07:00
2016-08-02 19:00:50 -07:00
internal static object DeserializeTimeSpan ( InternalDeserializer deserializer )
2016-07-29 13:02:49 -07:00
{
Dbg . Assert ( deserializer != null , "Caller should validate the parameter" );
try
{
2016-03-30 14:20:52 -07:00
return XmlConvert . ToTimeSpan ( deserializer . _reader . ReadElementContentAsString ());
2016-07-29 13:02:49 -07:00
}
catch ( FormatException e )
{
throw deserializer . NewXmlException ( Serialization . InvalidPrimitiveType , e , typeof ( TimeSpan ). FullName );
}
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
internal static object DeserializeUInt16 ( InternalDeserializer deserializer )
{
Dbg . Assert ( deserializer != null , "Caller should validate the parameter" );
Exception recognizedException = null ;
try
{
2016-03-30 14:20:52 -07:00
return XmlConvert . ToUInt16 ( deserializer . _reader . ReadElementContentAsString ());
2016-07-29 13:02:49 -07:00
}
catch ( FormatException e )
{
recognizedException = e ;
}
catch ( OverflowException e )
{
recognizedException = e ;
}
2018-12-23 22:20:06 -08:00
2016-07-29 13:02:49 -07:00
throw deserializer . NewXmlException ( Serialization . InvalidPrimitiveType , recognizedException , typeof ( UInt16 ). FullName );
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
internal static object DeserializeUInt32 ( InternalDeserializer deserializer )
{
Dbg . Assert ( deserializer != null , "Caller should validate the parameter" );
Exception recognizedException = null ;
try
{
2016-03-30 14:20:52 -07:00
return XmlConvert . ToUInt32 ( deserializer . _reader . ReadElementContentAsString ());
2016-07-29 13:02:49 -07:00
}
catch ( FormatException e )
{
recognizedException = e ;
}
catch ( OverflowException e )
{
recognizedException = e ;
}
2018-12-23 22:20:06 -08:00
2016-07-29 13:02:49 -07:00
throw deserializer . NewXmlException ( Serialization . InvalidPrimitiveType , recognizedException , typeof ( UInt32 ). FullName );
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
internal static object DeserializeUInt64 ( InternalDeserializer deserializer )
{
Dbg . Assert ( deserializer != null , "Caller should validate the parameter" );
Exception recognizedException = null ;
try
{
2016-03-30 14:20:52 -07:00
return XmlConvert . ToUInt64 ( deserializer . _reader . ReadElementContentAsString ());
2016-07-29 13:02:49 -07:00
}
catch ( FormatException e )
{
recognizedException = e ;
}
catch ( OverflowException e )
{
recognizedException = e ;
}
2018-12-23 22:20:06 -08:00
2016-07-29 13:02:49 -07:00
throw deserializer . NewXmlException ( Serialization . InvalidPrimitiveType , recognizedException , typeof ( UInt64 ). FullName );
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
internal static object DeserializeUri ( InternalDeserializer deserializer )
{
Dbg . Assert ( deserializer != null , "Caller should validate the parameter" );
try
{
string uriString = deserializer . ReadDecodedElementString ( SerializationStrings . AnyUriTag );
return new Uri ( uriString , UriKind . RelativeOrAbsolute );
}
catch ( UriFormatException e )
{
throw deserializer . NewXmlException ( Serialization . InvalidPrimitiveType , e , typeof ( Uri ). FullName );
}
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
internal static object DeserializeByteArray ( InternalDeserializer deserializer )
{
Dbg . Assert ( deserializer != null , "Caller should validate the parameter" );
try
{
2016-03-30 14:20:52 -07:00
return Convert . FromBase64String ( deserializer . _reader . ReadElementContentAsString ());
2016-07-29 13:02:49 -07:00
}
catch ( FormatException e )
{
throw deserializer . NewXmlException ( Serialization . InvalidPrimitiveType , e , typeof ( byte []). FullName );
}
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
/// <exception cref="System.Xml.XmlException"></exception>
internal static XmlDocument LoadUnsafeXmlDocument ( FileInfo xmlPath , bool preserveNonElements , int? maxCharactersInDocument )
{
XmlDocument doc = null ;
// same FileStream options as Reflector shows for XmlDocument.Load(path) / XmlDownloadManager.GetStream:
using ( Stream stream = new FileStream ( xmlPath . FullName , FileMode . Open , FileAccess . Read , FileShare . Read ))
{
doc = LoadUnsafeXmlDocument ( stream , preserveNonElements , maxCharactersInDocument );
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
return doc ;
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
/// <exception cref="System.Xml.XmlException"></exception>
internal static XmlDocument LoadUnsafeXmlDocument ( string xmlContents , bool preserveNonElements , int? maxCharactersInDocument )
{
using ( TextReader textReader = new StringReader ( xmlContents ))
{
return LoadUnsafeXmlDocument ( textReader , preserveNonElements , maxCharactersInDocument );
}
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
/// <exception cref="System.Xml.XmlException"></exception>
internal static XmlDocument LoadUnsafeXmlDocument ( Stream stream , bool preserveNonElements , int? maxCharactersInDocument )
{
using ( TextReader textReader = new StreamReader ( stream ))
{
return LoadUnsafeXmlDocument ( textReader , preserveNonElements , maxCharactersInDocument );
}
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
/// <exception cref="System.Xml.XmlException"></exception>
internal static XmlDocument LoadUnsafeXmlDocument ( TextReader textReader , bool preserveNonElements , int? maxCharactersInDocument )
{
XmlReaderSettings settings ;
if ( maxCharactersInDocument . HasValue || preserveNonElements )
{
settings = InternalDeserializer . XmlReaderSettingsForUntrustedXmlDocument . Clone ();
if ( maxCharactersInDocument . HasValue )
{
settings . MaxCharactersInDocument = maxCharactersInDocument . Value ;
}
2018-12-23 22:20:06 -08:00
2016-07-29 13:02:49 -07:00
if ( preserveNonElements )
{
settings . IgnoreWhitespace = false ;
settings . IgnoreProcessingInstructions = false ;
settings . IgnoreComments = false ;
}
}
else
{
settings = InternalDeserializer . XmlReaderSettingsForUntrustedXmlDocument ;
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
try
{
XmlReader xmlReader = XmlReader . Create ( textReader , settings );
XmlDocument xmlDocument = new XmlDocument ();
xmlDocument . PreserveWhitespace = preserveNonElements ;
xmlDocument . Load ( xmlReader );
return xmlDocument ;
}
catch ( InvalidOperationException invalidOperationException )
{
throw new XmlException ( invalidOperationException . Message , invalidOperationException );
}
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
internal static object DeserializeXmlDocument ( InternalDeserializer deserializer )
{
Dbg . Assert ( deserializer != null , "Caller should validate the parameter" );
string docAsString = deserializer . ReadDecodedElementString ( SerializationStrings . XmlDocumentTag );
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
try
{
int? maxCharactersInDocument = null ;
if ( deserializer . _context . MaximumAllowedMemory . HasValue )
{
maxCharactersInDocument = deserializer . _context . MaximumAllowedMemory . Value / sizeof ( char );
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
XmlDocument doc = InternalDeserializer . LoadUnsafeXmlDocument (
docAsString ,
true , /* preserve whitespace, comments, etc. */
maxCharactersInDocument );
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
deserializer . _context . LogExtraMemoryUsage (( docAsString . Length - doc . OuterXml . Length ) * sizeof ( char ));
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
return doc ;
}
catch ( XmlException e )
{
throw deserializer . NewXmlException ( Serialization . InvalidPrimitiveType , e , typeof ( XmlDocument ). FullName );
}
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
internal static object DeserializeProgressRecord ( InternalDeserializer deserializer )
{
Dbg . Assert ( deserializer != null , "Caller should validate the parameter" );
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
//
// read deserialized elements of a progress record
//
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
deserializer . ReadStartElement ( SerializationStrings . ProgressRecord );
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
string activity = null , currentOperation = null , prt = null , statusDescription = null ;
int activityId = 0 , parentActivityId = 0 , percentComplete = 0 , secondsRemaining = 0 ;
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
Exception recognizedException = null ;
try
{
activity = deserializer . ReadDecodedElementString ( SerializationStrings . ProgressRecordActivity );
activityId = int . Parse ( deserializer . ReadDecodedElementString ( SerializationStrings . ProgressRecordActivityId ), CultureInfo . InvariantCulture );
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
object tmp = deserializer . ReadOneObject ();
2020-11-20 06:42:51 +00:00
currentOperation = tmp ?. ToString ();
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
parentActivityId = int . Parse ( deserializer . ReadDecodedElementString ( SerializationStrings . ProgressRecordParentActivityId ), CultureInfo . InvariantCulture );
percentComplete = int . Parse ( deserializer . ReadDecodedElementString ( SerializationStrings . ProgressRecordPercentComplete ), CultureInfo . InvariantCulture );
prt = deserializer . ReadDecodedElementString ( SerializationStrings . ProgressRecordType );
secondsRemaining = int . Parse ( deserializer . ReadDecodedElementString ( SerializationStrings . ProgressRecordSecondsRemaining ), CultureInfo . InvariantCulture );
statusDescription = deserializer . ReadDecodedElementString ( SerializationStrings . ProgressRecordStatusDescription );
}
catch ( FormatException e )
{
recognizedException = e ;
}
catch ( OverflowException e )
{
recognizedException = e ;
}
2018-12-23 22:20:06 -08:00
2016-07-29 13:02:49 -07:00
if ( recognizedException != null )
{
throw deserializer . NewXmlException ( Serialization . InvalidPrimitiveType , recognizedException , typeof ( UInt64 ). FullName );
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
deserializer . ReadEndElement ();
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
//
// Build the progress record
//
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
ProgressRecordType type ;
try
{
type = ( ProgressRecordType ) Enum . Parse ( typeof ( ProgressRecordType ), prt , true );
}
catch ( ArgumentException e )
{
throw deserializer . NewXmlException ( Serialization . InvalidPrimitiveType , e , typeof ( ProgressRecord ). FullName );
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
try
{
ProgressRecord record = new ProgressRecord ( activityId , activity , statusDescription );
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
if (! string . IsNullOrEmpty ( currentOperation ))
{
record . CurrentOperation = currentOperation ;
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
record . ParentActivityId = parentActivityId ;
record . PercentComplete = percentComplete ;
record . RecordType = type ;
record . SecondsRemaining = secondsRemaining ;
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
return record ;
}
catch ( ArgumentException e )
{
throw deserializer . NewXmlException ( Serialization . InvalidPrimitiveType , e , typeof ( ProgressRecord ). FullName );
}
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
internal static object DeserializeSecureString ( InternalDeserializer deserializer )
{
Dbg . Assert ( deserializer != null , "Caller should validate the parameter" );
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
//
// read deserialized elements of a Secure String
//
return deserializer . ReadSecureString ();
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
#endregion known type deserialization
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
#region misc
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
/// <summary>
/// Check if LocalName of next element is "tag"
/// </summary>
/// <param name="tag"></param>
/// <returns></returns>
private bool IsNextElement ( string tag )
{
Dbg . Assert (! string . IsNullOrEmpty ( tag ), "Caller should validate the parameter" );
return ( _reader . LocalName == tag ) &&
2020-11-05 04:13:12 +00:00
((( _context . options & DeserializationOptions . NoNamespace ) != 0 ) ||
2016-07-29 13:02:49 -07:00
( _reader . NamespaceURI == SerializationStrings . MonadNamespace ));
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
/// <summary>
2019-01-06 04:40:24 +05:00
/// Read start element in monad namespace.
2016-07-29 13:02:49 -07:00
/// </summary>
2018-12-29 08:25:49 +05:00
/// <param name="element">Element tag to read.</param>
2018-12-25 21:43:03 +05:00
/// <returns>True if not an empty element else false.</returns>
2016-07-29 13:02:49 -07:00
internal bool ReadStartElementAndHandleEmpty ( string element )
{
Dbg . Assert (! string . IsNullOrEmpty ( element ), "Caller should validate the parameter" );
2016-03-30 14:20:52 -07:00
2019-01-06 06:51:20 +05:00
// IsEmpty is set to true when element is of the form <tag/>
2016-07-29 13:02:49 -07:00
bool isEmpty = _reader . IsEmptyElement ;
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
this . ReadStartElement ( element );
2016-03-30 14:20:52 -07:00
2019-01-06 06:51:20 +05:00
// This takes care of the case: <tag></tag> or <tag> </tag>. In
// this case isEmpty is false.
2020-11-13 04:39:25 +00:00
if (! isEmpty && _reader . NodeType == XmlNodeType . EndElement )
2016-07-29 13:02:49 -07:00
{
ReadEndElement ();
isEmpty = true ;
}
2018-12-23 22:20:06 -08:00
2016-07-29 13:02:49 -07:00
return ! isEmpty ;
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
private void ReadStartElement ( string element )
{
Dbg . Assert (! string . IsNullOrEmpty ( element ), "Caller should validate the parameter" );
2016-03-30 14:20:52 -07:00
2020-11-20 12:26:46 +00:00
if (( _context . options & DeserializationOptions . NoNamespace ) == DeserializationOptions . NoNamespace )
2016-07-29 13:02:49 -07:00
{
_reader . ReadStartElement ( element );
}
else
{
_reader . ReadStartElement ( element , SerializationStrings . MonadNamespace );
}
2018-12-23 22:20:06 -08:00
2016-07-29 13:02:49 -07:00
_reader . MoveToContent ();
}
private void ReadEndElement ()
{
_reader . ReadEndElement ();
_reader . MoveToContent ();
}
private string ReadDecodedElementString ( string element )
{
Dbg . Assert (! string . IsNullOrEmpty ( element ), "Caller should validate the parameter" );
this . CheckIfStopping ();
string temp = null ;
2020-11-20 12:26:46 +00:00
if (( _context . options & DeserializationOptions . NoNamespace ) == DeserializationOptions . NoNamespace )
2016-07-29 13:02:49 -07:00
{
2016-03-30 14:20:52 -07:00
temp = _reader . ReadElementContentAsString ( element , string . Empty );
2016-07-29 13:02:49 -07:00
}
else
{
temp = _reader . ReadElementContentAsString ( element , SerializationStrings . MonadNamespace );
}
2018-12-23 22:20:06 -08:00
2016-07-29 13:02:49 -07:00
_reader . MoveToContent ();
temp = DecodeString ( temp );
return temp ;
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
/// <summary>
2017-09-04 19:45:51 -07:00
/// Skips an element and all its child elements.
2016-07-29 13:02:49 -07:00
/// Moves cursor to next content Node.
/// </summary>
private void Skip ()
{
_reader . Skip ();
_reader . MoveToContent ();
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
/// <summary>
2019-01-06 04:40:24 +05:00
/// Reads Primary known type.
2016-07-29 13:02:49 -07:00
/// </summary>
/// <param name="pktInfo"></param>
/// <returns></returns>
private object ReadPrimaryKnownType ( TypeSerializationInfo pktInfo )
{
Dbg . Assert ( pktInfo != null , "Deserializer should be available" );
Dbg . Assert ( pktInfo . Deserializer != null , "Deserializer should be available" );
object result = pktInfo . Deserializer ( this );
_reader . MoveToContent ();
return result ;
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
private object ReadSecureString ()
{
2018-12-22 01:26:06 -08:00
string encryptedString = _reader . ReadElementContentAsString ();
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
try
{
object result ;
if ( _context . cryptoHelper != null )
{
result = _context . cryptoHelper . DecryptSecureString ( encryptedString );
}
else
{
result = Microsoft . PowerShell . SecureStringHelper . Unprotect ( encryptedString );
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
_reader . MoveToContent ();
return result ;
}
catch ( PSCryptoException )
{
throw NewXmlException ( Serialization . DeserializeSecureStringFailed , null );
}
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
/// <summary>
2019-01-06 04:40:24 +05:00
/// Helper function for building XmlException.
2016-07-29 13:02:49 -07:00
/// </summary>
/// <param name="resourceString">
2017-01-16 13:31:14 -08:00
/// resource String
2016-07-29 13:02:49 -07:00
/// </param>
/// <param name="innerException"></param>
/// <param name="args">
/// params for format string obtained from resourceId
/// </param>
private XmlException NewXmlException
(
string resourceString ,
Exception innerException ,
params object [] args
)
{
Dbg . Assert (! string . IsNullOrEmpty ( resourceString ), "Caller should validate the parameter" );
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
string message = StringUtil . Format ( resourceString , args );
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
XmlException ex = null ;
2016-03-30 14:20:52 -07:00
IXmlLineInfo xmlLineInfo = _reader as IXmlLineInfo ;
2016-07-29 13:02:49 -07:00
if ( xmlLineInfo != null )
{
if ( xmlLineInfo . HasLineInfo ())
{
ex = new XmlException
(
message ,
innerException ,
xmlLineInfo . LineNumber ,
xmlLineInfo . LinePosition
);
}
}
2016-03-30 14:20:52 -07:00
2016-08-02 22:25:13 -07:00
return ex ?? new XmlException ( message , innerException );
2016-07-29 13:02:49 -07:00
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
private string ReadNameAttribute ()
{
string encodedName = _reader . GetAttribute ( SerializationStrings . NameAttribute );
2020-07-30 16:06:38 -07:00
if ( encodedName == null )
2016-07-29 13:02:49 -07:00
{
throw NewXmlException ( Serialization . AttributeExpected , null , SerializationStrings . NameAttribute );
}
2018-12-23 22:20:06 -08:00
2016-07-29 13:02:49 -07:00
return DecodeString ( encodedName );
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
private static string DecodeString ( string s )
{
Dbg . Assert ( s != null , "Caller should validate the parameter" );
return XmlConvert . DecodeName ( s );
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
#endregion misc
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
[TraceSourceAttribute("InternalDeserializer", "InternalDeserializer class")]
private static readonly PSTraceSource s_trace = PSTraceSource . GetTracer ( "InternalDeserializer" , "InternalDeserializer class" );
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
/// <summary>
/// Helper class for generating reference id.
/// </summary>
internal class ReferenceIdHandlerForSerializer < T > where T : class
{
/// <summary>
/// Get new reference id.
/// </summary>
2018-12-25 21:43:03 +05:00
/// <returns>New reference id.</returns>
2016-07-29 13:02:49 -07:00
private UInt64 GetNewReferenceId ()
{
UInt64 refId = _seed ++;
return refId ;
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
/// <summary>
2019-01-06 04:40:24 +05:00
/// Seed is incremented by one after each reference generation.
2016-07-29 13:02:49 -07:00
/// </summary>
private UInt64 _seed ;
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
// note:
// any boxed UInt64 takes 16 bytes on the heap
// one-character string (i.e. "7") takes 20 bytes on the heap
private readonly IDictionary < T , UInt64 > _object2refId ;
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
internal ReferenceIdHandlerForSerializer ( IDictionary < T , UInt64 > dictionary )
{
_object2refId = dictionary ;
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
/// <summary>
2019-01-06 04:40:24 +05:00
/// Assigns a RefId to the given object.
2016-07-29 13:02:49 -07:00
/// </summary>
2018-12-29 08:25:49 +05:00
/// <param name="t">Object to assign a RefId to.</param>
2018-12-25 21:43:03 +05:00
/// <returns>RefId assigned to the object.</returns>
2016-07-29 13:02:49 -07:00
internal string SetRefId ( T t )
{
if ( _object2refId != null )
{
Dbg . Assert (! _object2refId . ContainsKey ( t ), "SetRefId shouldn't be called when the object is already assigned a ref id" );
UInt64 refId = GetNewReferenceId ();
_object2refId . Add ( t , refId );
return refId . ToString ( System . Globalization . CultureInfo . InvariantCulture );
}
else
{
return null ;
}
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
/// <summary>
2020-11-24 04:35:46 +00:00
/// Gets a RefId already assigned for the given object or <see langword="null"/> if there is no associated ref id.
2016-07-29 13:02:49 -07:00
/// </summary>
/// <param name="t"></param>
/// <returns></returns>
internal string GetRefId ( T t )
{
UInt64 refId ;
if (( _object2refId != null ) && ( _object2refId . TryGetValue ( t , out refId )))
{
return refId . ToString ( System . Globalization . CultureInfo . InvariantCulture );
}
else
{
return null ;
}
}
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
internal class ReferenceIdHandlerForDeserializer < T > where T : class
{
private readonly Dictionary < string , T > _refId2object = new Dictionary < string , T >();
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
internal void SetRefId ( T o , string refId , bool duplicateRefIdsAllowed )
{
2016-03-30 14:20:52 -07:00
#if DEBUG
2016-07-29 13:02:49 -07:00
if (! duplicateRefIdsAllowed )
{
Dbg . Assert (! _refId2object . ContainsKey ( refId ), "You can't change refId association" );
}
2016-03-30 14:20:52 -07:00
#endif
2016-07-29 13:02:49 -07:00
_refId2object [ refId ] = o ;
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
internal T GetReferencedObject ( string refId )
{
Dbg . Assert ( _refId2object . ContainsKey ( refId ), "Reference id wasn't seen earlier" );
T t ;
if ( _refId2object . TryGetValue ( refId , out t ))
{
return t ;
}
else
{
return null ;
}
}
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
/// <summary>
2019-01-06 04:40:24 +05:00
/// A delegate for serializing known type.
2016-07-29 13:02:49 -07:00
/// </summary>
internal delegate void TypeSerializerDelegate ( InternalSerializer serializer , string streamName , string property , object source , TypeSerializationInfo entry );
/// <summary>
2019-01-06 04:40:24 +05:00
/// A delegate for deserializing known type.
2016-07-29 13:02:49 -07:00
/// </summary>
internal delegate object TypeDeserializerDelegate ( InternalDeserializer deserializer );
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
/// <summary>
/// This class contains serialization information about a type.
/// </summary>
internal class TypeSerializationInfo
{
/// <summary>
2019-01-06 04:40:24 +05:00
/// Constructor.
2016-07-29 13:02:49 -07:00
/// </summary>
2018-12-28 16:39:06 +05:00
/// <param name="type">Type for which this entry is created.</param>
/// <param name="itemTag">ItemTag for the type.</param>
/// <param name="propertyTag">PropertyTag for the type.</param>
/// <param name="serializer">TypeSerializerDelegate for serializing the type.</param>
/// <param name="deserializer">TypeDeserializerDelegate for deserializing the type.</param>
2016-07-29 13:02:49 -07:00
internal TypeSerializationInfo ( Type type , string itemTag , string propertyTag , TypeSerializerDelegate serializer , TypeDeserializerDelegate deserializer )
{
2016-08-02 13:29:09 -07:00
Type = type ;
Serializer = serializer ;
Deserializer = deserializer ;
ItemTag = itemTag ;
PropertyTag = propertyTag ;
2016-07-29 13:02:49 -07:00
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
#region properties
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
/// <summary>
/// Get the type for which this TypeSerializationInfo is created.
/// </summary>
2016-08-02 13:29:09 -07:00
internal Type Type { get ; }
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
/// <summary>
2019-01-06 04:40:24 +05:00
/// Get the item tag for this type.
2016-07-29 13:02:49 -07:00
/// </summary>
2016-08-02 13:29:09 -07:00
internal string ItemTag { get ; }
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
/// <summary>
2019-01-06 04:40:24 +05:00
/// Get the Property tag for this type.
2016-07-29 13:02:49 -07:00
/// </summary>
2016-08-02 13:29:09 -07:00
internal string PropertyTag { get ; }
2016-07-29 13:02:49 -07:00
/// <summary>
2019-01-06 04:40:24 +05:00
/// Gets the delegate to serialize this type.
2016-07-29 13:02:49 -07:00
/// </summary>
2016-08-02 13:29:09 -07:00
internal TypeSerializerDelegate Serializer { get ; }
2016-07-29 13:02:49 -07:00
/// <summary>
2019-01-06 04:40:24 +05:00
/// Gets the delegate to deserialize this type.
2016-07-29 13:02:49 -07:00
/// </summary>
2016-08-02 13:29:09 -07:00
internal TypeDeserializerDelegate Deserializer { get ; }
2016-07-29 13:02:49 -07:00
#endregion properties
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
#region private
2016-08-02 13:29:09 -07:00
2016-07-29 13:02:49 -07:00
#endregion private
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
/// <summary>
/// A class for identifying types which are treated as KnownType by Monad.
2017-01-16 13:31:14 -08:00
/// A KnownType is guranteed to be available on machine on which monad is
2016-07-29 13:02:49 -07:00
/// running.
/// </summary>
internal static class KnownTypes
{
/// <summary>
2019-01-06 04:40:24 +05:00
/// Static constructor.
2016-07-29 13:02:49 -07:00
/// </summary>
static KnownTypes ()
{
for ( int i = 0 ; i < s_typeSerializationInfo . Length ; i ++)
{
s_knownTableKeyType . Add ( s_typeSerializationInfo [ i ]. Type . FullName , s_typeSerializationInfo [ i ]);
s_knownTableKeyItemTag . Add ( s_typeSerializationInfo [ i ]. ItemTag , s_typeSerializationInfo [ i ]);
}
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
/// <summary>
2019-01-06 04:40:24 +05:00
/// Gets the type serialization information about a type.
2016-07-29 13:02:49 -07:00
/// </summary>
2018-12-28 16:39:06 +05:00
/// <param name="type">Type for which information is retrieved.</param>
2018-12-25 21:43:03 +05:00
/// <returns>TypeSerializationInfo for the type, null if it doesn't exist.</returns>
2016-07-29 13:02:49 -07:00
internal static TypeSerializationInfo GetTypeSerializationInfo ( Type type )
{
TypeSerializationInfo temp ;
if (! s_knownTableKeyType . TryGetValue ( type . FullName , out temp ) && typeof ( XmlDocument ). IsAssignableFrom ( type ))
{
temp = s_xdInfo ;
}
2018-12-23 22:20:06 -08:00
2016-07-29 13:02:49 -07:00
return temp ;
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
/// <summary>
2019-01-06 04:40:24 +05:00
/// Get TypeSerializationInfo using ItemTag as key.
2016-07-29 13:02:49 -07:00
/// </summary>
2018-12-28 16:39:06 +05:00
/// <param name="itemTag">ItemTag for which TypeSerializationInfo is to be fetched.</param>
2018-12-25 21:43:03 +05:00
/// <returns>TypeSerializationInfo entry, null if no entry exist for the tag.</returns>
2016-07-29 13:02:49 -07:00
internal static TypeSerializationInfo GetTypeSerializationInfoFromItemTag ( string itemTag )
{
TypeSerializationInfo temp ;
s_knownTableKeyItemTag . TryGetValue ( itemTag , out temp );
return temp ;
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
#region private_fields
2016-03-30 14:20:52 -07:00
2019-01-06 06:51:20 +05:00
// TypeSerializationInfo for XmlDocument
2016-07-29 13:02:49 -07:00
private static readonly TypeSerializationInfo s_xdInfo =
new TypeSerializationInfo ( typeof ( XmlDocument ),
SerializationStrings . XmlDocumentTag ,
SerializationStrings . XmlDocumentTag ,
InternalSerializer . WriteXmlDocument ,
InternalDeserializer . DeserializeXmlDocument );
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
/// <summary>
/// Array of known types.
/// </summary>
private static readonly TypeSerializationInfo [] s_typeSerializationInfo = new TypeSerializationInfo []
{
2019-01-08 00:40:07 +05:00
new TypeSerializationInfo ( typeof ( bool ),
2016-07-29 13:02:49 -07:00
SerializationStrings . BooleanTag ,
SerializationStrings . BooleanTag ,
InternalSerializer . WriteBoolean ,
InternalDeserializer . DeserializeBoolean ),
2016-03-30 14:20:52 -07:00
2019-11-06 08:47:32 +05:00
new TypeSerializationInfo ( typeof ( byte ),
2016-07-29 13:02:49 -07:00
SerializationStrings . UnsignedByteTag ,
SerializationStrings . UnsignedByteTag ,
null ,
InternalDeserializer . DeserializeByte ),
2016-03-30 14:20:52 -07:00
2019-11-06 08:47:32 +05:00
new TypeSerializationInfo ( typeof ( char ),
2016-07-29 13:02:49 -07:00
SerializationStrings . CharTag ,
SerializationStrings . CharTag ,
InternalSerializer . WriteChar ,
InternalDeserializer . DeserializeChar ),
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
new TypeSerializationInfo ( typeof ( DateTime ),
SerializationStrings . DateTimeTag ,
SerializationStrings . DateTimeTag ,
InternalSerializer . WriteDateTime ,
InternalDeserializer . DeserializeDateTime ),
2016-03-30 14:20:52 -07:00
2019-11-06 08:47:32 +05:00
new TypeSerializationInfo ( typeof ( decimal ),
2016-07-29 13:02:49 -07:00
SerializationStrings . DecimalTag ,
SerializationStrings . DecimalTag ,
null ,
InternalDeserializer . DeserializeDecimal ),
2016-03-30 14:20:52 -07:00
2019-11-06 08:47:32 +05:00
new TypeSerializationInfo ( typeof ( double ),
2016-07-29 13:02:49 -07:00
SerializationStrings . DoubleTag ,
SerializationStrings . DoubleTag ,
InternalSerializer . WriteDouble ,
InternalDeserializer . DeserializeDouble ),
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
new TypeSerializationInfo ( typeof ( Guid ),
SerializationStrings . GuidTag ,
SerializationStrings . GuidTag ,
null ,
InternalDeserializer . DeserializeGuid ),
new TypeSerializationInfo ( typeof ( Int16 ),
SerializationStrings . ShortTag ,
SerializationStrings . ShortTag ,
null ,
InternalDeserializer . DeserializeInt16 ),
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
new TypeSerializationInfo ( typeof ( Int32 ),
SerializationStrings . IntTag ,
SerializationStrings . IntTag ,
null ,
InternalDeserializer . DeserializeInt32 ),
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
new TypeSerializationInfo ( typeof ( Int64 ),
SerializationStrings . LongTag ,
SerializationStrings . LongTag ,
null ,
InternalDeserializer . DeserializeInt64 ),
2016-03-30 14:20:52 -07:00
2019-11-06 08:47:32 +05:00
new TypeSerializationInfo ( typeof ( sbyte ),
2016-07-29 13:02:49 -07:00
SerializationStrings . ByteTag ,
SerializationStrings . ByteTag ,
null ,
InternalDeserializer . DeserializeSByte ),
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
new TypeSerializationInfo ( typeof ( Single ),
SerializationStrings . FloatTag ,
SerializationStrings . FloatTag ,
InternalSerializer . WriteSingle ,
InternalDeserializer . DeserializeSingle ),
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
new TypeSerializationInfo ( typeof ( ScriptBlock ),
SerializationStrings . ScriptBlockTag ,
SerializationStrings . ScriptBlockTag ,
InternalSerializer . WriteScriptBlock ,
InternalDeserializer . DeserializeScriptBlock ),
2016-03-30 14:20:52 -07:00
2019-11-06 08:47:32 +05:00
new TypeSerializationInfo ( typeof ( string ),
2016-07-29 13:02:49 -07:00
SerializationStrings . StringTag ,
SerializationStrings . StringTag ,
InternalSerializer . WriteEncodedString ,
InternalDeserializer . DeserializeString ),
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
new TypeSerializationInfo ( typeof ( TimeSpan ),
SerializationStrings . DurationTag ,
SerializationStrings . DurationTag ,
InternalSerializer . WriteTimeSpan ,
InternalDeserializer . DeserializeTimeSpan ),
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
new TypeSerializationInfo ( typeof ( UInt16 ),
SerializationStrings . UnsignedShortTag ,
SerializationStrings . UnsignedShortTag ,
null ,
InternalDeserializer . DeserializeUInt16 ),
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
new TypeSerializationInfo ( typeof ( UInt32 ),
SerializationStrings . UnsignedIntTag ,
SerializationStrings . UnsignedIntTag ,
null ,
InternalDeserializer . DeserializeUInt32 ),
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
new TypeSerializationInfo ( typeof ( UInt64 ),
SerializationStrings . UnsignedLongTag ,
SerializationStrings . UnsignedLongTag ,
null ,
InternalDeserializer . DeserializeUInt64 ),
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
new TypeSerializationInfo ( typeof ( Uri ),
SerializationStrings . AnyUriTag ,
SerializationStrings . AnyUriTag ,
InternalSerializer . WriteUri ,
InternalDeserializer . DeserializeUri ),
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
new TypeSerializationInfo ( typeof ( byte []),
SerializationStrings . Base64BinaryTag ,
SerializationStrings . Base64BinaryTag ,
InternalSerializer . WriteByteArray ,
InternalDeserializer . DeserializeByteArray ),
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
new TypeSerializationInfo ( typeof ( System . Version ),
SerializationStrings . VersionTag ,
SerializationStrings . VersionTag ,
InternalSerializer . WriteVersion ,
InternalDeserializer . DeserializeVersion ),
2016-08-01 13:57:57 -07:00
2016-07-29 13:02:49 -07:00
s_xdInfo ,
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
new TypeSerializationInfo ( typeof ( ProgressRecord ),
SerializationStrings . ProgressRecord ,
SerializationStrings . ProgressRecord ,
InternalSerializer . WriteProgressRecord ,
InternalDeserializer . DeserializeProgressRecord ),
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
new TypeSerializationInfo ( typeof ( SecureString ),
SerializationStrings . SecureStringTag ,
SerializationStrings . SecureStringTag ,
InternalSerializer . WriteSecureString ,
InternalDeserializer . DeserializeSecureString ),
2016-08-01 13:57:57 -07:00
};
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
/// <summary>
2017-01-16 13:31:14 -08:00
/// Hashtable of knowntypes.
2016-07-29 13:02:49 -07:00
/// Key is Type.FullName and value is Type object.
/// </summary>
private static readonly Dictionary < string , TypeSerializationInfo > s_knownTableKeyType = new Dictionary < string , TypeSerializationInfo >();
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
/// <summary>
2019-01-06 04:40:24 +05:00
/// Hashtable of knowntypes. Key is ItemTag.
2016-07-29 13:02:49 -07:00
/// </summary>
private static readonly Dictionary < string , TypeSerializationInfo > s_knownTableKeyItemTag = new Dictionary < string , TypeSerializationInfo >();
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
#endregion private_fields
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
/// <summary>
2019-01-06 04:40:24 +05:00
/// This class contains helper routined for serialization/deserialization.
2016-07-29 13:02:49 -07:00
/// </summary>
internal static class SerializationUtilities
{
/// <summary>
2019-01-06 04:40:24 +05:00
/// Extracts the value of a note property from a PSObject; returns null if the property does not exist.
2016-07-29 13:02:49 -07:00
/// </summary>
internal static object GetPropertyValue ( PSObject psObject , string propertyName )
{
PSNoteProperty property = ( PSNoteProperty ) psObject . Properties [ propertyName ];
2016-03-30 14:20:52 -07:00
2020-07-30 16:06:38 -07:00
if ( property == null )
2016-07-29 13:02:49 -07:00
{
return null ;
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
return property . Value ;
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
/// <summary>
2019-01-06 04:40:24 +05:00
/// Returns the BaseObject of a note property encoded as a PSObject; returns null if the property does not exist.
2016-07-29 13:02:49 -07:00
/// </summary>
internal static object GetPsObjectPropertyBaseObject ( PSObject psObject , string propertyName )
{
PSObject propertyPsObject = ( PSObject ) GetPropertyValue ( psObject , propertyName );
2016-03-30 14:20:52 -07:00
2020-07-30 16:06:38 -07:00
if ( propertyPsObject == null )
2016-07-29 13:02:49 -07:00
{
return null ;
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
return propertyPsObject . BaseObject ;
}
2016-03-30 14:20:52 -07:00
/// <summary>
2017-01-16 13:31:14 -08:00
/// Checks if source is known container type and returns appropriate
2019-01-06 04:40:24 +05:00
/// information.
2016-03-30 14:20:52 -07:00
/// </summary>
/// <param name="source"></param>
/// <param name="ct"></param>
/// <param name="dictionary"></param>
/// <param name="enumerable"></param>
internal static void GetKnownContainerTypeInfo (
object source ,
out ContainerType ct ,
out IDictionary dictionary ,
out IEnumerable enumerable )
{
Dbg . Assert ( source != null , "caller should validate the parameter" );
ct = ContainerType . None ;
dictionary = null ;
enumerable = null ;
dictionary = source as IDictionary ;
if ( dictionary != null )
{
ct = ContainerType . Dictionary ;
}
else if ( source is Stack )
{
ct = ContainerType . Stack ;
enumerable = LanguagePrimitives . GetEnumerable ( source );
Dbg . Assert ( enumerable != null , "Stack is enumerable" );
}
else if ( source is Queue )
{
ct = ContainerType . Queue ;
enumerable = LanguagePrimitives . GetEnumerable ( source );
Dbg . Assert ( enumerable != null , "Queue is enumerable" );
}
else if ( source is IList )
{
ct = ContainerType . List ;
enumerable = LanguagePrimitives . GetEnumerable ( source );
Dbg . Assert ( enumerable != null , "IList is enumerable" );
}
else
{
Type gt = source . GetType ();
2018-04-13 15:10:10 -07:00
if ( gt . IsGenericType )
2016-03-30 14:20:52 -07:00
{
if ( DerivesFromGenericType ( gt , typeof ( Stack <>)))
{
ct = ContainerType . Stack ;
enumerable = LanguagePrimitives . GetEnumerable ( source );
Dbg . Assert ( enumerable != null , "Stack is enumerable" );
}
else if ( DerivesFromGenericType ( gt , typeof ( Queue <>)))
{
ct = ContainerType . Queue ;
enumerable = LanguagePrimitives . GetEnumerable ( source );
Dbg . Assert ( enumerable != null , "Queue is enumerable" );
}
else if ( DerivesFromGenericType ( gt , typeof ( List <>)))
{
ct = ContainerType . List ;
enumerable = LanguagePrimitives . GetEnumerable ( source );
Dbg . Assert ( enumerable != null , "Queue is enumerable" );
}
}
}
// Check if LanguagePrimitive.GetEnumerable can do some magic to get IEnumerable instance
if ( ct == ContainerType . None )
{
try
{
enumerable = LanguagePrimitives . GetEnumerable ( source );
if ( enumerable != null )
{
ct = ContainerType . Enumerable ;
}
}
catch ( Exception exception )
{
// Catch-all OK. This is a third-party call-out.
PSEtwLog . LogAnalyticWarning ( PSEventId . Serializer_EnumerationFailed , PSOpcode . Exception ,
PSTask . Serialization , PSKeyword . Serializer , source . GetType (). AssemblyQualifiedName ,
exception . ToString ());
}
}
2019-01-06 06:51:20 +05:00
// Check if type is IEnumerable
// (LanguagePrimitives.GetEnumerable above should be enough - the check below is to preserve
2016-03-30 14:20:52 -07:00
// backcompatibility in some corner-cases (see bugs in Windows7 - #372562 and #372563))
if ( ct == ContainerType . None )
{
enumerable = source as IEnumerable ;
if ( enumerable != null )
{
2019-01-06 06:51:20 +05:00
// WinBlue: 206515 - There are no elements in the source. The source is of type XmlLinkedNode (which derives from XmlNode which implements IEnumerable).
2016-03-30 14:20:52 -07:00
// So, adding an additional check to see if this contains any elements
IEnumerator enumerator = enumerable . GetEnumerator ();
if ( enumerator != null && enumerator . MoveNext ())
{
ct = ContainerType . Enumerable ;
}
}
}
}
/// <summary>
2019-01-06 04:40:24 +05:00
/// Checks if derived is of type baseType or a type derived from baseType.
2016-03-30 14:20:52 -07:00
/// </summary>
/// <param name="derived"></param>
/// <param name="baseType"></param>
/// <returns></returns>
private static bool DerivesFromGenericType ( Type derived , Type baseType )
{
Dbg . Assert ( derived != null , "caller should validate the parameter" );
Dbg . Assert ( baseType != null , "caller should validate the parameter" );
while ( derived != null )
{
2018-04-13 15:10:10 -07:00
if ( derived . IsGenericType )
2016-03-30 14:20:52 -07:00
derived = derived . GetGenericTypeDefinition ();
if ( derived == baseType )
{
return true ;
}
2018-12-23 22:20:06 -08:00
2018-04-13 15:10:10 -07:00
derived = derived . BaseType ;
2016-03-30 14:20:52 -07:00
}
2018-12-23 22:20:06 -08:00
2016-03-30 14:20:52 -07:00
return false ;
}
/// <summary>
/// Gets the "ToString" from PSObject.
/// </summary>
/// <param name="source">
/// PSObject to be converted to string
/// </param>
/// <returns>
/// "ToString" value
/// </returns>
internal static string GetToString ( object source )
{
Dbg . Assert ( source != null , "caller should have validated the information" );
// fall back value
string result = null ;
try
{
result = Convert . ToString ( source , CultureInfo . InvariantCulture );
}
catch ( Exception e )
{
// Catch-all OK. This is a third-party call-out.
PSEtwLog . LogAnalyticWarning (
PSEventId . Serializer_ToStringFailed , PSOpcode . Exception , PSTask . Serialization ,
PSKeyword . Serializer | PSKeyword . UseAlwaysAnalytic ,
source . GetType (). AssemblyQualifiedName ,
e . ToString ());
}
return result ;
}
internal static string GetToStringForPrimitiveObject ( PSObject pso )
{
// if object is not wrapped in a PSObject, then nothing modifies the ToString value of the primitive object
2020-07-30 16:06:38 -07:00
if ( pso == null )
2016-03-30 14:20:52 -07:00
{
return null ;
}
// preserve ToString throughout deserialization/*re*serialization
if ( pso . ToStringFromDeserialization != null )
{
return pso . ToStringFromDeserialization ;
}
// preserve token text (i.e. double: 0E1517567410; see Windows 7 bug #694057 for more details)
string token = pso . TokenText ;
if ( token != null )
{
string originalToString = GetToString ( pso . BaseObject );
2020-07-30 16:06:38 -07:00
if ( originalToString == null || ! string . Equals ( token , originalToString , StringComparison . Ordinal ))
2016-03-30 14:20:52 -07:00
{
return token ;
}
}
// no need to write <ToString> element otherwise - the ToString method of a deserialized, live primitive object will return the right value
return null ;
}
internal static PSMemberInfoInternalCollection < PSPropertyInfo > GetSpecificPropertiesToSerialize ( PSObject source , Collection < CollectionEntry < PSPropertyInfo >> allPropertiesCollection , TypeTable typeTable )
{
2020-07-30 16:06:38 -07:00
if ( source == null )
2016-03-30 14:20:52 -07:00
{
return null ;
}
if ( source . GetSerializationMethod ( typeTable ) == SerializationMethod . SpecificProperties )
{
PSEtwLog . LogAnalyticVerbose (
PSEventId . Serializer_ModeOverride , PSOpcode . SerializationSettings , PSTask . Serialization ,
PSKeyword . Serializer | PSKeyword . UseAlwaysAnalytic ,
source . InternalTypeNames . Key ,
( UInt32 )( SerializationMethod . SpecificProperties ));
PSMemberInfoInternalCollection < PSPropertyInfo > specificProperties =
new PSMemberInfoInternalCollection < PSPropertyInfo >();
PSMemberInfoIntegratingCollection < PSPropertyInfo > allProperties =
new PSMemberInfoIntegratingCollection < PSPropertyInfo >(
source ,
allPropertiesCollection );
Collection < string > namesOfPropertiesToSerialize = source . GetSpecificPropertiesToSerialize ( typeTable );
foreach ( string propertyName in namesOfPropertiesToSerialize )
{
PSPropertyInfo property = allProperties [ propertyName ];
2020-07-30 16:06:38 -07:00
if ( property == null )
2016-03-30 14:20:52 -07:00
{
PSEtwLog . LogAnalyticWarning (
PSEventId . Serializer_SpecificPropertyMissing , PSOpcode . Exception , PSTask . Serialization ,
PSKeyword . Serializer | PSKeyword . UseAlwaysAnalytic ,
source . InternalTypeNames . Key ,
propertyName );
}
else
{
specificProperties . Add ( property );
}
}
return specificProperties ;
}
return null ;
}
internal static object GetPropertyValueInThreadSafeManner ( PSPropertyInfo property , bool canUseDefaultRunspaceInThreadSafeManner , out bool success )
{
Dbg . Assert ( property != null , "Caller should validate the parameter" );
if (! property . IsGettable )
{
success = false ;
return null ;
}
PSAliasProperty alias = property as PSAliasProperty ;
if ( alias != null )
{
property = alias . ReferencedMember as PSPropertyInfo ;
}
PSScriptProperty script = property as PSScriptProperty ;
2020-07-30 16:06:38 -07:00
Dbg . Assert ( script == null || script . GetterScript != null , "scriptProperty.IsGettable => (scriptProperty.GetterScript != null)" );
2016-03-30 14:20:52 -07:00
if (( script != null ) && (! canUseDefaultRunspaceInThreadSafeManner ))
{
PSEtwLog . LogAnalyticWarning (
PSEventId . Serializer_ScriptPropertyWithoutRunspace , PSOpcode . Exception , PSTask . Serialization ,
PSKeyword . Serializer | PSKeyword . UseAlwaysAnalytic ,
property . Name ,
2020-07-30 16:06:38 -07:00
property . instance == null ? string . Empty : PSObject . GetTypeNames ( property . instance ). Key ,
2016-03-30 14:20:52 -07:00
script . GetterScript . ToString ());
success = false ;
return null ;
}
try
{
object value = property . Value ;
success = true ;
return value ;
}
catch ( ExtendedTypeSystemException e )
{
PSEtwLog . LogAnalyticWarning (
PSEventId . Serializer_PropertyGetterFailed , PSOpcode . Exception , PSTask . Serialization ,
PSKeyword . Serializer | PSKeyword . UseAlwaysAnalytic ,
property . Name ,
2020-07-30 16:06:38 -07:00
property . instance == null ? string . Empty : PSObject . GetTypeNames ( property . instance ). Key ,
2016-03-30 14:20:52 -07:00
e . ToString (),
2020-07-30 16:06:38 -07:00
e . InnerException == null ? string . Empty : e . InnerException . ToString ());
2016-03-30 14:20:52 -07:00
success = false ;
return null ;
}
}
2016-07-29 13:02:49 -07:00
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
/// <summary>
/// A dictionary from object to T where
2017-01-16 13:31:14 -08:00
/// 1) keys are objects,
/// 2) keys use reference equality,
2019-01-06 04:40:24 +05:00
/// 3) dictionary keeps only weak references to keys.
2016-07-29 13:02:49 -07:00
/// </summary>
/// <typeparam name="T">type of dictionary values</typeparam>
internal class WeakReferenceDictionary < T > : IDictionary < object , T >
{
private class WeakReferenceEqualityComparer : IEqualityComparer < WeakReference >
{
public bool Equals ( WeakReference x , WeakReference y )
{
object tx = x . Target ;
2020-07-30 16:06:38 -07:00
if ( tx == null )
2016-07-29 13:02:49 -07:00
{
return false ; // collected object is not equal to anything (object.ReferenceEquals(null, null) == true)
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
object ty = y . Target ;
2020-07-30 16:06:38 -07:00
if ( ty == null )
2016-07-29 13:02:49 -07:00
{
return false ; // collected object is not equal to anything (object.ReferenceEquals(null, null) == true)
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
return object . ReferenceEquals ( tx , ty );
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
public int GetHashCode ( WeakReference obj )
{
object t = obj . Target ;
2020-07-30 16:06:38 -07:00
if ( t == null )
2016-07-29 13:02:49 -07:00
{
// collected object doesn't have a hash code
// return an arbitrary hashcode here and fall back on Equal method for comparison
2016-08-28 05:44:55 +00:00
return RuntimeHelpers . GetHashCode ( obj ); // RuntimeHelpers.GetHashCode(null) returns 0 - this would cause many hashtable collisions for WeakReferences to dead objects
2016-07-29 13:02:49 -07:00
}
else
{
return RuntimeHelpers . GetHashCode ( t );
}
}
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
private readonly IEqualityComparer < WeakReference > _weakEqualityComparer ;
private Dictionary < WeakReference , T > _dictionary ;
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
public WeakReferenceDictionary ()
{
_weakEqualityComparer = new WeakReferenceEqualityComparer ();
_dictionary = new Dictionary < WeakReference , T >( _weakEqualityComparer );
}
2016-03-30 14:20:52 -07:00
#if DEBUG
2016-07-29 13:02:49 -07:00
private const int initialCleanupTriggerSize = 2 ; // 2 will stress this code more
2016-03-30 14:20:52 -07:00
#else
2016-07-29 13:02:49 -07:00
private const int initialCleanupTriggerSize = 1000 ;
2016-03-30 14:20:52 -07:00
#endif
2016-07-29 13:02:49 -07:00
private int _cleanupTriggerSize = initialCleanupTriggerSize ;
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
private void CleanUp ()
{
if ( this . Count > _cleanupTriggerSize )
{
Dictionary < WeakReference , T > alive = new Dictionary < WeakReference , T >( _weakEqualityComparer );
foreach ( KeyValuePair < WeakReference , T > weakKeyValuePair in _dictionary )
{
object key = weakKeyValuePair . Key . Target ;
if ( key != null )
{
alive . Add ( weakKeyValuePair . Key , weakKeyValuePair . Value );
}
}
2018-12-23 22:20:06 -08:00
2016-07-29 13:02:49 -07:00
_dictionary = alive ;
_cleanupTriggerSize = initialCleanupTriggerSize + this . Count * 2 ;
}
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
#region IDictionary < object , T > Members
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
public void Add ( object key , T value )
{
_dictionary . Add ( new WeakReference ( key ), value );
this . CleanUp ();
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
public bool ContainsKey ( object key )
{
return _dictionary . ContainsKey ( new WeakReference ( key ));
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
public ICollection < object > Keys
{
get
{
List < object > keys = new List < object >( _dictionary . Keys . Count );
foreach ( WeakReference weakKey in _dictionary . Keys )
{
object key = weakKey . Target ;
if ( key != null )
{
keys . Add ( key );
}
}
2018-12-23 22:20:06 -08:00
2016-07-29 13:02:49 -07:00
return keys ;
}
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
public bool Remove ( object key )
{
return _dictionary . Remove ( new WeakReference ( key ));
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
public bool TryGetValue ( object key , out T value )
{
WeakReference weakKey = new WeakReference ( key );
return _dictionary . TryGetValue ( weakKey , out value );
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
public ICollection < T > Values
{
get
{
return _dictionary . Values ;
}
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
public T this [ object key ]
{
get
{
return _dictionary [ new WeakReference ( key )];
}
2018-12-23 22:20:06 -08:00
2016-07-29 13:02:49 -07:00
set
{
_dictionary [ new WeakReference ( key )] = value ;
this . CleanUp ();
}
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
#endregion
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
#region ICollection < KeyValuePair < object , T >> Members
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
private ICollection < KeyValuePair < WeakReference , T >> WeakCollection
{
get
{
return _dictionary ;
}
}
2016-03-30 14:20:52 -07:00
2016-08-02 19:00:50 -07:00
private static KeyValuePair < WeakReference , T > WeakKeyValuePair ( KeyValuePair < object , T > publicKeyValuePair )
2016-07-29 13:02:49 -07:00
{
return new KeyValuePair < WeakReference , T >( new WeakReference ( publicKeyValuePair . Key ), publicKeyValuePair . Value );
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
public void Add ( KeyValuePair < object , T > item )
{
this . WeakCollection . Add ( WeakKeyValuePair ( item ));
this . CleanUp ();
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
public void Clear ()
{
this . WeakCollection . Clear ();
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
public bool Contains ( KeyValuePair < object , T > item )
{
return this . WeakCollection . Contains ( WeakKeyValuePair ( item ));
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
public void CopyTo ( KeyValuePair < object , T >[] array , int arrayIndex )
{
List < KeyValuePair < object , T >> rawList = new List < KeyValuePair < object , T >>( this . WeakCollection . Count );
foreach ( KeyValuePair < object , T > keyValuePair in this )
{
rawList . Add ( keyValuePair );
}
2018-12-23 22:20:06 -08:00
2016-07-29 13:02:49 -07:00
rawList . CopyTo ( array , arrayIndex );
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
public int Count
{
get
{
return this . WeakCollection . Count ;
}
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
public bool IsReadOnly
{
get
{
return this . WeakCollection . IsReadOnly ;
}
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
public bool Remove ( KeyValuePair < object , T > item )
{
return this . WeakCollection . Remove ( WeakKeyValuePair ( item ));
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
#endregion
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
#region IEnumerable < KeyValuePair < object , T >> Members
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
public IEnumerator < KeyValuePair < object , T >> GetEnumerator ()
{
foreach ( KeyValuePair < WeakReference , T > weakKeyValuePair in this . WeakCollection )
{
object key = weakKeyValuePair . Key . Target ;
if ( key != null )
{
yield return new KeyValuePair < object , T >( key , weakKeyValuePair . Value );
}
}
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
#endregion
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
#region IEnumerable Members
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
IEnumerator IEnumerable . GetEnumerator ()
{
IEnumerable < KeyValuePair < object , T >> enumerable = this ;
IEnumerator < KeyValuePair < object , T >> enumerator = enumerable . GetEnumerator ();
return enumerator ;
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
#endregion
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
/// <summary>
2017-01-16 13:31:14 -08:00
/// <see cref="PSPrimitiveDictionary"/> is a <see cref="Hashtable"/> that is limited to
/// 1) case-insensitive strings as keys and
/// 2) values that can be serialized and deserialized during PowerShell remoting handshake
2016-07-29 13:02:49 -07:00
/// (in major-version compatible versions of PowerShell remoting)
/// </summary>
[Serializable]
public sealed class PSPrimitiveDictionary : Hashtable
{
#region Constructors
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
/// <summary>
2019-01-06 04:40:24 +05:00
/// Initializes a new empty instance of the <see cref="PSPrimitiveDictionary"/> class.
2016-07-29 13:02:49 -07:00
/// </summary>
public PSPrimitiveDictionary ()
: base ( StringComparer . OrdinalIgnoreCase )
{
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
/// <summary>
/// Initializes a new instance of the <see cref="PSPrimitiveDictionary"/> class with contents
/// copied from the <paramref name="other"/> hashtable.
/// </summary>
2018-12-29 08:25:49 +05:00
/// <param name="other">Hashtable to copy into the new instance of <see cref="PSPrimitiveDictionary"/></param>
2016-07-29 13:02:49 -07:00
/// <exception cref="ArgumentException">
/// This constructor will throw if the <paramref name="other"/> hashtable contains keys that are not a strings
/// or values that are not one of primitive types that will work during PowerShell remoting handshake.
/// </exception>
[SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors", Justification = "The class is sealed")]
public PSPrimitiveDictionary ( Hashtable other )
: base ( StringComparer . OrdinalIgnoreCase )
{
2020-07-30 16:06:38 -07:00
if ( other == null )
2016-07-29 13:02:49 -07:00
{
2020-05-19 19:57:52 +01:00
throw new ArgumentNullException ( nameof ( other ));
2016-07-29 13:02:49 -07:00
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
foreach ( DictionaryEntry entry in other )
{
Hashtable valueAsHashtable = PSObject . Base ( entry . Value ) as Hashtable ;
if ( valueAsHashtable != null )
{
this . Add ( entry . Key , new PSPrimitiveDictionary ( valueAsHashtable ));
}
else
{
this . Add ( entry . Key , entry . Value );
}
}
}
2016-03-30 14:20:52 -07:00
#if ! CORECLR // No .NET Serialization In CoreCLR
2016-07-29 13:02:49 -07:00
/// <summary>
2019-01-06 04:40:24 +05:00
/// Support for .NET serialization.
2016-07-29 13:02:49 -07:00
/// </summary>
private PSPrimitiveDictionary ( System . Runtime . Serialization . SerializationInfo info , System . Runtime . Serialization . StreamingContext context )
: base ( info , context )
{
}
2016-03-30 14:20:52 -07:00
#endif
2016-07-29 13:02:49 -07:00
#endregion
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
#region Plumbing to make Hashtable reject all non - primitive types
2016-03-30 14:20:52 -07:00
2020-11-27 08:10:43 +00:00
private static string VerifyKey ( object key )
2016-07-29 13:02:49 -07:00
{
key = PSObject . Base ( key );
string keyAsString = key as string ;
2020-07-30 16:06:38 -07:00
if ( keyAsString == null )
2016-07-29 13:02:49 -07:00
{
string message = StringUtil . Format ( Serialization . PrimitiveHashtableInvalidKey ,
key . GetType (). FullName );
throw new ArgumentException ( message );
}
else
{
return keyAsString ;
}
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
private static readonly Type [] s_handshakeFriendlyTypes = new Type [] {
2019-11-06 08:47:32 +05:00
typeof ( bool ),
typeof ( byte ),
typeof ( char ),
2016-07-29 13:02:49 -07:00
typeof ( DateTime ),
2019-11-06 08:47:32 +05:00
typeof ( decimal ),
typeof ( double ),
2016-07-29 13:02:49 -07:00
typeof ( Guid ),
typeof ( Int32 ),
typeof ( Int64 ),
2019-11-06 08:47:32 +05:00
typeof ( sbyte ),
2016-07-29 13:02:49 -07:00
typeof ( Single ),
2017-04-14 00:45:46 +04:00
// typeof(ScriptBlock) - don't want ScriptBlocks, because they are deserialized into strings
2019-11-06 08:47:32 +05:00
typeof ( string ),
2016-07-29 13:02:49 -07:00
typeof ( TimeSpan ),
typeof ( UInt16 ),
typeof ( UInt32 ),
typeof ( UInt64 ),
typeof ( Uri ),
typeof ( byte []),
typeof ( Version ),
typeof ( ProgressRecord ),
typeof ( XmlDocument ),
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
typeof ( PSPrimitiveDictionary )
};
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
private void VerifyValue ( object value )
{
// null is a primitive type
2020-07-30 16:06:38 -07:00
if ( value == null )
2016-07-29 13:02:49 -07:00
{
return ;
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
value = PSObject . Base ( value );
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
// this list is based on the list inside KnownTypes
// it is copied here to make sure that a list of "handshake friendly types"
// won't change even if we add new primitive types in v.next
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
Type valueType = value . GetType ();
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
// if "value" is a "primitiveType" then we are good
foreach ( Type goodType in s_handshakeFriendlyTypes )
{
if ( valueType == goodType )
{
return ;
}
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
// if "value" is an array of "primitiveType" items then we are good
// (note: we could have used IEnumerable<> or ICollection<> (covariance/contravariance concerns),
// but it is safer to limit the types to arrays.
// (one concern is that in v.next we might allow overriding SerializationMethod for
// types [i.e. check SerializationMethod *before* HandleKnownContainerTypes)
2016-03-30 14:20:52 -07:00
if (( valueType . IsArray ) || valueType == typeof ( ArrayList ))
2016-07-29 13:02:49 -07:00
{
foreach ( object o in ( IEnumerable ) value )
{
VerifyValue ( o );
}
2018-12-23 22:20:06 -08:00
2016-07-29 13:02:49 -07:00
return ;
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
string message = StringUtil . Format ( Serialization . PrimitiveHashtableInvalidValue ,
value . GetType (). FullName );
throw new ArgumentException ( message );
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
/// <summary>
2019-01-06 04:40:24 +05:00
/// Adds an element with the specified key and value into the Hashtable.
2016-07-29 13:02:49 -07:00
/// </summary>
2018-12-28 16:39:06 +05:00
/// <param name="key">The key of the element to add.</param>
/// <param name="value">The value of the element to add.</param>
2016-07-29 13:02:49 -07:00
/// <exception cref="ArgumentException">
/// This method will throw if the <paramref name="key"/> is not a string and the <paramref name="value"/>
/// is not one of primitive types that will work during PowerShell remoting handshake.
/// Use of strongly-typed overloads of this method is suggested if throwing an exception is not acceptable.
/// </exception>
public override void Add ( object key , object value )
{
2020-11-27 08:10:43 +00:00
string keyAsString = VerifyKey ( key );
2016-07-29 13:02:49 -07:00
this . VerifyValue ( value );
base . Add ( keyAsString , value );
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
/// <summary>
2017-01-16 13:31:14 -08:00
/// Gets or sets the value associated with the specified key.
2016-07-29 13:02:49 -07:00
/// </summary>
2018-12-28 16:39:06 +05:00
/// <param name="key">The key whose value to get or set.</param>
2016-07-29 13:02:49 -07:00
/// <returns>The value associated with the specified key.</returns>
/// <remarks>
2020-11-24 04:35:46 +00:00
/// If the specified key is not found, attempting to get it returns <see langword="null"/>
2016-07-29 13:02:49 -07:00
/// and attempting to set it creates a new element using the specified key.
/// </remarks>
/// <exception cref="ArgumentException">
/// The setter will throw if the <paramref name="key"/> is not a string and the value
/// is not one of primitive types that will work during PowerShell remoting handshake.
/// Use of strongly-typed overloads of Add method is suggested if throwing an exception is not acceptable.
/// </exception>
public override object this [ object key ]
{
get
{
return base [ key ];
}
2018-12-23 22:20:06 -08:00
2016-07-29 13:02:49 -07:00
set
{
2020-11-27 08:10:43 +00:00
string keyAsString = VerifyKey ( key );
2016-07-29 13:02:49 -07:00
this . VerifyValue ( value );
base [ keyAsString ] = value ;
}
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
/// <summary>
2017-01-16 13:31:14 -08:00
/// Gets or sets the value associated with the specified key.
2016-07-29 13:02:49 -07:00
/// </summary>
2018-12-28 16:39:06 +05:00
/// <param name="key">The key whose value to get or set.</param>
2016-07-29 13:02:49 -07:00
/// <returns>The value associated with the specified key.</returns>
/// <remarks>
2020-11-24 04:35:46 +00:00
/// If the specified key is not found, attempting to get it returns <see langword="null"/>
2016-07-29 13:02:49 -07:00
/// and attempting to set it creates a new element using the specified key.
/// </remarks>
/// <exception cref="ArgumentException">
/// The setter will throw if the value
/// is not one of primitive types that will work during PowerShell remoting handshake.
/// Use of strongly-typed overloads of Add method is suggested if throwing an exception is not acceptable.
/// </exception>
public object this [ string key ]
{
get
{
return base [ key ];
}
2018-12-23 22:20:06 -08:00
2016-07-29 13:02:49 -07:00
set
{
this . VerifyValue ( value );
base [ key ] = value ;
}
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
#endregion
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
#region Helper methods
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
/// <summary>
/// Creates a new instance by doing a shallow copy of the current instance.
/// </summary>
/// <returns></returns>
public override object Clone ()
{
return new PSPrimitiveDictionary ( this );
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
/// <summary>
2019-01-06 04:40:24 +05:00
/// Adds an element with the specified key and value into the Hashtable.
2016-07-29 13:02:49 -07:00
/// </summary>
2018-12-28 16:39:06 +05:00
/// <param name="key">The key of the element to add.</param>
/// <param name="value">The value of the element to add.</param>
2019-01-08 00:40:07 +05:00
public void Add ( string key , bool value )
2016-07-29 13:02:49 -07:00
{
this . Add (( object ) key , ( object ) value );
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
/// <summary>
2019-01-06 04:40:24 +05:00
/// Adds an element with the specified key and value into the Hashtable.
2016-07-29 13:02:49 -07:00
/// </summary>
2018-12-28 16:39:06 +05:00
/// <param name="key">The key of the element to add.</param>
/// <param name="value">The value of the element to add.</param>
2019-11-06 08:47:32 +05:00
public void Add ( string key , bool [] value )
2016-07-29 13:02:49 -07:00
{
this . Add (( object ) key , ( object ) value );
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
/// <summary>
2019-01-06 04:40:24 +05:00
/// Adds an element with the specified key and value into the Hashtable.
2016-07-29 13:02:49 -07:00
/// </summary>
2018-12-28 16:39:06 +05:00
/// <param name="key">The key of the element to add.</param>
/// <param name="value">The value of the element to add.</param>
2019-11-06 08:47:32 +05:00
public void Add ( string key , byte value )
2016-07-29 13:02:49 -07:00
{
this . Add (( object ) key , ( object ) value );
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
/// <summary>
2019-01-06 04:40:24 +05:00
/// Adds an element with the specified key and value into the Hashtable.
2016-07-29 13:02:49 -07:00
/// </summary>
2018-12-28 16:39:06 +05:00
/// <param name="key">The key of the element to add.</param>
/// <param name="value">The value of the element to add.</param>
2016-07-29 13:02:49 -07:00
public void Add ( string key , byte [] value )
{
this . Add (( object ) key , ( object ) value );
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
/// <summary>
2019-01-06 04:40:24 +05:00
/// Adds an element with the specified key and value into the Hashtable.
2016-07-29 13:02:49 -07:00
/// </summary>
2018-12-28 16:39:06 +05:00
/// <param name="key">The key of the element to add.</param>
/// <param name="value">The value of the element to add.</param>
2019-01-08 00:40:07 +05:00
public void Add ( string key , char value )
2016-07-29 13:02:49 -07:00
{
this . Add (( object ) key , ( object ) value );
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
/// <summary>
2019-01-06 04:40:24 +05:00
/// Adds an element with the specified key and value into the Hashtable.
2016-07-29 13:02:49 -07:00
/// </summary>
2018-12-28 16:39:06 +05:00
/// <param name="key">The key of the element to add.</param>
/// <param name="value">The value of the element to add.</param>
2019-01-08 00:40:07 +05:00
public void Add ( string key , char [] value )
2016-07-29 13:02:49 -07:00
{
this . Add (( object ) key , ( object ) value );
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
/// <summary>
2019-01-06 04:40:24 +05:00
/// Adds an element with the specified key and value into the Hashtable.
2016-07-29 13:02:49 -07:00
/// </summary>
2018-12-28 16:39:06 +05:00
/// <param name="key">The key of the element to add.</param>
/// <param name="value">The value of the element to add.</param>
2016-07-29 13:02:49 -07:00
public void Add ( string key , DateTime value )
{
this . Add (( object ) key , ( object ) value );
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
/// <summary>
2019-01-06 04:40:24 +05:00
/// Adds an element with the specified key and value into the Hashtable.
2016-07-29 13:02:49 -07:00
/// </summary>
2018-12-28 16:39:06 +05:00
/// <param name="key">The key of the element to add.</param>
/// <param name="value">The value of the element to add.</param>
2016-07-29 13:02:49 -07:00
public void Add ( string key , DateTime [] value )
{
this . Add (( object ) key , ( object ) value );
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
/// <summary>
2019-01-06 04:40:24 +05:00
/// Adds an element with the specified key and value into the Hashtable.
2016-07-29 13:02:49 -07:00
/// </summary>
2018-12-28 16:39:06 +05:00
/// <param name="key">The key of the element to add.</param>
/// <param name="value">The value of the element to add.</param>
2016-07-29 13:02:49 -07:00
public void Add ( string key , Decimal value )
{
this . Add (( object ) key , ( object ) value );
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
/// <summary>
2019-01-06 04:40:24 +05:00
/// Adds an element with the specified key and value into the Hashtable.
2016-07-29 13:02:49 -07:00
/// </summary>
2018-12-28 16:39:06 +05:00
/// <param name="key">The key of the element to add.</param>
/// <param name="value">The value of the element to add.</param>
2016-07-29 13:02:49 -07:00
public void Add ( string key , Decimal [] value )
{
this . Add (( object ) key , ( object ) value );
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
/// <summary>
2019-01-06 04:40:24 +05:00
/// Adds an element with the specified key and value into the Hashtable.
2016-07-29 13:02:49 -07:00
/// </summary>
2018-12-28 16:39:06 +05:00
/// <param name="key">The key of the element to add.</param>
/// <param name="value">The value of the element to add.</param>
2019-11-06 08:47:32 +05:00
public void Add ( string key , double value )
2016-07-29 13:02:49 -07:00
{
this . Add (( object ) key , ( object ) value );
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
/// <summary>
2019-01-06 04:40:24 +05:00
/// Adds an element with the specified key and value into the Hashtable.
2016-07-29 13:02:49 -07:00
/// </summary>
2018-12-28 16:39:06 +05:00
/// <param name="key">The key of the element to add.</param>
/// <param name="value">The value of the element to add.</param>
2019-11-06 08:47:32 +05:00
public void Add ( string key , double [] value )
2016-07-29 13:02:49 -07:00
{
this . Add (( object ) key , ( object ) value );
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
/// <summary>
2019-01-06 04:40:24 +05:00
/// Adds an element with the specified key and value into the Hashtable.
2016-07-29 13:02:49 -07:00
/// </summary>
2018-12-28 16:39:06 +05:00
/// <param name="key">The key of the element to add.</param>
/// <param name="value">The value of the element to add.</param>
2016-07-29 13:02:49 -07:00
public void Add ( string key , Guid value )
{
this . Add (( object ) key , ( object ) value );
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
/// <summary>
2019-01-06 04:40:24 +05:00
/// Adds an element with the specified key and value into the Hashtable.
2016-07-29 13:02:49 -07:00
/// </summary>
2018-12-28 16:39:06 +05:00
/// <param name="key">The key of the element to add.</param>
/// <param name="value">The value of the element to add.</param>
2016-07-29 13:02:49 -07:00
public void Add ( string key , Guid [] value )
{
this . Add (( object ) key , ( object ) value );
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
/// <summary>
2019-01-06 04:40:24 +05:00
/// Adds an element with the specified key and value into the Hashtable.
2016-07-29 13:02:49 -07:00
/// </summary>
2018-12-28 16:39:06 +05:00
/// <param name="key">The key of the element to add.</param>
/// <param name="value">The value of the element to add.</param>
2016-07-29 13:02:49 -07:00
public void Add ( string key , Int32 value )
{
this . Add (( object ) key , ( object ) value );
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
/// <summary>
2019-01-06 04:40:24 +05:00
/// Adds an element with the specified key and value into the Hashtable.
2016-07-29 13:02:49 -07:00
/// </summary>
2018-12-28 16:39:06 +05:00
/// <param name="key">The key of the element to add.</param>
/// <param name="value">The value of the element to add.</param>
2016-07-29 13:02:49 -07:00
public void Add ( string key , Int32 [] value )
{
this . Add (( object ) key , ( object ) value );
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
/// <summary>
2019-01-06 04:40:24 +05:00
/// Adds an element with the specified key and value into the Hashtable.
2016-07-29 13:02:49 -07:00
/// </summary>
2018-12-28 16:39:06 +05:00
/// <param name="key">The key of the element to add.</param>
/// <param name="value">The value of the element to add.</param>
2016-07-29 13:02:49 -07:00
public void Add ( string key , Int64 value )
{
this . Add (( object ) key , ( object ) value );
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
/// <summary>
2019-01-06 04:40:24 +05:00
/// Adds an element with the specified key and value into the Hashtable.
2016-07-29 13:02:49 -07:00
/// </summary>
2018-12-28 16:39:06 +05:00
/// <param name="key">The key of the element to add.</param>
/// <param name="value">The value of the element to add.</param>
2016-07-29 13:02:49 -07:00
public void Add ( string key , Int64 [] value )
{
this . Add (( object ) key , ( object ) value );
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
/// <summary>
2019-01-06 04:40:24 +05:00
/// Adds an element with the specified key and value into the Hashtable.
2016-07-29 13:02:49 -07:00
/// </summary>
2018-12-28 16:39:06 +05:00
/// <param name="key">The key of the element to add.</param>
/// <param name="value">The value of the element to add.</param>
2019-11-06 08:47:32 +05:00
public void Add ( string key , sbyte value )
2016-07-29 13:02:49 -07:00
{
this . Add (( object ) key , ( object ) value );
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
/// <summary>
2019-01-06 04:40:24 +05:00
/// Adds an element with the specified key and value into the Hashtable.
2016-07-29 13:02:49 -07:00
/// </summary>
2018-12-28 16:39:06 +05:00
/// <param name="key">The key of the element to add.</param>
/// <param name="value">The value of the element to add.</param>
2019-11-06 08:47:32 +05:00
public void Add ( string key , sbyte [] value )
2016-07-29 13:02:49 -07:00
{
this . Add (( object ) key , ( object ) value );
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
/// <summary>
2019-01-06 04:40:24 +05:00
/// Adds an element with the specified key and value into the Hashtable.
2016-07-29 13:02:49 -07:00
/// </summary>
2018-12-28 16:39:06 +05:00
/// <param name="key">The key of the element to add.</param>
/// <param name="value">The value of the element to add.</param>
2016-07-29 13:02:49 -07:00
public void Add ( string key , Single value )
{
this . Add (( object ) key , ( object ) value );
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
/// <summary>
2019-01-06 04:40:24 +05:00
/// Adds an element with the specified key and value into the Hashtable.
2016-07-29 13:02:49 -07:00
/// </summary>
2018-12-28 16:39:06 +05:00
/// <param name="key">The key of the element to add.</param>
/// <param name="value">The value of the element to add.</param>
2016-07-29 13:02:49 -07:00
public void Add ( string key , Single [] value )
{
this . Add (( object ) key , ( object ) value );
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
/// <summary>
2019-01-06 04:40:24 +05:00
/// Adds an element with the specified key and value into the Hashtable.
2016-07-29 13:02:49 -07:00
/// </summary>
2018-12-28 16:39:06 +05:00
/// <param name="key">The key of the element to add.</param>
/// <param name="value">The value of the element to add.</param>
2019-01-07 23:46:00 +05:00
public void Add ( string key , string value )
2016-07-29 13:02:49 -07:00
{
this . Add (( object ) key , ( object ) value );
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
/// <summary>
2019-01-06 04:40:24 +05:00
/// Adds an element with the specified key and value into the Hashtable.
2016-07-29 13:02:49 -07:00
/// </summary>
2018-12-28 16:39:06 +05:00
/// <param name="key">The key of the element to add.</param>
/// <param name="value">The value of the element to add.</param>
2019-01-07 23:46:00 +05:00
public void Add ( string key , string [] value )
2016-07-29 13:02:49 -07:00
{
this . Add (( object ) key , ( object ) value );
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
/// <summary>
2019-01-06 04:40:24 +05:00
/// Adds an element with the specified key and value into the Hashtable.
2016-07-29 13:02:49 -07:00
/// </summary>
2018-12-28 16:39:06 +05:00
/// <param name="key">The key of the element to add.</param>
/// <param name="value">The value of the element to add.</param>
2016-07-29 13:02:49 -07:00
public void Add ( string key , TimeSpan value )
{
this . Add (( object ) key , ( object ) value );
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
/// <summary>
2019-01-06 04:40:24 +05:00
/// Adds an element with the specified key and value into the Hashtable.
2016-07-29 13:02:49 -07:00
/// </summary>
2018-12-28 16:39:06 +05:00
/// <param name="key">The key of the element to add.</param>
/// <param name="value">The value of the element to add.</param>
2016-07-29 13:02:49 -07:00
public void Add ( string key , TimeSpan [] value )
{
this . Add (( object ) key , ( object ) value );
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
/// <summary>
2019-01-06 04:40:24 +05:00
/// Adds an element with the specified key and value into the Hashtable.
2016-07-29 13:02:49 -07:00
/// </summary>
2018-12-28 16:39:06 +05:00
/// <param name="key">The key of the element to add.</param>
/// <param name="value">The value of the element to add.</param>
2016-07-29 13:02:49 -07:00
public void Add ( string key , UInt16 value )
{
this . Add (( object ) key , ( object ) value );
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
/// <summary>
2019-01-06 04:40:24 +05:00
/// Adds an element with the specified key and value into the Hashtable.
2016-07-29 13:02:49 -07:00
/// </summary>
2018-12-28 16:39:06 +05:00
/// <param name="key">The key of the element to add.</param>
/// <param name="value">The value of the element to add.</param>
2016-07-29 13:02:49 -07:00
public void Add ( string key , UInt16 [] value )
{
this . Add (( object ) key , ( object ) value );
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
/// <summary>
2019-01-06 04:40:24 +05:00
/// Adds an element with the specified key and value into the Hashtable.
2016-07-29 13:02:49 -07:00
/// </summary>
2018-12-28 16:39:06 +05:00
/// <param name="key">The key of the element to add.</param>
/// <param name="value">The value of the element to add.</param>
2016-07-29 13:02:49 -07:00
public void Add ( string key , UInt32 value )
{
this . Add (( object ) key , ( object ) value );
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
/// <summary>
2019-01-06 04:40:24 +05:00
/// Adds an element with the specified key and value into the Hashtable.
2016-07-29 13:02:49 -07:00
/// </summary>
2018-12-28 16:39:06 +05:00
/// <param name="key">The key of the element to add.</param>
/// <param name="value">The value of the element to add.</param>
2016-07-29 13:02:49 -07:00
public void Add ( string key , UInt32 [] value )
{
this . Add (( object ) key , ( object ) value );
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
/// <summary>
2019-01-06 04:40:24 +05:00
/// Adds an element with the specified key and value into the Hashtable.
2016-07-29 13:02:49 -07:00
/// </summary>
2018-12-28 16:39:06 +05:00
/// <param name="key">The key of the element to add.</param>
/// <param name="value">The value of the element to add.</param>
2016-07-29 13:02:49 -07:00
public void Add ( string key , UInt64 value )
{
this . Add (( object ) key , ( object ) value );
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
/// <summary>
2019-01-06 04:40:24 +05:00
/// Adds an element with the specified key and value into the Hashtable.
2016-07-29 13:02:49 -07:00
/// </summary>
2018-12-28 16:39:06 +05:00
/// <param name="key">The key of the element to add.</param>
/// <param name="value">The value of the element to add.</param>
2016-07-29 13:02:49 -07:00
public void Add ( string key , UInt64 [] value )
{
this . Add (( object ) key , ( object ) value );
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
/// <summary>
2019-01-06 04:40:24 +05:00
/// Adds an element with the specified key and value into the Hashtable.
2016-07-29 13:02:49 -07:00
/// </summary>
2018-12-28 16:39:06 +05:00
/// <param name="key">The key of the element to add.</param>
/// <param name="value">The value of the element to add.</param>
2016-07-29 13:02:49 -07:00
public void Add ( string key , Uri value )
{
this . Add (( object ) key , ( object ) value );
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
/// <summary>
2019-01-06 04:40:24 +05:00
/// Adds an element with the specified key and value into the Hashtable.
2016-07-29 13:02:49 -07:00
/// </summary>
2018-12-28 16:39:06 +05:00
/// <param name="key">The key of the element to add.</param>
/// <param name="value">The value of the element to add.</param>
2016-07-29 13:02:49 -07:00
public void Add ( string key , Uri [] value )
{
this . Add (( object ) key , ( object ) value );
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
/// <summary>
2019-01-06 04:40:24 +05:00
/// Adds an element with the specified key and value into the Hashtable.
2016-07-29 13:02:49 -07:00
/// </summary>
2018-12-28 16:39:06 +05:00
/// <param name="key">The key of the element to add.</param>
/// <param name="value">The value of the element to add.</param>
2016-07-29 13:02:49 -07:00
public void Add ( string key , Version value )
{
this . Add (( object ) key , ( object ) value );
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
/// <summary>
2019-01-06 04:40:24 +05:00
/// Adds an element with the specified key and value into the Hashtable.
2016-07-29 13:02:49 -07:00
/// </summary>
2018-12-28 16:39:06 +05:00
/// <param name="key">The key of the element to add.</param>
/// <param name="value">The value of the element to add.</param>
2016-07-29 13:02:49 -07:00
public void Add ( string key , Version [] value )
{
this . Add (( object ) key , ( object ) value );
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
/// <summary>
2019-01-06 04:40:24 +05:00
/// Adds an element with the specified key and value into the Hashtable.
2016-07-29 13:02:49 -07:00
/// </summary>
2018-12-28 16:39:06 +05:00
/// <param name="key">The key of the element to add.</param>
/// <param name="value">The value of the element to add.</param>
2016-07-29 13:02:49 -07:00
public void Add ( string key , PSPrimitiveDictionary value )
{
this . Add (( object ) key , ( object ) value );
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
/// <summary>
2019-01-06 04:40:24 +05:00
/// Adds an element with the specified key and value into the Hashtable.
2016-07-29 13:02:49 -07:00
/// </summary>
2018-12-28 16:39:06 +05:00
/// <param name="key">The key of the element to add.</param>
/// <param name="value">The value of the element to add.</param>
2016-07-29 13:02:49 -07:00
public void Add ( string key , PSPrimitiveDictionary [] value )
{
this . Add (( object ) key , ( object ) value );
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
#endregion
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
#region Internal Methods
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
/// <summary>
2017-01-16 13:31:14 -08:00
/// If originalHash contains PSVersionTable, then just returns the Cloned copy of
2016-07-29 13:02:49 -07:00
/// the original hash. Othewise, creates a clone copy and add PSVersionInfo.GetPSVersionTable
/// to the clone and returns.
/// </summary>
/// <param name="originalHash"></param>
/// <returns></returns>
internal static PSPrimitiveDictionary CloneAndAddPSVersionTable ( PSPrimitiveDictionary originalHash )
{
2018-06-26 02:37:09 +05:00
if (( originalHash != null ) &&
2016-07-29 13:02:49 -07:00
( originalHash . ContainsKey ( PSVersionInfo . PSVersionTableName )))
{
return ( PSPrimitiveDictionary ) originalHash . Clone ();
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
PSPrimitiveDictionary result = originalHash ;
2018-06-26 02:37:09 +05:00
if ( originalHash != null )
2016-07-29 13:02:49 -07:00
{
result = ( PSPrimitiveDictionary ) originalHash . Clone ();
}
else
{
result = new PSPrimitiveDictionary ();
}
2018-12-23 22:20:06 -08:00
2016-08-02 09:36:58 -07:00
PSPrimitiveDictionary versionTable = new PSPrimitiveDictionary ( PSVersionInfo . GetPSVersionTableForDownLevel ())
{
{ "PSSemanticVersion" , PSVersionInfo . PSVersion . ToString ()}
};
2016-07-29 13:02:49 -07:00
result . Add ( PSVersionInfo . PSVersionTableName , versionTable );
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
return result ;
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
/// <summary>
/// Tries to get a value that might be present in a chain of nested PSPrimitiveDictionaries.
/// For example to get $sessionInfo.ApplicationPrivateData.ImplicitRemoting.Hash you could call
/// TryPathGet<string>($sessionInfo.ApplicationPrivateData, out myHash, "ImplicitRemoting", "Hash").
/// </summary>
/// <typeparam name="T">Expected type of the value</typeparam>
2018-12-28 16:39:06 +05:00
/// <param name="data">The root dictionary.</param>
2016-07-29 13:02:49 -07:00
/// <param name="result"></param>
2018-12-28 16:39:06 +05:00
/// <param name="keys">A chain of keys leading from the root dictionary (<paramref name="data"/>) to the value.</param>
2020-11-24 04:35:46 +00:00
/// <returns><see langword="true"/> if the value was found and was of the correct type; <see langword="false"/> otherwise.</returns>
2016-08-02 19:00:50 -07:00
internal static bool TryPathGet < T >( IDictionary data , out T result , params string [] keys )
2016-07-29 13:02:49 -07:00
{
Dbg . Assert ( keys != null , "Caller should verify that keys != null" );
Dbg . Assert ( keys . Length >= 1 , "Caller should verify that keys.Length >= 1" );
Dbg . Assert ( keys [ 0 ] != null , "Caller should verify that keys[i] != null" );
2016-03-30 14:20:52 -07:00
2020-07-30 16:06:38 -07:00
if ( data == null || ! data . Contains ( keys [ 0 ]))
2016-07-29 13:02:49 -07:00
{
result = default ( T );
return false ;
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
if ( keys . Length == 1 )
{
return LanguagePrimitives . TryConvertTo < T >( data [ keys [ 0 ]], out result );
}
else
{
IDictionary subData ;
if ( LanguagePrimitives . TryConvertTo < IDictionary >( data [ keys [ 0 ]], out subData )
&& subData != null )
{
string [] subKeys = new string [ keys . Length - 1 ];
Array . Copy ( keys , 1 , subKeys , 0 , subKeys . Length );
return TryPathGet < T >( subData , out result , subKeys );
}
else
{
result = default ( T );
return false ;
}
}
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
#endregion
}
2016-03-30 14:20:52 -07:00
}
namespace Microsoft.PowerShell
{
2016-07-29 13:02:49 -07:00
using System.Management.Automation ;
using System.Security.Principal ;
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
/// <summary>
/// Rehydrating type converter used during deserialization.
/// It takes results of serializing some common types
/// and rehydrates them back from property bags into live objects.
/// </summary>
/// <!--
/// To add a new type for rehydration:
/// - Add a new T RehydrateT(PSObject pso) method below
/// - Add this method to converters dictionary in the static constructor below
/// - If implicit rehydration is required then
/// - Add appropriate types.ps1 xml entries for
/// - SerializationDepth=X
/// - For types depending only on ToString for rehydration set
/// - SerializationMethod=SpecificProperties
/// - PropertySerializationSet=<empty>
/// - TargetTypeForDeserialization=DeserializingTypeConverter
/// - Add a field of that type in unit tests / S.M.A.Test.SerializationTest+RehydratedType
/// (testsrc\admintest\monad\DRT\engine\UnitTests\SerializationTest.cs)
/// -->
public sealed class DeserializingTypeConverter : PSTypeConverter
{
2016-03-30 14:20:52 -07:00
#region Infrastructure
2016-07-29 13:02:49 -07:00
private static readonly Dictionary < Type , Func < PSObject , object >> s_converter ;
2016-03-30 14:20:52 -07:00
static DeserializingTypeConverter ()
{
2016-07-29 13:02:49 -07:00
s_converter = new Dictionary < Type , Func < PSObject , object >>();
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
s_converter . Add ( typeof ( PSPrimitiveDictionary ), RehydratePrimitiveHashtable );
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
s_converter . Add ( typeof ( SwitchParameter ), RehydrateSwitchParameter );
s_converter . Add ( typeof ( PSListModifier ), RehydratePSListModifier );
s_converter . Add ( typeof ( PSCredential ), RehydratePSCredential );
s_converter . Add ( typeof ( PSSenderInfo ), RehydratePSSenderInfo );
s_converter . Add ( typeof ( CultureInfo ), RehydrateCultureInfo );
s_converter . Add ( typeof ( ParameterSetMetadata ), RehydrateParameterSetMetadata );
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
s_converter . Add ( typeof ( System . Security . Cryptography . X509Certificates . X509Certificate2 ), RehydrateX509Certificate2 );
s_converter . Add ( typeof ( System . Security . Cryptography . X509Certificates . X500DistinguishedName ), RehydrateX500DistinguishedName );
s_converter . Add ( typeof ( System . Net . IPAddress ), RehydrateIPAddress );
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
s_converter . Add ( typeof ( MailAddress ), RehydrateMailAddress );
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
s_converter . Add ( typeof ( System . Security . AccessControl . DirectorySecurity ), RehydrateObjectSecurity < System . Security . AccessControl . DirectorySecurity >);
s_converter . Add ( typeof ( System . Security . AccessControl . FileSecurity ), RehydrateObjectSecurity < System . Security . AccessControl . FileSecurity >);
s_converter . Add ( typeof ( System . Security . AccessControl . RegistrySecurity ), RehydrateObjectSecurity < System . Security . AccessControl . RegistrySecurity >);
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
s_converter . Add ( typeof ( ExtendedTypeDefinition ), RehydrateExtendedTypeDefinition );
s_converter . Add ( typeof ( FormatViewDefinition ), RehydrateFormatViewDefinition );
s_converter . Add ( typeof ( PSControl ), RehydratePSControl );
s_converter . Add ( typeof ( PSControlGroupBy ), RehydrateGroupBy );
s_converter . Add ( typeof ( DisplayEntry ), RehydrateDisplayEntry );
s_converter . Add ( typeof ( EntrySelectedBy ), RehydrateEntrySelectedBy );
s_converter . Add ( typeof ( TableControlColumnHeader ), RehydrateTableControlColumnHeader );
s_converter . Add ( typeof ( TableControlRow ), RehydrateTableControlRow );
s_converter . Add ( typeof ( TableControlColumn ), RehydrateTableControlColumn );
s_converter . Add ( typeof ( ListControlEntry ), RehydrateListControlEntry );
s_converter . Add ( typeof ( ListControlEntryItem ), RehydrateListControlEntryItem );
s_converter . Add ( typeof ( WideControlEntryItem ), RehydrateWideControlEntryItem );
s_converter . Add ( typeof ( CustomControlEntry ), RehydrateCustomControlEntry );
s_converter . Add ( typeof ( CustomItemBase ), RehydrateCustomItemBase );
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
s_converter . Add ( typeof ( CompletionResult ), RehydrateCompletionResult );
s_converter . Add ( typeof ( ModuleSpecification ), RehydrateModuleSpecification );
s_converter . Add ( typeof ( CommandCompletion ), RehydrateCommandCompletion );
s_converter . Add ( typeof ( JobStateInfo ), RehydrateJobStateInfo );
s_converter . Add ( typeof ( JobStateEventArgs ), RehydrateJobStateEventArgs );
s_converter . Add ( typeof ( PSSessionOption ), RehydratePSSessionOption );
s_converter . Add ( typeof ( LineBreakpoint ), RehydrateLineBreakpoint );
s_converter . Add ( typeof ( CommandBreakpoint ), RehydrateCommandBreakpoint );
s_converter . Add ( typeof ( VariableBreakpoint ), RehydrateVariableBreakpoint );
s_converter . Add ( typeof ( BreakpointUpdatedEventArgs ), RehydrateBreakpointUpdatedEventArgs );
s_converter . Add ( typeof ( DebuggerCommand ), RehydrateDebuggerCommand );
s_converter . Add ( typeof ( DebuggerCommandResults ), RehydrateDebuggerCommandResults );
s_converter . Add ( typeof ( DebuggerStopEventArgs ), RehydrateDebuggerStopEventArgs );
2016-03-30 14:20:52 -07:00
}
2016-07-29 13:02:49 -07:00
/// <summary>
/// Determines if the converter can convert the <paramref name="sourceValue"/> parameter to the <paramref name="destinationType"/> parameter.
/// </summary>
2018-12-28 16:39:06 +05:00
/// <param name="sourceValue">The value to convert from.</param>
/// <param name="destinationType">The type to convert to.</param>
2016-07-29 13:02:49 -07:00
/// <returns>True if the converter can convert the <paramref name="sourceValue"/> parameter to the <paramref name="destinationType"/> parameter, otherwise false.</returns>
public override bool CanConvertFrom ( PSObject sourceValue , Type destinationType )
{
foreach ( Type type in s_converter . Keys )
{
if ( Deserializer . IsDeserializedInstanceOfType ( sourceValue , type ))
{
return true ;
}
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
return false ;
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
/// <summary>
2019-01-06 04:40:24 +05:00
/// Converts the <paramref name="sourceValue"/> parameter to the <paramref name="destinationType"/> parameter using formatProvider and ignoreCase.
2016-07-29 13:02:49 -07:00
/// </summary>
2018-12-28 16:39:06 +05:00
/// <param name="sourceValue">The value to convert from.</param>
/// <param name="destinationType">The type to convert to.</param>
/// <param name="formatProvider">The format provider to use like in IFormattable's ToString.</param>
2018-12-29 08:25:49 +05:00
/// <param name="ignoreCase">True if case should be ignored.</param>
2018-12-25 21:43:03 +05:00
/// <returns>The <paramref name="sourceValue"/> parameter converted to the <paramref name="destinationType"/> parameter using formatProvider and ignoreCase.</returns>
2018-12-29 08:25:49 +05:00
/// <exception cref="InvalidCastException">If no conversion was possible.</exception>
2016-07-29 13:02:49 -07:00
public override object ConvertFrom ( PSObject sourceValue , Type destinationType , IFormatProvider formatProvider , bool ignoreCase )
{
2020-07-30 16:06:38 -07:00
if ( destinationType == null )
2016-07-29 13:02:49 -07:00
{
2020-05-19 19:57:52 +01:00
throw PSTraceSource . NewArgumentNullException ( nameof ( destinationType ));
2016-07-29 13:02:49 -07:00
}
2016-03-30 14:20:52 -07:00
2020-07-30 16:06:38 -07:00
if ( sourceValue == null )
2016-07-29 13:02:49 -07:00
{
throw new PSInvalidCastException (
"InvalidCastWhenRehydratingFromNull" ,
2020-05-19 19:57:52 +01:00
PSTraceSource . NewArgumentNullException ( nameof ( sourceValue )),
2016-07-29 13:02:49 -07:00
ExtendedTypeSystem . InvalidCastFromNull ,
destinationType . ToString ());
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
foreach ( KeyValuePair < Type , Func < PSObject , object >> item in s_converter )
{
Type type = item . Key ;
Func < PSObject , object > typeConverter = item . Value ;
if ( Deserializer . IsDeserializedInstanceOfType ( sourceValue , type ))
{
return ConvertFrom ( sourceValue , typeConverter );
}
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
throw new PSInvalidCastException (
"InvalidCastEnumFromTypeNotAString" ,
null ,
ExtendedTypeSystem . InvalidCastException ,
sourceValue ,
2019-02-20 23:55:39 -08:00
typeof ( PSObject ),
2016-07-29 13:02:49 -07:00
destinationType );
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
private static object ConvertFrom ( PSObject o , Func < PSObject , object > converter )
{
// rehydrate
PSObject dso = o ;
object rehydratedObject = converter ( dso );
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
// re-add instance properties
// (dso.InstanceMembers includes both instance and *type table* properties;
// therefore this will also re-add type table properties if they are not present when the deserializer runs;
// this is ok)
bool returnPSObject = false ;
PSObject rehydratedPSObject = PSObject . AsPSObject ( rehydratedObject );
foreach ( PSMemberInfo member in dso . InstanceMembers )
{
if ( member . MemberType == ( member . MemberType & ( PSMemberTypes . Properties | PSMemberTypes . MemberSet | PSMemberTypes . PropertySet )))
{
2020-07-30 16:06:38 -07:00
if ( rehydratedPSObject . Members [ member . Name ] == null )
2016-07-29 13:02:49 -07:00
{
rehydratedPSObject . InstanceMembers . Add ( member );
returnPSObject = true ;
}
}
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
if ( returnPSObject )
{
return rehydratedPSObject ;
}
else
{
return rehydratedObject ;
}
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
/// <summary>
2019-01-06 04:40:24 +05:00
/// Returns true if the converter can convert the <paramref name="sourceValue"/> parameter to the <paramref name="destinationType"/> parameter.
2016-07-29 13:02:49 -07:00
/// </summary>
2018-12-28 16:39:06 +05:00
/// <param name="sourceValue">The value to convert from.</param>
/// <param name="destinationType">The type to convert to.</param>
2016-07-29 13:02:49 -07:00
/// <returns>True if the converter can convert the <paramref name="sourceValue"/> parameter to the <paramref name="destinationType"/> parameter, otherwise false.</returns>
public override bool CanConvertTo ( object sourceValue , Type destinationType )
{
return false ;
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
/// <summary>
2019-01-06 04:40:24 +05:00
/// Converts the <paramref name="sourceValue"/> parameter to the <paramref name="destinationType"/> parameter using formatProvider and ignoreCase.
2016-07-29 13:02:49 -07:00
/// </summary>
2018-12-28 16:39:06 +05:00
/// <param name="sourceValue">The value to convert from.</param>
/// <param name="destinationType">The type to convert to.</param>
/// <param name="formatProvider">The format provider to use like in IFormattable's ToString.</param>
2018-12-29 08:25:49 +05:00
/// <param name="ignoreCase">True if case should be ignored.</param>
2018-12-25 21:43:03 +05:00
/// <returns>SourceValue converted to the <paramref name="destinationType"/> parameter using formatProvider and ignoreCase.</returns>
2018-12-29 08:25:49 +05:00
/// <exception cref="InvalidCastException">If no conversion was possible.</exception>
2016-07-29 13:02:49 -07:00
public override object ConvertTo ( object sourceValue , Type destinationType , IFormatProvider formatProvider , bool ignoreCase )
{
throw PSTraceSource . NewNotSupportedException ();
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
/// <summary>
2019-01-06 04:40:24 +05:00
/// This method is not implemented - an overload taking a PSObject is implemented instead.
2016-07-29 13:02:49 -07:00
/// </summary>
public override bool CanConvertFrom ( object sourceValue , Type destinationType )
{
throw new NotImplementedException ();
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
/// <summary>
2019-01-06 04:40:24 +05:00
/// This method is not implemented - an overload taking a PSObject is implemented instead.
2016-07-29 13:02:49 -07:00
/// </summary>
public override bool CanConvertTo ( PSObject sourceValue , Type destinationType )
{
throw new NotImplementedException ();
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
/// <summary>
2019-01-06 04:40:24 +05:00
/// This method is not implemented - an overload taking a PSObject is implemented instead.
2016-07-29 13:02:49 -07:00
/// </summary>
public override object ConvertFrom ( object sourceValue , Type destinationType , IFormatProvider formatProvider , bool ignoreCase )
{
throw new NotImplementedException ();
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
/// <summary>
2019-01-06 04:40:24 +05:00
/// This method is not implemented - an overload taking a PSObject is implemented instead.
2016-07-29 13:02:49 -07:00
/// </summary>
public override object ConvertTo ( PSObject sourceValue , Type destinationType , IFormatProvider formatProvider , bool ignoreCase )
{
throw new NotImplementedException ();
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
#endregion
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
#region Rehydration helpers
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
[Flags]
internal enum RehydrationFlags
{
NullValueBad = 0 ,
NullValueOk = 0x1 ,
NullValueMeansEmptyList = 0x3 ,
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
MissingPropertyBad = 0 ,
MissingPropertyOk = 0x4 ,
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
/// <summary>
2017-01-16 13:31:14 -08:00
/// Gets value of a property (has to be present, value has to be non-null).
2016-07-29 13:02:49 -07:00
/// Can throw any exception (which is ok - LanguagePrimitives.ConvertTo will catch that).
/// </summary>
/// <typeparam name="T">Expected type of the property</typeparam>
2018-12-28 16:39:06 +05:00
/// <param name="pso">Deserialized object.</param>
/// <param name="propertyName">Property name.</param>
2016-07-29 13:02:49 -07:00
/// <returns></returns>
private static T GetPropertyValue < T >( PSObject pso , string propertyName )
{
return GetPropertyValue < T >( pso , propertyName , RehydrationFlags . NullValueBad | RehydrationFlags . MissingPropertyBad );
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
/// <summary>
/// Gets value of a property. Can throw any exception (which is ok - LanguagePrimitives.ConvertTo will catch that).
/// </summary>
/// <typeparam name="T">Expected type of the property</typeparam>
2018-12-28 16:39:06 +05:00
/// <param name="pso">Deserialized object.</param>
/// <param name="propertyName">Property name.</param>
2016-07-29 13:02:49 -07:00
/// <param name="flags"></param>
/// <returns></returns>
internal static T GetPropertyValue < T >( PSObject pso , string propertyName , RehydrationFlags flags )
{
Dbg . Assert ( pso != null , "Caller should verify pso != null" );
Dbg . Assert (! string . IsNullOrEmpty ( propertyName ), "Caller should verify propertyName != null" );
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
PSPropertyInfo property = pso . Properties [ propertyName ];
2020-11-20 12:26:46 +00:00
if (( property == null ) && (( flags & RehydrationFlags . MissingPropertyOk ) == RehydrationFlags . MissingPropertyOk ))
2016-07-29 13:02:49 -07:00
{
return default ( T );
}
else
{
object propertyValue = property . Value ;
2020-11-20 12:26:46 +00:00
if (( propertyValue == null ) && (( flags & RehydrationFlags . NullValueOk ) == RehydrationFlags . NullValueOk ))
2016-07-29 13:02:49 -07:00
{
return default ( T );
}
else
{
T t = ( T ) LanguagePrimitives . ConvertTo ( propertyValue , typeof ( T ), CultureInfo . InvariantCulture );
return t ;
}
}
}
2016-03-30 14:20:52 -07:00
private static ListType RehydrateList < ListType , ItemType >( PSObject pso , string propertyName , RehydrationFlags flags )
where ListType : IList , new ()
{
ArrayList deserializedList = GetPropertyValue < ArrayList >( pso , propertyName , flags );
2020-07-30 16:06:38 -07:00
if ( deserializedList == null )
2016-03-30 14:20:52 -07:00
{
2020-11-20 12:26:46 +00:00
if (( flags & RehydrationFlags . NullValueMeansEmptyList ) == RehydrationFlags . NullValueMeansEmptyList )
2016-03-30 14:20:52 -07:00
{
return new ListType ();
}
else
{
return default ( ListType );
}
}
else
{
ListType newList = new ListType ();
foreach ( object deserializedItem in deserializedList )
{
ItemType item = ( ItemType ) LanguagePrimitives . ConvertTo ( deserializedItem , typeof ( ItemType ), CultureInfo . InvariantCulture );
newList . Add ( item );
}
2018-12-23 22:20:06 -08:00
2016-03-30 14:20:52 -07:00
return newList ;
}
}
2016-07-29 13:02:49 -07:00
#endregion
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
#region Rehydration of miscellaneous types
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
private static object RehydratePrimitiveHashtable ( PSObject pso )
{
Hashtable hashtable = ( Hashtable ) LanguagePrimitives . ConvertTo ( pso , typeof ( Hashtable ), CultureInfo . InvariantCulture );
return new PSPrimitiveDictionary ( hashtable );
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
private static object RehydrateSwitchParameter ( PSObject pso )
{
return GetPropertyValue < SwitchParameter >( pso , "IsPresent" );
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
private static CultureInfo RehydrateCultureInfo ( PSObject pso )
{
string s = pso . ToString ();
return new CultureInfo ( s );
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
private static PSListModifier RehydratePSListModifier ( PSObject pso )
{
Hashtable h = new Hashtable ();
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
PSPropertyInfo addProperty = pso . Properties [ PSListModifier . AddKey ];
if (( addProperty != null ) && ( addProperty . Value != null ))
{
h . Add ( PSListModifier . AddKey , addProperty . Value );
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
PSPropertyInfo removeProperty = pso . Properties [ PSListModifier . RemoveKey ];
if (( removeProperty != null ) && ( removeProperty . Value != null ))
{
h . Add ( PSListModifier . RemoveKey , removeProperty . Value );
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
PSPropertyInfo replaceProperty = pso . Properties [ PSListModifier . ReplaceKey ];
if (( replaceProperty != null ) && ( replaceProperty . Value != null ))
{
h . Add ( PSListModifier . ReplaceKey , replaceProperty . Value );
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
return new PSListModifier ( h );
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
private static CompletionResult RehydrateCompletionResult ( PSObject pso )
{
string completionText = GetPropertyValue < string >( pso , "CompletionText" );
string listItemText = GetPropertyValue < string >( pso , "ListItemText" );
string toolTip = GetPropertyValue < string >( pso , "ToolTip" );
CompletionResultType resultType = GetPropertyValue < CompletionResultType >( pso , "ResultType" );
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
return new CompletionResult ( completionText , listItemText , resultType , toolTip );
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
private static ModuleSpecification RehydrateModuleSpecification ( PSObject pso )
{
return new ModuleSpecification
{
Name = GetPropertyValue < string >( pso , "Name" ),
Guid = GetPropertyValue < Guid ?>( pso , "Guid" ),
Version = GetPropertyValue < Version >( pso , "Version" ),
MaximumVersion = GetPropertyValue < string >( pso , "MaximumVersion" ),
RequiredVersion =
2016-03-30 14:20:52 -07:00
GetPropertyValue < Version >( pso , "RequiredVersion" )
2016-07-29 13:02:49 -07:00
};
}
private static CommandCompletion RehydrateCommandCompletion ( PSObject pso )
{
var completions = new Collection < CompletionResult >();
2016-03-30 14:20:52 -07:00
foreach ( var match in GetPropertyValue < ArrayList >( pso , "CompletionMatches" ))
2016-07-29 13:02:49 -07:00
{
completions . Add (( CompletionResult ) match );
}
2018-12-23 22:20:06 -08:00
2016-07-29 13:02:49 -07:00
var currentMatchIndex = GetPropertyValue < int >( pso , "CurrentMatchIndex" );
var replacementIndex = GetPropertyValue < int >( pso , "ReplacementIndex" );
var replacementLength = GetPropertyValue < int >( pso , "ReplacementLength" );
return new CommandCompletion ( completions , currentMatchIndex , replacementIndex , replacementLength );
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
private static JobStateInfo RehydrateJobStateInfo ( PSObject pso )
{
var jobState = GetPropertyValue < JobState >( pso , "State" );
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
Exception reason = null ;
object propertyValue = null ;
PSPropertyInfo property = pso . Properties [ "Reason" ];
string message = string . Empty ;
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
if ( property != null )
{
propertyValue = property . Value ;
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
if ( propertyValue != null )
{
if ( Deserializer . IsDeserializedInstanceOfType ( propertyValue , typeof ( Exception )))
{
// if we have a deserialized remote or any other exception, use its message to construct
// an exception
message = PSObject . AsPSObject ( propertyValue ). Properties [ "Message" ]. Value as string ;
}
else if ( propertyValue is Exception )
{
reason = ( Exception ) propertyValue ;
}
else
{
message = propertyValue . ToString ();
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
if (! string . IsNullOrEmpty ( message ))
{
try
{
reason = ( Exception ) LanguagePrimitives . ConvertTo ( message , typeof ( Exception ), CultureInfo . InvariantCulture );
}
catch ( Exception )
{
// it is ok to eat this exception since we do not want
// rehydration to fail
reason = null ;
}
}
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
return new JobStateInfo ( jobState , reason );
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
internal static JobStateEventArgs RehydrateJobStateEventArgs ( PSObject pso )
{
var jobStateInfo = RehydrateJobStateInfo ( PSObject . AsPSObject ( pso . Properties [ "JobStateInfo" ]. Value ));
JobStateInfo previousJobStateInfo = null ;
var previousJobStateInfoProperty = pso . Properties [ "PreviousJobStateInfo" ];
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
if ( previousJobStateInfoProperty != null && previousJobStateInfoProperty . Value != null )
{
previousJobStateInfo = RehydrateJobStateInfo ( PSObject . AsPSObject ( previousJobStateInfoProperty . Value ));
}
return new JobStateEventArgs ( jobStateInfo , previousJobStateInfo );
}
2016-03-30 14:20:52 -07:00
internal static PSSessionOption RehydratePSSessionOption ( PSObject pso )
{
PSSessionOption option = new PSSessionOption ();
2016-07-29 13:02:49 -07:00
2016-03-30 14:20:52 -07:00
option . ApplicationArguments = GetPropertyValue < PSPrimitiveDictionary >( pso , "ApplicationArguments" );
2016-07-29 13:02:49 -07:00
option . CancelTimeout = GetPropertyValue < TimeSpan >( pso , "CancelTimeout" );
option . Culture = GetPropertyValue < CultureInfo >( pso , "Culture" );
option . IdleTimeout = GetPropertyValue < TimeSpan >( pso , "IdleTimeout" );
2016-03-30 14:20:52 -07:00
option . MaximumConnectionRedirectionCount = GetPropertyValue < int >( pso , "MaximumConnectionRedirectionCount" );
2018-12-21 10:07:01 -08:00
option . MaximumReceivedDataSizePerCommand = GetPropertyValue < int? >( pso , "MaximumReceivedDataSizePerCommand" );
option . MaximumReceivedObjectSize = GetPropertyValue < int? >( pso , "MaximumReceivedObjectSize" );
2016-03-30 14:20:52 -07:00
option . NoCompression = GetPropertyValue < bool >( pso , "NoCompression" );
option . NoEncryption = GetPropertyValue < bool >( pso , "NoEncryption" );
2016-07-29 13:02:49 -07:00
option . NoMachineProfile = GetPropertyValue < bool >( pso , "NoMachineProfile" );
option . OpenTimeout = GetPropertyValue < TimeSpan >( pso , "OpenTimeout" );
option . OperationTimeout = GetPropertyValue < TimeSpan >( pso , "OperationTimeout" );
option . OutputBufferingMode = GetPropertyValue < OutputBufferingMode >( pso , "OutputBufferingMode" );
2016-03-30 14:20:52 -07:00
option . MaxConnectionRetryCount = GetPropertyValue < int >( pso , "MaxConnectionRetryCount" );
option . ProxyAccessType = GetPropertyValue < ProxyAccessType >( pso , "ProxyAccessType" );
option . ProxyAuthentication = GetPropertyValue < AuthenticationMechanism >( pso , "ProxyAuthentication" );
option . ProxyCredential = GetPropertyValue < PSCredential >( pso , "ProxyCredential" );
2016-07-29 13:02:49 -07:00
option . SkipCACheck = GetPropertyValue < bool >( pso , "SkipCACheck" );
option . SkipCNCheck = GetPropertyValue < bool >( pso , "SkipCNCheck" );
option . SkipRevocationCheck = GetPropertyValue < bool >( pso , "SkipRevocationCheck" );
option . UICulture = GetPropertyValue < CultureInfo >( pso , "UICulture" );
option . UseUTF16 = GetPropertyValue < bool >( pso , "UseUTF16" );
2016-03-30 14:20:52 -07:00
option . IncludePortInSPN = GetPropertyValue < bool >( pso , "IncludePortInSPN" );
2016-07-29 13:02:49 -07:00
2016-03-30 14:20:52 -07:00
return option ;
}
internal static LineBreakpoint RehydrateLineBreakpoint ( PSObject pso )
{
string script = GetPropertyValue < string >( pso , "Script" );
int line = GetPropertyValue < int >( pso , "Line" );
int column = GetPropertyValue < int >( pso , "Column" );
int id = GetPropertyValue < int >( pso , "Id" );
bool enabled = GetPropertyValue < bool >( pso , "Enabled" );
ScriptBlock action = RehydrateScriptBlock (
GetPropertyValue < string >( pso , "Action" , RehydrationFlags . MissingPropertyOk ));
var bp = new LineBreakpoint ( script , line , column , action , id );
bp . SetEnabled ( enabled );
return bp ;
}
internal static CommandBreakpoint RehydrateCommandBreakpoint ( PSObject pso )
{
2019-08-15 18:55:45 -03:00
string script = GetPropertyValue < string >( pso , "Script" , RehydrationFlags . MissingPropertyOk | RehydrationFlags . NullValueOk );
2016-03-30 14:20:52 -07:00
string command = GetPropertyValue < string >( pso , "Command" );
int id = GetPropertyValue < int >( pso , "Id" );
bool enabled = GetPropertyValue < bool >( pso , "Enabled" );
WildcardPattern pattern = WildcardPattern . Get ( command , WildcardOptions . Compiled | WildcardOptions . IgnoreCase );
ScriptBlock action = RehydrateScriptBlock (
GetPropertyValue < string >( pso , "Action" , RehydrationFlags . MissingPropertyOk ));
var bp = new CommandBreakpoint ( script , pattern , command , action , id );
bp . SetEnabled ( enabled );
return bp ;
}
internal static VariableBreakpoint RehydrateVariableBreakpoint ( PSObject pso )
{
2019-08-15 18:55:45 -03:00
string script = GetPropertyValue < string >( pso , "Script" , RehydrationFlags . MissingPropertyOk | RehydrationFlags . NullValueOk );
2016-03-30 14:20:52 -07:00
string variableName = GetPropertyValue < string >( pso , "Variable" );
int id = GetPropertyValue < int >( pso , "Id" );
bool enabled = GetPropertyValue < bool >( pso , "Enabled" );
VariableAccessMode access = GetPropertyValue < VariableAccessMode >( pso , "AccessMode" );
ScriptBlock action = RehydrateScriptBlock (
GetPropertyValue < string >( pso , "Action" , RehydrationFlags . MissingPropertyOk ));
var bp = new VariableBreakpoint ( script , variableName , access , action , id );
bp . SetEnabled ( enabled );
return bp ;
}
internal static BreakpointUpdatedEventArgs RehydrateBreakpointUpdatedEventArgs ( PSObject pso )
{
Breakpoint bp = GetPropertyValue < Breakpoint >( pso , "Breakpoint" );
BreakpointUpdateType bpUpdateType = GetPropertyValue < BreakpointUpdateType >( pso , "UpdateType" );
int bpCount = GetPropertyValue < int >( pso , "BreakpointCount" );
return new BreakpointUpdatedEventArgs ( bp , bpUpdateType , bpCount );
}
internal static DebuggerCommand RehydrateDebuggerCommand ( PSObject pso )
{
string command = GetPropertyValue < string >( pso , "Command" );
bool repeatOnEnter = GetPropertyValue < bool >( pso , "RepeatOnEnter" );
bool executedByDebugger = GetPropertyValue < bool >( pso , "ExecutedByDebugger" );
DebuggerResumeAction ? resumeAction = GetPropertyValue < DebuggerResumeAction ?>( pso , "ResumeAction" , RehydrationFlags . NullValueOk );
return new DebuggerCommand ( command , resumeAction , repeatOnEnter , executedByDebugger );
}
internal static DebuggerCommandResults RehydrateDebuggerCommandResults ( PSObject pso )
{
DebuggerResumeAction ? resumeAction = GetPropertyValue < DebuggerResumeAction ?>( pso , "ResumeAction" , RehydrationFlags . NullValueOk );
bool evaluatedByDebugger = GetPropertyValue < bool >( pso , "EvaluatedByDebugger" );
return new DebuggerCommandResults ( resumeAction , evaluatedByDebugger );
}
internal static DebuggerStopEventArgs RehydrateDebuggerStopEventArgs ( PSObject pso )
{
PSObject psoInvocationInfo = GetPropertyValue < PSObject >( pso , "SerializedInvocationInfo" , RehydrationFlags . NullValueOk | RehydrationFlags . MissingPropertyOk );
InvocationInfo invocationInfo = ( psoInvocationInfo != null ) ? new InvocationInfo ( psoInvocationInfo ) : null ;
DebuggerResumeAction resumeAction = GetPropertyValue < DebuggerResumeAction >( pso , "ResumeAction" );
Collection < Breakpoint > breakpoints = new Collection < Breakpoint >();
foreach ( var item in GetPropertyValue < ArrayList >( pso , "Breakpoints" ))
{
Breakpoint bp = item as Breakpoint ;
if ( bp != null )
{
breakpoints . Add ( bp );
}
}
return new DebuggerStopEventArgs ( invocationInfo , breakpoints , resumeAction );
}
private static ScriptBlock RehydrateScriptBlock ( string script )
{
if (! string . IsNullOrEmpty ( script ))
{
return ScriptBlock . Create ( script );
}
return null ;
}
#endregion
2016-07-29 13:02:49 -07:00
#region Rehydration of security - related types
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
private static PSCredential RehydratePSCredential ( PSObject pso )
{
string userName = GetPropertyValue < string >( pso , "UserName" );
System . Security . SecureString password = GetPropertyValue < System . Security . SecureString >( pso , "Password" );
2016-03-30 14:20:52 -07:00
2018-12-31 15:10:15 +05:00
if ( string . IsNullOrEmpty ( userName ))
2016-07-29 13:02:49 -07:00
{
return PSCredential . Empty ;
}
else
{
return new PSCredential ( userName , password );
}
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
internal static PSSenderInfo RehydratePSSenderInfo ( PSObject pso )
{
PSObject userInfo = GetPropertyValue < PSObject >( pso , "UserInfo" );
PSObject userIdentity = GetPropertyValue < PSObject >( userInfo , "Identity" );
PSObject certDetails = GetPropertyValue < PSObject >( userIdentity , "CertificateDetails" );
2016-03-30 14:20:52 -07:00
2020-07-30 16:06:38 -07:00
PSCertificateDetails psCertDetails = certDetails == null ? null : new PSCertificateDetails (
2016-07-29 13:02:49 -07:00
GetPropertyValue < string >( certDetails , "Subject" ),
GetPropertyValue < string >( certDetails , "IssuerName" ),
GetPropertyValue < string >( certDetails , "IssuerThumbprint" ));
PSIdentity psIdentity = new PSIdentity (
GetPropertyValue < string >( userIdentity , "AuthenticationType" ),
GetPropertyValue < bool >( userIdentity , "IsAuthenticated" ),
GetPropertyValue < string >( userIdentity , "Name" ),
psCertDetails );
PSPrincipal psPrincipal = new PSPrincipal ( psIdentity , WindowsIdentity . GetCurrent ());
PSSenderInfo senderInfo = new PSSenderInfo ( psPrincipal , GetPropertyValue < string >( pso , "ConnectionString" ));
2016-03-30 14:20:52 -07:00
2017-08-08 01:27:14 +04:00
senderInfo . ClientTimeZone = TimeZoneInfo . Local ;
2016-07-29 13:02:49 -07:00
senderInfo . ApplicationArguments = GetPropertyValue < PSPrimitiveDictionary >( pso , "ApplicationArguments" );
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
return senderInfo ;
}
2016-03-30 14:20:52 -07:00
private static System . Security . Cryptography . X509Certificates . X509Certificate2 RehydrateX509Certificate2 ( PSObject pso )
{
byte [] rawData = GetPropertyValue < byte []>( pso , "RawData" );
return new System . Security . Cryptography . X509Certificates . X509Certificate2 ( rawData );
}
private static System . Security . Cryptography . X509Certificates . X500DistinguishedName RehydrateX500DistinguishedName ( PSObject pso )
{
byte [] rawData = GetPropertyValue < byte []>( pso , "RawData" );
return new System . Security . Cryptography . X509Certificates . X500DistinguishedName ( rawData );
}
private static System . Net . IPAddress RehydrateIPAddress ( PSObject pso )
{
string s = pso . ToString ();
return System . Net . IPAddress . Parse ( s );
}
private static MailAddress RehydrateMailAddress ( PSObject pso )
{
string s = pso . ToString ();
return new MailAddress ( s );
}
2016-07-29 13:02:49 -07:00
private static T RehydrateObjectSecurity < T >( PSObject pso )
where T : System . Security . AccessControl . ObjectSecurity , new ()
{
string sddl = GetPropertyValue < string >( pso , "SDDL" );
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
T t = new T ();
t . SetSecurityDescriptorSddlForm ( sddl );
return t ;
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
#endregion
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
#region Rehydration of types needed by implicit remoting
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
/// <summary>
2019-01-06 04:40:24 +05:00
/// Gets the boolean properties of ParameterSetMetadata object encoded as an integer.
2016-07-29 13:02:49 -07:00
/// </summary>
/// <param name="instance">
/// The PSObject for which to obtain the flags
/// </param>
/// <returns>
/// Boolean properties of ParameterSetMetadata object encoded as an integer
/// </returns>
public static UInt32 GetParameterSetMetadataFlags ( PSObject instance )
{
2020-07-30 16:06:38 -07:00
if ( instance == null )
2016-07-29 13:02:49 -07:00
{
2020-05-19 19:57:52 +01:00
throw PSTraceSource . NewArgumentNullException ( nameof ( instance ));
2016-07-29 13:02:49 -07:00
}
2016-03-30 14:20:52 -07:00
2020-11-05 16:58:48 +00:00
if (!( instance . BaseObject is ParameterSetMetadata parameterSetMetadata ))
2016-07-29 13:02:49 -07:00
{
2020-05-19 19:57:52 +01:00
throw PSTraceSource . NewArgumentNullException ( nameof ( instance ));
2016-07-29 13:02:49 -07:00
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
return ( UInt32 )( parameterSetMetadata . Flags );
}
2016-03-30 14:20:52 -07:00
/// <summary>
/// Gets the full remoting serialized PSObject for the InvocationInfo property
/// of the DebuggerStopEventArgs type.
/// </summary>
/// <param name="instance">InvocationInfo instance.</param>
2016-08-28 05:44:55 +00:00
/// <returns>PSObject containing serialized InvocationInfo.</returns>
2016-03-30 14:20:52 -07:00
public static PSObject GetInvocationInfo ( PSObject instance )
{
2020-07-30 16:06:38 -07:00
if ( instance == null )
2016-03-30 14:20:52 -07:00
{
2020-05-19 19:57:52 +01:00
throw PSTraceSource . NewArgumentNullException ( nameof ( instance ));
2016-03-30 14:20:52 -07:00
}
2020-11-05 16:58:48 +00:00
if (!( instance . BaseObject is DebuggerStopEventArgs dbgStopEventArgs ))
2016-03-30 14:20:52 -07:00
{
2020-05-19 19:57:52 +01:00
throw PSTraceSource . NewArgumentNullException ( nameof ( instance ));
2016-03-30 14:20:52 -07:00
}
2020-07-30 16:06:38 -07:00
if ( dbgStopEventArgs . InvocationInfo == null )
2016-03-30 14:20:52 -07:00
{
return null ;
}
PSObject psoInvocationInfo = new PSObject ();
dbgStopEventArgs . InvocationInfo . ToPSObjectForRemoting ( psoInvocationInfo );
return psoInvocationInfo ;
}
private static ParameterSetMetadata RehydrateParameterSetMetadata ( PSObject pso )
{
int position = GetPropertyValue < int >( pso , "Position" );
UInt32 flags = GetPropertyValue < UInt32 >( pso , "Flags" );
string helpMessage = GetPropertyValue < string >( pso , "HelpMessage" );
return new ParameterSetMetadata ( position , ( ParameterSetMetadata . ParameterFlags ) flags , helpMessage );
}
2016-07-29 13:02:49 -07:00
private static DisplayEntry RehydrateDisplayEntry ( PSObject deserializedDisplayEntry )
{
var result = new DisplayEntry
{
Value = GetPropertyValue < string >( deserializedDisplayEntry , "Value" ),
ValueType = GetPropertyValue < DisplayEntryValueType >( deserializedDisplayEntry , "ValueType" )
};
return result ;
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
private static EntrySelectedBy RehydrateEntrySelectedBy ( PSObject deserializedEsb )
{
var result = new EntrySelectedBy
{
TypeNames = RehydrateList < List < string >, string >( deserializedEsb , "TypeNames" , RehydrationFlags . MissingPropertyOk ),
SelectionCondition = RehydrateList < List < DisplayEntry >, DisplayEntry >( deserializedEsb , "SelectionCondition" , RehydrationFlags . MissingPropertyOk )
};
return result ;
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
private static WideControlEntryItem RehydrateWideControlEntryItem ( PSObject deserializedEntryItem )
{
var entrySelectedBy = GetPropertyValue < EntrySelectedBy >( deserializedEntryItem , "EntrySelectedBy" , RehydrationFlags . MissingPropertyOk );
2020-07-30 16:06:38 -07:00
if ( entrySelectedBy == null )
2016-07-29 13:02:49 -07:00
{
var selectedBy = RehydrateList < List < string >, string >( deserializedEntryItem , "SelectedBy" , RehydrationFlags . MissingPropertyOk );
2016-03-30 14:20:52 -07:00
entrySelectedBy = EntrySelectedBy . Get ( selectedBy , null );
}
2016-07-29 13:02:49 -07:00
var result = new WideControlEntryItem
{
DisplayEntry = GetPropertyValue < DisplayEntry >( deserializedEntryItem , "DisplayEntry" ),
EntrySelectedBy = entrySelectedBy ,
2016-03-30 14:20:52 -07:00
FormatString = GetPropertyValue < string >( deserializedEntryItem , "FormatString" , RehydrationFlags . MissingPropertyOk ),
2016-07-29 13:02:49 -07:00
};
return result ;
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
private static ListControlEntryItem RehydrateListControlEntryItem ( PSObject deserializedEntryItem )
{
var result = new ListControlEntryItem
{
DisplayEntry = GetPropertyValue < DisplayEntry >( deserializedEntryItem , "DisplayEntry" ),
2016-03-30 14:20:52 -07:00
ItemSelectionCondition = GetPropertyValue < DisplayEntry >( deserializedEntryItem , "ItemSelectionCondition" , RehydrationFlags . MissingPropertyOk ),
FormatString = GetPropertyValue < string >( deserializedEntryItem , "FormatString" , RehydrationFlags . MissingPropertyOk ),
2016-07-29 13:02:49 -07:00
Label = GetPropertyValue < string >( deserializedEntryItem , "Label" , RehydrationFlags . NullValueOk )
};
return result ;
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
private static ListControlEntry RehydrateListControlEntry ( PSObject deserializedEntry )
{
var entrySelectedBy = GetPropertyValue < EntrySelectedBy >( deserializedEntry , "EntrySelectedBy" , RehydrationFlags . MissingPropertyOk );
2020-07-30 16:06:38 -07:00
if ( entrySelectedBy == null )
2016-07-29 13:02:49 -07:00
{
var selectedBy = RehydrateList < List < string >, string >( deserializedEntry , "SelectedBy" , RehydrationFlags . MissingPropertyOk );
2016-03-30 14:20:52 -07:00
entrySelectedBy = EntrySelectedBy . Get ( selectedBy , null );
}
2016-07-29 13:02:49 -07:00
var result = new ListControlEntry
{
Items = RehydrateList < List < ListControlEntryItem >, ListControlEntryItem >( deserializedEntry , "Items" , RehydrationFlags . NullValueBad ),
EntrySelectedBy = entrySelectedBy
};
return result ;
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
private static TableControlColumnHeader RehydrateTableControlColumnHeader ( PSObject deserializedHeader )
{
var result = new TableControlColumnHeader
{
Alignment = GetPropertyValue < Alignment >( deserializedHeader , "Alignment" ),
Label = GetPropertyValue < string >( deserializedHeader , "Label" , RehydrationFlags . NullValueOk ),
Width = GetPropertyValue < int >( deserializedHeader , "Width" )
};
return result ;
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
private static TableControlColumn RehydrateTableControlColumn ( PSObject deserializedColumn )
{
var result = new TableControlColumn
{
Alignment = GetPropertyValue < Alignment >( deserializedColumn , "Alignment" ),
DisplayEntry = GetPropertyValue < DisplayEntry >( deserializedColumn , "DisplayEntry" ),
FormatString = GetPropertyValue < string >( deserializedColumn , "FormatString" , RehydrationFlags . MissingPropertyOk )
};
return result ;
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
private static TableControlRow RehydrateTableControlRow ( PSObject deserializedRow )
{
var result = new TableControlRow
{
Wrap = GetPropertyValue < bool >( deserializedRow , "Wrap" , RehydrationFlags . MissingPropertyOk ),
2016-03-30 14:20:52 -07:00
SelectedBy = GetPropertyValue < EntrySelectedBy >( deserializedRow , "EntrySelectedBy" , RehydrationFlags . MissingPropertyOk ),
2016-07-29 13:02:49 -07:00
Columns = RehydrateList < List < TableControlColumn >, TableControlColumn >( deserializedRow , "Columns" , RehydrationFlags . NullValueBad )
};
return result ;
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
private static CustomControlEntry RehydrateCustomControlEntry ( PSObject deserializedEntry )
{
var result = new CustomControlEntry
{
CustomItems = RehydrateList < List < CustomItemBase >, CustomItemBase >( deserializedEntry , "CustomItems" , RehydrationFlags . MissingPropertyBad ),
2016-03-30 14:20:52 -07:00
SelectedBy = GetPropertyValue < EntrySelectedBy >( deserializedEntry , "SelectedBy" , RehydrationFlags . MissingPropertyOk )
2016-07-29 13:02:49 -07:00
};
return result ;
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
private static CustomItemBase RehydrateCustomItemBase ( PSObject deserializedItem )
{
CustomItemBase result ;
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
if ( Deserializer . IsDeserializedInstanceOfType ( deserializedItem , typeof ( CustomItemNewline )))
{
result = new CustomItemNewline
{
Count = GetPropertyValue < int >( deserializedItem , "Count" , RehydrationFlags . MissingPropertyBad )
};
}
else if ( Deserializer . IsDeserializedInstanceOfType ( deserializedItem , typeof ( CustomItemText )))
{
result = new CustomItemText
{
Text = GetPropertyValue < string >( deserializedItem , "Text" , RehydrationFlags . MissingPropertyBad )
};
}
else if ( Deserializer . IsDeserializedInstanceOfType ( deserializedItem , typeof ( CustomItemFrame )))
{
result = new CustomItemFrame
{
2016-03-30 14:20:52 -07:00
FirstLineHanging = GetPropertyValue < uint >( deserializedItem , "FirstLineHanging" ),
FirstLineIndent = GetPropertyValue < uint >( deserializedItem , "FirstLineIndent" ),
RightIndent = GetPropertyValue < uint >( deserializedItem , "RightIndent" ),
LeftIndent = GetPropertyValue < uint >( deserializedItem , "LeftIndent" ),
CustomItems = RehydrateList < List < CustomItemBase >, CustomItemBase >( deserializedItem , "CustomItems" , RehydrationFlags . MissingPropertyBad )
2016-07-29 13:02:49 -07:00
};
}
else if ( Deserializer . IsDeserializedInstanceOfType ( deserializedItem , typeof ( CustomItemExpression )))
{
result = new CustomItemExpression
{
2016-03-30 14:20:52 -07:00
EnumerateCollection = GetPropertyValue < bool >( deserializedItem , "EnumerateCollection" ),
CustomControl = GetPropertyValue < CustomControl >( deserializedItem , "CustomControl" , RehydrationFlags . MissingPropertyOk ),
Expression = GetPropertyValue < DisplayEntry >( deserializedItem , "Expression" , RehydrationFlags . MissingPropertyOk ),
ItemSelectionCondition = GetPropertyValue < DisplayEntry >( deserializedItem , "ItemSelectionCondition" , RehydrationFlags . MissingPropertyOk )
2016-07-29 13:02:49 -07:00
};
}
else
{
2020-05-19 19:57:52 +01:00
throw PSTraceSource . NewArgumentException ( nameof ( deserializedItem ));
2016-07-29 13:02:49 -07:00
}
2018-12-23 22:20:06 -08:00
2016-07-29 13:02:49 -07:00
return result ;
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
private static PSControl RehydratePSControl ( PSObject deserializedControl )
{
2016-03-30 14:20:52 -07:00
// Earlier versions of PowerShell did not have all of the possible properties in a control, so we must
2016-08-28 05:44:55 +00:00
// use MissingPropertyOk to allow for connections to those older endpoints.
2016-07-29 13:02:49 -07:00
PSControl result ;
if ( Deserializer . IsDeserializedInstanceOfType ( deserializedControl , typeof ( TableControl )))
{
var tableControl = new TableControl
{
AutoSize = GetPropertyValue < bool >( deserializedControl , "AutoSize" , RehydrationFlags . MissingPropertyOk ),
2016-03-30 14:20:52 -07:00
HideTableHeaders = GetPropertyValue < bool >( deserializedControl , "HideTableHeaders" , RehydrationFlags . MissingPropertyOk ),
2016-07-29 13:02:49 -07:00
Headers = RehydrateList < List < TableControlColumnHeader >, TableControlColumnHeader >( deserializedControl , "Headers" , RehydrationFlags . NullValueBad ),
Rows = RehydrateList < List < TableControlRow >, TableControlRow >( deserializedControl , "Rows" , RehydrationFlags . NullValueBad )
};
result = tableControl ;
}
else if ( Deserializer . IsDeserializedInstanceOfType ( deserializedControl , typeof ( ListControl )))
{
var listControl = new ListControl
{
Entries = RehydrateList < List < ListControlEntry >, ListControlEntry >( deserializedControl , "Entries" , RehydrationFlags . NullValueBad )
};
result = listControl ;
}
else if ( Deserializer . IsDeserializedInstanceOfType ( deserializedControl , typeof ( WideControl )))
{
var wideControl = new WideControl
{
AutoSize = GetPropertyValue < bool >( deserializedControl , "Alignment" , RehydrationFlags . MissingPropertyOk ),
Columns = GetPropertyValue < uint >( deserializedControl , "Columns" ),
Entries = RehydrateList < List < WideControlEntryItem >, WideControlEntryItem >( deserializedControl , "Entries" , RehydrationFlags . NullValueBad )
};
result = wideControl ;
}
else if ( Deserializer . IsDeserializedInstanceOfType ( deserializedControl , typeof ( CustomControl )))
{
var customControl = new CustomControl
{
Entries = RehydrateList < List < CustomControlEntry >, CustomControlEntry >( deserializedControl , "Entries" , RehydrationFlags . NullValueBad )
};
result = customControl ;
}
else
{
throw PSTraceSource . NewArgumentException ( "pso" );
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
result . GroupBy = GetPropertyValue < PSControlGroupBy >( deserializedControl , "GroupBy" , RehydrationFlags . MissingPropertyOk );
result . OutOfBand = GetPropertyValue < bool >( deserializedControl , "OutOfBand" , RehydrationFlags . MissingPropertyOk );
return result ;
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
private static PSControlGroupBy RehydrateGroupBy ( PSObject deserializedGroupBy )
{
var result = new PSControlGroupBy
{
CustomControl = GetPropertyValue < CustomControl >( deserializedGroupBy , "CustomControl" , RehydrationFlags . MissingPropertyOk ),
Expression = GetPropertyValue < DisplayEntry >( deserializedGroupBy , "Expression" , RehydrationFlags . MissingPropertyOk ),
Label = GetPropertyValue < string >( deserializedGroupBy , "Label" , RehydrationFlags . NullValueOk )
};
return result ;
}
2016-03-30 14:20:52 -07:00
/// <summary>
2019-01-06 04:40:24 +05:00
/// Gets the boolean properties of ParameterSetMetadata object encoded as an integer.
2016-03-30 14:20:52 -07:00
/// </summary>
/// <param name="instance">
/// The PSObject for which to obtain the flags
/// </param>
/// <returns>
/// Boolean properties of ParameterSetMetadata object encoded as an integer
/// </returns>
public static Guid GetFormatViewDefinitionInstanceId ( PSObject instance )
2016-07-29 13:02:49 -07:00
{
2020-07-30 16:06:38 -07:00
if ( instance == null )
2016-07-29 13:02:49 -07:00
{
2020-05-19 19:57:52 +01:00
throw PSTraceSource . NewArgumentNullException ( nameof ( instance ));
2016-07-29 13:02:49 -07:00
}
2016-03-30 14:20:52 -07:00
2020-11-05 16:58:48 +00:00
if (!( instance . BaseObject is FormatViewDefinition formatViewDefinition ))
2016-07-29 13:02:49 -07:00
{
2020-05-19 19:57:52 +01:00
throw PSTraceSource . NewArgumentNullException ( nameof ( instance ));
2016-07-29 13:02:49 -07:00
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
return formatViewDefinition . InstanceId ;
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
private static FormatViewDefinition RehydrateFormatViewDefinition ( PSObject deserializedViewDefinition )
{
string name = GetPropertyValue < string >( deserializedViewDefinition , "Name" );
Guid instanceId = GetPropertyValue < Guid >( deserializedViewDefinition , "InstanceId" );
PSControl control = GetPropertyValue < PSControl >( deserializedViewDefinition , "Control" );
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
return new FormatViewDefinition ( name , control , instanceId );
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
private static ExtendedTypeDefinition RehydrateExtendedTypeDefinition ( PSObject deserializedTypeDefinition )
{
2016-03-30 14:20:52 -07:00
// Prefer TypeNames to TypeName - as it was incorrect to create multiple ExtendedTypeDefinitions for a group of types.
// But if a new PowerShell connects to an old endpoint, TypeNames will be missing, so fall back to TypeName in that case.
2016-07-29 13:02:49 -07:00
string typeName ;
var typeNames = RehydrateList < List < string >, string >( deserializedTypeDefinition , "TypeNames" , RehydrationFlags . MissingPropertyOk );
2020-07-30 16:06:38 -07:00
if ( typeNames == null || typeNames . Count == 0 )
2016-07-29 13:02:49 -07:00
{
2016-03-30 14:20:52 -07:00
typeName = GetPropertyValue < string >( deserializedTypeDefinition , "TypeName" );
2016-07-29 13:02:49 -07:00
}
2016-03-30 14:20:52 -07:00
else
2016-07-29 13:02:49 -07:00
{
2016-03-30 14:20:52 -07:00
typeName = typeNames [ 0 ];
2016-07-29 13:02:49 -07:00
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
List < FormatViewDefinition > viewDefinitions = RehydrateList < List < FormatViewDefinition >, FormatViewDefinition >(
deserializedTypeDefinition ,
"FormatViewDefinition" ,
RehydrationFlags . NullValueBad );
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
var result = new ExtendedTypeDefinition ( typeName , viewDefinitions );
if ( typeNames != null && typeNames . Count > 1 )
{
for ( var i = 1 ; i < typeNames . Count ; i ++)
{
result . TypeNames . Add ( typeNames [ i ]);
}
}
2018-12-23 22:20:06 -08:00
2016-07-29 13:02:49 -07:00
return result ;
}
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
#endregion
}
2016-03-30 14:20:52 -07:00
}