/// <summary>
 /// Parses an XMP metadata object from a stream, including de-aliasing and normalisation.
 /// </summary>
 /// <exception cref="XmpException">Thrown if parsing or normalisation fails.</exception>
 public static IXmpMeta Parse(string xmlStr, ParseOptions options = null)
 {
     ParameterAsserts.AssertNotNull(xmlStr);
     options = options ?? new ParseOptions();
     var doc = ParseXmlString(xmlStr, options);
     return ParseXmlDoc(doc, options);
 }
 /// <summary>
 /// Parses an XMP metadata object from a stream, including de-aliasing and normalisation.
 /// </summary>
 /// <exception cref="XmpException">Thrown if parsing or normalisation fails.</exception>
 public static IXmpMeta Parse(byte[] bytes, ParseOptions options = null)
 {
     ParameterAsserts.AssertNotNull(bytes);
     options = options ?? new ParseOptions();
     var doc = ParseXmlFromByteBuffer(new ByteBuffer(bytes), options);
     return ParseXmlDoc(doc, options);
 }
 /// <summary>
 /// Parses an XMP metadata object from a stream, including de-aliasing and normalisation.
 /// </summary>
 /// <exception cref="XmpException">Thrown if parsing or normalisation fails.</exception>
 public static IXmpMeta Parse(Stream stream, ParseOptions options = null)
 {
     ParameterAsserts.AssertNotNull(stream);
     options = options ?? new ParseOptions();
     var doc = ParseXmlFromInputStream(stream, options);
     return ParseXmlDoc(doc, options);
 }
 /// <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="XmpException">Collects all severe processing errors.</exception>
 internal static IXmpMeta Process(XmpMeta xmp, ParseOptions options)
 {
     var tree = xmp.GetRoot();
     TouchUpDataModel(xmp);
     MoveExplicitAliases(tree, options);
     TweakOldXmp(tree);
     DeleteEmptySchemas(tree);
     return xmp;
 }
        private static IXmpMeta ParseXmlDoc(XDocument document, ParseOptions options)
        {
            object[] result = new object[3];

            result = FindRootNode(document.Nodes(), options.RequireXmpMeta, result);
            if (result != null && result[1] == XmpRdf)
            {
                var xmp = ParseRdf.Parse((XElement)result[0]);
                xmp.SetPacketHeader((string)result[2]);
                // Check if the XMP object shall be normalized
                if (!options.OmitNormalization)
                {
                    return XmpNormalizer.Process(xmp, options);
                }
                return xmp;
            }
            // no appropriate root node found, return empty metadata object
            return new XmpMeta();
        }
        /// <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="XmpException">Forwards XMP errors</exception>
        private static void MoveExplicitAliases(XmpNode tree, ParseOptions options)
        {
            if (!tree.HasAliases)
            {
                return;
            }
            tree.HasAliases = false;
            var strictAliasing = options.StrictAliasing;
            for (var schemaIt = tree.GetUnmodifiableChildren().Iterator(); schemaIt.HasNext(); )
            {
                var currSchema = (XmpNode)schemaIt.Next();
                if (!currSchema.HasAliases)
                {
                    continue;
                }
                for (var propertyIt = currSchema.IterateChildren(); propertyIt.HasNext(); )
                {
                    var currProp = (XmpNode)propertyIt.Next();
                    if (!currProp.IsAlias)
                    {
                        continue;
                    }
                    currProp.IsAlias = false;
                    // Find the base path, look for the base schema and root node.
                    var info = XmpMetaFactory.SchemaRegistry.FindAlias(currProp.Name);
                    if (info != null)
                    {
                        // find or create schema
                        var baseSchema = XmpNodeUtils.FindSchemaNode(tree, info.Namespace, null, true);
                        baseSchema.IsImplicit = false;
                        var baseNode = XmpNodeUtils.FindChildNode(baseSchema, info.Prefix + info.PropName, false);
                        if (baseNode == null)
                        {
                            if (info.AliasForm.IsSimple())
                            {
                                // A top-to-top alias, transplant the property.
                                // change the alias property name to the base name
                                var qname = info.Prefix + info.PropName;
                                currProp.Name = 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.Prefix + info.PropName, info.AliasForm.ToPropertyOptions());
                                baseSchema.AddChild(baseNode);
                                TransplantArrayItemAlias(propertyIt, currProp, baseNode);
                            }
                        }
                        else if (info.AliasForm.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.AliasForm.IsArrayAltText)
                            {
                                var xdIndex = XmpNodeUtils.LookupLanguageItem(baseNode, XmpConstants.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.HasAliases = false;
            }
        }
Exemple #7
0
 /// <exception cref="XmpException"/>
 public void Normalize(ParseOptions options)
 {
     if (options == null)
     {
         options = new ParseOptions();
     }
     XmpNormalizer.Process(this, options);
 }
 /// <summary>Creates an <c>XMPMeta</c>-object from a byte-buffer.</summary>
 /// <seealso cref="Parse(Stream, ParseOptions)"/>
 /// <param name="buffer">a String contain an XMP-file.</param>
 /// <param name="options">Options controlling the parsing.</param>
 /// <returns>Returns the <c>XMPMeta</c>-object created from the input.</returns>
 /// <exception cref="XmpException">If the file is not well-formed XML or if the parsing fails.</exception>
 public static IXmpMeta ParseFromBuffer(byte[] buffer, ParseOptions options = null)
 {
     return XmpMetaParser.Parse(buffer, options);
 }
 /// <summary>Creates an <c>XMPMeta</c>-object from a string.</summary>
 /// <seealso cref="ParseFromString(string, ParseOptions)"/>
 /// <param name="packet">a String contain an XMP-file.</param>
 /// <param name="options">Options controlling the parsing.</param>
 /// <returns>Returns the <c>XMPMeta</c>-object created from the input.</returns>
 /// <exception cref="XmpException">If the file is not well-formed XML or if the parsing fails.</exception>
 public static IXmpMeta ParseFromString(string packet, ParseOptions options = null)
 {
     return XmpMetaParser.Parse(packet, options);
 }
 /// <summary>
 /// These functions support parsing serialized RDF into an XMP object, and serializing an XMP
 /// object into RDF.
 /// </summary>
 /// <remarks>
 /// These functions support parsing serialized RDF into an XMP object, and serializing 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.
 /// <para />
 /// <c>parseFromBuffer()</c> parses RDF from an <c>Stream</c>. The encoding
 /// is recognized automatically.
 /// </remarks>
 /// <param name="stream">an <c>Stream</c></param>
 /// <param name="options">Options controlling the parsing.
 /// The available options are:
 /// <list type="bullet">
 ///   <item>XMP_REQUIRE_XMPMETA - The &lt;x:xmpmeta&gt; XML element is required around <tt>&lt;rdf:RDF&gt;</tt>.</item>
 ///   <item>XMP_STRICT_ALIASING - Do not reconcile alias differences, throw an exception.</item>
 /// </list>
 /// Note: The XMP_STRICT_ALIASING option is not yet implemented.
 /// </param>
 /// <returns>Returns the <c>XMPMeta</c>-object created from the input.</returns>
 /// <exception cref="XmpException">If the file is not well-formed XML or if the parsing fails.</exception>
 public static IXmpMeta Parse(Stream stream, ParseOptions options = null)
 {
     return XmpMetaParser.Parse(stream, options);
 }
 /// <summary>
 /// Parses XML from an <see cref="Stream"/>,
 /// fixing the encoding (Latin-1 to UTF-8) and illegal control character optionally.
 /// </summary>
 /// <param name="stream">an <c>Stream</c></param>
 /// <param name="options">the parsing options</param>
 /// <returns>Returns an XML DOM-Document.</returns>
 /// <exception cref="XmpException">Thrown when the parsing fails.</exception>
 private static XDocument ParseXmlFromInputStream(Stream stream, ParseOptions options)
 {
     if (!options.AcceptLatin1 && !options.FixControlChars)
     {
         return ParseStream(stream);
     }
     // load stream into bytebuffer
     try
     {
         var buffer = new ByteBuffer(stream);
         return ParseXmlFromByteBuffer(buffer, options);
     }
     catch (IOException e)
     {
         throw new XmpException("Error reading the XML-file", XmpErrorCode.BadStream, e);
     }
 }
 /// <summary>
 /// Parses XML from a <see cref="string"/>, fixing the illegal control character optionally.
 /// </summary>
 /// <param name="input">a <c>String</c> containing the XMP packet</param>
 /// <param name="options">the parsing options</param>
 /// <returns>Returns an XML DOM-Document.</returns>
 /// <exception cref="XmpException">Thrown when the parsing fails.</exception>
 private static XDocument ParseXmlString(string input, ParseOptions options)
 {
     try
     {
         return ParseStream(new MemoryStream(Encoding.UTF8.GetBytes(input)));
     }
     catch (XmpException e)
     {
         if (e.GetErrorCode() == XmpErrorCode.BadXml && options.FixControlChars)
             return ParseTextReader(new FixAsciiControlsReader(new StreamReader(new MemoryStream(Encoding.UTF8.GetBytes(input)))));
         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="XmpException">Thrown when the parsing fails.</exception>
 private static XDocument ParseXmlFromByteBuffer(ByteBuffer buffer, ParseOptions options)
 {
     try
     {
         return ParseStream(buffer.GetByteStream());
     }
     catch (XmpException e)
     {
         if (e.GetErrorCode() == XmpErrorCode.BadXml || e.GetErrorCode() == XmpErrorCode.BadStream)
         {
             if (options.AcceptLatin1)
             {
                 buffer = Latin1Converter.Convert(buffer);
             }
             if (options.FixControlChars)
             {
                 try
                 {
                     return ParseTextReader(new FixAsciiControlsReader(new StreamReader(buffer.GetByteStream(), buffer.GetEncoding())));
                 }
                 catch
                 {
                     // can normally not happen as the encoding is provided by a util function
                     throw new XmpException("Unsupported Encoding", XmpErrorCode.InternalFailure, e);
                 }
             }
             return ParseStream(buffer.GetByteStream());
         }
         throw;
     }
 }