Implementation for IXmpMeta. @since 17.02.2006
Inheritance: XmpConst, IXmpMeta
Ejemplo n.º 1
0
        /// <summary>
        /// Serializes an <code>XMPMeta</code>-object as RDF into a byte buffer.
        /// </summary>
        /// <param name="xmp"> a metadata implementation object </param>
        /// <param name="options"> Options to control the serialization (see <seealso cref="SerializeOptions"/>). </param>
        /// <returns> Returns a byte buffer containing the serialized RDF. </returns>
        /// <exception cref="XmpException"> on serializsation errors. </exception>
        public static byte[] SerializeToBuffer(XmpMetaImpl xmp, SerializeOptions options)
        {
            MemoryStream @out = new MemoryStream(2048);

            Serialize(xmp, @out, options);
            return(@out.GetBuffer());
        }
Ejemplo n.º 2
0
        /// <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="XmpException"> Thrown if parsing or normalisation fails. </exception>
        public static XMPMeta Parse(object input, ParseOptions options)
        {
            ParameterAsserts.AssertNotNull(input);
            options = options ?? new ParseOptions();

            XmlDocument document = ParseXml(input, options);

            bool xmpmetaRequired = options.RequireXmpMeta;

            object[] result = new object[3];
            result = FindRootNode(document, xmpmetaRequired, result);

            if (result != null && result[1] == XmpRdf)
            {
                XmpMetaImpl xmp = ParseRdf.Parse((XmlNode)result[0]);
                xmp.PacketHeader = (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 XmpMetaImpl());
        }
Ejemplo n.º 3
0
        /// <summary>
        /// Static method to Serialize the metadata object. For each serialisation, a new XMPSerializer
        /// instance is created, either XMPSerializerRDF or XMPSerializerPlain so thats its possible to 
        /// serialialize the same XMPMeta objects in two threads.
        /// </summary>
        /// <param name="xmp"> a metadata implementation object </param>
        /// <param name="out"> the output stream to Serialize to </param>
        /// <param name="options"> serialization options, can be <code>null</code> for default. </param>
        /// <exception cref="XmpException"> </exception>
        public static void Serialize(XmpMetaImpl xmp, Stream @out, SerializeOptions options) {
            options = options ?? new SerializeOptions();

            // sort the internal data model on demand
            if (options.Sort) {
                xmp.Sort();
            }
            (new XmpSerializerRdf()).Serialize(xmp, @out, options);
        }
        /// <summary>
        /// Constructor with optionsl initial values. If <code>propName</code> is provided,
        /// <code>schemaNs</code> has also be provided. </summary>
        /// <param name="xmp"> the iterated metadata object. </param>
        /// <param name="schemaNs"> the iteration is reduced to this schema (optional) </param>
        /// <param name="propPath"> the iteration is redurce to this property within the <code>schemaNs</code> </param>
        /// <param name="options"> advanced iteration options, see <seealso cref="IteratorOptions"/> </param>
        /// <exception cref="XmpException"> If the node defined by the paramters is not existing.  </exception>
        public XmpIteratorImpl(XmpMetaImpl xmp, string schemaNs, string propPath, IteratorOptions options)
        {
            // make sure that options is defined at least with defaults
            _options = options ?? new IteratorOptions();

            // the start node of the iteration depending on the schema and property filter
            XmpNode startNode;
            string  initialPath  = null;
            bool    baseSchema   = !String.IsNullOrEmpty(schemaNs);
            bool    baseProperty = !String.IsNullOrEmpty(propPath);

            if (!baseSchema && !baseProperty)
            {
                // complete tree will be iterated
                startNode = xmp.Root;
            }
            else if (baseSchema && baseProperty)
            {
                // Schema and property node provided
                XmpPath path = XmpPathParser.ExpandXPath(schemaNs, propPath);

                // base path is the prop path without the property leaf
                XmpPath basePath = new XmpPath();
                for (int i = 0; i < path.Size() - 1; i++)
                {
                    basePath.Add(path.GetSegment(i));
                }

                startNode   = XmpNodeUtils.FindNode(xmp.Root, path, false, null);
                _baseNs     = schemaNs;
                initialPath = basePath.ToString();
            }
            else if (baseSchema && !baseProperty)
            {
                // Only Schema provided
                startNode = XmpNodeUtils.FindSchemaNode(xmp.Root, schemaNs, false);
            }
            else // !baseSchema  &&  baseProperty
            {
                // No schema but property provided -> error
                throw new XmpException("Schema namespace URI is required", XmpError.BADSCHEMA);
            }


            // create iterator
            if (startNode != null)
            {
                _nodeIterator = (!_options.JustChildren)
                                    ? new NodeIterator(this, startNode, initialPath, 1)
                                    : new NodeIteratorChildren(this, startNode, initialPath);
            }
            else
            {
                // create null iterator
                _nodeIterator = EmptyList.GetEnumerator();
            }
        }
Ejemplo n.º 5
0
        /// <summary>
        /// Static method to Serialize the metadata object. For each serialisation, a new XMPSerializer
        /// instance is created, either XMPSerializerRDF or XMPSerializerPlain so thats its possible to
        /// serialialize the same XMPMeta objects in two threads.
        /// </summary>
        /// <param name="xmp"> a metadata implementation object </param>
        /// <param name="out"> the output stream to Serialize to </param>
        /// <param name="options"> serialization options, can be <code>null</code> for default. </param>
        /// <exception cref="XmpException"> </exception>
        public static void Serialize(XmpMetaImpl xmp, Stream @out, SerializeOptions options)
        {
            options = options ?? new SerializeOptions();

            // sort the internal data model on demand
            if (options.Sort)
            {
                xmp.Sort();
            }
            (new XmpSerializerRdf()).Serialize(xmp, @out, options);
        }
Ejemplo n.º 6
0
        /// <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 XMPMeta Process(XmpMetaImpl xmp, ParseOptions options) {
            XmpNode tree = xmp.Root;

            TouchUpDataModel(xmp);
            MoveExplicitAliases(tree, options);

            TweakOldXmp(tree);

            DeleteEmptySchemas(tree);

            return xmp;
        }
Ejemplo n.º 7
0
        /// <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 XMPMeta Process(XmpMetaImpl xmp, ParseOptions options)
        {
            XmpNode tree = xmp.Root;

            TouchUpDataModel(xmp);
            MoveExplicitAliases(tree, options);

            TweakOldXmp(tree);

            DeleteEmptySchemas(tree);

            return(xmp);
        }
Ejemplo n.º 8
0
        /// <seealso cref= XMPUtils#appendProperties(XMPMeta, XMPMeta, boolean, boolean) </seealso>
        /// <param name="source"> The source XMP object. </param>
        /// <param name="destination"> The destination XMP object. </param>
        /// <param name="doAllProperties"> Do internal properties in addition to external properties. </param>
        /// <param name="replaceOldValues"> Replace the values of existing properties. </param>
        /// <param name="deleteEmptyValues"> Delete destination values if source property is empty. </param>
        /// <exception cref="XmpException"> Forwards the Exceptions from the metadata processing </exception>
        public static void AppendProperties(IXmpMeta source, IXmpMeta destination, bool doAllProperties,
                                            bool replaceOldValues, bool deleteEmptyValues)
        {
            ParameterAsserts.AssertImplementation(source);
            ParameterAsserts.AssertImplementation(destination);

            XmpMetaImpl src  = (XmpMetaImpl)source;
            XmpMetaImpl dest = (XmpMetaImpl)destination;

            for (IEnumerator it = src.Root.IterateChildren(); it.MoveNext();)
            {
                XmpNode sourceSchema = (XmpNode)it.Current;
                if (sourceSchema == null)
                {
                    continue;
                }
                // Make sure we have a destination schema node
                XmpNode destSchema    = XmpNodeUtils.FindSchemaNode(dest.Root, sourceSchema.Name, false);
                bool    createdSchema = false;
                if (destSchema == null)
                {
                    PropertyOptions propertyOptions = new PropertyOptions();
                    propertyOptions.SchemaNode = true;
                    destSchema = new XmpNode(sourceSchema.Name, sourceSchema.Value,
                                             propertyOptions);
                    dest.Root.AddChild(destSchema);
                    createdSchema = true;
                }

                // Process the source schema's children.
                for (IEnumerator ic = sourceSchema.IterateChildren(); ic.MoveNext();)
                {
                    XmpNode sourceProp = (XmpNode)ic.Current;
                    if (sourceProp == null)
                    {
                        continue;
                    }
                    if (doAllProperties || !Utils.IsInternalProperty(sourceSchema.Name, sourceProp.Name))
                    {
                        AppendSubtree(dest, sourceProp, destSchema, replaceOldValues, deleteEmptyValues);
                    }
                }

                if (!destSchema.HasChildren() && (createdSchema || deleteEmptyValues))
                {
                    // Don't create an empty schema / remove empty schema.
                    dest.Root.RemoveChild(destSchema);
                }
            }
        }
Ejemplo n.º 9
0
        /// <summary>
        /// Constructor with optionsl initial values. If <code>propName</code> is provided, 
        /// <code>schemaNs</code> has also be provided. </summary>
        /// <param name="xmp"> the iterated metadata object. </param>
        /// <param name="schemaNs"> the iteration is reduced to this schema (optional) </param>
        /// <param name="propPath"> the iteration is redurce to this property within the <code>schemaNs</code> </param>
        /// <param name="options"> advanced iteration options, see <seealso cref="IteratorOptions"/> </param>
        /// <exception cref="XmpException"> If the node defined by the paramters is not existing.  </exception>
        public XmpIteratorImpl(XmpMetaImpl xmp, string schemaNs, string propPath, IteratorOptions options) {
            // make sure that options is defined at least with defaults
            _options = options ?? new IteratorOptions();

            // the start node of the iteration depending on the schema and property filter
            XmpNode startNode;
            string initialPath = null;
            bool baseSchema = !String.IsNullOrEmpty(schemaNs);
            bool baseProperty = !String.IsNullOrEmpty(propPath);

            if (!baseSchema && !baseProperty) {
                // complete tree will be iterated
                startNode = xmp.Root;
            }
            else if (baseSchema && baseProperty) {
                // Schema and property node provided
                XmpPath path = XmpPathParser.ExpandXPath(schemaNs, propPath);

                // base path is the prop path without the property leaf
                XmpPath basePath = new XmpPath();
                for (int i = 0; i < path.Size() - 1; i++) {
                    basePath.Add(path.GetSegment(i));
                }

                startNode = XmpNodeUtils.FindNode(xmp.Root, path, false, null);
                _baseNs = schemaNs;
                initialPath = basePath.ToString();
            }
            else if (baseSchema && !baseProperty) {
                // Only Schema provided
                startNode = XmpNodeUtils.FindSchemaNode(xmp.Root, schemaNs, false);
            }
            else // !baseSchema  &&  baseProperty
            {
                // No schema but property provided -> error
                throw new XmpException("Schema namespace URI is required", XmpError.BADSCHEMA);
            }


            // create iterator
            if (startNode != null) {
                _nodeIterator = (!_options.JustChildren)
                                    ? new NodeIterator(this, startNode, initialPath, 1)
                                    : new NodeIteratorChildren(this, startNode, initialPath);
            }
            else {
                // create null iterator
                _nodeIterator = EmptyList.GetEnumerator();
            }
        }
