// EMPTY
		/// <summary>
		/// Parses the input source into an XMP metadata object, including
		/// de-aliasing and normalisation.
		/// </summary>
		/// <param name="input">
		/// the input can be an <code>InputStream</code>, a <code>String</code> or
		/// a byte buffer containing the XMP packet.
		/// </param>
		/// <param name="options">the parse options</param>
		/// <returns>Returns the resulting XMP metadata object</returns>
		/// <exception cref="Com.Adobe.Xmp.XMPException">Thrown if parsing or normalisation fails.</exception>
		public static XMPMeta Parse(object input, ParseOptions options)
		{
			ParameterAsserts.AssertNotNull(input);
			options = options != null ? options : new ParseOptions();
			XmlDocument document = ParseXml(input, options);
			bool xmpmetaRequired = options.GetRequireXMPMeta();
			object[] result = new object[3];
			result = FindRootNode(document, xmpmetaRequired, result);
			if (result != null && result[1] == XmpRdf)
			{
				XMPMetaImpl xmp = ParseRDF.Parse((XmlNode)result[0]);
				xmp.SetPacketHeader((string)result[2]);
				// Check if the XMP object shall be normalized
				if (!options.GetOmitNormalization())
				{
					return XMPNormalizer.Process(xmp, options);
				}
				else
				{
					return xmp;
				}
			}
			else
			{
				// no appropriate root node found, return empty metadata object
				return new XMPMetaImpl();
			}
		}
 // EMPTY
 /// <summary>Normalizes a raw parsed XMPMeta-Object</summary>
 /// <param name="xmp">the raw metadata object</param>
 /// <param name="options">the parsing options</param>
 /// <returns>Returns the normalized metadata object</returns>
 /// <exception cref="Com.Adobe.Xmp.XMPException">Collects all severe processing errors.</exception>
 internal static XMPMeta Process(XMPMetaImpl xmp, ParseOptions options)
 {
     XMPNode tree = xmp.GetRoot();
     TouchUpDataModel(xmp);
     MoveExplicitAliases(tree, options);
     TweakOldXMP(tree);
     DeleteEmptySchemas(tree);
     return xmp;
 }
		/// <seealso cref="Com.Adobe.Xmp.XMPMeta.Normalize(Com.Adobe.Xmp.Options.ParseOptions)"/>
		/// <exception cref="Com.Adobe.Xmp.XMPException"/>
		public virtual void Normalize(ParseOptions options)
		{
			if (options == null)
			{
				options = new ParseOptions();
			}
			XMPNormalizer.Process(this, options);
		}
 /// <summary>Visit all of the top level nodes looking for aliases.</summary>
 /// <remarks>
 /// Visit all of the top level nodes looking for aliases. If there is
 /// no base, transplant the alias subtree. If there is a base and strict
 /// aliasing is on, make sure the alias and base subtrees match.
 /// </remarks>
 /// <param name="tree">the root of the metadata tree</param>
 /// <param name="options">th parsing options</param>
 /// <exception cref="Com.Adobe.Xmp.XMPException">Forwards XMP errors</exception>
 private static void MoveExplicitAliases(XMPNode tree, ParseOptions options)
 {
     if (!tree.GetHasAliases())
     {
         return;
     }
     tree.SetHasAliases(false);
     bool strictAliasing = options.GetStrictAliasing();
     for (Iterator schemaIt = tree.GetUnmodifiableChildren().Iterator(); schemaIt.HasNext(); )
     {
         XMPNode currSchema = (XMPNode)schemaIt.Next();
         if (!currSchema.GetHasAliases())
         {
             continue;
         }
         for (Iterator propertyIt = currSchema.IterateChildren(); propertyIt.HasNext(); )
         {
             XMPNode currProp = (XMPNode)propertyIt.Next();
             if (!currProp.IsAlias())
             {
                 continue;
             }
             currProp.SetAlias(false);
             // Find the base path, look for the base schema and root node.
             XMPAliasInfo info = XMPMetaFactory.GetSchemaRegistry().FindAlias(currProp.GetName());
             if (info != null)
             {
                 // find or create schema
                 XMPNode baseSchema = XMPNodeUtils.FindSchemaNode(tree, info.GetNamespace(), null, true);
                 baseSchema.SetImplicit(false);
                 XMPNode baseNode = XMPNodeUtils.FindChildNode(baseSchema, info.GetPrefix() + info.GetPropName(), false);
                 if (baseNode == null)
                 {
                     if (info.GetAliasForm().IsSimple())
                     {
                         // A top-to-top alias, transplant the property.
                         // change the alias property name to the base name
                         string qname = info.GetPrefix() + info.GetPropName();
                         currProp.SetName(qname);
                         baseSchema.AddChild(currProp);
                         // remove the alias property
                         propertyIt.Remove();
                     }
                     else
                     {
                         // An alias to an array item,
                         // create the array and transplant the property.
                         baseNode = new XMPNode(info.GetPrefix() + info.GetPropName(), info.GetAliasForm().ToPropertyOptions());
                         baseSchema.AddChild(baseNode);
                         TransplantArrayItemAlias(propertyIt, currProp, baseNode);
                     }
                 }
                 else
                 {
                     if (info.GetAliasForm().IsSimple())
                     {
                         // The base node does exist and this is a top-to-top alias.
                         // Check for conflicts if strict aliasing is on.
                         // Remove and delete the alias subtree.
                         if (strictAliasing)
                         {
                             CompareAliasedSubtrees(currProp, baseNode, true);
                         }
                         propertyIt.Remove();
                     }
                     else
                     {
                         // This is an alias to an array item and the array exists.
                         // Look for the aliased item.
                         // Then transplant or check & delete as appropriate.
                         XMPNode itemNode = null;
                         if (info.GetAliasForm().IsArrayAltText())
                         {
                             int xdIndex = XMPNodeUtils.LookupLanguageItem(baseNode, XMPConstConstants.XDefault);
                             if (xdIndex != -1)
                             {
                                 itemNode = baseNode.GetChild(xdIndex);
                             }
                         }
                         else
                         {
                             if (baseNode.HasChildren())
                             {
                                 itemNode = baseNode.GetChild(1);
                             }
                         }
                         if (itemNode == null)
                         {
                             TransplantArrayItemAlias(propertyIt, currProp, baseNode);
                         }
                         else
                         {
                             if (strictAliasing)
                             {
                                 CompareAliasedSubtrees(currProp, itemNode, true);
                             }
                             propertyIt.Remove();
                         }
                     }
                 }
             }
         }
         currSchema.SetHasAliases(false);
     }
 }
		/// <summary>Parses the raw XML metadata packet considering the parsing options.</summary>
		/// <remarks>
		/// Parses the raw XML metadata packet considering the parsing options.
		/// Latin-1/ISO-8859-1 can be accepted when the input is a byte stream
		/// (some old toolkits versions such packets). The stream is
		/// then wrapped in another stream that converts Latin-1 to UTF-8.
		/// <p>
		/// If control characters shall be fixed, a reader is used that fixes the chars to spaces
		/// (if the input is a byte stream is has to be read as character stream).
		/// <p>
		/// Both options reduce the performance of the parser.
		/// </remarks>
		/// <param name="input">
		/// the input can be an <code>InputStream</code>, a <code>String</code> or
		/// a byte buffer containing the XMP packet.
		/// </param>
		/// <param name="options">the parsing options</param>
		/// <returns>Returns the parsed XML document or an exception.</returns>
		/// <exception cref="Com.Adobe.Xmp.XMPException">Thrown if the parsing fails for different reasons</exception>
		private static XmlDocument ParseXml(object input, ParseOptions options)
		{
			if (input is InputStream)
			{
				return ParseXmlFromInputStream((InputStream)input, options);
			}
			else
			{
				if (input is sbyte[])
				{
					return ParseXmlFromBytebuffer(new ByteBuffer((sbyte[])input), options);
				}
				else
				{
					return ParseXmlFromString((string)input, options);
				}
			}
		}
		/// <summary>
		/// Parses XML from a
		/// <see cref="string"/>
		/// ,
		/// fixing the illegal control character optionally.
		/// </summary>
		/// <param name="input">a <code>String</code> containing the XMP packet</param>
		/// <param name="options">the parsing options</param>
		/// <returns>Returns an XML DOM-Document.</returns>
		/// <exception cref="Com.Adobe.Xmp.XMPException">Thrown when the parsing fails.</exception>
		private static XmlDocument ParseXmlFromString(string input, ParseOptions options)
		{
			InputSource source = new InputSource(new Sharpen.StringReader(input));
			try
			{
				return ParseInputSource(source);
			}
			catch (XMPException e)
			{
				if (e.GetErrorCode() == XMPErrorConstants.Badxml && options.GetFixControlChars())
				{
					source = new InputSource(new FixASCIIControlsReader(new Sharpen.StringReader(input)));
					return ParseInputSource(source);
				}
				else
				{
					throw;
				}
			}
		}
		/// <summary>
		/// Parses XML from a byte buffer,
		/// fixing the encoding (Latin-1 to UTF-8) and illegal control character optionally.
		/// </summary>
		/// <param name="buffer">a byte buffer containing the XMP packet</param>
		/// <param name="options">the parsing options</param>
		/// <returns>Returns an XML DOM-Document.</returns>
		/// <exception cref="Com.Adobe.Xmp.XMPException">Thrown when the parsing fails.</exception>
		private static XmlDocument ParseXmlFromBytebuffer(ByteBuffer buffer, ParseOptions options)
		{
			InputSource source = new InputSource(buffer.GetByteStream());
			try
			{
				return ParseInputSource(source);
			}
			catch (XMPException e)
			{
				if (e.GetErrorCode() == XMPErrorConstants.Badxml || e.GetErrorCode() == XMPErrorConstants.Badstream)
				{
					if (options.GetAcceptLatin1())
					{
						buffer = Latin1Converter.Convert(buffer);
					}
					if (options.GetFixControlChars())
					{
						try
						{
							string encoding = buffer.GetEncoding();
							System.IO.StreamReader fixReader = new FixASCIIControlsReader(new InputStreamReader(buffer.GetByteStream(), encoding));
							return ParseInputSource(new InputSource(fixReader));
						}
						catch (UnsupportedEncodingException)
						{
							// can normally not happen as the encoding is provided by a util function
							throw new XMPException("Unsupported Encoding", XMPErrorConstants.Internalfailure, e);
						}
					}
					source = new InputSource(buffer.GetByteStream());
					return ParseInputSource(source);
				}
				else
				{
					throw;
				}
			}
		}
		/// <summary>
		/// Parses XML from an
		/// <see cref="InputStream"/>
		/// ,
		/// fixing the encoding (Latin-1 to UTF-8) and illegal control character optionally.
		/// </summary>
		/// <param name="stream">an <code>InputStream</code></param>
		/// <param name="options">the parsing options</param>
		/// <returns>Returns an XML DOM-Document.</returns>
		/// <exception cref="Com.Adobe.Xmp.XMPException">Thrown when the parsing fails.</exception>
		private static XmlDocument ParseXmlFromInputStream(InputStream stream, ParseOptions options)
		{
			if (!options.GetAcceptLatin1() && !options.GetFixControlChars())
			{
				return ParseInputSource(new InputSource(stream));
			}
			else
			{
				// load stream into bytebuffer
				try
				{
					ByteBuffer buffer = new ByteBuffer(stream);
					return ParseXmlFromBytebuffer(buffer, options);
				}
				catch (IOException e)
				{
					throw new XMPException("Error reading the XML-file", XMPErrorConstants.Badstream, e);
				}
			}
		}
 /// <summary>Creates an <code>XMPMeta</code>-object from a string.</summary>
 /// <seealso cref="ParseFromString(string, Com.Adobe.Xmp.Options.ParseOptions)"/>
 /// <param name="packet">a String contain an XMP-file.</param>
 /// <param name="options">Options controlling the parsing.</param>
 /// <returns>Returns the <code>XMPMeta</code>-object created from the input.</returns>
 /// <exception cref="XMPException">If the file is not well-formed XML or if the parsing fails.</exception>
 /// <exception cref="Com.Adobe.Xmp.XMPException"/>
 public static XMPMeta ParseFromString(string packet, ParseOptions options)
 {
     return XMPMetaParser.Parse(packet, options);
 }
 /// <summary>Creates an <code>XMPMeta</code>-object from a byte-buffer.</summary>
 /// <seealso cref="Parse(System.IO.InputStream, Com.Adobe.Xmp.Options.ParseOptions)"/>
 /// <param name="buffer">a String contain an XMP-file.</param>
 /// <param name="options">Options controlling the parsing.</param>
 /// <returns>Returns the <code>XMPMeta</code>-object created from the input.</returns>
 /// <exception cref="XMPException">If the file is not well-formed XML or if the parsing fails.</exception>
 /// <exception cref="Com.Adobe.Xmp.XMPException"/>
 public static XMPMeta ParseFromBuffer(sbyte[] buffer, ParseOptions options)
 {
     return XMPMetaParser.Parse(buffer, options);
 }
 /// <summary>
 /// These functions support parsing serialized RDF into an XMP object, and serailizing an XMP
 /// object into RDF.
 /// </summary>
 /// <remarks>
 /// These functions support parsing serialized RDF into an XMP object, and serailizing an XMP
 /// object into RDF. The input for parsing may be any valid Unicode
 /// encoding. ISO Latin-1 is also recognized, but its use is strongly discouraged. Serialization
 /// is always as UTF-8.
 /// <p>
 /// <code>parseFromBuffer()</code> parses RDF from an <code>InputStream</code>. The encoding
 /// is recognized automatically.
 /// </remarks>
 /// <param name="in">an <code>InputStream</code></param>
 /// <param name="options">
 /// Options controlling the parsing.<br />
 /// The available options are:
 /// <ul>
 /// <li> XMP_REQUIRE_XMPMETA - The &lt;x:xmpmeta&gt; XML element is required around
 /// <tt>&lt;rdf:RDF&gt;</tt>.
 /// <li> XMP_STRICT_ALIASING - Do not reconcile alias differences, throw an exception.
 /// </ul>
 /// <em>Note:</em>The XMP_STRICT_ALIASING option is not yet implemented.
 /// </param>
 /// <returns>Returns the <code>XMPMeta</code>-object created from the input.</returns>
 /// <exception cref="XMPException">If the file is not well-formed XML or if the parsing fails.</exception>
 /// <exception cref="Com.Adobe.Xmp.XMPException"/>
 public static XMPMeta Parse(InputStream @in, ParseOptions options)
 {
     return XMPMetaParser.Parse(@in, options);
 }