Team Ai
Datasetpublic

MegaBites-AI/Windows-powershell

sourceHugging Facemitupdated 6mo agoView on Hugging Face
0likes308downloads
serialization.cs7680 linesDownload Raw Back to engine
1// Copyright (c) Microsoft Corporation.2// Licensed under the MIT License.3 4using System;5using System.Collections;6using System.Collections.Generic;7using System.Collections.Specialized;8using System.Collections.ObjectModel;9using System.Diagnostics.CodeAnalysis;10using System.Globalization;11using System.IO;12using System.Linq;13using System.Management.Automation.Internal;14using System.Management.Automation.Language;15using System.Management.Automation.Remoting;16using System.Management.Automation.Runspaces;17using System.Management.Automation.Tracing;18using System.Net.Mail;19using System.Reflection;20using System.Runtime.CompilerServices;21using System.Security;22using System.Text;23using System.Xml;24 25using Microsoft.Management.Infrastructure;26using Microsoft.Management.Infrastructure.Serialization;27using Microsoft.PowerShell.Commands;28 29using Dbg = System.Management.Automation.Diagnostics;30 31namespace System.Management.Automation32{33    [Flags]34    internal enum SerializationOptions35    {36        None = 0,37        UseDepthFromTypes = 1,38        NoRootElement = 2,39        NoNamespace = 4,40        NoObjectRefIds = 8,41        PreserveSerializationSettingOfOriginal = 16,42 43        RemotingOptions = UseDepthFromTypes | NoRootElement | NoNamespace | PreserveSerializationSettingOfOriginal,44    }45 46    internal class SerializationContext47    {48        private const int DefaultSerializationDepth = 2;49 50        internal SerializationContext()51            : this(DefaultSerializationDepth, true)52        {53        }54 55        internal SerializationContext(int depth, bool useDepthFromTypes)56            : this(57                    depth,58                    (useDepthFromTypes ? SerializationOptions.UseDepthFromTypes : SerializationOptions.None) |59                       SerializationOptions.PreserveSerializationSettingOfOriginal,60                    null)61        {62        }63 64        internal SerializationContext(int depth, SerializationOptions options, PSRemotingCryptoHelper cryptoHelper)65        {66            if (depth < 1)67            {68                throw PSTraceSource.NewArgumentException("writer", Serialization.DepthOfOneRequired);69            }70 71            this.depth = depth;72            this.options = options;73            this.cryptoHelper = cryptoHelper;74        }75 76        internal readonly int depth;77        internal readonly SerializationOptions options;78        internal readonly PSRemotingCryptoHelper cryptoHelper;79 80        internal readonly CimClassSerializationCache<CimClassSerializationId> cimClassSerializationIdCache = new CimClassSerializationCache<CimClassSerializationId>();81    }82 83    /// <summary>84    /// This class provides public functionality for serializing a PSObject.85    /// </summary>86    public static class PSSerializer87    {88        /// <summary>89        /// Serializes an object into PowerShell CliXml.90        /// </summary>91        /// <param name="source">The input object to serialize. Serializes to a default depth of 1.</param>92        /// <returns>The serialized object, as CliXml.</returns>93        public static string Serialize(object source)94        {95            return Serialize(source, s_mshDefaultSerializationDepth);96        }97 98        /// <summary>99        /// Serializes an object into PowerShell CliXml.100        /// </summary>101        /// <param name="source">The input object to serialize.</param>102        /// <param name="depth">The depth of the members to serialize.</param>103        /// <returns>The serialized object, as CliXml.</returns>104        public static string Serialize(object source, int depth)105        {106            // Create an xml writer107            StringBuilder sb = new StringBuilder();108            XmlWriterSettings xmlSettings = new XmlWriterSettings();109            xmlSettings.CloseOutput = true;110            xmlSettings.Encoding = System.Text.Encoding.Unicode;111            xmlSettings.Indent = true;112            xmlSettings.OmitXmlDeclaration = true;113            XmlWriter xw = XmlWriter.Create(sb, xmlSettings);114 115            // Serialize the objects116            Serializer serializer = new Serializer(xw, depth, true);117            serializer.Serialize(source);118            serializer.Done();119            serializer = null;120 121            // Return the output122            return sb.ToString();123        }124 125        /// <summary>126        /// Serializes list of objects into PowerShell CliXml.127        /// </summary>128        /// <param name="source">The input objects to serialize.</param>129        /// <param name="depth">The depth of the members to serialize.</param>130        /// <param name="enumerate">Enumerates input objects and serializes one at a time.</param>131        /// <returns>The serialized object, as CliXml.</returns>132        internal static string Serialize(IList<object> source, int depth, bool enumerate)133        {134            StringBuilder sb = new();135 136            XmlWriterSettings xmlSettings = new()137            {138                CloseOutput = true,139                Encoding = Encoding.Unicode,140                Indent = true,141                OmitXmlDeclaration = true142            };143 144            XmlWriter xw = XmlWriter.Create(sb, xmlSettings);145            Serializer serializer = new(xw, depth, useDepthFromTypes: true);146 147            if (enumerate)148            {149                foreach (object item in source)150                {151                    serializer.Serialize(item);152                }153            }154            else155            {156                serializer.Serialize(source);157            }158 159            serializer.Done();160 161            return sb.ToString();162        }163 164        /// <summary>165        /// Deserializes PowerShell CliXml into an object.166        /// </summary>167        /// <param name="source">The CliXml the represents the object to deserialize.</param>168        /// <returns>An object that represents the serialized content.</returns>169        public static object Deserialize(string source)170        {171            object[] results = DeserializeAsList(source);172 173            // Return the results174            if (results.Length == 0)175            {176                return null;177            }178            else if (results.Length == 1)179            {180                return results[0];181            }182            else183            {184                return results;185            }186        }187 188        /// <summary>189        /// Deserializes PowerShell CliXml into a list of objects.190        /// </summary>191        /// <param name="source">The CliXml the represents the object to deserialize.</param>192        /// <returns>An object array represents the serialized content.</returns>193        public static object[] DeserializeAsList(string source)194        {195            List<object> results = new List<object>();196 197            // Create the text reader to hold the content198            TextReader textReader = new StringReader(source);199            XmlReader xmlReader = XmlReader.Create(textReader, InternalDeserializer.XmlReaderSettingsForCliXml);200 201            // Deserialize the content202            Deserializer deserializer = new Deserializer(xmlReader);203            while (!deserializer.Done())204            {205                object result = deserializer.Deserialize();206                results.Add(result);207            }208 209            return results.ToArray();210        }211 212        /// <summary>213        /// Default depth of serialization.214        /// </summary>215        private static readonly int s_mshDefaultSerializationDepth = 1;216    }217 218    /// <summary>219    /// This class provides functionality for serializing a PSObject.220    /// </summary>221    internal class Serializer222    {223        #region constructor224 225        private readonly InternalSerializer _serializer;226 227        /// <summary>228        /// Creates a Serializer using default serialization context.229        /// </summary>230        /// <param name="writer">Writer to be used for serialization.</param>231        internal Serializer(XmlWriter writer)232            : this(writer, new SerializationContext())233        {234        }235 236        /// <summary>237        /// Creates a Serializer using specified serialization context.238        /// </summary>239        /// <param name="writer">Writer to be used for serialization.</param>240        /// <param name="depth">Depth of serialization.</param>241        /// <param name="useDepthFromTypes">242        /// if <see langword="true"/> then types.ps1xml can override depth243        /// for a particular types (using SerializationDepth property)244        /// </param>245        internal Serializer(XmlWriter writer, int depth, bool useDepthFromTypes)246            : this(writer, new SerializationContext(depth, useDepthFromTypes))247        {248        }249 250        /// <summary>251        /// Creates a Serializer using specified serialization context.252        /// </summary>253        /// <param name="writer">Writer to be used for serialization.</param>254        /// <param name="context">Serialization context.</param>255        internal Serializer(XmlWriter writer, SerializationContext context)256        {257            if (writer == null)258            {259                throw PSTraceSource.NewArgumentException(nameof(writer));260            }261 262            if (context == null)263            {264                throw PSTraceSource.NewArgumentException(nameof(context));265            }266 267            _serializer = new InternalSerializer(writer, context);268            _serializer.Start();269        }270 271        #endregion constructor272 273        #region public methods / properties274 275        /// <summary>276        /// Used by Remoting infrastructure. This TypeTable instance277        /// will be used by Serializer if ExecutionContext is not278        /// available (to get the ExecutionContext's TypeTable)279        /// </summary>280        internal TypeTable TypeTable281        {282            get { return _serializer.TypeTable; }283 284            set { _serializer.TypeTable = value; }285        }286 287        /// <summary>288        /// Serializes the object.289        /// </summary>290        /// <param name="source">Object to be serialized.</param>291        /// <remarks>292        /// Please note that this method shouldn't throw any exceptions.293        /// If it throws - please open a bug.294        /// </remarks>295        internal void Serialize(object source)296        {297            Serialize(source, null);298        }299 300        /// <summary>301        /// Serializes passed in object.302        /// </summary>303        /// <param name="source">304        /// object to be serialized305        /// </param>306        /// <param name="streamName">307        /// Stream to which this object belong. Ex: Output, Error etc.308        /// </param>309        /// <remarks>310        /// Please note that this method shouldn't throw any exceptions.311        /// If it throws - please open a bug.312        /// </remarks>313        internal void Serialize(object source, string streamName)314        {315            _serializer.WriteOneTopLevelObject(source, streamName);316        }317 318        /// <summary>319        /// Write the end of root element.320        /// </summary>321        internal void Done()322        {323            _serializer.End();324        }325 326        internal void Stop()327        {328            _serializer.Stop();329        }330 331        #endregion332    }333 334    [Flags]335    internal enum DeserializationOptions336    {337        None = 0,338        NoRootElement = 256,            // I start at 256 to try not to overlap339        NoNamespace = 512,              // with SerializationOptions and to catch bugs early340        DeserializeScriptBlocks = 1024,341 342        RemotingOptions = NoRootElement | NoNamespace,343    }344 345    internal class DeserializationContext346    {347        internal DeserializationContext()348            : this(DeserializationOptions.None, null)349        {350        }351 352        internal DeserializationContext(DeserializationOptions options, PSRemotingCryptoHelper cryptoHelper)353        {354            this.options = options;355            this.cryptoHelper = cryptoHelper;356        }357 358        /// <summary>359        /// Limits the total data processed by the deserialization context. Deserialization context360        /// is used by PriorityReceivedDataCollection (remoting) to process incoming data from the361        /// remote end. A value of Null means that the max memory is unlimited.362        /// </summary>363        internal int? MaximumAllowedMemory { get; set; }364 365        /// <summary>366        /// Logs that memory used by deserialized objects is not related to the size of input xml.367        /// Used mainly to account for memory usage of cloned TypeNames when calculating memory quota usage.368        /// </summary>369        /// <param name="amountOfExtraMemory"></param>370        internal void LogExtraMemoryUsage(int amountOfExtraMemory)371        {372            if (amountOfExtraMemory < 0)373            {374                return;375            }376 377            if (MaximumAllowedMemory.HasValue)378            {379                if (amountOfExtraMemory > (MaximumAllowedMemory.Value - _totalDataProcessedSoFar))380                {381                    string message = StringUtil.Format(Serialization.DeserializationMemoryQuota, ((double)MaximumAllowedMemory.Value) / (1 << 20),382                                                       ConfigurationDataFromXML.MAXRCVDOBJSIZETOKEN_CamelCase,383                                                       ConfigurationDataFromXML.MAXRCVDCMDSIZETOKEN_CamelCase);384                    throw new XmlException(message);385                }386 387                _totalDataProcessedSoFar += amountOfExtraMemory;388            }389        }390 391        private int _totalDataProcessedSoFar;392 393        internal readonly DeserializationOptions options;394        internal readonly PSRemotingCryptoHelper cryptoHelper;395 396        internal static readonly int MaxItemsInCimClassCache = 100;397        internal readonly CimClassDeserializationCache<CimClassSerializationId> cimClassSerializationIdCache = new CimClassDeserializationCache<CimClassSerializationId>();398    }399 400    internal class CimClassDeserializationCache<TKey>401    {402        private readonly Dictionary<TKey, CimClass> _cimClassIdToClass = new Dictionary<TKey, CimClass>();403 404        internal void AddCimClassToCache(TKey key, CimClass cimClass)405        {406            if (_cimClassIdToClass.Count >= DeserializationContext.MaxItemsInCimClassCache)407            {408                _cimClassIdToClass.Clear();409            }410 411            _cimClassIdToClass.Add(key, cimClass);412 413            /* PRINTF DEBUG414            Console.WriteLine("Contents of deserialization cache (after a call to AddCimClassToCache ({0})):", key);415            Console.WriteLine("  Count = {0}", this._cimClassIdToClass.Count);416            foreach (var t in this._cimClassIdToClass.Keys)417            {418                Console.WriteLine("  {0}", t);419            }420             */421        }422 423        internal CimClass GetCimClassFromCache(TKey key)424        {425            CimClass cimClass;426            if (_cimClassIdToClass.TryGetValue(key, out cimClass))427            {428                /* PRINTF DEBUG429                Console.WriteLine("GetCimClassFromCache - class found: {0}", key);430                 */431 432                return cimClass;433            }434 435            /* PRINTF DEBUG436            Console.WriteLine("GetCimClassFromCache - class NOT found: {0}", key);437             */438 439            return null;440        }441    }442 443    internal class CimClassSerializationCache<TKey>444    {445        private readonly HashSet<TKey> _cimClassesHeldByDeserializer = new HashSet<TKey>(EqualityComparer<TKey>.Default);446 447        internal bool DoesDeserializerAlreadyHaveCimClass(TKey key)448        {449            return _cimClassesHeldByDeserializer.Contains(key);450        }451 452        internal void AddClassToCache(TKey key)453        {454            Dbg.Assert(!_cimClassesHeldByDeserializer.Contains(key), "This method should not be called for classes already in the cache");455 456            if (_cimClassesHeldByDeserializer.Count >= DeserializationContext.MaxItemsInCimClassCache)457            {458                _cimClassesHeldByDeserializer.Clear();459            }460 461            _cimClassesHeldByDeserializer.Add(key);462 463            /* PRINTF DEBUG464            Console.WriteLine("Contents of serialization cache (after adding {0}):", key);465            Console.WriteLine("  Count = {0}", this._cimClassesHeldByDeserializer.Count);466            foreach (var t in _cimClassesHeldByDeserializer)467            {468                Console.WriteLine("  {0}", t);469            }470             */471        }472    }473 474    internal class CimClassSerializationId : Tuple<string, string, string, int>475    {476        public CimClassSerializationId(string className, string namespaceName, string computerName, int hashCode)477            : base(className, namespaceName, computerName, hashCode)478        {479        }480 481        public string ClassName { get { return this.Item1; } }482 483        public string NamespaceName { get { return this.Item2; } }484 485        public string ComputerName { get { return this.Item3; } }486 487        public int ClassHashCode { get { return this.Item4; } }488    }489 490    /// <summary>491    /// This class provides functionality for deserializing a PSObject.492    /// </summary>493    internal class Deserializer494    {495        #region constructor496 497        private readonly XmlReader _reader;498        private readonly InternalDeserializer _deserializer;499        private readonly DeserializationContext _context;500 501        /// <summary>502        /// Creates a Deserializer using default deserialization context.503        /// </summary>504        /// <param name="reader">Reader to be used for deserialization.</param>505        /// <exception cref="XmlException">506        /// Thrown when the xml is in an incorrect format507        /// </exception>508        internal Deserializer(XmlReader reader)509            : this(reader, new DeserializationContext())510        {511        }512 513        /// <summary>514        /// Creates a Deserializer using specified serialization context.515        /// </summary>516        /// <param name="reader">Reader to be used for deserialization.</param>517        /// <param name="context">Serialization context.</param>518        /// <exception cref="XmlException">519        /// Thrown when the xml is in an incorrect format520        /// </exception>521        internal Deserializer(XmlReader reader, DeserializationContext context)522        {523            if (reader == null)524            {525                throw PSTraceSource.NewArgumentNullException(nameof(reader));526            }527 528            _reader = reader;529            _context = context;530            _deserializer = new InternalDeserializer(_reader, _context);531 532            try533            {534                Start();535            }536            catch (XmlException exception)537            {538                ReportExceptionForETW(exception);539                throw;540            }541        }542 543        #endregion constructor544 545        #region public method / properties546 547        private static void ReportExceptionForETW(XmlException exception)548        {549            PSEtwLog.LogAnalyticError(550                PSEventId.Serializer_XmlExceptionWhenDeserializing, PSOpcode.Exception, PSTask.Serialization,551                PSKeyword.Serializer | PSKeyword.UseAlwaysAnalytic,552                exception.LineNumber, exception.LinePosition, exception.ToString());553        }554 555        private bool _done = false;556 557        /// <summary>558        /// Used by Remoting infrastructure. This TypeTable instance559        /// will be used by Deserializer if ExecutionContext is not560        /// available (to get the ExecutionContext's TypeTable)561        /// </summary>562        internal TypeTable TypeTable563        {564            get { return _deserializer.TypeTable; }565 566            set { _deserializer.TypeTable = value; }567        }568 569        /// <summary>570        /// Read the root element tag and set the cursor to start tag of571        /// first object.572        /// </summary>573        private void Start()574        {575            Dbg.Assert(_reader.ReadState == ReadState.Initial, "When deserialization starts we should have XmlReader.ReadState == Initial");576            Dbg.Assert(_reader.NodeType == XmlNodeType.None, "When deserialization starts we should have XmlReader.NodeType == None");577            _reader.Read();578 579            // If version is not provided, we assume it is the default580            string version = InternalSerializer.DefaultVersion;581            if ((_context.options & DeserializationOptions.NoRootElement) == DeserializationOptions.NoRootElement)582            {583                _done = _reader.EOF;584            }585            else586            {587                // Make sure the reader is positioned on the root ( <Objs> ) element (not on XmlDeclaration for example)588                _reader.MoveToContent();589                Dbg.Assert(_reader.EOF || (_reader.NodeType == XmlNodeType.Element), "When deserialization starts reading we should have XmlReader.NodeType == Element");590 591                // Read version attribute and validate it.592                string versionAttribute = _reader.GetAttribute(SerializationStrings.VersionAttribute);593                if (versionAttribute != null)594                {595                    version = versionAttribute;596                }597 598                // If the root element tag is empty, there are no objects to read.599                if (!_deserializer.ReadStartElementAndHandleEmpty(SerializationStrings.RootElementTag))600                {601                    _done = true;602                }603            }604 605            _deserializer.ValidateVersion(version);606        }607 608        internal bool Done()609        {610            if (!_done)611            {612                if ((_context.options & DeserializationOptions.NoRootElement) == DeserializationOptions.NoRootElement)613                {614                    _done = _reader.EOF;615                }616                else617                {618                    if (_reader.NodeType == XmlNodeType.EndElement)619                    {620                        try621                        {622                            _reader.ReadEndElement();623                        }624                        catch (XmlException exception)625                        {626                            ReportExceptionForETW(exception);627                            throw;628                        }629 630                        _done = true;631                    }632                }633            }634 635            return _done;636        }637 638        internal void Stop()639        {640            _deserializer.Stop();641        }642 643        /// <summary>644        /// Deserializes next object.645        /// </summary>646        /// <exception cref="XmlException">647        /// Thrown when the xml is in an incorrect format648        /// </exception>649        internal object Deserialize()650        {651            string ignore;652            return Deserialize(out ignore);653        }654 655        /// <summary>656        /// Deserializes next object.657        /// </summary>658        /// <param name="streamName">Stream the object belongs to (i.e. "Error", "Output", etc.).</param>659        /// <exception cref="XmlException">660        /// Thrown when the xml is in an incorrect format661        /// </exception>662        internal object Deserialize(out string streamName)663        {664            if (Done())665            {666                throw PSTraceSource.NewInvalidOperationException(Serialization.ReadCalledAfterDone);667            }668 669            try670            {671                return _deserializer.ReadOneObject(out streamName);672            }673            catch (XmlException exception)674            {675                ReportExceptionForETW(exception);676                throw;677            }678        }679 680        #endregion public methods681 682        #region Helper methods for dealing with "Deserialized." prefix683 684        /// <summary>685        /// Adds "Deserialized." prefix to passed in argument if not already present.686        /// </summary>687        /// <param name="type"></param>688        internal static void AddDeserializationPrefix(ref string type)689        {690            Dbg.Assert(type != null, "caller should validate the parameter");691            if (!type.StartsWith(Deserializer.DeserializationTypeNamePrefix, StringComparison.OrdinalIgnoreCase))692            {693                type = type.Insert(0, Deserializer.DeserializationTypeNamePrefix);694            }695        }696 697        /// <summary>698        /// Checks if an object <paramref name="o"/> is either a live or deserialized instance of class <paramref name="type"/> or one of its subclasses.699        /// </summary>700        /// <param name="o"></param>701        /// <param name="type"></param>702        /// <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>703        internal static bool IsInstanceOfType(object o, Type type)704        {705            if (type == null)706            {707                throw PSTraceSource.NewArgumentNullException(nameof(type));708            }709 710            if (o == null)711            {712                return false;713            }714 715            return type.IsInstanceOfType(PSObject.Base(o)) || IsDeserializedInstanceOfType(o, type);716        }717 718        /// <summary>719        /// Checks if an object <paramref name="o"/> is a deserialized instance of class <paramref name="type"/> or one of its subclasses.720        /// </summary>721        /// <param name="o"></param>722        /// <param name="type"></param>723        /// <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>724        internal static bool IsDeserializedInstanceOfType(object o, Type type)725        {726            if (type == null)727            {728                throw PSTraceSource.NewArgumentNullException(nameof(type));729            }730 731            if (o == null)732            {733                return false;734            }735 736            PSObject pso = o as PSObject;737            if (pso != null)738            {739                IEnumerable<string> typeNames = pso.InternalTypeNames;740                if (typeNames != null)741                {742                    foreach (string typeName in typeNames)743                    {744                        if (typeName.Length == Deserializer.DeserializationTypeNamePrefix.Length + type.FullName.Length &&745                            typeName.StartsWith(Deserializer.DeserializationTypeNamePrefix, StringComparison.OrdinalIgnoreCase) &&746                            typeName.EndsWith(type.FullName, StringComparison.OrdinalIgnoreCase))747                        {748                            return true;749                        }750                    }751                }752            }753 754            // not the right type755            return false;756        }757 758        internal static string MaskDeserializationPrefix(string typeName)759        {760            if (typeName == null)761            {762                return null;763            }764 765            if (typeName.StartsWith(Deserializer.DeserializationTypeNamePrefix, StringComparison.OrdinalIgnoreCase))766            {767                typeName = typeName.Substring(Deserializer.DeserializationTypeNamePrefix.Length);768            }769 770            return typeName;771        }772 773        /// <summary>774        /// Gets a new collection of typenames without "Deserialization." prefix775        /// in the typename. This will allow to map type info/format info of the original type776        /// for deserialized objects.777        /// </summary>778        /// <param name="typeNames"></param>779        /// <returns>780        /// Null if no type with "Deserialized." prefix is found.781        /// Otherwise <paramref name="typeNames"/> with the prefix removed if any.782        /// </returns>783        internal static Collection<string> MaskDeserializationPrefix(Collection<string> typeNames)784        {785            Dbg.Assert(typeNames != null, "typeNames cannot be null");786 787            bool atleastOneDeserializedTypeFound = false;788 789            Collection<string> typesWithoutPrefix = new Collection<string>();790            foreach (string type in typeNames)791            {792                if (type.StartsWith(Deserializer.DeserializationTypeNamePrefix,793                    StringComparison.OrdinalIgnoreCase))794                {795                    atleastOneDeserializedTypeFound = true;796                    // remove *only* the prefix797                    typesWithoutPrefix.Add(type.Substring(Deserializer.DeserializationTypeNamePrefix.Length));798                }799                else800                {801                    typesWithoutPrefix.Add(type);802                }803            }804 805            if (atleastOneDeserializedTypeFound)806            {807                return typesWithoutPrefix;808            }809 810            return null;811        }812 813        /// <summary>814        /// Used to prefix a typename for deserialization.815        /// </summary>816        private const string DeserializationTypeNamePrefix = "Deserialized.";817 818        #endregion819    }820 821    /// <summary>822    /// Types of known type container supported by monad.823    /// </summary>824    internal enum ContainerType825    {826        Dictionary,827        Queue,828        Stack,829        List,830        Enumerable,831        None832    }833 834    /// <summary>835    /// This internal helper class provides methods for serializing mshObject.836    /// </summary>837    internal class InternalSerializer838    {839        #region constructor840 841        internal const string DefaultVersion = "1.1.0.1";842 843        /// <summary>844        /// Xml writer to be used.845        /// </summary>846        private readonly XmlWriter _writer;847 848        /// <summary>849        /// Serialization context.850        /// </summary>851        private readonly SerializationContext _context;852 853        /// Used by Remoting infrastructure. This TypeTable instance854        /// will be used by Serializer if ExecutionContext is not855        /// available (to get the ExecutionContext's TypeTable)856        private TypeTable _typeTable;857 858        /// <summary>859        /// Depth below top level - used to prevent infinitely deep serialization860        /// (without this protection it would be possible i.e. with SerializationDepth and recursion)861        /// </summary>862        private int _depthBelowTopLevel;863 864        private const int MaxDepthBelowTopLevel = 50;865 866        private readonly ReferenceIdHandlerForSerializer<object> _objectRefIdHandler;867        private readonly ReferenceIdHandlerForSerializer<ConsolidatedString> _typeRefIdHandler;868 869        internal InternalSerializer(XmlWriter writer, SerializationContext context)870        {871            Dbg.Assert(writer != null, "caller should validate the parameter");872            Dbg.Assert(context != null, "caller should validate the parameter");873            _writer = writer;874            _context = context;875 876            IDictionary<object, ulong> objectRefIdDictionary = null;877            if ((_context.options & SerializationOptions.NoObjectRefIds) == 0)878            {879                objectRefIdDictionary = new WeakReferenceDictionary<UInt64>();880            }881 882            _objectRefIdHandler = new ReferenceIdHandlerForSerializer<object>(objectRefIdDictionary);883 884            _typeRefIdHandler = new ReferenceIdHandlerForSerializer<ConsolidatedString>(885                new Dictionary<ConsolidatedString, UInt64>(ConsolidatedString.EqualityComparer));886        }887 888        #endregion889 890        /// <summary>891        /// Used by Remoting infrastructure. This TypeTable instance892        /// will be used by Serializer if ExecutionContext is not893        /// available (to get the ExecutionContext's TypeTable)894        /// </summary>895        internal TypeTable TypeTable896        {897            get { return _typeTable; }898 899            set { _typeTable = value; }900        }901 902        /// <summary>903        /// Writes the start of root element.904        /// </summary>905        internal void Start()906        {907            if ((_context.options & SerializationOptions.NoRootElement) != SerializationOptions.NoRootElement)908            {909                this.WriteStartElement(SerializationStrings.RootElementTag);910                this.WriteAttribute(SerializationStrings.VersionAttribute, InternalSerializer.DefaultVersion);911            }912        }913 914        /// <summary>915        /// Writes the end of root element.916        /// </summary>917        internal void End()918        {919            if ((_context.options & SerializationOptions.NoRootElement) != SerializationOptions.NoRootElement)920            {921                _writer.WriteEndElement();922            }923 924            _writer.Flush();925        }926 927        private bool _isStopping = false;928 929        /// <summary>930        /// Called from a separate thread will stop the serialization process.931        /// </summary>932        internal void Stop()933        {934            _isStopping = true;935        }936 937        private void CheckIfStopping()938        {939            if (_isStopping)940            {941                throw PSTraceSource.NewInvalidOperationException(Serialization.Stopping);942            }943        }944 945        internal static bool IsPrimitiveKnownType(Type input)946        {947            // Check if source is of primitive known type948            TypeSerializationInfo pktInfo = KnownTypes.GetTypeSerializationInfo(input);949            return (pktInfo != null);950        }951 952        /// <summary>953        /// This writes one object.954        /// </summary>955        /// <param name="source">956        /// source to be serialized.957        /// </param>958        /// <param name="streamName">959        /// Stream to which source belongs960        /// </param>961        internal void WriteOneTopLevelObject962        (963            object source,964            string streamName965        )966        {967            Dbg.Assert(_depthBelowTopLevel == 0, "InternalSerializer.depthBelowTopLevel should be 0 at top-level");968            WriteOneObject(source, streamName, null, _context.depth);969        }970 971        private void WriteOneObject972        (973            object source,974            string streamName,975            string property,976            int depth977        )978        {979            Dbg.Assert(depth >= 0, "depth should always be greater or equal to zero");980            this.CheckIfStopping();981 982            if (source == null)983            {984                WriteNull(streamName, property);985                return;986            }987 988            try989            {990                _depthBelowTopLevel++;991                Dbg.Assert(_depthBelowTopLevel <= MaxDepthBelowTopLevel, "depthBelowTopLevel should be <= MaxDepthBelowTopLevel");992                if (HandleMaxDepth(source, streamName, property))993                {994                    return;995                }996 997                depth = GetDepthOfSerialization(source, depth);998 999                if (HandlePrimitiveKnownTypeByConvertingToPSObject(source, streamName, property, depth))1000                {1001                    return;1002                }1003 1004                // Object is not of primitive known type. Check if this has1005                // already been serialized.1006                string refId = _objectRefIdHandler.GetRefId(source);1007                if (refId != null)1008                {1009                    WritePSObjectReference(streamName, property, refId);1010                    return;1011                }1012 1013                if (HandlePrimitiveKnownTypePSObject(source, streamName, property, depth))1014                {1015                    return;1016                }1017 1018                // Note: We do not use containers in depth calculation. i.e even if the1019                // current depth is zero, we serialize the container. All contained items will1020                // get serialized with depth zero.1021                if (HandleKnownContainerTypes(source, streamName, property, depth))1022                {1023                    return;1024                }1025 1026                PSObject mshSource = PSObject.AsPSObject(source);1027                // If depth is zero, complex type should be serialized as string.1028                if (depth == 0 || SerializeAsString(mshSource))1029                {1030                    HandlePSObjectAsString(mshSource, streamName, property, depth);1031                    return;1032                }1033 1034                HandleComplexTypePSObject(source, streamName, property, depth);1035                return;1036            }1037            finally1038            {1039                _depthBelowTopLevel--;1040                Dbg.Assert(_depthBelowTopLevel >= 0, "depthBelowTopLevel should be >= 0");1041            }1042        }1043 1044        private bool HandleMaxDepth(object source, string streamName, string property)1045        {1046            if (_depthBelowTopLevel == MaxDepthBelowTopLevel)1047            {1048                // assert commented out because of clashes with Wei's tests1049                // Dbg.Assert(false, "We should never reach MaxDepthBelowTopLevel with non-malicious input");1050 1051                PSEtwLog.LogAnalyticError(PSEventId.Serializer_MaxDepthWhenSerializing, PSOpcode.Exception,1052                    PSTask.Serialization, PSKeyword.Serializer, source.GetType().AssemblyQualifiedName, property, _depthBelowTopLevel);1053 1054                string content = Serialization.DeserializationTooDeep;1055                HandlePrimitiveKnownType(content, streamName, property);1056                return true;1057            }1058            else1059            {1060                return false;1061            }1062        }1063 1064        /// <summary>1065        /// Serializes Primitive Known Types.1066        /// </summary>1067        /// <returns>1068        /// true if source is handled, else false.1069        /// </returns>1070        private bool HandlePrimitiveKnownType1071        (1072            object source,1073            string streamName,1074            string property1075        )1076        {1077            Dbg.Assert(source != null, "caller should validate the parameter");1078 1079            // Check if source is of primitive known type1080            TypeSerializationInfo pktInfo = KnownTypes.GetTypeSerializationInfo(source.GetType());1081            if (pktInfo != null)1082            {1083                WriteOnePrimitiveKnownType(this, streamName, property, source, pktInfo);1084                return true;1085            }1086 1087            return false;1088        }1089 1090        /// <summary>1091        /// Handles primitive known type by first converting it to a PSObject.In W8, extended1092        /// property data is stored external to PSObject. By converting to PSObject, we will1093        /// be able to retrieve and serialize the extended properties. This is tracked by1094        /// Win8: 414042.1095        /// </summary>1096        /// <param name="source"></param>1097        /// <param name="streamName"></param>1098        /// <param name="property"></param>1099        /// <param name="depth"></param>1100        /// <returns></returns>1101        private bool HandlePrimitiveKnownTypeByConvertingToPSObject(1102            object source,1103            string streamName,1104            string property,1105            int depth1106        )1107        {1108            Dbg.Assert(source != null, "caller should validate the parameter");1109            // Check if source is of primitive known type1110            TypeSerializationInfo pktInfo = KnownTypes.GetTypeSerializationInfo(source.GetType());1111            if (pktInfo != null)1112            {1113                PSObject pktInfoPSObject = PSObject.AsPSObject(source);1114                return HandlePrimitiveKnownTypePSObject(pktInfoPSObject, streamName, property, depth);1115            }1116 1117            return false;1118        }1119 1120        /// <summary>1121        /// </summary>1122        /// <param name="source"></param>1123        /// <param name="streamName"></param>1124        /// <param name="property"></param>1125        /// <returns></returns>1126        private bool HandleSecureString(object source, string streamName, string property)1127        {1128            Dbg.Assert(source != null, "caller should validate the parameter");1129 1130            SecureString secureString = null;1131            secureString = source as SecureString;1132            PSObject moSource;1133 1134            if (secureString != null)1135            {1136                moSource = PSObject.AsPSObject(secureString);1137            }1138            else1139            {1140                moSource = source as PSObject;1141            }1142 1143            if (moSource != null && !moSource.ImmediateBaseObjectIsEmpty)1144            {1145                // check if source is of type secure string1146                secureString = moSource.ImmediateBaseObject as SecureString;1147                if (secureString != null)1148                {1149                    // the principle used in serialization is that serialization1150                    // never throws, and if something can't be serialized nothing1151                    // is written. So we write the elements only if encryption succeeds.1152                    // However, in the case for non-Windows where secure string encryption1153                    // is not yet supported, a PSCryptoException will be thrown.1154                    string encryptedString;1155                    if (_context.cryptoHelper != null)1156                    {1157                        encryptedString = _context.cryptoHelper.EncryptSecureString(secureString);1158                    }1159                    else1160                    {1161                        encryptedString = Microsoft.PowerShell.SecureStringHelper.Protect(secureString);1162                    }1163 1164                    if (property != null)1165                    {1166                        WriteStartElement(SerializationStrings.SecureStringTag);1167                        WriteNameAttribute(property);1168                    }1169                    else1170                    {1171                        WriteStartElement(SerializationStrings.SecureStringTag);1172                    }1173 1174                    if (streamName != null)1175                    {1176                        WriteAttribute(SerializationStrings.StreamNameAttribute, streamName);1177                    }1178 1179                    // Note: We do not use WriteRaw for serializing secure string. WriteString1180                    // does necessary escaping which may be needed for certain1181                    // characters.1182                    _writer.WriteString(encryptedString);1183 1184                    _writer.WriteEndElement();1185 1186                    return true;1187                }1188            }1189 1190            return false;1191        }1192 1193        /// <summary>1194        /// Serializes PSObject whose base objects are of primitive known type.1195        /// </summary>1196        /// <param name="source"></param>1197        /// <param name="streamName"></param>1198        /// <param name="property"></param>1199        /// <param name="depth"></param>1200        /// <returns>

Showing the first 1,200 of 7680 lines. Download the file for the rest.