Ejemplo n.º 10
0
        /// <summary>
        /// Serializes an <code>XMPMeta</code>-object as RDF into a string.
        /// <em>Note:</em> Encoding is forced to UTF-16 when serializing to a
        /// string to ensure the correctness of &quot;exact packet size&quot;.
        /// </summary>
        /// <param name="xmp"> a metadata implementation object </param>
        /// <param name="options"> Options to control the serialization (see
        ///            <seealso cref="SerializeOptions"/>). </param>
        /// <returns> Returns a string containing the serialized RDF. </returns>
        /// <exception cref="XmpException"> on serializsation errors. </exception>
        public static string SerializeToString(XmpMetaImpl xmp, SerializeOptions options) {
            // forces the encoding to be UTF-16 to get the correct string length
            options = options ?? new SerializeOptions();
            options.EncodeUtf16Be = true;

            MemoryStream @out = new MemoryStream(2048);
            Serialize(xmp, @out, options);

            try {
                return Encoding.GetEncoding(options.Encoding).GetString(@out.GetBuffer());
            }
            catch (Exception) {
                // cannot happen as UTF-8/16LE/BE is required to be implemented in
                // Java
                return GetString(@out.GetBuffer());
            }
        }
Ejemplo n.º 11
0
        /// <summary>
        /// Visit all schemas to do general fixes and handle special cases.
        /// </summary>
        /// <param name="xmp"> the metadata object implementation </param>
        /// <exception cref="XmpException"> Thrown if the normalisation fails. </exception>
        private static void TouchUpDataModel(XmpMetaImpl xmp)
        {
            // make sure the DC schema is existing, because it might be needed within the normalization
            // if not touched it will be removed by removeEmptySchemas
            XmpNodeUtils.FindSchemaNode(xmp.Root, XmpConst.NS_DC, true);

            // Do the special case fixes within each schema.
            IEnumerator it = xmp.Root.IterateChildren();

            while (it.MoveNext())
            {
                XmpNode currSchema = (XmpNode)it.Current;
                if (currSchema != null && XmpConst.NS_DC.Equals(currSchema.Name))
                {
                    NormalizeDcArrays(currSchema);
                }
                else if (currSchema != null && XmpConst.NS_EXIF.Equals(currSchema.Name))
                {
                    // Do a special case fix for exif:GPSTimeStamp.
                    FixGpsTimeStamp(currSchema);
                    XmpNode arrayNode = XmpNodeUtils.FindChildNode(currSchema, "exif:UserComment", false);
                    if (arrayNode != null)
                    {
                        RepairAltText(arrayNode);
                    }
                }
                else if (currSchema != null && XmpConst.NS_DM.Equals(currSchema.Name))
                {
                    // Do a special case migration of xmpDM:copyright to
                    // dc:rights['x-default'].
                    XmpNode dmCopyright = XmpNodeUtils.FindChildNode(currSchema, "xmpDM:copyright", false);
                    if (dmCopyright != null)
                    {
                        MigrateAudioCopyright(xmp, dmCopyright);
                    }
                }
                else if (currSchema != null && XmpConst.NS_XMP_RIGHTS.Equals(currSchema.Name))
                {
                    XmpNode arrayNode = XmpNodeUtils.FindChildNode(currSchema, "xmpRights:UsageTerms", false);
                    if (arrayNode != null)
                    {
                        RepairAltText(arrayNode);
                    }
                }
            }
        }
Ejemplo n.º 12
0
        /// <summary>
        /// Serializes an <code>XMPMeta</code>-object as RDF into a string.
        /// <em>Note:</em> Encoding is forced to UTF-16 when serializing to a
        /// string to ensure the correctness of &quot;exact packet size&quot;.
        /// </summary>
        /// <param name="xmp"> a metadata implementation object </param>
        /// <param name="options"> Options to control the serialization (see
        ///            <seealso cref="SerializeOptions"/>). </param>
        /// <returns> Returns a string containing the serialized RDF. </returns>
        /// <exception cref="XmpException"> on serializsation errors. </exception>
        public static string SerializeToString(XmpMetaImpl xmp, SerializeOptions options)
        {
            // forces the encoding to be UTF-16 to get the correct string length
            options = options ?? new SerializeOptions();
            options.EncodeUtf16Be = true;

            MemoryStream @out = new MemoryStream(2048);

            Serialize(xmp, @out, options);

            try {
                return(Encoding.GetEncoding(options.Encoding).GetString(@out.GetBuffer()));
            }
            catch (Exception) {
                // cannot happen as UTF-8/16LE/BE is required to be implemented in
                // Java
                return(GetString(@out.GetBuffer()));
            }
        }
Ejemplo n.º 13
0
        /// <summary>
        /// Utility to find or create the array used by <code>separateArrayItems()</code>. </summary>
        /// <param name="schemaNs"> a the namespace fo the array </param>
        /// <param name="arrayName"> the name of the array </param>
        /// <param name="arrayOptions"> the options for the array if newly created </param>
        /// <param name="xmp"> the xmp object </param>
        /// <returns> Returns the array node. </returns>
        /// <exception cref="XmpException"> Forwards exceptions </exception>
        private static XmpNode SeparateFindCreateArray(string schemaNs, string arrayName, PropertyOptions arrayOptions,
                                                       XmpMetaImpl xmp)
        {
            arrayOptions = XmpNodeUtils.VerifySetOptions(arrayOptions, null);
            if (!arrayOptions.OnlyArrayOptions)
            {
                throw new XmpException("Options can only provide array form", XmpError.BADOPTIONS);
            }

            // Find the array node, make sure it is OK. Move the current children
            // aside, to be readded later if kept.
            XmpPath arrayPath = XmpPathParser.ExpandXPath(schemaNs, arrayName);
            XmpNode arrayNode = XmpNodeUtils.FindNode(xmp.Root, arrayPath, false, null);

            if (arrayNode != null)
            {
                // The array exists, make sure the form is compatible. Zero
                // arrayForm means take what exists.
                PropertyOptions arrayForm = arrayNode.Options;
                if (!arrayForm.Array || arrayForm.ArrayAlternate)
                {
                    throw new XmpException("Named property must be non-alternate array", XmpError.BADXPATH);
                }
                if (arrayOptions.EqualArrayTypes(arrayForm))
                {
                    throw new XmpException("Mismatch of specified and existing array form", XmpError.BADXPATH);
                    // *** Right error?
                }
            }
            else
            {
                // The array does not exist, try to create it.
                // don't modify the options handed into the method
                arrayOptions.Array = true;
                arrayNode          = XmpNodeUtils.FindNode(xmp.Root, arrayPath, true, arrayOptions);
                if (arrayNode == null)
                {
                    throw new XmpException("Failed to create named array", XmpError.BADXPATH);
                }
            }
            return(arrayNode);
        }
Ejemplo n.º 14
0
        /// <summary>
        /// 7.2.16 literalPropertyElt
        ///		start-element ( URI == propertyElementURIs, 
        ///				attributes == set ( idAttr?, datatypeAttr?) )
        ///		text()
        ///		end-element()
        /// 
        /// Add a leaf node with the text value and qualifiers for the attributes. </summary>
        /// <param name="xmp"> the xmp metadata object that is generated </param>
        /// <param name="xmpParent"> the parent xmp node </param>
        /// <param name="xmlNode"> the currently processed XML node </param>
        /// <param name="isTopLevel"> Flag if the node is a top-level node </param>
        /// <exception cref="XmpException"> thown on parsing errors </exception>
        private static void RdfLiteralPropertyElement(XmpMetaImpl xmp, XmpNode xmpParent, XmlNode xmlNode,
                                                      bool isTopLevel) {
            XmpNode newChild = AddChildNode(xmp, xmpParent, xmlNode, null, isTopLevel);
            if (xmlNode.Attributes != null) {
                for (int i = 0; i < xmlNode.Attributes.Count; i++) {
                    XmlNode attribute = xmlNode.Attributes[i];
                    if ("xmlns".Equals(attribute.Prefix) || (attribute.Prefix == null && "xmlns".Equals(attribute.Name))) {
                        continue;
                    }

                    string attrNs = attribute.NamespaceURI;
                    string attrLocal = attribute.LocalName;
                    if (XML_LANG.Equals(attribute.Name)) {
                        AddQualifierNode(newChild, XML_LANG, attribute.Value);
                    } else if (NS_RDF.Equals(attrNs) && ("ID".Equals(attrLocal) || "datatype".Equals(attrLocal))) {
                        continue; // Ignore all rdf:ID and rdf:datatype attributes.
                    } else
                        throw new XmpException("Invalid attribute for literal property element", XmpError.BADRDF);
                }
            }
            string textValue = "";
            for (int i = 0; i < xmlNode.ChildNodes.Count; i++) {
                XmlNode child = xmlNode.ChildNodes[i];
                if (child.NodeType == XmlNodeType.Text) {
                    textValue += child.Value;
                }
                else {
                    throw new XmpException("Invalid child of literal property element", XmpError.BADRDF);
                }
            }
            newChild.Value = textValue;
        }
