/// <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; } }
/// <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 <x:xmpmeta> XML element is required around <tt><rdf:RDF></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; } }