Ejemplo n.º 15
0
        /// <summary>
        /// 7.2.15 resourcePropertyElt
        ///		start-element ( URI == propertyElementURIs, attributes == set ( idAttr? ) )
        ///		ws* nodeElement ws*
        ///		end-element()
        /// 
        /// This handles structs using an rdf:Description node, 
        /// arrays using rdf:Bag/Seq/Alt, and typedNodes. It also catches and cleans up qualified 
        /// properties written with rdf:Description and rdf:value.
        /// </summary>
        /// <param name="xmp"> the xmp metadata object that is generated </param>
        /// <param name="xmpParent"> the parent xmp node </param>
        /// <param name="xmlNode"> the currently processed XML node </param>
        /// <param name="isTopLevel"> Flag if the node is a top-level node </param>
        /// <exception cref="XmpException"> thown on parsing errors </exception>
        private static void RdfResourcePropertyElement(XmpMetaImpl xmp, XmpNode xmpParent, XmlNode xmlNode,
                                                       bool isTopLevel) {
            if (isTopLevel && "iX:changes".Equals(xmlNode.Name)) {
                // Strip old "punchcard" chaff which has on the prefix "iX:".
                return;
            }

            XmpNode newCompound = AddChildNode(xmp, xmpParent, xmlNode, "", isTopLevel);

            // walk through the attributes
            if (xmlNode.Attributes != null) {
                for (int i = 0; i < xmlNode.Attributes.Count; i++) {
                    XmlNode attribute = xmlNode.Attributes[i];
                    if ("xmlns".Equals(attribute.Prefix) || (attribute.Prefix == null && "xmlns".Equals(attribute.Name))) {
                        continue;
                    }

                    string attrLocal = attribute.LocalName;
                    string attrNs = attribute.NamespaceURI;
                    if (XML_LANG.Equals(attribute.Name)) {
                        AddQualifierNode(newCompound, XML_LANG, attribute.Value);
                    }
                    else if ("ID".Equals(attrLocal) && NS_RDF.Equals(attrNs)) {
                        continue; // Ignore all rdf:ID attributes.
                    }
                    throw new XmpException("Invalid attribute for resource property element", XmpError.BADRDF);
                }
            }

            // walk through the children

            bool found = false;
            for (int i = 0; i < xmlNode.ChildNodes.Count; i++) {
                XmlNode currChild = xmlNode.ChildNodes[i];
                if (!IsWhitespaceNode(currChild)) {
                    if (currChild.NodeType == XmlNodeType.Element && !found) {
                        bool isRdf = NS_RDF.Equals(currChild.NamespaceURI);
                        string childLocal = currChild.LocalName;

                        if (isRdf && "Bag".Equals(childLocal)) {
                            newCompound.Options.Array = true;
                        }
                        else if (isRdf && "Seq".Equals(childLocal)) {
                            newCompound.Options.Array = true;
                            newCompound.Options.ArrayOrdered = true;
                        }
                        else if (isRdf && "Alt".Equals(childLocal)) {
                            newCompound.Options.Array = true;
                            newCompound.Options.ArrayOrdered = true;
                            newCompound.Options.ArrayAlternate = true;
                        }
                        else {
                            newCompound.Options.Struct = true;
                            if (!isRdf && !"Description".Equals(childLocal)) {
                                string typeName = currChild.NamespaceURI;
                                if (typeName == null) {
                                    throw new XmpException("All XML elements must be in a namespace",
                                                           XmpError.BADXMP);
                                }
                                typeName += ':' + childLocal;
                                AddQualifierNode(newCompound, "rdf:type", typeName);
                            }
                        }

                        RdfNodeElement(xmp, newCompound, currChild, false);

                        if (newCompound.HasValueChild) {
                            FixupQualifiedNode(newCompound);
                        }
                        else if (newCompound.Options.ArrayAlternate) {
                            XmpNodeUtils.DetectAltText(newCompound);
                        }

                        found = true;
                    }
                    else if (found) {
                        // found second child element
                        throw new XmpException("Invalid child of resource property element", XmpError.BADRDF);
                    }
                    else {
                        throw new XmpException("Children of resource property element must be XML elements",
                                               XmpError.BADRDF);
                    }
                }
            }

            if (!found) {
                // didn't found any child elements
                throw new XmpException("Missing child of resource property element", XmpError.BADRDF);
            }
        }
Ejemplo n.º 16
0
        /// <summary>
        /// 7.2.14 propertyElt
        /// 
        ///		resourcePropertyElt | literalPropertyElt | parseTypeLiteralPropertyElt |
        ///		parseTypeResourcePropertyElt | parseTypeCollectionPropertyElt | 
        ///		parseTypeOtherPropertyElt | emptyPropertyElt
        /// 
        /// 7.2.15 resourcePropertyElt
        ///		start-element ( URI == propertyElementURIs, attributes == set ( idAttr? ) )
        ///		ws* nodeElement ws*
        ///		end-element()
        /// 
        /// 7.2.16 literalPropertyElt
        ///		start-element (
        ///			URI == propertyElementURIs, attributes == set ( idAttr?, datatypeAttr?) )
        ///		text()
        ///		end-element()
        /// 
        /// 7.2.17 parseTypeLiteralPropertyElt
        ///		start-element (
        ///			URI == propertyElementURIs, attributes == set ( idAttr?, parseLiteral ) )
        ///		literal
        ///		end-element()
        /// 
        /// 7.2.18 parseTypeResourcePropertyElt
        ///		start-element (
        ///			 URI == propertyElementURIs, attributes == set ( idAttr?, parseResource ) )
        ///		propertyEltList
        ///		end-element()
        /// 
        /// 7.2.19 parseTypeCollectionPropertyElt
        ///		start-element (
        ///			URI == propertyElementURIs, attributes == set ( idAttr?, parseCollection ) )
        ///		nodeElementList
        ///		end-element()
        /// 
        /// 7.2.20 parseTypeOtherPropertyElt
        ///		start-element ( URI == propertyElementURIs, attributes == set ( idAttr?, parseOther ) )
        ///		propertyEltList
        ///		end-element()
        /// 
        /// 7.2.21 emptyPropertyElt
        ///		start-element ( URI == propertyElementURIs,
        ///			attributes == set ( idAttr?, ( resourceAttr | nodeIdAttr )?, propertyAttr* ) )
        ///		end-element()
        /// 
        /// The various property element forms are not distinguished by the XML element name, 
        /// but by their attributes for the most part. The exceptions are resourcePropertyElt and 
        /// literalPropertyElt. They are distinguished by their XML element content.
        /// 
        /// NOTE: The RDF syntax does not explicitly include the xml:lang attribute although it can 
        /// appear in many of these. We have to allow for it in the attibute counts below.	 
        /// </summary>
        /// <param name="xmp"> the xmp metadata object that is generated </param>
        /// <param name="xmpParent"> the parent xmp node </param>
        /// <param name="xmlNode"> the currently processed XML node </param>
        /// <param name="isTopLevel"> Flag if the node is a top-level node </param>
        /// <exception cref="XmpException"> thown on parsing errors </exception>
        private static void RdfPropertyElement(XmpMetaImpl xmp, XmpNode xmpParent, XmlNode xmlNode, bool isTopLevel) {
            int nodeTerm = GetRdfTermKind(xmlNode);
            if (!IsPropertyElementName(nodeTerm)) {
                throw new XmpException("Invalid property element name", XmpError.BADRDF);
            }

            // remove the namespace-definitions from the list
            XmlAttributeCollection attributes = xmlNode.Attributes;
            if (attributes == null)
                return;
            IList nsAttrs = null;
            for (int i = 0; i < attributes.Count; i++) {
                XmlNode attribute = attributes[i];
                if ("xmlns".Equals(attribute.Prefix) || (attribute.Prefix == null && "xmlns".Equals(attribute.Name))) {
                    if (nsAttrs == null) {
                        nsAttrs = new ArrayList();
                    }
                    nsAttrs.Add(attribute.Name);
                }
            }
            if (nsAttrs != null) {
                for (IEnumerator it = nsAttrs.GetEnumerator(); it.MoveNext();) {
                    string ns = (string) it.Current;
                    attributes.RemoveNamedItem(ns);
                }
            }


            if (attributes.Count > 3) {
                // Only an emptyPropertyElt can have more than 3 attributes.
                RdfEmptyPropertyElement(xmp, xmpParent, xmlNode, isTopLevel);
            }
            else {
                // Look through the attributes for one that isn't rdf:ID or xml:lang, 
                // it will usually tell what we should be dealing with. 
                // The called routines must verify their specific syntax!

                for (int i = 0; i < attributes.Count; i++) {
                    XmlNode attribute = attributes[i];
                    string attrLocal = attribute.LocalName;
                    string attrNs = attribute.NamespaceURI;
                    string attrValue = attribute.Value;
                    if (!(XML_LANG.Equals(attribute.Name) && !("ID".Equals(attrLocal) && NS_RDF.Equals(attrNs)))) {
                        if ("datatype".Equals(attrLocal) && NS_RDF.Equals(attrNs)) {
                            RdfLiteralPropertyElement(xmp, xmpParent, xmlNode, isTopLevel);
                        }
                        else if (!("parseType".Equals(attrLocal) && NS_RDF.Equals(attrNs))) {
                            RdfEmptyPropertyElement(xmp, xmpParent, xmlNode, isTopLevel);
                        }
                        else if ("Literal".Equals(attrValue)) {
                            RdfParseTypeLiteralPropertyElement();
                        }
                        else if ("Resource".Equals(attrValue)) {
                            RdfParseTypeResourcePropertyElement(xmp, xmpParent, xmlNode, isTopLevel);
                        }
                        else if ("Collection".Equals(attrValue)) {
                            RdfParseTypeCollectionPropertyElement();
                        }
                        else {
                            RdfParseTypeOtherPropertyElement();
                        }

                        return;
                    }
                }

                // Only rdf:ID and xml:lang, could be a resourcePropertyElt, a literalPropertyElt, 
                // or an emptyPropertyElt. Look at the child XML nodes to decide which.

                if (xmlNode.HasChildNodes) {
                    for (int i = 0; i < xmlNode.ChildNodes.Count; i++) {
                        XmlNode currChild = xmlNode.ChildNodes[i];
                        if (currChild.NodeType != XmlNodeType.Text) {
                            RdfResourcePropertyElement(xmp, xmpParent, xmlNode, isTopLevel);
                            return;
                        }
                    }

                    RdfLiteralPropertyElement(xmp, xmpParent, xmlNode, isTopLevel);
                }
                else {
                    RdfEmptyPropertyElement(xmp, xmpParent, xmlNode, isTopLevel);
                }
            }
        }
Ejemplo n.º 17
0
 /// <summary>
 /// 7.2.13 propertyEltList
 /// ws* ( propertyElt ws* )*
 /// </summary>
 /// <param name="xmp"> the xmp metadata object that is generated </param>
 /// <param name="xmpParent"> the parent xmp node </param>
 /// <param name="xmlParent"> the currently processed XML node </param>
 /// <param name="isTopLevel"> Flag if the node is a top-level node </param>
 /// <exception cref="XmpException"> thown on parsing errors </exception>
 private static void RdfPropertyElementList(XmpMetaImpl xmp, XmpNode xmpParent, XmlNode xmlParent,
                                            bool isTopLevel) {
     for (int i = 0; i < xmlParent.ChildNodes.Count; i++) {
         XmlNode currChild = xmlParent.ChildNodes[i];
         if (IsWhitespaceNode(currChild)) {
             continue;
         }
         if (currChild.NodeType != XmlNodeType.Element) {
             throw new XmpException("Expected property element node not found", XmpError.BADRDF);
         }
         RdfPropertyElement(xmp, xmpParent, currChild, isTopLevel);
     }
 }
Ejemplo n.º 18
0
        /// <seealso cref= XMPUtils#catenateArrayItems(XMPMeta, String, String, String, String,
        ///      boolean)
        /// </seealso>
        /// <param name="xmp">
        ///            The XMP object containing the array to be catenated. </param>
        /// <param name="schemaNs">
        ///            The schema namespace URI for the array. Must not be null or
        ///            the empty string. </param>
        /// <param name="arrayName">
        ///            The name of the array. May be a general path expression, must
        ///            not be null or the empty string. Each item in the array must
        ///            be a simple string value. </param>
        /// <param name="separator">
        ///            The string to be used to separate the items in the catenated
        ///            string. Defaults to &quot;; &quot;, ASCII semicolon and space
        ///            (U+003B, U+0020). </param>
        /// <param name="quotes">
        ///            The characters to be used as quotes around array items that
        ///            contain a separator. Defaults to &apos;&quot;&apos; </param>
        /// <param name="allowCommas">
        ///            Option flag to control the catenation. </param>
        /// <returns> Returns the string containing the catenated array items. </returns>
        /// <exception cref="XmpException">
        ///             Forwards the Exceptions from the metadata processing </exception>
        public static string CatenateArrayItems(IXmpMeta xmp, string schemaNs, string arrayName, string separator,
                                                string quotes, bool allowCommas)
        {
            ParameterAsserts.AssertSchemaNs(schemaNs);
            ParameterAsserts.AssertArrayName(arrayName);
            ParameterAsserts.AssertImplementation(xmp);
            if (string.IsNullOrEmpty(separator))
            {
                separator = "; ";
            }
            if (string.IsNullOrEmpty(quotes))
            {
                quotes = "\"";
            }

            XmpMetaImpl xmpImpl = (XmpMetaImpl)xmp;

            // Return an empty result if the array does not exist,
            // hurl if it isn't the right form.
            XmpPath arrayPath = XmpPathParser.ExpandXPath(schemaNs, arrayName);
            XmpNode arrayNode = XmpNodeUtils.FindNode(xmpImpl.Root, arrayPath, false, null);

            if (arrayNode == null)
            {
                return("");
            }
            if (!arrayNode.Options.Array || arrayNode.Options.ArrayAlternate)
            {
                throw new XmpException("Named property must be non-alternate array", XmpError.BADPARAM);
            }

            // Make sure the separator is OK.
            CheckSeparator(separator);
            // Make sure the open and close quotes are a legitimate pair.
            char openQuote  = quotes[0];
            char closeQuote = CheckQuotes(quotes, openQuote);

            // Build the result, quoting the array items, adding separators.
            // Hurl if any item isn't simple.

            StringBuilder catinatedString = new StringBuilder();

            for (IEnumerator it = arrayNode.IterateChildren(); it.MoveNext();)
            {
                XmpNode currItem = (XmpNode)it.Current;
                if (currItem == null)
                {
                    continue;
                }
                if (currItem.Options.CompositeProperty)
                {
                    throw new XmpException("Array items must be simple", XmpError.BADPARAM);
                }
                string str = ApplyQuotes(currItem.Value, openQuote, closeQuote, allowCommas);

                catinatedString.Append(str);
                if (it.MoveNext())
                {
                    catinatedString.Append(separator);
                }
            }

            return(catinatedString.ToString());
        }
Ejemplo n.º 19
0
        /// <summary>
        /// Adds a child node.
        /// </summary>
        /// <param name="xmp"> the xmp metadata object that is generated </param>
        /// <param name="xmpParent"> the parent xmp node </param>
        /// <param name="xmlNode"> the currently processed XML node </param>
        /// <param name="value"> Node value </param>
        /// <param name="isTopLevel"> Flag if the node is a top-level node </param>
        /// <returns> Returns the newly created child node. </returns>
        /// <exception cref="XmpException"> thown on parsing errors </exception>
        private static XmpNode AddChildNode(XmpMetaImpl xmp, XmpNode xmpParent, XmlNode xmlNode, string value,
                                            bool isTopLevel) {
            IXmpSchemaRegistry registry = XmpMetaFactory.SchemaRegistry;
            string @namespace = xmlNode.NamespaceURI;
            string childName;
            if (@namespace != null) {
                if (NS_DC_DEPRECATED.Equals(@namespace)) {
                    // Fix a legacy DC namespace
                    @namespace = NS_DC;
                }

                string prefix = registry.GetNamespacePrefix(@namespace);
                if (prefix == null) {
                    prefix = xmlNode.Prefix ?? DEFAULT_PREFIX;
                    prefix = registry.RegisterNamespace(@namespace, prefix);
                }
                childName = prefix + xmlNode.LocalName;
            }
            else {
                throw new XmpException("XML namespace required for all elements and attributes",
                                       XmpError.BADRDF);
            }


            // create schema node if not already there
            PropertyOptions childOptions = new PropertyOptions();
            bool isAlias = false;
            if (isTopLevel) {
                // Lookup the schema node, adjust the XMP parent pointer.
                // Incoming parent must be the tree root.
                XmpNode schemaNode = XmpNodeUtils.FindSchemaNode(xmp.Root, @namespace, DEFAULT_PREFIX, true);
                schemaNode.Implicit = false; // Clear the implicit node bit.
                // need runtime check for proper 32 bit code.
                xmpParent = schemaNode;

                // If this is an alias set the alias flag in the node 
                // and the hasAliases flag in the tree.
                if (registry.FindAlias(childName) != null) {
                    isAlias = true;
                    xmp.Root.HasAliases = true;
                    schemaNode.HasAliases = true;
                }
            }


            // Make sure that this is not a duplicate of a named node.
            bool isArrayItem = "rdf:li".Equals(childName);
            bool isValueNode = "rdf:value".Equals(childName);

            // Create XMP node and so some checks
            XmpNode newChild = new XmpNode(childName, value, childOptions);
            newChild.Alias = isAlias;

            // Add the new child to the XMP parent node, a value node first.
            if (!isValueNode) {
                xmpParent.AddChild(newChild);
            }
            else {
                xmpParent.AddChild(1, newChild);
            }


            if (isValueNode) {
                if (isTopLevel || !xmpParent.Options.Struct) {
                    throw new XmpException("Misplaced rdf:value element", XmpError.BADRDF);
                }
                xmpParent.HasValueChild = true;
            }

            if (isArrayItem) {
                if (!xmpParent.Options.Array) {
                    throw new XmpException("Misplaced rdf:li element", XmpError.BADRDF);
                }
                newChild.Name = ARRAY_ITEM_NAME;
            }

            return newChild;
        }
Ejemplo n.º 20
0
 /// <summary>
 /// Each of these parsing methods is responsible for recognizing an RDF
 /// syntax production and adding the appropriate structure to the XMP tree.
 /// They simply return for success, failures will throw an exception.
 /// </summary>
 /// <param name="xmp"> the xmp metadata object that is generated </param>
 /// <param name="rdfRdfNode"> the top-level xml node </param>
 /// <exception cref="XmpException"> thown on parsing errors </exception>
 internal static void RdfRdf(XmpMetaImpl xmp, XmlNode rdfRdfNode) {
     if (rdfRdfNode.Attributes != null && rdfRdfNode.Attributes.Count > 0) {
         RdfNodeElementList(xmp, xmp.Root, rdfRdfNode);
     }
     else {
         throw new XmpException("Invalid attributes of rdf:RDF element", XmpError.BADRDF);
     }
 }
Ejemplo n.º 21
0
        /// <summary>
        /// see {@link XMPUtils#separateArrayItems(XMPMeta, String, String, String,
        /// PropertyOptions, boolean)}
        /// </summary>
        /// <param name="xmp">
        ///            The XMP object containing the array to be updated. </param>
        /// <param name="schemaNs">
        ///            The schema namespace URI for the array. Must not be null or
        ///            the empty string. </param>
        /// <param name="arrayName">
        ///            The name of the array. May be a general path expression, must
        ///            not be null or the empty string. Each item in the array must
        ///            be a simple string value. </param>
        /// <param name="catedStr">
        ///            The string to be separated into the array items. </param>
        /// <param name="arrayOptions">
        ///            Option flags to control the separation. </param>
        /// <param name="preserveCommas">
        ///            Flag if commas shall be preserved
        /// </param>
        /// <exception cref="XmpException">
        ///             Forwards the Exceptions from the metadata processing </exception>
        public static void SeparateArrayItems(IXmpMeta xmp, string schemaNs, string arrayName, string catedStr,
                                              PropertyOptions arrayOptions, bool preserveCommas)
        {
            ParameterAsserts.AssertSchemaNs(schemaNs);
            ParameterAsserts.AssertArrayName(arrayName);
            if (catedStr == null)
            {
                throw new XmpException("Parameter must not be null", XmpError.BADPARAM);
            }
            ParameterAsserts.AssertImplementation(xmp);
            XmpMetaImpl xmpImpl = (XmpMetaImpl)xmp;

            // Keep a zero value, has special meaning below.
            XmpNode arrayNode = SeparateFindCreateArray(schemaNs, arrayName, arrayOptions, xmpImpl);

            // Extract the item values one at a time, until the whole input string is done.
            int  charKind = UCK_NORMAL;
            char ch       = (char)0;

            int itemEnd = 0;
            int endPos  = catedStr.Length;

            while (itemEnd < endPos)
            {
                string itemValue;
                int    itemStart;
                // Skip any leading spaces and separation characters. Always skip commas here.
                // They can be kept when within a value, but not when alone between values.
                for (itemStart = itemEnd; itemStart < endPos; itemStart++)
                {
                    ch       = catedStr[itemStart];
                    charKind = ClassifyCharacter(ch);
                    if (charKind == UCK_NORMAL || charKind == UCK_QUOTE)
                    {
                        break;
                    }
                }
                if (itemStart >= endPos)
                {
                    break;
                }
                int nextKind;
                if (charKind != UCK_QUOTE)
                {
                    // This is not a quoted value. Scan for the end, create an array
                    // item from the substring.
                    for (itemEnd = itemStart; itemEnd < endPos; itemEnd++)
                    {
                        ch       = catedStr[itemEnd];
                        charKind = ClassifyCharacter(ch);

                        if (charKind == UCK_NORMAL || charKind == UCK_QUOTE || (charKind == UCK_COMMA && preserveCommas))
                        {
                            continue;
                        }
                        if (charKind != UCK_SPACE)
                        {
                            break;
                        }
                        if ((itemEnd + 1) < endPos)
                        {
                            ch       = catedStr[itemEnd + 1];
                            nextKind = ClassifyCharacter(ch);
                            if (nextKind == UCK_NORMAL || nextKind == UCK_QUOTE ||
                                (nextKind == UCK_COMMA && preserveCommas))
                            {
                                continue;
                            }
                        }

                        // Anything left?
                        break; // Have multiple spaces, or a space followed by a
                        // separator.
                    }
                    itemValue = catedStr.Substring(itemStart, itemEnd - itemStart);
                }
                else
                {
                    // Accumulate quoted values into a local string, undoubling
                    // internal quotes that
                    // match the surrounding quotes. Do not undouble "unmatching"
                    // quotes.

                    char openQuote  = ch;
                    char closeQuote = GetClosingQuote(openQuote);

                    itemStart++; // Skip the opening quote;
                    itemValue = "";

                    for (itemEnd = itemStart; itemEnd < endPos; itemEnd++)
                    {
                        ch       = catedStr[itemEnd];
                        charKind = ClassifyCharacter(ch);

                        if (charKind != UCK_QUOTE || !IsSurroundingQuote(ch, openQuote, closeQuote))
                        {
                            // This is not a matching quote, just append it to the
                            // item value.
                            itemValue += ch;
                        }
                        else
                        {
                            // This is a "matching" quote. Is it doubled, or the
                            // final closing quote?
                            // Tolerate various edge cases like undoubled opening
                            // (non-closing) quotes,
                            // or end of input.
                            char nextChar;
                            if ((itemEnd + 1) < endPos)
                            {
                                nextChar = catedStr[itemEnd + 1];
                                nextKind = ClassifyCharacter(nextChar);
                            }
                            else
                            {
                                nextKind = UCK_SEMICOLON;
                                nextChar = (char)0x3B;
                            }

                            if (ch == nextChar)
                            {
                                // This is doubled, copy it and skip the double.
                                itemValue += ch;
                                // Loop will add in charSize.
                                itemEnd++;
                            }
                            else if (!IsClosingingQuote(ch, openQuote, closeQuote))
                            {
                                // This is an undoubled, non-closing quote, copy it.
                                itemValue += ch;
                            }
                            else
                            {
                                // This is an undoubled closing quote, skip it and
                                // exit the loop.
                                itemEnd++;
                                break;
                            }
                        }
                    }
                }

                // Add the separated item to the array.
                // Keep a matching old value in case it had separators.
                int foundIndex = -1;
                for (int oldChild = 1; oldChild <= arrayNode.ChildrenLength; oldChild++)
                {
                    if (itemValue.Equals(arrayNode.GetChild(oldChild).Value))
                    {
                        foundIndex = oldChild;
                        break;
                    }
                }

                if (foundIndex < 0)
                {
                    XmpNode newItem = new XmpNode(ARRAY_ITEM_NAME, itemValue, null);
                    arrayNode.AddChild(newItem);
                }
            }
        }
Ejemplo n.º 22
0
        /// <summary>
        /// The actual serialization.
        /// </summary>
        /// <param name="xmp"> the metadata object to be serialized </param>
        /// <param name="out"> outputStream the output stream to Serialize to </param>
        /// <param name="options"> the serialization options
        /// </param>
        /// <exception cref="XmpException"> If case of wrong options or any other serialization error. </exception>
        public virtual void Serialize(IXmpMeta xmp, Stream @out, SerializeOptions options) {
            try {
                _outputStream = new CountOutputStream(@out);
                _writer = new StreamWriter(_outputStream, Encoding.GetEncoding(options.Encoding));

                _xmp = (XmpMetaImpl) xmp;
                _options = options;
                _padding = options.Padding;

                _writer = new StreamWriter(_outputStream, Encoding.GetEncoding(options.Encoding));

                CheckOptionsConsistence();

                // serializes the whole packet, but don't write the tail yet 
                // and flush to make sure that the written bytes are calculated correctly
                string tailStr = SerializeAsRdf();
                _writer.Flush();

                // adds padding
                AddPadding(tailStr.Length);

                // writes the tail
                Write(tailStr);
                _writer.Flush();

                _outputStream.Close();
            }
            catch (IOException) {
                throw new XmpException("Error writing to the OutputStream", XmpError.UNKNOWN);
            }
        }
Ejemplo n.º 23
0
        /// <seealso cref= XMPUtilsImpl#appendProperties(XMPMeta, XMPMeta, boolean, boolean, boolean) </seealso>
        /// <param name="destXmp"> The destination XMP object. </param>
        /// <param name="sourceNode"> the source node </param>
        /// <param name="destParent"> the parent of the destination node </param>
        /// <param name="replaceOldValues"> Replace the values of existing properties. </param>
        /// <param name="deleteEmptyValues"> flag if properties with empty values should be deleted 
        /// 		   in the destination object. </param>
        /// <exception cref="XmpException"> </exception>
        private static void AppendSubtree(XmpMetaImpl destXmp, XmpNode sourceNode, XmpNode destParent,
                                          bool replaceOldValues, bool deleteEmptyValues) {
            XmpNode destNode = XmpNodeUtils.FindChildNode(destParent, sourceNode.Name, false);

            bool valueIsEmpty = false;
            if (deleteEmptyValues) {
                valueIsEmpty = sourceNode.Options.Simple
                                   ? string.IsNullOrEmpty(sourceNode.Value)
                                   : !sourceNode.HasChildren();
            }

            if (deleteEmptyValues && valueIsEmpty) {
                if (destNode != null) {
                    destParent.RemoveChild(destNode);
                }
            }
            else if (destNode == null) {
                // The one easy case, the destination does not exist.
                destParent.AddChild((XmpNode) sourceNode.Clone());
            }
            else if (replaceOldValues) {
                // The destination exists and should be replaced.
                destXmp.SetNode(destNode, sourceNode.Value, sourceNode.Options, true);
                destParent.RemoveChild(destNode);
                destNode = (XmpNode) sourceNode.Clone();
                destParent.AddChild(destNode);
            }
            else {
                // The destination exists and is not totally replaced. Structs and
                // arrays are merged.

                PropertyOptions sourceForm = sourceNode.Options;
                PropertyOptions destForm = destNode.Options;
                if (sourceForm != destForm) {
                    return;
                }
                if (sourceForm.Struct) {
                    // To merge a struct process the fields recursively. E.g. add simple missing fields.
                    // The recursive call to AppendSubtree will handle deletion for fields with empty 
                    // values.
                    for (IEnumerator it = sourceNode.IterateChildren(); it.MoveNext();) {
                        XmpNode sourceField = (XmpNode) it.Current;
                        if (sourceField == null)
                            continue;
                        AppendSubtree(destXmp, sourceField, destNode, replaceOldValues, deleteEmptyValues);
                        if (deleteEmptyValues && !destNode.HasChildren()) {
                            destParent.RemoveChild(destNode);
                        }
                    }
                }
                else if (sourceForm.ArrayAltText) {
                    // Merge AltText arrays by the "xml:lang" qualifiers. Make sure x-default is first. 
                    // Make a special check for deletion of empty values. Meaningful in AltText arrays 
                    // because the "xml:lang" qualifier provides unambiguous source/dest correspondence.
                    for (IEnumerator it = sourceNode.IterateChildren(); it.MoveNext();) {
                        XmpNode sourceItem = (XmpNode) it.Current;
                        if (sourceItem == null)
                            continue;
                        if (!sourceItem.HasQualifier() || !XML_LANG.Equals(sourceItem.GetQualifier(1).Name)) {
                            continue;
                        }

                        int destIndex = XmpNodeUtils.LookupLanguageItem(destNode, sourceItem.GetQualifier(1).Value);
                        if (deleteEmptyValues && (string.IsNullOrEmpty(sourceItem.Value))) {
                            if (destIndex != -1) {
                                destNode.RemoveChild(destIndex);
                                if (!destNode.HasChildren()) {
                                    destParent.RemoveChild(destNode);
                                }
                            }
                        }
                        else if (destIndex == -1) {
                            // Not replacing, keep the existing item.						
                            if (!X_DEFAULT.Equals(sourceItem.GetQualifier(1).Value) || !destNode.HasChildren()) {
                                sourceItem.CloneSubtree(destNode);
                            }
                            else {
                                XmpNode destItem = new XmpNode(sourceItem.Name, sourceItem.Value, sourceItem.Options);
                                sourceItem.CloneSubtree(destItem);
                                destNode.AddChild(1, destItem);
                            }
                        }
                    }
                }
                else if (sourceForm.Array) {
                    // Merge other arrays by item values. Don't worry about order or duplicates. Source 
                    // items with empty values do not cause deletion, that conflicts horribly with 
                    // merging.

                    for (IEnumerator @is = sourceNode.IterateChildren(); @is.MoveNext();) {
                        XmpNode sourceItem = (XmpNode) @is.Current;
                        if (sourceItem == null)
                            continue;
                        bool match = false;
                        for (IEnumerator id = destNode.IterateChildren(); id.MoveNext();) {
                            XmpNode destItem = (XmpNode) id.Current;
                            if (destItem == null)
                                continue;
                            if (ItemValuesMatch(sourceItem, destItem)) {
                                match = true;
                            }
                        }
                        if (!match) {
                            destNode = (XmpNode) sourceItem.Clone();
                            destParent.AddChild(destNode);
                        }
                    }
                }
            }
        }
Ejemplo n.º 24
0
        /// <summary>
        /// Utility to find or create the array used by <code>separateArrayItems()</code>. </summary>
        /// <param name="schemaNs"> a the namespace fo the array </param>
        /// <param name="arrayName"> the name of the array </param>
        /// <param name="arrayOptions"> the options for the array if newly created </param>
        /// <param name="xmp"> the xmp object </param>
        /// <returns> Returns the array node. </returns>
        /// <exception cref="XmpException"> Forwards exceptions </exception>
        private static XmpNode SeparateFindCreateArray(string schemaNs, string arrayName, PropertyOptions arrayOptions,
                                                       XmpMetaImpl xmp) {
            arrayOptions = XmpNodeUtils.VerifySetOptions(arrayOptions, null);
            if (!arrayOptions.OnlyArrayOptions) {
                throw new XmpException("Options can only provide array form", XmpError.BADOPTIONS);
            }

            // Find the array node, make sure it is OK. Move the current children
            // aside, to be readded later if kept.
            XmpPath arrayPath = XmpPathParser.ExpandXPath(schemaNs, arrayName);
            XmpNode arrayNode = XmpNodeUtils.FindNode(xmp.Root, arrayPath, false, null);
            if (arrayNode != null) {
                // The array exists, make sure the form is compatible. Zero
                // arrayForm means take what exists.
                PropertyOptions arrayForm = arrayNode.Options;
                if (!arrayForm.Array || arrayForm.ArrayAlternate) {
                    throw new XmpException("Named property must be non-alternate array", XmpError.BADXPATH);
                }
                if (arrayOptions.EqualArrayTypes(arrayForm)) {
                    throw new XmpException("Mismatch of specified and existing array form", XmpError.BADXPATH);
                    // *** Right error?
                }
            }
            else {
                // The array does not exist, try to create it.
                // don't modify the options handed into the method
                arrayOptions.Array = true;
                arrayNode = XmpNodeUtils.FindNode(xmp.Root, arrayPath, true, arrayOptions);
                if (arrayNode == null) {
                    throw new XmpException("Failed to create named array", XmpError.BADXPATH);
                }
            }
            return arrayNode;
        }
Ejemplo n.º 25
0
        /// <summary>
        /// 7.2.18 parseTypeResourcePropertyElt
        ///		start-element ( URI == propertyElementURIs, 
        ///			attributes == set ( idAttr?, parseResource ) )
        ///		propertyEltList
        ///		end-element()
        /// 
        /// Add a new struct node with a qualifier for the possible rdf:ID attribute. 
        /// Then process the XML child nodes to get the struct fields.
        /// </summary>
        /// <param name="xmp"> the xmp metadata object that is generated </param>
        /// <param name="xmpParent"> the parent xmp node </param>
        /// <param name="xmlNode"> the currently processed XML node </param>
        /// <param name="isTopLevel"> Flag if the node is a top-level node </param>
        /// <exception cref="XmpException"> thown on parsing errors </exception>
        private static void RdfParseTypeResourcePropertyElement(XmpMetaImpl xmp, XmpNode xmpParent, XmlNode xmlNode,
                                                                bool isTopLevel) {
            XmpNode newStruct = AddChildNode(xmp, xmpParent, xmlNode, "", isTopLevel);

            newStruct.Options.Struct = true;

            if (xmlNode.Attributes != null) {
                for (int i = 0; i < xmlNode.Attributes.Count; i++) {
                    XmlNode attribute = xmlNode.Attributes[i];
                    if ("xmlns".Equals(attribute.Prefix) || (attribute.Prefix == null && "xmlns".Equals(attribute.Name))) {
                        continue;
                    }

                    string attrLocal = attribute.LocalName;
                    string attrNs = attribute.NamespaceURI;
                    if (XML_LANG.Equals(attribute.Name)) {
                        AddQualifierNode(newStruct, XML_LANG, attribute.Value);
                    }
                    else if (NS_RDF.Equals(attrNs) && ("ID".Equals(attrLocal) || "parseType".Equals(attrLocal))) {
                        continue; // The caller ensured the value is "Resource".
                        // Ignore all rdf:ID attributes.
                    }
                    throw new XmpException("Invalid attribute for ParseTypeResource property element",
                                           XmpError.BADRDF);
                }
            }

            RdfPropertyElementList(xmp, newStruct, xmlNode, false);

            if (newStruct.HasValueChild) {
                FixupQualifiedNode(newStruct);
            }
        }
Ejemplo n.º 26
0
 /// <summary>
 /// 7.2.10 nodeElementList<br>
 /// ws* ( nodeElement ws* )*
 /// 
 /// Note: this method is only called from the rdf:RDF-node (top level) </summary>
 /// <param name="xmp"> the xmp metadata object that is generated </param>
 /// <param name="xmpParent"> the parent xmp node </param>
 /// <param name="rdfRdfNode"> the top-level xml node </param>
 /// <exception cref="XmpException"> thown on parsing errors </exception>
 private static void RdfNodeElementList(XmpMetaImpl xmp, XmpNode xmpParent, XmlNode rdfRdfNode) {
     for (int i = 0; i < rdfRdfNode.ChildNodes.Count; i++) {
         XmlNode child = rdfRdfNode.ChildNodes[i];
         // filter whitespaces (and all text nodes)
         if (!IsWhitespaceNode(child)) {
             RdfNodeElement(xmp, xmpParent, child, true);
         }
     }
 }
Ejemplo n.º 27
0
        /// <summary>
        /// 7.2.21 emptyPropertyElt
        ///		start-element ( URI == propertyElementURIs,
        ///						attributes == set (
        ///							idAttr?, ( resourceAttr | nodeIdAttr )?, propertyAttr* ) )
        ///		end-element()
        /// 
        /// <ns:Prop1/>  <!-- a simple property with an empty value --> 
        /// <ns:Prop2 rdf:resource="http: *www.adobe.com/"/> <!-- a URI value --> 
        /// <ns:Prop3 rdf:value="..." ns:Qual="..."/> <!-- a simple qualified property --> 
        /// <ns:Prop4 ns:Field1="..." ns:Field2="..."/> <!-- a struct with simple fields -->
        /// 
        /// An emptyPropertyElt is an element with no contained content, just a possibly empty set of
        /// attributes. An emptyPropertyElt can represent three special cases of simple XMP properties: a
        /// simple property with an empty value (ns:Prop1), a simple property whose value is a URI
        /// (ns:Prop2), or a simple property with simple qualifiers (ns:Prop3). 
        /// An emptyPropertyElt can also represent an XMP struct whose fields are all simple and 
        /// unqualified (ns:Prop4).
        /// 
        /// It is an error to use both rdf:value and rdf:resource - that can lead to invalid  RDF in the
        /// verbose form written using a literalPropertyElt.
        /// 
        /// The XMP mapping for an emptyPropertyElt is a bit different from generic RDF, partly for 
        /// design reasons and partly for historical reasons. The XMP mapping rules are:
        /// <ol> 
        ///		<li> If there is an rdf:value attribute then this is a simple property
        ///				 with a text value.
        ///		All other attributes are qualifiers.
        ///		<li> If there is an rdf:resource attribute then this is a simple property 
        ///			with a URI value. 
        ///		All other attributes are qualifiers.
        ///		<li> If there are no attributes other than xml:lang, rdf:ID, or rdf:nodeID
        ///				then this is a simple 
        ///		property with an empty value. 
        ///		<li> Otherwise this is a struct, the attributes other than xml:lang, rdf:ID, 
        ///				or rdf:nodeID are fields. 
        /// </ol>
        /// </summary>
        /// <param name="xmp"> the xmp metadata object that is generated </param>
        /// <param name="xmpParent"> the parent xmp node </param>
        /// <param name="xmlNode"> the currently processed XML node </param>
        /// <param name="isTopLevel"> Flag if the node is a top-level node </param>
        /// <exception cref="XmpException"> thown on parsing errors </exception>
        private static void RdfEmptyPropertyElement(XmpMetaImpl xmp, XmpNode xmpParent, XmlNode xmlNode,
                                                    bool isTopLevel) {
            bool hasPropertyAttrs = false;
            bool hasResourceAttr = false;
            bool hasNodeIdAttr = false;
            bool hasValueAttr = false;

            XmlNode valueNode = null; // ! Can come from rdf:value or rdf:resource.

            if (xmlNode.HasChildNodes) {
                throw new XmpException("Nested content not allowed with rdf:resource or property attributes",
                                       XmpError.BADRDF);
            }

            // First figure out what XMP this maps to and remember the XML node for a simple value.
            if (xmlNode.Attributes != null) {
                for (int i = 0; i < xmlNode.Attributes.Count; i++) {
                    XmlNode attribute = xmlNode.Attributes[i];
                    if ("xmlns".Equals(attribute.Prefix) || (attribute.Prefix == null && "xmlns".Equals(attribute.Name))) {
                        continue;
                    }

                    int attrTerm = GetRdfTermKind(attribute);

                    switch (attrTerm) {
                        case RDFTERM_ID:
                            // Nothing to do.
                            break;

                        case RDFTERM_RESOURCE:
                            if (hasNodeIdAttr) {
                                throw new XmpException(
                                    "Empty property element can't have both rdf:resource and rdf:nodeID",
                                    XmpError.BADRDF);
                            }
                            if (hasValueAttr) {
                                throw new XmpException(
                                    "Empty property element can't have both rdf:value and rdf:resource",
                                    XmpError.BADXMP);
                            }

                            hasResourceAttr = true;
                            if (!hasValueAttr) {
                                valueNode = attribute;
                            }
                            break;

                        case RDFTERM_NODE_ID:
                            if (hasResourceAttr) {
                                throw new XmpException(
                                    "Empty property element can't have both rdf:resource and rdf:nodeID",
                                    XmpError.BADRDF);
                            }
                            hasNodeIdAttr = true;
                            break;

                        case RDFTERM_OTHER:
                            if ("value".Equals(attribute.LocalName) && NS_RDF.Equals(attribute.NamespaceURI)) {
                                if (hasResourceAttr) {
                                    throw new XmpException(
                                        "Empty property element can't have both rdf:value and rdf:resource",
                                        XmpError.BADXMP);
                                }
                                hasValueAttr = true;
                                valueNode = attribute;
                            }
                            else if (!XML_LANG.Equals(attribute.Name)) {
                                hasPropertyAttrs = true;
                            }
                            break;

                        default:
                            throw new XmpException("Unrecognized attribute of empty property element",
                                                   XmpError.BADRDF);
                    }
                }
            }

            // Create the right kind of child node and visit the attributes again 
            // to add the fields or qualifiers.
            // ! Because of implementation vagaries, 
            //   the xmpParent is the tree root for top level properties.
            // ! The schema is found, created if necessary, by addChildNode.

            XmpNode childNode = AddChildNode(xmp, xmpParent, xmlNode, "", isTopLevel);
            bool childIsStruct = false;

            if (hasValueAttr || hasResourceAttr) {
                childNode.Value = valueNode != null ? valueNode.Value : "";
                if (!hasValueAttr) {
                    // ! Might have both rdf:value and rdf:resource.
                    childNode.Options.Uri = true;
                }
            }
            else if (hasPropertyAttrs) {
                childNode.Options.Struct = true;
                childIsStruct = true;
            }

            if (xmlNode.Attributes != null) {
                for (int i = 0; i < xmlNode.Attributes.Count; i++) {
                    XmlNode attribute = xmlNode.Attributes[i];
                    if (attribute == valueNode || "xmlns".Equals(attribute.Prefix) ||
                        (attribute.Prefix == null && "xmlns".Equals(attribute.Name))) {
                        continue; // Skip the rdf:value or rdf:resource attribute holding the value.
                    }

                    int attrTerm = GetRdfTermKind(attribute);

                    switch (attrTerm) {
                        case RDFTERM_ID:
                        case RDFTERM_NODE_ID:
                            break; // Ignore all rdf:ID and rdf:nodeID attributes.
                        case RDFTERM_RESOURCE:
                            AddQualifierNode(childNode, "rdf:resource", attribute.Value);
                            break;

                        case RDFTERM_OTHER:
                            if (!childIsStruct) {
                                AddQualifierNode(childNode, attribute.Name, attribute.Value);
                            }
                            else if (XML_LANG.Equals(attribute.Name)) {
                                AddQualifierNode(childNode, XML_LANG, attribute.Value);
                            }
                            else {
                                AddChildNode(xmp, childNode, attribute, attribute.Value, false);
                            }
                            break;

                        default:
                            throw new XmpException("Unrecognized attribute of empty property element",
                                                   XmpError.BADRDF);
                    }
                }
            }
        }
Ejemplo n.º 28
0
 /// <summary>
 /// Serializes an <code>XMPMeta</code>-object as RDF into a byte buffer.
 /// </summary>
 /// <param name="xmp"> a metadata implementation object </param>
 /// <param name="options"> Options to control the serialization (see <seealso cref="SerializeOptions"/>). </param>
 /// <returns> Returns a byte buffer containing the serialized RDF. </returns>
 /// <exception cref="XmpException"> on serializsation errors. </exception>
 public static byte[] SerializeToBuffer(XmpMetaImpl xmp, SerializeOptions options) {
     MemoryStream @out = new MemoryStream(2048);
     Serialize(xmp, @out, options);
     return @out.GetBuffer();
 }
Ejemplo n.º 29
0
 /// <summary>
 /// The main parsing method. The XML tree is walked through from the root node and and XMP tree
 /// is created. This is a raw parse, the normalisation of the XMP tree happens outside.
 /// </summary>
 /// <param name="xmlRoot"> the XML root node </param>
 /// <returns> Returns an XMP metadata object (not normalized) </returns>
 /// <exception cref="XmpException"> Occurs if the parsing fails for any reason. </exception>
 internal static XmpMetaImpl Parse(XmlNode xmlRoot) {
     XmpMetaImpl xmp = new XmpMetaImpl();
     RdfRdf(xmp, xmlRoot);
     return xmp;
 }
Ejemplo n.º 30
0
        /// <seealso cref= XMPUtilsImpl#appendProperties(XMPMeta, XMPMeta, boolean, boolean, boolean) </seealso>
        /// <param name="destXmp"> The destination XMP object. </param>
        /// <param name="sourceNode"> the source node </param>
        /// <param name="destParent"> the parent of the destination node </param>
        /// <param name="replaceOldValues"> Replace the values of existing properties. </param>
        /// <param name="deleteEmptyValues"> flag if properties with empty values should be deleted
        ///            in the destination object. </param>
        /// <exception cref="XmpException"> </exception>
        private static void AppendSubtree(XmpMetaImpl destXmp, XmpNode sourceNode, XmpNode destParent,
                                          bool replaceOldValues, bool deleteEmptyValues)
        {
            XmpNode destNode = XmpNodeUtils.FindChildNode(destParent, sourceNode.Name, false);

            bool valueIsEmpty = false;

            if (deleteEmptyValues)
            {
                valueIsEmpty = sourceNode.Options.Simple
                                   ? string.IsNullOrEmpty(sourceNode.Value)
                                   : !sourceNode.HasChildren();
            }

            if (deleteEmptyValues && valueIsEmpty)
            {
                if (destNode != null)
                {
                    destParent.RemoveChild(destNode);
                }
            }
            else if (destNode == null)
            {
                // The one easy case, the destination does not exist.
                destParent.AddChild((XmpNode)sourceNode.Clone());
            }
            else if (replaceOldValues)
            {
                // The destination exists and should be replaced.
                destXmp.SetNode(destNode, sourceNode.Value, sourceNode.Options, true);
                destParent.RemoveChild(destNode);
                destNode = (XmpNode)sourceNode.Clone();
                destParent.AddChild(destNode);
            }
            else
            {
                // The destination exists and is not totally replaced. Structs and
                // arrays are merged.

                PropertyOptions sourceForm = sourceNode.Options;
                PropertyOptions destForm   = destNode.Options;
                if (sourceForm != destForm)
                {
                    return;
                }
                if (sourceForm.Struct)
                {
                    // To merge a struct process the fields recursively. E.g. add simple missing fields.
                    // The recursive call to AppendSubtree will handle deletion for fields with empty
                    // values.
                    for (IEnumerator it = sourceNode.IterateChildren(); it.MoveNext();)
                    {
                        XmpNode sourceField = (XmpNode)it.Current;
                        if (sourceField == null)
                        {
                            continue;
                        }
                        AppendSubtree(destXmp, sourceField, destNode, replaceOldValues, deleteEmptyValues);
                        if (deleteEmptyValues && !destNode.HasChildren())
                        {
                            destParent.RemoveChild(destNode);
                        }
                    }
                }
                else if (sourceForm.ArrayAltText)
                {
                    // Merge AltText arrays by the "xml:lang" qualifiers. Make sure x-default is first.
                    // Make a special check for deletion of empty values. Meaningful in AltText arrays
                    // because the "xml:lang" qualifier provides unambiguous source/dest correspondence.
                    for (IEnumerator it = sourceNode.IterateChildren(); it.MoveNext();)
                    {
                        XmpNode sourceItem = (XmpNode)it.Current;
                        if (sourceItem == null)
                        {
                            continue;
                        }
                        if (!sourceItem.HasQualifier() || !XML_LANG.Equals(sourceItem.GetQualifier(1).Name))
                        {
                            continue;
                        }

                        int destIndex = XmpNodeUtils.LookupLanguageItem(destNode, sourceItem.GetQualifier(1).Value);
                        if (deleteEmptyValues && (string.IsNullOrEmpty(sourceItem.Value)))
                        {
                            if (destIndex != -1)
                            {
                                destNode.RemoveChild(destIndex);
                                if (!destNode.HasChildren())
                                {
                                    destParent.RemoveChild(destNode);
                                }
                            }
                        }
                        else if (destIndex == -1)
                        {
                            // Not replacing, keep the existing item.
                            if (!X_DEFAULT.Equals(sourceItem.GetQualifier(1).Value) || !destNode.HasChildren())
                            {
                                sourceItem.CloneSubtree(destNode);
                            }
                            else
                            {
                                XmpNode destItem = new XmpNode(sourceItem.Name, sourceItem.Value, sourceItem.Options);
                                sourceItem.CloneSubtree(destItem);
                                destNode.AddChild(1, destItem);
                            }
                        }
                    }
                }
                else if (sourceForm.Array)
                {
                    // Merge other arrays by item values. Don't worry about order or duplicates. Source
                    // items with empty values do not cause deletion, that conflicts horribly with
                    // merging.

                    for (IEnumerator @is = sourceNode.IterateChildren(); @is.MoveNext();)
                    {
                        XmpNode sourceItem = (XmpNode)@is.Current;
                        if (sourceItem == null)
                        {
                            continue;
                        }
                        bool match = false;
                        for (IEnumerator id = destNode.IterateChildren(); id.MoveNext();)
                        {
                            XmpNode destItem = (XmpNode)id.Current;
                            if (destItem == null)
                            {
                                continue;
                            }
                            if (ItemValuesMatch(sourceItem, destItem))
                            {
                                match = true;
                            }
                        }
                        if (!match)
                        {
                            destNode = (XmpNode)sourceItem.Clone();
                            destParent.AddChild(destNode);
                        }
                    }
                }
            }
        }
Ejemplo n.º 31
0
 /// <summary>
 /// 7.2.5 nodeElementURIs
 /// 		anyURI - ( coreSyntaxTerms | rdf:li | oldTerms )
 /// 
 /// 7.2.11 nodeElement
 /// 		start-element ( URI == nodeElementURIs,
 /// 		attributes == set ( ( idAttr | nodeIdAttr | aboutAttr )?, propertyAttr* ) )
 /// 		propertyEltList
 /// 		end-element()
 /// 
 /// A node element URI is rdf:Description or anything else that is not an RDF
 /// term.
 /// </summary>
 /// <param name="xmp"> the xmp metadata object that is generated </param>
 /// <param name="xmpParent"> the parent xmp node </param>
 /// <param name="xmlNode"> the currently processed XML node </param>
 /// <param name="isTopLevel"> Flag if the node is a top-level node </param>
 /// <exception cref="XmpException"> thown on parsing errors </exception>
 private static void RdfNodeElement(XmpMetaImpl xmp, XmpNode xmpParent, XmlNode xmlNode, bool isTopLevel) {
     int nodeTerm = GetRdfTermKind(xmlNode);
     if (nodeTerm != RDFTERM_DESCRIPTION && nodeTerm != RDFTERM_OTHER) {
         throw new XmpException("Node element must be rdf:Description or typed node", XmpError.BADRDF);
     }
     if (isTopLevel && nodeTerm == RDFTERM_OTHER) {
         throw new XmpException("Top level typed node not allowed", XmpError.BADXMP);
     }
     RdfNodeElementAttrs(xmp, xmpParent, xmlNode, isTopLevel);
     RdfPropertyElementList(xmp, xmpParent, xmlNode, isTopLevel);
 }
Ejemplo n.º 32
0
        /// <seealso cref= XMPUtils#removeProperties(XMPMeta, String, String, boolean, boolean)
        /// </seealso>
        /// <param name="xmp">
        ///            The XMP object containing the properties to be removed.
        /// </param>
        /// <param name="schemaNs">
        ///            Optional schema namespace URI for the properties to be
        ///            removed.
        /// </param>
        /// <param name="propName">
        ///            Optional path expression for the property to be removed.
        /// </param>
        /// <param name="doAllProperties">
        ///            Option flag to control the deletion: do internal properties in
        ///            addition to external properties. </param>
        /// <param name="includeAliases">
        ///            Option flag to control the deletion: Include aliases in the
        ///            "named schema" case above. </param>
        /// <exception cref="XmpException"> If metadata processing fails </exception>
        public static void RemoveProperties(IXmpMeta xmp, string schemaNs, string propName, bool doAllProperties,
                                            bool includeAliases)
        {
            ParameterAsserts.AssertImplementation(xmp);
            XmpMetaImpl xmpImpl = (XmpMetaImpl)xmp;

            if (!string.IsNullOrEmpty(propName))
            {
                // Remove just the one indicated property. This might be an alias,
                // the named schema might not actually exist. So don't lookup the
                // schema node.

                if (string.IsNullOrEmpty(schemaNs))
                {
                    throw new XmpException("Property name requires schema namespace", XmpError.BADPARAM);
                }

                XmpPath expPath = XmpPathParser.ExpandXPath(schemaNs, propName);

                XmpNode propNode = XmpNodeUtils.FindNode(xmpImpl.Root, expPath, false, null);
                if (propNode != null)
                {
                    if (doAllProperties ||
                        !Utils.IsInternalProperty(expPath.GetSegment((int)XmpPath.STEP_SCHEMA).Name,
                                                  expPath.GetSegment((int)XmpPath.STEP_ROOT_PROP).Name))
                    {
                        XmpNode parent = propNode.Parent;
                        parent.RemoveChild(propNode);
                        if (parent.Options.SchemaNode && !parent.HasChildren())
                        {
                            // remove empty schema node
                            parent.Parent.RemoveChild(parent);
                        }
                    }
                }
            }
            else if (!string.IsNullOrEmpty(schemaNs))
            {
                // Remove all properties from the named schema. Optionally include
                // aliases, in which case
                // there might not be an actual schema node.

                // XMP_NodePtrPos schemaPos;
                XmpNode schemaNode = XmpNodeUtils.FindSchemaNode(xmpImpl.Root, schemaNs, false);
                if (schemaNode != null)
                {
                    if (RemoveSchemaChildren(schemaNode, doAllProperties))
                    {
                        xmpImpl.Root.RemoveChild(schemaNode);
                    }
                }

                if (includeAliases)
                {
                    // We're removing the aliases also. Look them up by their
                    // namespace prefix.
                    // But that takes more code and the extra speed isn't worth it.
                    // Lookup the XMP node
                    // from the alias, to make sure the actual exists.

                    IXmpAliasInfo[] aliases = XmpMetaFactory.SchemaRegistry.FindAliases(schemaNs);
                    for (int i = 0; i < aliases.Length; i++)
                    {
                        IXmpAliasInfo info       = aliases[i];
                        XmpPath       path       = XmpPathParser.ExpandXPath(info.Namespace, info.PropName);
                        XmpNode       actualProp = XmpNodeUtils.FindNode(xmpImpl.Root, path, false, null);
                        if (actualProp != null)
                        {
                            XmpNode parent = actualProp.Parent;
                            parent.RemoveChild(actualProp);
                        }
                    }
                }
            }
            else
            {
                // Remove all appropriate properties from all schema. In this case
                // we don't have to be
                // concerned with aliases, they are handled implicitly from the
                // actual properties.
                ArrayList schemasToRemove = new ArrayList();
                for (IEnumerator it = xmpImpl.Root.IterateChildren(); it.MoveNext();)
                {
                    XmpNode schema = (XmpNode)it.Current;
                    if (schema == null)
                    {
                        continue;
                    }
                    if (RemoveSchemaChildren(schema, doAllProperties))
                    {
                        schemasToRemove.Add(schema);
                    }
                }
                foreach (XmpNode xmpNode in schemasToRemove)
                {
                    xmpImpl.Root.Children.Remove(xmpNode);
                }
                schemasToRemove.Clear();
            }
        }
Ejemplo n.º 33
0
        /// 
        /// <summary>
        /// 7.2.7 propertyAttributeURIs
        /// 		anyURI - ( coreSyntaxTerms | rdf:Description | rdf:li | oldTerms )
        /// 
        /// 7.2.11 nodeElement
        /// start-element ( URI == nodeElementURIs,
        /// 					attributes == set ( ( idAttr | nodeIdAttr | aboutAttr )?, propertyAttr* ) )
        /// 					propertyEltList
        /// 					end-element()
        /// 
        /// Process the attribute list for an RDF node element. A property attribute URI is 
        /// anything other than an RDF term. The rdf:ID and rdf:nodeID attributes are simply ignored, 
        /// as are rdf:about attributes on inner nodes.
        /// </summary>
        /// <param name="xmp"> the xmp metadata object that is generated </param>
        /// <param name="xmpParent"> the parent xmp node </param>
        /// <param name="xmlNode"> the currently processed XML node </param>
        /// <param name="isTopLevel"> Flag if the node is a top-level node </param>
        /// <exception cref="XmpException"> thown on parsing errors </exception>
        private static void RdfNodeElementAttrs(XmpMetaImpl xmp, XmpNode xmpParent, XmlNode xmlNode, bool isTopLevel) {
            // Used to detect attributes that are mutually exclusive.
            int exclusiveAttrs = 0;
            if (xmlNode == null || xmlNode.Attributes == null)
                return;

            for (int i = 0; i < xmlNode.Attributes.Count; i++) {
                XmlNode attribute = xmlNode.Attributes[i];

                // quick hack, ns declarations do not appear in C++
                // ignore "ID" without namespace
                if ("xmlns".Equals(attribute.Prefix) || (attribute.Prefix == null && "xmlns".Equals(attribute.Name))) {
                    continue;
                }

                int attrTerm = GetRdfTermKind(attribute);

                switch (attrTerm) {
                    case RDFTERM_ID:
                    case RDFTERM_NODE_ID:
                    case RDFTERM_ABOUT:
                        if (exclusiveAttrs > 0) {
                            throw new XmpException("Mutally exclusive about, ID, nodeID attributes",
                                                   XmpError.BADRDF);
                        }

                        exclusiveAttrs++;

                        if (isTopLevel && (attrTerm == RDFTERM_ABOUT)) {
                            // This is the rdf:about attribute on a top level node. Set
                            // the XMP tree name if
                            // it doesn't have a name yet. Make sure this name matches
                            // the XMP tree name.
                            if (!string.IsNullOrEmpty(xmpParent.Name)) {
                                if (!xmpParent.Name.Equals(attribute.Value)) {
                                    throw new XmpException("Mismatched top level rdf:about values",
                                                           XmpError.BADXMP);
                                }
                            }
                            else {
                                xmpParent.Name = attribute.Value;
                            }
                        }
                        break;

                    case RDFTERM_OTHER:
                        AddChildNode(xmp, xmpParent, attribute, attribute.Value, isTopLevel);
                        break;

                    default:
                        throw new XmpException("Invalid nodeElement attribute", XmpError.BADRDF);
                }
            }
        }
Ejemplo n.º 34
0
        /// <summary>
        /// Visit all schemas to do general fixes and handle special cases.
        /// </summary>
        /// <param name="xmp"> the metadata object implementation </param>
        /// <exception cref="XmpException"> Thrown if the normalisation fails. </exception>
        private static void TouchUpDataModel(XmpMetaImpl xmp) {
            // make sure the DC schema is existing, because it might be needed within the normalization
            // if not touched it will be removed by removeEmptySchemas
            XmpNodeUtils.FindSchemaNode(xmp.Root, XmpConst.NS_DC, true);

            // Do the special case fixes within each schema.
            IEnumerator it = xmp.Root.IterateChildren();
            while (it.MoveNext()) {
                XmpNode currSchema = (XmpNode) it.Current;
                if (currSchema != null && XmpConst.NS_DC.Equals(currSchema.Name)) {
                    NormalizeDcArrays(currSchema);
                }
                else if (currSchema != null && XmpConst.NS_EXIF.Equals(currSchema.Name)) {
                    // Do a special case fix for exif:GPSTimeStamp.
                    FixGpsTimeStamp(currSchema);
                    XmpNode arrayNode = XmpNodeUtils.FindChildNode(currSchema, "exif:UserComment", false);
                    if (arrayNode != null) {
                        RepairAltText(arrayNode);
                    }
                }
                else if (currSchema != null && XmpConst.NS_DM.Equals(currSchema.Name)) {
                    // Do a special case migration of xmpDM:copyright to
                    // dc:rights['x-default'].
                    XmpNode dmCopyright = XmpNodeUtils.FindChildNode(currSchema, "xmpDM:copyright", false);
                    if (dmCopyright != null) {
                        MigrateAudioCopyright(xmp, dmCopyright);
                    }
                }
                else if (currSchema != null && XmpConst.NS_XMP_RIGHTS.Equals(currSchema.Name)) {
                    XmpNode arrayNode = XmpNodeUtils.FindChildNode(currSchema, "xmpRights:UsageTerms", false);
                    if (arrayNode != null) {
                        RepairAltText(arrayNode);
                    }
                }
            }
        }