Exemple #1
0
        /// <summary>Find or create a child node under a given parent node.</summary>
        /// <remarks>
        /// Find or create a child node under a given parent node. If the parent node is no
        /// Returns the found or created child node.
        /// </remarks>
        /// <param name="parent">the parent node</param>
        /// <param name="childName">the node name to find</param>
        /// <param name="createNodes">flag, if new nodes shall be created.</param>
        /// <returns>Returns the found or created node or <code>null</code>.</returns>
        /// <exception cref="Com.Adobe.Xmp.XMPException">Thrown if</exception>
        internal static XMPNode FindChildNode(XMPNode parent, string childName, bool createNodes)
        {
            if (!parent.GetOptions().IsSchemaNode() && !parent.GetOptions().IsStruct())
            {
                if (!parent.IsImplicit())
                {
                    throw new XMPException("Named children only allowed for schemas and structs", XMPErrorConstants.Badxpath);
                }
                else
                {
                    if (parent.GetOptions().IsArray())
                    {
                        throw new XMPException("Named children not allowed for arrays", XMPErrorConstants.Badxpath);
                    }
                    else
                    {
                        if (createNodes)
                        {
                            parent.GetOptions().SetStruct(true);
                        }
                    }
                }
            }
            XMPNode childNode = parent.FindChildByName(childName);

            if (childNode == null && createNodes)
            {
                PropertyOptions options = new PropertyOptions();
                childNode = new XMPNode(childName, options);
                childNode.SetImplicit(true);
                parent.AddChild(childNode);
            }
            System.Diagnostics.Debug.Assert(childNode != null || !createNodes);
            return(childNode);
        }
Exemple #2
0
        // EMPTY
        /// <seealso cref="Com.Adobe.Xmp.XMPUtils.CatenateArrayItems(Com.Adobe.Xmp.XMPMeta, string, string, string, string, bool)"/>
        /// <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="Com.Adobe.Xmp.XMPException">Forwards the Exceptions from the metadata processing</exception>
        public static string CatenateArrayItems(XMPMeta xmp, string schemaNS, string arrayName, string separator, string quotes, bool allowCommas)
        {
            ParameterAsserts.AssertSchemaNS(schemaNS);
            ParameterAsserts.AssertArrayName(arrayName);
            ParameterAsserts.AssertImplementation(xmp);
            if (separator == null || separator.Length == 0)
            {
                separator = "; ";
            }
            if (quotes == null || quotes.Length == 0)
            {
                quotes = "\"";
            }
            XMPMetaImpl xmpImpl   = (XMPMetaImpl)xmp;
            XMPNode     arrayNode = null;
            XMPNode     currItem  = null;
            // Return an empty result if the array does not exist,
            // hurl if it isn't the right form.
            XMPPath arrayPath = XMPPathParser.ExpandXPath(schemaNS, arrayName);

            arrayNode = XMPNodeUtils.FindNode(xmpImpl.GetRoot(), arrayPath, false, null);
            if (arrayNode == null)
            {
                return(string.Empty);
            }
            else
            {
                if (!arrayNode.GetOptions().IsArray() || arrayNode.GetOptions().IsArrayAlternate())
                {
                    throw new XMPException("Named property must be non-alternate array", XMPErrorConstants.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 (Iterator it = arrayNode.IterateChildren(); it.HasNext();)
            {
                currItem = (XMPNode)it.Next();
                if (currItem.GetOptions().IsCompositeProperty())
                {
                    throw new XMPException("Array items must be simple", XMPErrorConstants.Badparam);
                }
                string str = ApplyQuotes(currItem.GetValue(), openQuote, closeQuote, allowCommas);
                catinatedString.Append(str);
                if (it.HasNext())
                {
                    catinatedString.Append(separator);
                }
            }
            return(catinatedString.ToString());
        }
Exemple #3
0
        /// <summary>
        /// Searches for a field selector in a node:
        /// [fieldName="value] - an element in an array of structs, chosen by a field value.
        /// </summary>
        /// <remarks>
        /// Searches for a field selector in a node:
        /// [fieldName="value] - an element in an array of structs, chosen by a field value.
        /// No implicit nodes are created by field selectors.
        /// </remarks>
        /// <param name="arrayNode"/>
        /// <param name="fieldName"/>
        /// <param name="fieldValue"/>
        /// <returns>Returns the index of the field if found, otherwise -1.</returns>
        /// <exception cref="Com.Adobe.Xmp.XMPException"></exception>
        private static int LookupFieldSelector(XMPNode arrayNode, string fieldName, string fieldValue)
        {
            int result = -1;

            for (int index = 1; index <= arrayNode.GetChildrenLength() && result < 0; index++)
            {
                XMPNode currItem = arrayNode.GetChild(index);
                if (!currItem.GetOptions().IsStruct())
                {
                    throw new XMPException("Field selector must be used on array of struct", XMPErrorConstants.Badxpath);
                }
                for (int f = 1; f <= currItem.GetChildrenLength(); f++)
                {
                    XMPNode currField = currItem.GetChild(f);
                    if (!fieldName.Equals(currField.GetName()))
                    {
                        continue;
                    }
                    if (fieldValue.Equals(currField.GetValue()))
                    {
                        result = index;
                        break;
                    }
                }
            }
            return(result);
        }
Exemple #4
0
 /// <summary>Make sure the x-default item is first.</summary>
 /// <remarks>
 /// Make sure the x-default item is first. Touch up &quot;single value&quot;
 /// arrays that have a default plus one real language. This case should have
 /// the same value for both items. Older Adobe apps were hardwired to only
 /// use the &quot;x-default&quot; item, so we copy that value to the other
 /// item.
 /// </remarks>
 /// <param name="arrayNode">an alt text array node</param>
 internal static void NormalizeLangArray(XMPNode arrayNode)
 {
     if (!arrayNode.GetOptions().IsArrayAltText())
     {
         return;
     }
     // check if node with x-default qual is first place
     for (int i = 2; i <= arrayNode.GetChildrenLength(); i++)
     {
         XMPNode child = arrayNode.GetChild(i);
         if (child.HasQualifier() && XMPConstConstants.XDefault.Equals(child.GetQualifier(1).GetValue()))
         {
             // move node to first place
             try
             {
                 arrayNode.RemoveChild(i);
                 arrayNode.AddChild(1, child);
             }
             catch (XMPException)
             {
                 // cannot occur, because same child is removed before
                 System.Diagnostics.Debug.Assert(false);
             }
             if (i == 2)
             {
                 arrayNode.GetChild(2).SetValue(child.GetValue());
             }
             break;
         }
     }
 }
Exemple #5
0
 /// <summary>Constructor</summary>
 /// <param name="parentNode">the node which children shall be iterated.</param>
 /// <param name="parentPath">the full path of the former node without the leaf node.</param>
 public NodeIteratorChildren(XMPIteratorImpl _enclosing, XMPNode parentNode, string parentPath)
     : base(_enclosing)
 {
     this._enclosing = _enclosing;
     if (parentNode.GetOptions().IsSchemaNode())
     {
         this._enclosing.SetBaseNS(parentNode.GetName());
     }
     this.parentPath       = this.AccumulatePath(parentNode, parentPath, 1);
     this.childrenIterator = parentNode.IterateChildren();
 }
 /// <summary>
 /// Undo the denormalization performed by the XMP used in Acrobat 5.<br />
 /// If a Dublin Core array had only one item, it was serialized as a simple
 /// property.
 /// </summary>
 /// <remarks>
 /// Undo the denormalization performed by the XMP used in Acrobat 5.<br />
 /// If a Dublin Core array had only one item, it was serialized as a simple
 /// property. <br />
 /// The <code>xml:lang</code> attribute was dropped from an
 /// <code>alt-text</code> item if the language was <code>x-default</code>.
 /// </remarks>
 /// <param name="dcSchema">the DC schema node</param>
 /// <exception cref="Com.Adobe.Xmp.XMPException">Thrown if normalization fails</exception>
 private static void NormalizeDCArrays(XMPNode dcSchema)
 {
     for (int i = 1; i <= dcSchema.GetChildrenLength(); i++)
     {
         XMPNode         currProp  = dcSchema.GetChild(i);
         PropertyOptions arrayForm = (PropertyOptions)dcArrayForms.Get(currProp.GetName());
         if (arrayForm == null)
         {
             continue;
         }
         else
         {
             if (currProp.GetOptions().IsSimple())
             {
                 // create a new array and add the current property as child,
                 // if it was formerly simple
                 XMPNode newArray = new XMPNode(currProp.GetName(), arrayForm);
                 currProp.SetName(XMPConstConstants.ArrayItemName);
                 newArray.AddChild(currProp);
                 dcSchema.ReplaceChild(i, newArray);
                 // fix language alternatives
                 if (arrayForm.IsArrayAltText() && !currProp.GetOptions().GetHasLanguage())
                 {
                     XMPNode newLang = new XMPNode(XMPConstConstants.XmlLang, XMPConstConstants.XDefault, null);
                     currProp.AddQualifier(newLang);
                 }
             }
             else
             {
                 // clear array options and add corrected array form if it has been an array before
                 currProp.GetOptions().SetOption(PropertyOptions.Array | PropertyOptions.ArrayOrdered | PropertyOptions.ArrayAlternate | PropertyOptions.ArrayAltText, false);
                 currProp.GetOptions().MergeWith(arrayForm);
                 if (arrayForm.IsArrayAltText())
                 {
                     // applying for "dc:description", "dc:rights", "dc:title"
                     RepairAltText(currProp);
                 }
             }
         }
     }
 }
Exemple #7
0
 /// <summary>See if an array is an alt-text array.</summary>
 /// <remarks>
 /// See if an array is an alt-text array. If so, make sure the x-default item
 /// is first.
 /// </remarks>
 /// <param name="arrayNode">the array node to check if its an alt-text array</param>
 internal static void DetectAltText(XMPNode arrayNode)
 {
     if (arrayNode.GetOptions().IsArrayAlternate() && arrayNode.HasChildren())
     {
         bool isAltText = false;
         for (Iterator it = arrayNode.IterateChildren(); it.HasNext();)
         {
             XMPNode child = (XMPNode)it.Next();
             if (child.GetOptions().GetHasLanguage())
             {
                 isAltText = true;
                 break;
             }
         }
         if (isAltText)
         {
             arrayNode.GetOptions().SetArrayAltText(true);
             NormalizeLangArray(arrayNode);
         }
     }
 }
Exemple #8
0
 /// <summary>Constructor for the node iterator.</summary>
 /// <param name="visitedNode">the currently visited node</param>
 /// <param name="parentPath">the accumulated path of the node</param>
 /// <param name="index">the index within the parent node (only for arrays)</param>
 public NodeIterator(XMPIteratorImpl _enclosing, XMPNode visitedNode, string parentPath, int index)
 {
     this._enclosing = _enclosing;
     // EMPTY
     this.visitedNode = visitedNode;
     this.state       = XMPIteratorImpl.NodeIterator.IterateNode;
     if (visitedNode.GetOptions().IsSchemaNode())
     {
         this._enclosing.SetBaseNS(visitedNode.GetName());
     }
     // for all but the root node and schema nodes
     this.path = this.AccumulatePath(visitedNode, parentPath, index);
 }
Exemple #9
0
        /// <summary>This is setting the value of a leaf node.</summary>
        /// <param name="node">an XMPNode</param>
        /// <param name="value">a value</param>
        internal static void SetNodeValue(XMPNode node, object value)
        {
            string strValue = SerializeNodeValue(value);

            if (!(node.GetOptions().IsQualifier() && XMPConstConstants.XmlLang.Equals(node.GetName())))
            {
                node.SetValue(strValue);
            }
            else
            {
                node.SetValue(Utils.NormalizeLangValue(strValue));
            }
        }
Exemple #10
0
 /// <summary>Prepares the next node to return if not already done.</summary>
 /// <seealso cref="Sharpen.Iterator{E}.HasNext()"/>
 public override bool HasNext()
 {
     if (this.GetReturnProperty() != null)
     {
         // hasNext has been called before
         return(true);
     }
     else
     {
         if (this._enclosing.skipSiblings)
         {
             return(false);
         }
         else
         {
             if (this.childrenIterator.HasNext())
             {
                 XMPNode child = (XMPNode)this.childrenIterator.Next();
                 this.index++;
                 string path = null;
                 if (child.GetOptions().IsSchemaNode())
                 {
                     this._enclosing.SetBaseNS(child.GetName());
                 }
                 else
                 {
                     if (child.GetParent() != null)
                     {
                         // for all but the root node and schema nodes
                         path = this.AccumulatePath(child, this.parentPath, this.index);
                     }
                 }
                 // report next property, skip not-leaf nodes in case options is set
                 if (!this._enclosing.GetOptions().IsJustLeafnodes() || !child.HasChildren())
                 {
                     this.SetReturnProperty(this.CreatePropertyInfo(child, this._enclosing.GetBaseNS(), path));
                     return(true);
                 }
                 else
                 {
                     return(this.HasNext());
                 }
             }
             else
             {
                 return(false);
             }
         }
     }
 }
 /// <summary>Make sure that the array is well-formed AltText.</summary>
 /// <remarks>
 /// Make sure that the array is well-formed AltText. Each item must be simple
 /// and have an "xml:lang" qualifier. If repairs are needed, keep simple
 /// non-empty items by adding the "xml:lang" with value "x-repair".
 /// </remarks>
 /// <param name="arrayNode">the property node of the array to repair.</param>
 /// <exception cref="Com.Adobe.Xmp.XMPException">Forwards unexpected exceptions.</exception>
 private static void RepairAltText(XMPNode arrayNode)
 {
     if (arrayNode == null || !arrayNode.GetOptions().IsArray())
     {
         // Already OK or not even an array.
         return;
     }
     // fix options
     arrayNode.GetOptions().SetArrayOrdered(true).SetArrayAlternate(true).SetArrayAltText(true);
     for (Iterator it = arrayNode.IterateChildren(); it.HasNext();)
     {
         XMPNode currChild = (XMPNode)it.Next();
         if (currChild.GetOptions().IsCompositeProperty())
         {
             // Delete non-simple children.
             it.Remove();
         }
         else
         {
             if (!currChild.GetOptions().GetHasLanguage())
             {
                 string childValue = currChild.GetValue();
                 if (childValue == null || childValue.Length == 0)
                 {
                     // Delete empty valued children that have no xml:lang.
                     it.Remove();
                 }
                 else
                 {
                     // Add an xml:lang qualifier with the value "x-repair".
                     XMPNode repairLang = new XMPNode(XMPConstConstants.XmlLang, "x-repair", null);
                     currChild.AddQualifier(repairLang);
                 }
             }
         }
     }
 }
 /// <summary>Moves an alias node of array form to another schema into an array</summary>
 /// <param name="propertyIt">the property iterator of the old schema (used to delete the property)</param>
 /// <param name="childNode">the node to be moved</param>
 /// <param name="baseArray">the base array for the array item</param>
 /// <exception cref="Com.Adobe.Xmp.XMPException">Forwards XMP errors</exception>
 private static void TransplantArrayItemAlias(Iterator propertyIt, XMPNode childNode, XMPNode baseArray)
 {
     if (baseArray.GetOptions().IsArrayAltText())
     {
         if (childNode.GetOptions().GetHasLanguage())
         {
             throw new XMPException("Alias to x-default already has a language qualifier", XMPErrorConstants.Badxmp);
         }
         XMPNode langQual = new XMPNode(XMPConstConstants.XmlLang, XMPConstConstants.XDefault, null);
         childNode.AddQualifier(langQual);
     }
     propertyIt.Remove();
     childNode.SetName(XMPConstConstants.ArrayItemName);
     baseArray.AddChild(childNode);
 }
Exemple #13
0
        /// <summary>Deletes the the given node and its children from its parent.</summary>
        /// <remarks>
        /// Deletes the the given node and its children from its parent.
        /// Takes care about adjusting the flags.
        /// </remarks>
        /// <param name="node">the top-most node to delete.</param>
        internal static void DeleteNode(XMPNode node)
        {
            XMPNode parent = node.GetParent();

            if (node.GetOptions().IsQualifier())
            {
                // root is qualifier
                parent.RemoveQualifier(node);
            }
            else
            {
                // root is NO qualifier
                parent.RemoveChild(node);
            }
            // delete empty Schema nodes
            if (!parent.HasChildren() && parent.GetOptions().IsSchemaNode())
            {
                parent.GetParent().RemoveChild(parent);
            }
        }
Exemple #14
0
            /// <param name="currNode">the node that will be added to the path.</param>
            /// <param name="parentPath">the path up to this node.</param>
            /// <param name="currentIndex">the current array index if an arrey is traversed</param>
            /// <returns>Returns the updated path.</returns>
            protected internal virtual string AccumulatePath(XMPNode currNode, string parentPath, int currentIndex)
            {
                string separator;
                string segmentName;

                if (currNode.GetParent() == null || currNode.GetOptions().IsSchemaNode())
                {
                    return(null);
                }
                else
                {
                    if (currNode.GetParent().GetOptions().IsArray())
                    {
                        separator   = string.Empty;
                        segmentName = "[" + currentIndex.ToString() + "]";
                    }
                    else
                    {
                        separator   = "/";
                        segmentName = currNode.GetName();
                    }
                }
                if (parentPath == null || parentPath.Length == 0)
                {
                    return(segmentName);
                }
                else
                {
                    if (this._enclosing.GetOptions().IsJustLeafname())
                    {
                        return(!segmentName.StartsWith("?") ? segmentName : Sharpen.Runtime.Substring(segmentName, 1));
                    }
                    else
                    {
                        // qualifier
                        return(parentPath + separator + segmentName);
                    }
                }
            }
Exemple #15
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="Com.Adobe.Xmp.XMPException">Forwards exceptions</exception>
        private static XMPNode SeparateFindCreateArray(string schemaNS, string arrayName, PropertyOptions arrayOptions, XMPMetaImpl xmp)
        {
            arrayOptions = XMPNodeUtils.VerifySetOptions(arrayOptions, null);
            if (!arrayOptions.IsOnlyArrayOptions())
            {
                throw new XMPException("Options can only provide array form", XMPErrorConstants.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.GetRoot(), arrayPath, false, null);

            if (arrayNode != null)
            {
                // The array exists, make sure the form is compatible. Zero
                // arrayForm means take what exists.
                PropertyOptions arrayForm = arrayNode.GetOptions();
                if (!arrayForm.IsArray() || arrayForm.IsArrayAlternate())
                {
                    throw new XMPException("Named property must be non-alternate array", XMPErrorConstants.Badxpath);
                }
                if (arrayOptions.EqualArrayTypes(arrayForm))
                {
                    throw new XMPException("Mismatch of specified and existing array form", XMPErrorConstants.Badxpath);
                }
            }
            else
            {
                // *** Right error?
                // The array does not exist, try to create it.
                // don't modify the options handed into the method
                arrayNode = XMPNodeUtils.FindNode(xmp.GetRoot(), arrayPath, true, arrayOptions.SetArray(true));
                if (arrayNode == null)
                {
                    throw new XMPException("Failed to create named array", XMPErrorConstants.Badxpath);
                }
            }
            return(arrayNode);
        }
Exemple #16
0
 /// <summary>Looks for the appropriate language item in a text alternative array.item</summary>
 /// <param name="arrayNode">an array node</param>
 /// <param name="language">the requested language</param>
 /// <returns>Returns the index if the language has been found, -1 otherwise.</returns>
 /// <exception cref="Com.Adobe.Xmp.XMPException"/>
 internal static int LookupLanguageItem(XMPNode arrayNode, string language)
 {
     if (!arrayNode.GetOptions().IsArray())
     {
         throw new XMPException("Language item must be used on array", XMPErrorConstants.Badxpath);
     }
     for (int index = 1; index <= arrayNode.GetChildrenLength(); index++)
     {
         XMPNode child = arrayNode.GetChild(index);
         if (!child.HasQualifier() || !XMPConstConstants.XmlLang.Equals(child.GetQualifier(1).GetName()))
         {
             continue;
         }
         else
         {
             if (language.Equals(child.GetQualifier(1).GetValue()))
             {
                 return(index);
             }
         }
     }
     return(-1);
 }
 /// <summary>The outermost call is special.</summary>
 /// <remarks>
 /// The outermost call is special. The names almost certainly differ. The
 /// qualifiers (and hence options) will differ for an alias to the x-default
 /// item of a langAlt array.
 /// </remarks>
 /// <param name="aliasNode">the alias node</param>
 /// <param name="baseNode">the base node of the alias</param>
 /// <param name="outerCall">marks the outer call of the recursion</param>
 /// <exception cref="Com.Adobe.Xmp.XMPException">Forwards XMP errors</exception>
 private static void CompareAliasedSubtrees(XMPNode aliasNode, XMPNode baseNode, bool outerCall)
 {
     if (!aliasNode.GetValue().Equals(baseNode.GetValue()) || aliasNode.GetChildrenLength() != baseNode.GetChildrenLength())
     {
         throw new XMPException("Mismatch between alias and base nodes", XMPErrorConstants.Badxmp);
     }
     if (!outerCall && (!aliasNode.GetName().Equals(baseNode.GetName()) || !aliasNode.GetOptions().Equals(baseNode.GetOptions()) || aliasNode.GetQualifierLength() != baseNode.GetQualifierLength()))
     {
         throw new XMPException("Mismatch between alias and base nodes", XMPErrorConstants.Badxmp);
     }
     for (Iterator an = aliasNode.IterateChildren(), bn = baseNode.IterateChildren(); an.HasNext() && bn.HasNext(); )
     {
         XMPNode aliasChild = (XMPNode)an.Next();
         XMPNode baseChild = (XMPNode)bn.Next();
         CompareAliasedSubtrees(aliasChild, baseChild, false);
     }
     for (Iterator an_1 = aliasNode.IterateQualifier(), bn_1 = baseNode.IterateQualifier(); an_1.HasNext() && bn_1.HasNext(); )
     {
         XMPNode aliasQual = (XMPNode)an_1.Next();
         XMPNode baseQual = (XMPNode)bn_1.Next();
         CompareAliasedSubtrees(aliasQual, baseQual, false);
     }
 }
 /// <summary>The outermost call is special.</summary>
 /// <remarks>
 /// The outermost call is special. The names almost certainly differ. The
 /// qualifiers (and hence options) will differ for an alias to the x-default
 /// item of a langAlt array.
 /// </remarks>
 /// <param name="aliasNode">the alias node</param>
 /// <param name="baseNode">the base node of the alias</param>
 /// <param name="outerCall">marks the outer call of the recursion</param>
 /// <exception cref="Com.Adobe.Xmp.XMPException">Forwards XMP errors</exception>
 private static void CompareAliasedSubtrees(XMPNode aliasNode, XMPNode baseNode, bool outerCall)
 {
     if (!aliasNode.GetValue().Equals(baseNode.GetValue()) || aliasNode.GetChildrenLength() != baseNode.GetChildrenLength())
     {
         throw new XMPException("Mismatch between alias and base nodes", XMPErrorConstants.Badxmp);
     }
     if (!outerCall && (!aliasNode.GetName().Equals(baseNode.GetName()) || !aliasNode.GetOptions().Equals(baseNode.GetOptions()) || aliasNode.GetQualifierLength() != baseNode.GetQualifierLength()))
     {
         throw new XMPException("Mismatch between alias and base nodes", XMPErrorConstants.Badxmp);
     }
     for (Iterator an = aliasNode.IterateChildren(), bn = baseNode.IterateChildren(); an.HasNext() && bn.HasNext();)
     {
         XMPNode aliasChild = (XMPNode)an.Next();
         XMPNode baseChild  = (XMPNode)bn.Next();
         CompareAliasedSubtrees(aliasChild, baseChild, false);
     }
     for (Iterator an_1 = aliasNode.IterateQualifier(), bn_1 = baseNode.IterateQualifier(); an_1.HasNext() && bn_1.HasNext();)
     {
         XMPNode aliasQual = (XMPNode)an_1.Next();
         XMPNode baseQual  = (XMPNode)bn_1.Next();
         CompareAliasedSubtrees(aliasQual, baseQual, false);
     }
 }
		/// <summary>Serializes a simple property.</summary>
		/// <param name="node">an XMPNode</param>
		/// <returns>Returns an array containing the flags emitEndTag and indentEndTag.</returns>
		/// <exception cref="System.IO.IOException">Forwards the writer exceptions.</exception>
		private object[] SerializeCompactRDFSimpleProp(XMPNode node)
		{
			// This is a simple property.
			bool emitEndTag = true;
			bool indentEndTag = true;
			if (node.GetOptions().IsURI())
			{
				Write(" rdf:resource=\"");
				AppendNodeValue(node.GetValue(), true);
				Write("\"/>");
				WriteNewline();
				emitEndTag = false;
			}
			else
			{
				if (node.GetValue() == null || node.GetValue().Length == 0)
				{
					Write("/>");
					WriteNewline();
					emitEndTag = false;
				}
				else
				{
					Write('>');
					AppendNodeValue(node.GetValue(), false);
					indentEndTag = false;
				}
			}
			return new object[] { emitEndTag, indentEndTag };
		}
 /// <summary>Deletes the the given node and its children from its parent.</summary>
 /// <remarks>
 /// Deletes the the given node and its children from its parent.
 /// Takes care about adjusting the flags.
 /// </remarks>
 /// <param name="node">the top-most node to delete.</param>
 internal static void DeleteNode(XMPNode node)
 {
     XMPNode parent = node.GetParent();
     if (node.GetOptions().IsQualifier())
     {
         // root is qualifier
         parent.RemoveQualifier(node);
     }
     else
     {
         // root is NO qualifier
         parent.RemoveChild(node);
     }
     // delete empty Schema nodes
     if (!parent.HasChildren() && parent.GetOptions().IsSchemaNode())
     {
         parent.GetParent().RemoveChild(parent);
     }
 }
		/// <summary>Recursively handles the "value" for a node.</summary>
		/// <remarks>
		/// Recursively handles the "value" for a node. It does not matter if it is a
		/// top level property, a field of a struct, or an item of an array. The
		/// indent is that for the property element. An xml:lang qualifier is written
		/// as an attribute of the property start tag, not by itself forcing the
		/// qualified property form. The patterns below mostly ignore attribute
		/// qualifiers like xml:lang. Except for the one struct case, attribute
		/// qualifiers don't affect the output form.
		/// <blockquote>
		/// <pre>
		/// &lt;ns:UnqualifiedSimpleProperty&gt;value&lt;/ns:UnqualifiedSimpleProperty&gt;
		/// &lt;ns:UnqualifiedStructProperty&gt; (If no rdf:resource qualifier)
		/// &lt;rdf:Description&gt;
		/// ... Fields, same forms as top level properties
		/// &lt;/rdf:Description&gt;
		/// &lt;/ns:UnqualifiedStructProperty&gt;
		/// &lt;ns:ResourceStructProperty rdf:resource=&quot;URI&quot;
		/// ... Fields as attributes
		/// &gt;
		/// &lt;ns:UnqualifiedArrayProperty&gt;
		/// &lt;rdf:Bag&gt; or Seq or Alt
		/// ... Array items as rdf:li elements, same forms as top level properties
		/// &lt;/rdf:Bag&gt;
		/// &lt;/ns:UnqualifiedArrayProperty&gt;
		/// &lt;ns:QualifiedProperty&gt;
		/// &lt;rdf:Description&gt;
		/// &lt;rdf:value&gt; ... Property &quot;value&quot; following the unqualified
		/// forms ... &lt;/rdf:value&gt;
		/// ... Qualifiers looking like named struct fields
		/// &lt;/rdf:Description&gt;
		/// &lt;/ns:QualifiedProperty&gt;
		/// </pre>
		/// </blockquote>
		/// </remarks>
		/// <param name="node">the property node</param>
		/// <param name="emitAsRDFValue">property shall be rendered as attribute rather than tag</param>
		/// <param name="useCanonicalRDF">
		/// use canonical form with inner description tag or
		/// the compact form with rdf:ParseType=&quot;resource&quot; attribute.
		/// </param>
		/// <param name="indent">the current indent level</param>
		/// <exception cref="System.IO.IOException">Forwards all writer exceptions.</exception>
		/// <exception cref="Com.Adobe.Xmp.XMPException">If &quot;rdf:resource&quot; and general qualifiers are mixed.</exception>
		private void SerializeCanonicalRDFProperty(XMPNode node, bool useCanonicalRDF, bool emitAsRDFValue, int indent)
		{
			bool emitEndTag = true;
			bool indentEndTag = true;
			// Determine the XML element name. Open the start tag with the name and
			// attribute qualifiers.
			string elemName = node.GetName();
			if (emitAsRDFValue)
			{
				elemName = "rdf:value";
			}
			else
			{
				if (XMPConstConstants.ArrayItemName.Equals(elemName))
				{
					elemName = "rdf:li";
				}
			}
			WriteIndent(indent);
			Write('<');
			Write(elemName);
			bool hasGeneralQualifiers = false;
			bool hasRDFResourceQual = false;
			for (Iterator it = node.IterateQualifier(); it.HasNext(); )
			{
				XMPNode qualifier = (XMPNode)it.Next();
				if (!RdfAttrQualifier.Contains(qualifier.GetName()))
				{
					hasGeneralQualifiers = true;
				}
				else
				{
					hasRDFResourceQual = "rdf:resource".Equals(qualifier.GetName());
					if (!emitAsRDFValue)
					{
						Write(' ');
						Write(qualifier.GetName());
						Write("=\"");
						AppendNodeValue(qualifier.GetValue(), true);
						Write('"');
					}
				}
			}
			// Process the property according to the standard patterns.
			if (hasGeneralQualifiers && !emitAsRDFValue)
			{
				// This node has general, non-attribute, qualifiers. Emit using the
				// qualified property form.
				// ! The value is output by a recursive call ON THE SAME NODE with
				// emitAsRDFValue set.
				if (hasRDFResourceQual)
				{
					throw new XMPException("Can't mix rdf:resource and general qualifiers", XMPErrorConstants.Badrdf);
				}
				// Change serialization to canonical format with inner rdf:Description-tag
				// depending on option
				if (useCanonicalRDF)
				{
					Write(">");
					WriteNewline();
					indent++;
					WriteIndent(indent);
					Write(RdfStructStart);
					Write(">");
				}
				else
				{
					Write(" rdf:parseType=\"Resource\">");
				}
				WriteNewline();
				SerializeCanonicalRDFProperty(node, useCanonicalRDF, true, indent + 1);
				for (Iterator it_1 = node.IterateQualifier(); it_1.HasNext(); )
				{
					XMPNode qualifier = (XMPNode)it_1.Next();
					if (!RdfAttrQualifier.Contains(qualifier.GetName()))
					{
						SerializeCanonicalRDFProperty(qualifier, useCanonicalRDF, false, indent + 1);
					}
				}
				if (useCanonicalRDF)
				{
					WriteIndent(indent);
					Write(RdfStructEnd);
					WriteNewline();
					indent--;
				}
			}
			else
			{
				// This node has no general qualifiers. Emit using an unqualified form.
				if (!node.GetOptions().IsCompositeProperty())
				{
					// This is a simple property.
					if (node.GetOptions().IsURI())
					{
						Write(" rdf:resource=\"");
						AppendNodeValue(node.GetValue(), true);
						Write("\"/>");
						WriteNewline();
						emitEndTag = false;
					}
					else
					{
						if (node.GetValue() == null || string.Empty.Equals(node.GetValue()))
						{
							Write("/>");
							WriteNewline();
							emitEndTag = false;
						}
						else
						{
							Write('>');
							AppendNodeValue(node.GetValue(), false);
							indentEndTag = false;
						}
					}
				}
				else
				{
					if (node.GetOptions().IsArray())
					{
						// This is an array.
						Write('>');
						WriteNewline();
						EmitRDFArrayTag(node, true, indent + 1);
						if (node.GetOptions().IsArrayAltText())
						{
							XMPNodeUtils.NormalizeLangArray(node);
						}
						for (Iterator it_1 = node.IterateChildren(); it_1.HasNext(); )
						{
							XMPNode child = (XMPNode)it_1.Next();
							SerializeCanonicalRDFProperty(child, useCanonicalRDF, false, indent + 2);
						}
						EmitRDFArrayTag(node, false, indent + 1);
					}
					else
					{
						if (!hasRDFResourceQual)
						{
							// This is a "normal" struct, use the rdf:parseType="Resource" form.
							if (!node.HasChildren())
							{
								// Change serialization to canonical format with inner rdf:Description-tag
								// if option is set
								if (useCanonicalRDF)
								{
									Write(">");
									WriteNewline();
									WriteIndent(indent + 1);
									Write(RdfEmptyStruct);
								}
								else
								{
									Write(" rdf:parseType=\"Resource\"/>");
									emitEndTag = false;
								}
								WriteNewline();
							}
							else
							{
								// Change serialization to canonical format with inner rdf:Description-tag
								// if option is set
								if (useCanonicalRDF)
								{
									Write(">");
									WriteNewline();
									indent++;
									WriteIndent(indent);
									Write(RdfStructStart);
									Write(">");
								}
								else
								{
									Write(" rdf:parseType=\"Resource\">");
								}
								WriteNewline();
								for (Iterator it_1 = node.IterateChildren(); it_1.HasNext(); )
								{
									XMPNode child = (XMPNode)it_1.Next();
									SerializeCanonicalRDFProperty(child, useCanonicalRDF, false, indent + 1);
								}
								if (useCanonicalRDF)
								{
									WriteIndent(indent);
									Write(RdfStructEnd);
									WriteNewline();
									indent--;
								}
							}
						}
						else
						{
							// This is a struct with an rdf:resource attribute, use the
							// "empty property element" form.
							for (Iterator it_1 = node.IterateChildren(); it_1.HasNext(); )
							{
								XMPNode child = (XMPNode)it_1.Next();
								if (!CanBeRDFAttrProp(child))
								{
									throw new XMPException("Can't mix rdf:resource and complex fields", XMPErrorConstants.Badrdf);
								}
								WriteNewline();
								WriteIndent(indent + 1);
								Write(' ');
								Write(child.GetName());
								Write("=\"");
								AppendNodeValue(child.GetValue(), true);
								Write('"');
							}
							Write("/>");
							WriteNewline();
							emitEndTag = false;
						}
					}
				}
			}
			// Emit the property element end tag.
			if (emitEndTag)
			{
				if (indentEndTag)
				{
					WriteIndent(indent);
				}
				Write("</");
				Write(elemName);
				Write('>');
				WriteNewline();
			}
		}
Exemple #22
0
        /// <summary>
        /// After processing by ExpandXPath, a step can be of these forms:
        /// <ul>
        /// <li>qualName - A top level property or struct field.
        /// </summary>
        /// <remarks>
        /// After processing by ExpandXPath, a step can be of these forms:
        /// <ul>
        /// <li>qualName - A top level property or struct field.
        /// <li>[index] - An element of an array.
        /// <li>[last()] - The last element of an array.
        /// <li>[qualName="value"] - An element in an array of structs, chosen by a field value.
        /// <li>[?qualName="value"] - An element in an array, chosen by a qualifier value.
        /// <li>?qualName - A general qualifier.
        /// </ul>
        /// Find the appropriate child node, resolving aliases, and optionally creating nodes.
        /// </remarks>
        /// <param name="parentNode">the node to start to start from</param>
        /// <param name="nextStep">the xpath segment</param>
        /// <param name="createNodes"></param>
        /// <returns>returns the found or created XMPPath node</returns>
        /// <exception cref="Com.Adobe.Xmp.XMPException"></exception>
        private static XMPNode FollowXPathStep(XMPNode parentNode, XMPPathSegment nextStep, bool createNodes)
        {
            XMPNode nextNode = null;
            int     index    = 0;
            int     stepKind = nextStep.GetKind();

            if (stepKind == XMPPath.StructFieldStep)
            {
                nextNode = FindChildNode(parentNode, nextStep.GetName(), createNodes);
            }
            else
            {
                if (stepKind == XMPPath.QualifierStep)
                {
                    nextNode = FindQualifierNode(parentNode, Sharpen.Runtime.Substring(nextStep.GetName(), 1), createNodes);
                }
                else
                {
                    // This is an array indexing step. First get the index, then get the node.
                    if (!parentNode.GetOptions().IsArray())
                    {
                        throw new XMPException("Indexing applied to non-array", XMPErrorConstants.Badxpath);
                    }
                    if (stepKind == XMPPath.ArrayIndexStep)
                    {
                        index = FindIndexedItem(parentNode, nextStep.GetName(), createNodes);
                    }
                    else
                    {
                        if (stepKind == XMPPath.ArrayLastStep)
                        {
                            index = parentNode.GetChildrenLength();
                        }
                        else
                        {
                            if (stepKind == XMPPath.FieldSelectorStep)
                            {
                                string[] result     = Utils.SplitNameAndValue(nextStep.GetName());
                                string   fieldName  = result[0];
                                string   fieldValue = result[1];
                                index = LookupFieldSelector(parentNode, fieldName, fieldValue);
                            }
                            else
                            {
                                if (stepKind == XMPPath.QualSelectorStep)
                                {
                                    string[] result    = Utils.SplitNameAndValue(nextStep.GetName());
                                    string   qualName  = result[0];
                                    string   qualValue = result[1];
                                    index = LookupQualSelector(parentNode, qualName, qualValue, nextStep.GetAliasForm());
                                }
                                else
                                {
                                    throw new XMPException("Unknown array indexing step in FollowXPathStep", XMPErrorConstants.Internalfailure);
                                }
                            }
                        }
                    }
                    if (1 <= index && index <= parentNode.GetChildrenLength())
                    {
                        nextNode = parentNode.GetChild(index);
                    }
                }
            }
            return(nextNode);
        }
 /// <summary>The parent is an RDF pseudo-struct containing an rdf:value field.</summary>
 /// <remarks>
 /// The parent is an RDF pseudo-struct containing an rdf:value field. Fix the
 /// XMP data model. The rdf:value node must be the first child, the other
 /// children are qualifiers. The form, value, and children of the rdf:value
 /// node are the real ones. The rdf:value node's qualifiers must be added to
 /// the others.
 /// </remarks>
 /// <param name="xmpParent">the parent xmp node</param>
 /// <exception cref="Com.Adobe.Xmp.XMPException">thown on parsing errors</exception>
 private static void FixupQualifiedNode(XMPNode xmpParent)
 {
     System.Diagnostics.Debug.Assert(xmpParent.GetOptions().IsStruct() && xmpParent.HasChildren());
     XMPNode valueNode = xmpParent.GetChild(1);
     System.Diagnostics.Debug.Assert("rdf:value".Equals(valueNode.GetName()));
     // Move the qualifiers on the value node to the parent.
     // Make sure an xml:lang qualifier stays at the front.
     // Check for duplicate names between the value node's qualifiers and the parent's children.
     // The parent's children are about to become qualifiers. Check here, between the groups.
     // Intra-group duplicates are caught by XMPNode#addChild(...).
     if (valueNode.GetOptions().GetHasLanguage())
     {
         if (xmpParent.GetOptions().GetHasLanguage())
         {
             throw new XMPException("Redundant xml:lang for rdf:value element", XMPErrorConstants.Badxmp);
         }
         XMPNode langQual = valueNode.GetQualifier(1);
         valueNode.RemoveQualifier(langQual);
         xmpParent.AddQualifier(langQual);
     }
     // Start the remaining copy after the xml:lang qualifier.
     for (int i = 1; i <= valueNode.GetQualifierLength(); i++)
     {
         XMPNode qualifier = valueNode.GetQualifier(i);
         xmpParent.AddQualifier(qualifier);
     }
     // Change the parent's other children into qualifiers.
     // This loop starts at 1, child 0 is the rdf:value node.
     for (int i_1 = 2; i_1 <= xmpParent.GetChildrenLength(); i_1++)
     {
         XMPNode qualifier = xmpParent.GetChild(i_1);
         xmpParent.AddQualifier(qualifier);
     }
     // Move the options and value last, other checks need the parent's original options.
     // Move the value node's children to be the parent's children.
     System.Diagnostics.Debug.Assert(xmpParent.GetOptions().IsStruct() || xmpParent.GetHasValueChild());
     xmpParent.SetHasValueChild(false);
     xmpParent.GetOptions().SetStruct(false);
     xmpParent.GetOptions().MergeWith(valueNode.GetOptions());
     xmpParent.SetValue(valueNode.GetValue());
     xmpParent.RemoveChildren();
     for (Iterator it = valueNode.IterateChildren(); it.HasNext(); )
     {
         XMPNode child = (XMPNode)it.Next();
         xmpParent.AddChild(child);
     }
 }
 /// <summary>Find or create a child node under a given parent node.</summary>
 /// <remarks>
 /// Find or create a child node under a given parent node. If the parent node is no
 /// Returns the found or created child node.
 /// </remarks>
 /// <param name="parent">the parent node</param>
 /// <param name="childName">the node name to find</param>
 /// <param name="createNodes">flag, if new nodes shall be created.</param>
 /// <returns>Returns the found or created node or <code>null</code>.</returns>
 /// <exception cref="Com.Adobe.Xmp.XMPException">Thrown if</exception>
 internal static XMPNode FindChildNode(XMPNode parent, string childName, bool createNodes)
 {
     if (!parent.GetOptions().IsSchemaNode() && !parent.GetOptions().IsStruct())
     {
         if (!parent.IsImplicit())
         {
             throw new XMPException("Named children only allowed for schemas and structs", XMPErrorConstants.Badxpath);
         }
         else
         {
             if (parent.GetOptions().IsArray())
             {
                 throw new XMPException("Named children not allowed for arrays", XMPErrorConstants.Badxpath);
             }
             else
             {
                 if (createNodes)
                 {
                     parent.GetOptions().SetStruct(true);
                 }
             }
         }
     }
     XMPNode childNode = parent.FindChildByName(childName);
     if (childNode == null && createNodes)
     {
         PropertyOptions options = new PropertyOptions();
         childNode = new XMPNode(childName, options);
         childNode.SetImplicit(true);
         parent.AddChild(childNode);
     }
     System.Diagnostics.Debug.Assert(childNode != null || !createNodes);
     return childNode;
 }
		/// <summary>
		/// A node can be serialized as RDF-Attribute, if it meets the following conditions:
		/// <ul>
		/// <li>is not array item
		/// <li>don't has qualifier
		/// <li>is no URI
		/// <li>is no composite property
		/// </ul>
		/// </summary>
		/// <param name="node">an XMPNode</param>
		/// <returns>Returns true if the node serialized as RDF-Attribute</returns>
		private bool CanBeRDFAttrProp(XMPNode node)
		{
			return !node.HasQualifier() && !node.GetOptions().IsURI() && !node.GetOptions().IsCompositeProperty() && !XMPConstConstants.ArrayItemName.Equals(node.GetName());
		}
 /// <param name="currNode">the node that will be added to the path.</param>
 /// <param name="parentPath">the path up to this node.</param>
 /// <param name="currentIndex">the current array index if an arrey is traversed</param>
 /// <returns>Returns the updated path.</returns>
 protected internal virtual string AccumulatePath(XMPNode currNode, string parentPath, int currentIndex)
 {
     string separator;
     string segmentName;
     if (currNode.GetParent() == null || currNode.GetOptions().IsSchemaNode())
     {
         return null;
     }
     else
     {
         if (currNode.GetParent().GetOptions().IsArray())
         {
             separator = string.Empty;
             segmentName = "[" + currentIndex.ToString() + "]";
         }
         else
         {
             separator = "/";
             segmentName = currNode.GetName();
         }
     }
     if (parentPath == null || parentPath.Length == 0)
     {
         return segmentName;
     }
     else
     {
         if (this._enclosing.GetOptions().IsJustLeafname())
         {
             return !segmentName.StartsWith("?") ? segmentName : Sharpen.Runtime.Substring(segmentName, 1);
         }
         else
         {
             // qualifier
             return parentPath + separator + segmentName;
         }
     }
 }
 /// <summary>
 /// After processing by ExpandXPath, a step can be of these forms:
 /// <ul>
 /// <li>qualName - A top level property or struct field.
 /// </summary>
 /// <remarks>
 /// After processing by ExpandXPath, a step can be of these forms:
 /// <ul>
 /// <li>qualName - A top level property or struct field.
 /// <li>[index] - An element of an array.
 /// <li>[last()] - The last element of an array.
 /// <li>[qualName="value"] - An element in an array of structs, chosen by a field value.
 /// <li>[?qualName="value"] - An element in an array, chosen by a qualifier value.
 /// <li>?qualName - A general qualifier.
 /// </ul>
 /// Find the appropriate child node, resolving aliases, and optionally creating nodes.
 /// </remarks>
 /// <param name="parentNode">the node to start to start from</param>
 /// <param name="nextStep">the xpath segment</param>
 /// <param name="createNodes"></param>
 /// <returns>returns the found or created XMPPath node</returns>
 /// <exception cref="Com.Adobe.Xmp.XMPException"></exception>
 private static XMPNode FollowXPathStep(XMPNode parentNode, XMPPathSegment nextStep, bool createNodes)
 {
     XMPNode nextNode = null;
     int index = 0;
     int stepKind = nextStep.GetKind();
     if (stepKind == XMPPath.StructFieldStep)
     {
         nextNode = FindChildNode(parentNode, nextStep.GetName(), createNodes);
     }
     else
     {
         if (stepKind == XMPPath.QualifierStep)
         {
             nextNode = FindQualifierNode(parentNode, Sharpen.Runtime.Substring(nextStep.GetName(), 1), createNodes);
         }
         else
         {
             // This is an array indexing step. First get the index, then get the node.
             if (!parentNode.GetOptions().IsArray())
             {
                 throw new XMPException("Indexing applied to non-array", XMPErrorConstants.Badxpath);
             }
             if (stepKind == XMPPath.ArrayIndexStep)
             {
                 index = FindIndexedItem(parentNode, nextStep.GetName(), createNodes);
             }
             else
             {
                 if (stepKind == XMPPath.ArrayLastStep)
                 {
                     index = parentNode.GetChildrenLength();
                 }
                 else
                 {
                     if (stepKind == XMPPath.FieldSelectorStep)
                     {
                         string[] result = Utils.SplitNameAndValue(nextStep.GetName());
                         string fieldName = result[0];
                         string fieldValue = result[1];
                         index = LookupFieldSelector(parentNode, fieldName, fieldValue);
                     }
                     else
                     {
                         if (stepKind == XMPPath.QualSelectorStep)
                         {
                             string[] result = Utils.SplitNameAndValue(nextStep.GetName());
                             string qualName = result[0];
                             string qualValue = result[1];
                             index = LookupQualSelector(parentNode, qualName, qualValue, nextStep.GetAliasForm());
                         }
                         else
                         {
                             throw new XMPException("Unknown array indexing step in FollowXPathStep", XMPErrorConstants.Internalfailure);
                         }
                     }
                 }
             }
             if (1 <= index && index <= parentNode.GetChildrenLength())
             {
                 nextNode = parentNode.GetChild(index);
             }
         }
     }
     return nextNode;
 }
Exemple #28
0
        /// <summary>
        /// <ol>
        /// <li>Look for an exact match with the specific language.
        /// </summary>
        /// <remarks>
        /// <ol>
        /// <li>Look for an exact match with the specific language.
        /// <li>If a generic language is given, look for partial matches.
        /// <li>Look for an "x-default"-item.
        /// <li>Choose the first item.
        /// </ol>
        /// </remarks>
        /// <param name="arrayNode">the alt text array node</param>
        /// <param name="genericLang">the generic language</param>
        /// <param name="specificLang">the specific language</param>
        /// <returns>
        /// Returns the kind of match as an Integer and the found node in an
        /// array.
        /// </returns>
        /// <exception cref="Com.Adobe.Xmp.XMPException"/>
        internal static object[] ChooseLocalizedText(XMPNode arrayNode, string genericLang, string specificLang)
        {
            // See if the array has the right form. Allow empty alt arrays,
            // that is what parsing returns.
            if (!arrayNode.GetOptions().IsArrayAltText())
            {
                throw new XMPException("Localized text array is not alt-text", XMPErrorConstants.Badxpath);
            }
            else
            {
                if (!arrayNode.HasChildren())
                {
                    return(new object[] { Com.Adobe.Xmp.Impl.XMPNodeUtils.CltNoValues, null });
                }
            }
            int     foundGenericMatches = 0;
            XMPNode resultNode          = null;
            XMPNode xDefault            = null;

            // Look for the first partial match with the generic language.
            for (Iterator it = arrayNode.IterateChildren(); it.HasNext();)
            {
                XMPNode currItem = (XMPNode)it.Next();
                // perform some checks on the current item
                if (currItem.GetOptions().IsCompositeProperty())
                {
                    throw new XMPException("Alt-text array item is not simple", XMPErrorConstants.Badxpath);
                }
                else
                {
                    if (!currItem.HasQualifier() || !XMPConstConstants.XmlLang.Equals(currItem.GetQualifier(1).GetName()))
                    {
                        throw new XMPException("Alt-text array item has no language qualifier", XMPErrorConstants.Badxpath);
                    }
                }
                string currLang = currItem.GetQualifier(1).GetValue();
                // Look for an exact match with the specific language.
                if (specificLang.Equals(currLang))
                {
                    return(new object[] { Com.Adobe.Xmp.Impl.XMPNodeUtils.CltSpecificMatch, currItem });
                }
                else
                {
                    if (genericLang != null && currLang.StartsWith(genericLang))
                    {
                        if (resultNode == null)
                        {
                            resultNode = currItem;
                        }
                        // ! Don't return/break, need to look for other matches.
                        foundGenericMatches++;
                    }
                    else
                    {
                        if (XMPConstConstants.XDefault.Equals(currLang))
                        {
                            xDefault = currItem;
                        }
                    }
                }
            }
            // evaluate loop
            if (foundGenericMatches == 1)
            {
                return(new object[] { Com.Adobe.Xmp.Impl.XMPNodeUtils.CltSingleGeneric, resultNode });
            }
            else
            {
                if (foundGenericMatches > 1)
                {
                    return(new object[] { Com.Adobe.Xmp.Impl.XMPNodeUtils.CltMultipleGeneric, resultNode });
                }
                else
                {
                    if (xDefault != null)
                    {
                        return(new object[] { Com.Adobe.Xmp.Impl.XMPNodeUtils.CltXdefault, xDefault });
                    }
                    else
                    {
                        // Everything failed, choose the first item.
                        return(new object[] { Com.Adobe.Xmp.Impl.XMPNodeUtils.CltFirstItem, arrayNode.GetChild(1) });
                    }
                }
            }
        }
 /// <summary>This is setting the value of a leaf node.</summary>
 /// <param name="node">an XMPNode</param>
 /// <param name="value">a value</param>
 internal static void SetNodeValue(XMPNode node, object value)
 {
     string strValue = SerializeNodeValue(value);
     if (!(node.GetOptions().IsQualifier() && XMPConstConstants.XmlLang.Equals(node.GetName())))
     {
         node.SetValue(strValue);
     }
     else
     {
         node.SetValue(Utils.NormalizeLangValue(strValue));
     }
 }
 /// <summary>Make sure the x-default item is first.</summary>
 /// <remarks>
 /// Make sure the x-default item is first. Touch up &quot;single value&quot;
 /// arrays that have a default plus one real language. This case should have
 /// the same value for both items. Older Adobe apps were hardwired to only
 /// use the &quot;x-default&quot; item, so we copy that value to the other
 /// item.
 /// </remarks>
 /// <param name="arrayNode">an alt text array node</param>
 internal static void NormalizeLangArray(XMPNode arrayNode)
 {
     if (!arrayNode.GetOptions().IsArrayAltText())
     {
         return;
     }
     // check if node with x-default qual is first place
     for (int i = 2; i <= arrayNode.GetChildrenLength(); i++)
     {
         XMPNode child = arrayNode.GetChild(i);
         if (child.HasQualifier() && XMPConstConstants.XDefault.Equals(child.GetQualifier(1).GetValue()))
         {
             // move node to first place
             try
             {
                 arrayNode.RemoveChild(i);
                 arrayNode.AddChild(1, child);
             }
             catch (XMPException)
             {
                 // cannot occur, because same child is removed before
                 System.Diagnostics.Debug.Assert(false);
             }
             if (i == 2)
             {
                 arrayNode.GetChild(2).SetValue(child.GetValue());
             }
             break;
         }
     }
 }
 /// <summary>Looks for the appropriate language item in a text alternative array.item</summary>
 /// <param name="arrayNode">an array node</param>
 /// <param name="language">the requested language</param>
 /// <returns>Returns the index if the language has been found, -1 otherwise.</returns>
 /// <exception cref="Com.Adobe.Xmp.XMPException"/>
 internal static int LookupLanguageItem(XMPNode arrayNode, string language)
 {
     if (!arrayNode.GetOptions().IsArray())
     {
         throw new XMPException("Language item must be used on array", XMPErrorConstants.Badxpath);
     }
     for (int index = 1; index <= arrayNode.GetChildrenLength(); index++)
     {
         XMPNode child = arrayNode.GetChild(index);
         if (!child.HasQualifier() || !XMPConstConstants.XmlLang.Equals(child.GetQualifier(1).GetName()))
         {
             continue;
         }
         else
         {
             if (language.Equals(child.GetQualifier(1).GetValue()))
             {
                 return index;
             }
         }
     }
     return -1;
 }
 /// <summary>Creates a property info object from an <code>XMPNode</code>.</summary>
 /// <param name="node">an <code>XMPNode</code></param>
 /// <param name="baseNS">the base namespace to report</param>
 /// <param name="path">the full property path</param>
 /// <returns>Returns a <code>XMPProperty</code>-object that serves representation of the node.</returns>
 protected internal virtual XMPPropertyInfo CreatePropertyInfo(XMPNode node, string baseNS, string path)
 {
     string value = node.GetOptions().IsSchemaNode() ? null : node.GetValue();
     return new _XMPPropertyInfo_450(node, baseNS, path, value);
 }
 /// <summary>Moves an alias node of array form to another schema into an array</summary>
 /// <param name="propertyIt">the property iterator of the old schema (used to delete the property)</param>
 /// <param name="childNode">the node to be moved</param>
 /// <param name="baseArray">the base array for the array item</param>
 /// <exception cref="Com.Adobe.Xmp.XMPException">Forwards XMP errors</exception>
 private static void TransplantArrayItemAlias(Iterator propertyIt, XMPNode childNode, XMPNode baseArray)
 {
     if (baseArray.GetOptions().IsArrayAltText())
     {
         if (childNode.GetOptions().GetHasLanguage())
         {
             throw new XMPException("Alias to x-default already has a language qualifier", XMPErrorConstants.Badxmp);
         }
         XMPNode langQual = new XMPNode(XMPConstConstants.XmlLang, XMPConstConstants.XDefault, null);
         childNode.AddQualifier(langQual);
     }
     propertyIt.Remove();
     childNode.SetName(XMPConstConstants.ArrayItemName);
     baseArray.AddChild(childNode);
 }
Exemple #34
0
        /// <summary>Compares two nodes including its children and qualifier.</summary>
        /// <param name="leftNode">an <code>XMPNode</code></param>
        /// <param name="rightNode">an <code>XMPNode</code></param>
        /// <returns>Returns true if the nodes are equal, false otherwise.</returns>
        /// <exception cref="Com.Adobe.Xmp.XMPException">Forwards exceptions to the calling method.</exception>
        private static bool ItemValuesMatch(XMPNode leftNode, XMPNode rightNode)
        {
            PropertyOptions leftForm  = leftNode.GetOptions();
            PropertyOptions rightForm = rightNode.GetOptions();

            if (leftForm.Equals(rightForm))
            {
                return(false);
            }
            if (leftForm.GetOptions() == 0)
            {
                // Simple nodes, check the values and xml:lang qualifiers.
                if (!leftNode.GetValue().Equals(rightNode.GetValue()))
                {
                    return(false);
                }
                if (leftNode.GetOptions().GetHasLanguage() != rightNode.GetOptions().GetHasLanguage())
                {
                    return(false);
                }
                if (leftNode.GetOptions().GetHasLanguage() && !leftNode.GetQualifier(1).GetValue().Equals(rightNode.GetQualifier(1).GetValue()))
                {
                    return(false);
                }
            }
            else
            {
                if (leftForm.IsStruct())
                {
                    // Struct nodes, see if all fields match, ignoring order.
                    if (leftNode.GetChildrenLength() != rightNode.GetChildrenLength())
                    {
                        return(false);
                    }
                    for (Iterator it = leftNode.IterateChildren(); it.HasNext();)
                    {
                        XMPNode leftField  = (XMPNode)it.Next();
                        XMPNode rightField = XMPNodeUtils.FindChildNode(rightNode, leftField.GetName(), false);
                        if (rightField == null || !ItemValuesMatch(leftField, rightField))
                        {
                            return(false);
                        }
                    }
                }
                else
                {
                    // Array nodes, see if the "leftNode" values are present in the
                    // "rightNode", ignoring order, duplicates,
                    // and extra values in the rightNode-> The rightNode is the
                    // destination for AppendProperties.
                    System.Diagnostics.Debug.Assert(leftForm.IsArray());
                    for (Iterator il = leftNode.IterateChildren(); il.HasNext();)
                    {
                        XMPNode leftItem = (XMPNode)il.Next();
                        bool    match    = false;
                        for (Iterator ir = rightNode.IterateChildren(); ir.HasNext();)
                        {
                            XMPNode rightItem = (XMPNode)ir.Next();
                            if (ItemValuesMatch(leftItem, rightItem))
                            {
                                match = true;
                                break;
                            }
                        }
                        if (!match)
                        {
                            return(false);
                        }
                    }
                }
            }
            return(true);
        }
		/// <summary>
		/// The internals for SetProperty() and related calls, used after the node is
		/// found or created.
		/// </summary>
		/// <param name="node">the newly created node</param>
		/// <param name="value">the node value, can be <code>null</code></param>
		/// <param name="newOptions">options for the new node, must not be <code>null</code>.</param>
		/// <param name="deleteExisting">flag if the existing value is to be overwritten</param>
		/// <exception cref="Com.Adobe.Xmp.XMPException">thrown if options and value do not correspond</exception>
		internal virtual void SetNode(XMPNode node, object value, PropertyOptions newOptions, bool deleteExisting)
		{
			if (deleteExisting)
			{
				node.Clear();
			}
			// its checked by SetOptions(), if the merged result is a valid options set
			node.GetOptions().MergeWith(newOptions);
			if (!node.GetOptions().IsCompositeProperty())
			{
				// This is setting the value of a leaf node.
				XMPNodeUtils.SetNodeValue(node, value);
			}
			else
			{
				if (value != null && value.ToString().Length > 0)
				{
					throw new XMPException("Composite nodes can't have values", XMPErrorConstants.Badxpath);
				}
				node.RemoveChildren();
			}
		}
 /// <summary>Constructor for the node iterator.</summary>
 /// <param name="visitedNode">the currently visited node</param>
 /// <param name="parentPath">the accumulated path of the node</param>
 /// <param name="index">the index within the parent node (only for arrays)</param>
 public NodeIterator(XMPIteratorImpl _enclosing, XMPNode visitedNode, string parentPath, int index)
 {
     this._enclosing = _enclosing;
     // EMPTY
     this.visitedNode = visitedNode;
     this.state = XMPIteratorImpl.NodeIterator.IterateNode;
     if (visitedNode.GetOptions().IsSchemaNode())
     {
         this._enclosing.SetBaseNS(visitedNode.GetName());
     }
     // for all but the root node and schema nodes
     this.path = this.AccumulatePath(visitedNode, parentPath, index);
 }
 /// <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="Com.Adobe.Xmp.XMPException">thown on parsing errors</exception>
 private static XMPNode AddChildNode(XMPMetaImpl xmp, XMPNode xmpParent, XmlNode xmlNode, string value, bool isTopLevel)
 {
     XMPSchemaRegistry registry = XMPMetaFactory.GetSchemaRegistry();
     string @namespace = xmlNode.NamespaceURI;
     string childName;
     if (@namespace != null)
     {
         if (XMPConstConstants.NsDcDeprecated.Equals(@namespace))
         {
             // Fix a legacy DC namespace
             @namespace = XMPConstConstants.NsDc;
         }
         string prefix = registry.GetNamespacePrefix(@namespace);
         if (prefix == null)
         {
             prefix = xmlNode.Prefix != null ? xmlNode.Prefix : DefaultPrefix;
             prefix = registry.RegisterNamespace(@namespace, prefix);
         }
         childName = prefix + xmlNode.LocalName;
     }
     else
     {
         throw new XMPException("XML namespace required for all elements and attributes", XMPErrorConstants.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.GetRoot(), @namespace, DefaultPrefix, true);
         schemaNode.SetImplicit(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.GetRoot().SetHasAliases(true);
             schemaNode.SetHasAliases(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.SetAlias(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.GetOptions().IsStruct())
         {
             throw new XMPException("Misplaced rdf:value element", XMPErrorConstants.Badrdf);
         }
         xmpParent.SetHasValueChild(true);
     }
     if (isArrayItem)
     {
         if (!xmpParent.GetOptions().IsArray())
         {
             throw new XMPException("Misplaced rdf:li element", XMPErrorConstants.Badrdf);
         }
         newChild.SetName(XMPConstConstants.ArrayItemName);
     }
     return newChild;
 }
		/// <seealso cref="AppendProperties(Com.Adobe.Xmp.XMPMeta, Com.Adobe.Xmp.XMPMeta, bool, bool, bool)"/>
		/// <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="Com.Adobe.Xmp.XMPException"/>
		private static void AppendSubtree(XMPMetaImpl destXMP, XMPNode sourceNode, XMPNode destParent, bool replaceOldValues, bool deleteEmptyValues)
		{
			XMPNode destNode = XMPNodeUtils.FindChildNode(destParent, sourceNode.GetName(), false);
			bool valueIsEmpty = false;
			if (deleteEmptyValues)
			{
				valueIsEmpty = sourceNode.GetOptions().IsSimple() ? sourceNode.GetValue() == null || sourceNode.GetValue().Length == 0 : !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.GetValue(), sourceNode.GetOptions(), 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.GetOptions();
						PropertyOptions destForm = destNode.GetOptions();
						if (sourceForm != destForm)
						{
							return;
						}
						if (sourceForm.IsStruct())
						{
							// 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 (Iterator it = sourceNode.IterateChildren(); it.HasNext(); )
							{
								XMPNode sourceField = (XMPNode)it.Next();
								AppendSubtree(destXMP, sourceField, destNode, replaceOldValues, deleteEmptyValues);
								if (deleteEmptyValues && !destNode.HasChildren())
								{
									destParent.RemoveChild(destNode);
								}
							}
						}
						else
						{
							if (sourceForm.IsArrayAltText())
							{
								// 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 (Iterator it = sourceNode.IterateChildren(); it.HasNext(); )
								{
									XMPNode sourceItem = (XMPNode)it.Next();
									if (!sourceItem.HasQualifier() || !XMPConstConstants.XmlLang.Equals(sourceItem.GetQualifier(1).GetName()))
									{
										continue;
									}
									int destIndex = XMPNodeUtils.LookupLanguageItem(destNode, sourceItem.GetQualifier(1).GetValue());
									if (deleteEmptyValues && (sourceItem.GetValue() == null || sourceItem.GetValue().Length == 0))
									{
										if (destIndex != -1)
										{
											destNode.RemoveChild(destIndex);
											if (!destNode.HasChildren())
											{
												destParent.RemoveChild(destNode);
											}
										}
									}
									else
									{
										if (destIndex == -1)
										{
											// Not replacing, keep the existing item.						
											if (!XMPConstConstants.XDefault.Equals(sourceItem.GetQualifier(1).GetValue()) || !destNode.HasChildren())
											{
												sourceItem.CloneSubtree(destNode);
											}
											else
											{
												XMPNode destItem = new XMPNode(sourceItem.GetName(), sourceItem.GetValue(), sourceItem.GetOptions());
												sourceItem.CloneSubtree(destItem);
												destNode.AddChild(1, destItem);
											}
										}
									}
								}
							}
							else
							{
								if (sourceForm.IsArray())
								{
									// 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 (Iterator @is = sourceNode.IterateChildren(); @is.HasNext(); )
									{
										XMPNode sourceItem = (XMPNode)@is.Next();
										bool match = false;
										for (Iterator id = destNode.IterateChildren(); id.HasNext(); )
										{
											XMPNode destItem = (XMPNode)id.Next();
											if (ItemValuesMatch(sourceItem, destItem))
											{
												match = true;
											}
										}
										if (!match)
										{
											destNode = (XMPNode)sourceItem.Clone();
											destParent.AddChild(destNode);
										}
									}
								}
							}
						}
					}
				}
			}
		}
 /// <summary>See if an array is an alt-text array.</summary>
 /// <remarks>
 /// See if an array is an alt-text array. If so, make sure the x-default item
 /// is first.
 /// </remarks>
 /// <param name="arrayNode">the array node to check if its an alt-text array</param>
 internal static void DetectAltText(XMPNode arrayNode)
 {
     if (arrayNode.GetOptions().IsArrayAlternate() && arrayNode.HasChildren())
     {
         bool isAltText = false;
         for (Iterator it = arrayNode.IterateChildren(); it.HasNext(); )
         {
             XMPNode child = (XMPNode)it.Next();
             if (child.GetOptions().GetHasLanguage())
             {
                 isAltText = true;
                 break;
             }
         }
         if (isAltText)
         {
             arrayNode.GetOptions().SetArrayAltText(true);
             NormalizeLangArray(arrayNode);
         }
     }
 }
		/// <summary>
		/// Evaluates a raw node value to the given value type, apply special
		/// conversions for defined types in XMP.
		/// </summary>
		/// <param name="valueType">an int indicating the value type</param>
		/// <param name="propNode">the node containing the value</param>
		/// <returns>Returns a literal value for the node.</returns>
		/// <exception cref="Com.Adobe.Xmp.XMPException"/>
		private object EvaluateNodeValue(int valueType, XMPNode propNode)
		{
			object value;
			string rawValue = propNode.GetValue();
			switch (valueType)
			{
				case ValueBoolean:
				{
					value = XMPUtils.ConvertToBoolean(rawValue);
					break;
				}

				case ValueInteger:
				{
					value = XMPUtils.ConvertToInteger(rawValue);
					break;
				}

				case ValueLong:
				{
					value = XMPUtils.ConvertToLong(rawValue);
					break;
				}

				case ValueDouble:
				{
					value = XMPUtils.ConvertToDouble(rawValue);
					break;
				}

				case ValueDate:
				{
					value = XMPUtils.ConvertToDate(rawValue);
					break;
				}

				case ValueCalendar:
				{
					XMPDateTime dt = XMPUtils.ConvertToDate(rawValue);
					value = dt.GetCalendar();
					break;
				}

				case ValueBase64:
				{
					value = XMPUtils.DecodeBase64(rawValue);
					break;
				}

				case ValueString:
				default:
				{
					// leaf values return empty string instead of null
					// for the other cases the converter methods provides a "null"
					// value.
					// a default value can only occur if this method is made public.
					value = rawValue != null || propNode.GetOptions().IsCompositeProperty() ? rawValue : string.Empty;
					break;
				}
			}
			return value;
		}
		/// <summary>Compares two nodes including its children and qualifier.</summary>
		/// <param name="leftNode">an <code>XMPNode</code></param>
		/// <param name="rightNode">an <code>XMPNode</code></param>
		/// <returns>Returns true if the nodes are equal, false otherwise.</returns>
		/// <exception cref="Com.Adobe.Xmp.XMPException">Forwards exceptions to the calling method.</exception>
		private static bool ItemValuesMatch(XMPNode leftNode, XMPNode rightNode)
		{
			PropertyOptions leftForm = leftNode.GetOptions();
			PropertyOptions rightForm = rightNode.GetOptions();
			if (leftForm.Equals(rightForm))
			{
				return false;
			}
			if (leftForm.GetOptions() == 0)
			{
				// Simple nodes, check the values and xml:lang qualifiers.
				if (!leftNode.GetValue().Equals(rightNode.GetValue()))
				{
					return false;
				}
				if (leftNode.GetOptions().GetHasLanguage() != rightNode.GetOptions().GetHasLanguage())
				{
					return false;
				}
				if (leftNode.GetOptions().GetHasLanguage() && !leftNode.GetQualifier(1).GetValue().Equals(rightNode.GetQualifier(1).GetValue()))
				{
					return false;
				}
			}
			else
			{
				if (leftForm.IsStruct())
				{
					// Struct nodes, see if all fields match, ignoring order.
					if (leftNode.GetChildrenLength() != rightNode.GetChildrenLength())
					{
						return false;
					}
					for (Iterator it = leftNode.IterateChildren(); it.HasNext(); )
					{
						XMPNode leftField = (XMPNode)it.Next();
						XMPNode rightField = XMPNodeUtils.FindChildNode(rightNode, leftField.GetName(), false);
						if (rightField == null || !ItemValuesMatch(leftField, rightField))
						{
							return false;
						}
					}
				}
				else
				{
					// Array nodes, see if the "leftNode" values are present in the
					// "rightNode", ignoring order, duplicates,
					// and extra values in the rightNode-> The rightNode is the
					// destination for AppendProperties.
					System.Diagnostics.Debug.Assert(leftForm.IsArray());
					for (Iterator il = leftNode.IterateChildren(); il.HasNext(); )
					{
						XMPNode leftItem = (XMPNode)il.Next();
						bool match = false;
						for (Iterator ir = rightNode.IterateChildren(); ir.HasNext(); )
						{
							XMPNode rightItem = (XMPNode)ir.Next();
							if (ItemValuesMatch(leftItem, rightItem))
							{
								match = true;
								break;
							}
						}
						if (!match)
						{
							return false;
						}
					}
				}
			}
			return true;
		}
Exemple #42
0
        /// <summary>Follow an expanded path expression to find or create a node.</summary>
        /// <param name="xmpTree">the node to begin the search.</param>
        /// <param name="xpath">the complete xpath</param>
        /// <param name="createNodes">
        /// flag if nodes shall be created
        /// (when called by <code>setProperty()</code>)
        /// </param>
        /// <param name="leafOptions">
        /// the options for the created leaf nodes (only when
        /// <code>createNodes == true</code>).
        /// </param>
        /// <returns>Returns the node if found or created or <code>null</code>.</returns>
        /// <exception cref="Com.Adobe.Xmp.XMPException">
        /// An exception is only thrown if an error occurred,
        /// not if a node was not found.
        /// </exception>
        internal static XMPNode FindNode(XMPNode xmpTree, XMPPath xpath, bool createNodes, PropertyOptions leafOptions)
        {
            // check if xpath is set.
            if (xpath == null || xpath.Size() == 0)
            {
                throw new XMPException("Empty XMPPath", XMPErrorConstants.Badxpath);
            }
            // Root of implicitly created subtree to possible delete it later.
            // Valid only if leaf is new.
            XMPNode rootImplicitNode = null;
            XMPNode currNode         = null;

            // resolve schema step
            currNode = FindSchemaNode(xmpTree, xpath.GetSegment(XMPPath.StepSchema).GetName(), createNodes);
            if (currNode == null)
            {
                return(null);
            }
            else
            {
                if (currNode.IsImplicit())
                {
                    currNode.SetImplicit(false);
                    // Clear the implicit node bit.
                    rootImplicitNode = currNode;
                }
            }
            // Save the top most implicit node.
            // Now follow the remaining steps of the original XMPPath.
            try
            {
                for (int i = 1; i < xpath.Size(); i++)
                {
                    currNode = FollowXPathStep(currNode, xpath.GetSegment(i), createNodes);
                    if (currNode == null)
                    {
                        if (createNodes)
                        {
                            // delete implicitly created nodes
                            DeleteNode(rootImplicitNode);
                        }
                        return(null);
                    }
                    else
                    {
                        if (currNode.IsImplicit())
                        {
                            // clear the implicit node flag
                            currNode.SetImplicit(false);
                            // if node is an ALIAS (can be only in root step, auto-create array
                            // when the path has been resolved from a not simple alias type
                            if (i == 1 && xpath.GetSegment(i).IsAlias() && xpath.GetSegment(i).GetAliasForm() != 0)
                            {
                                currNode.GetOptions().SetOption(xpath.GetSegment(i).GetAliasForm(), true);
                            }
                            else
                            {
                                // "CheckImplicitStruct" in C++
                                if (i < xpath.Size() - 1 && xpath.GetSegment(i).GetKind() == XMPPath.StructFieldStep && !currNode.GetOptions().IsCompositeProperty())
                                {
                                    currNode.GetOptions().SetStruct(true);
                                }
                            }
                            if (rootImplicitNode == null)
                            {
                                rootImplicitNode = currNode;
                            }
                        }
                    }
                }
            }
            catch (XMPException e)
            {
                // Save the top most implicit node.
                // if new notes have been created prior to the error, delete them
                if (rootImplicitNode != null)
                {
                    DeleteNode(rootImplicitNode);
                }
                throw;
            }
            if (rootImplicitNode != null)
            {
                // set options only if a node has been successful created
                currNode.GetOptions().MergeWith(leafOptions);
                currNode.SetOptions(currNode.GetOptions());
            }
            return(currNode);
        }
 /// <summary>Constructor</summary>
 /// <param name="parentNode">the node which children shall be iterated.</param>
 /// <param name="parentPath">the full path of the former node without the leaf node.</param>
 public NodeIteratorChildren(XMPIteratorImpl _enclosing, XMPNode parentNode, string parentPath)
     : base(_enclosing)
 {
     this._enclosing = _enclosing;
     if (parentNode.GetOptions().IsSchemaNode())
     {
         this._enclosing.SetBaseNS(parentNode.GetName());
     }
     this.parentPath = this.AccumulatePath(parentNode, parentPath, 1);
     this.childrenIterator = parentNode.IterateChildren();
 }
		/// <summary>Writes all used namespaces of the subtree in node to the output.</summary>
		/// <remarks>
		/// Writes all used namespaces of the subtree in node to the output.
		/// The subtree is recursivly traversed.
		/// </remarks>
		/// <param name="node">the root node of the subtree</param>
		/// <param name="usedPrefixes">a set containing currently used prefixes</param>
		/// <param name="indent">the current indent level</param>
		/// <exception cref="System.IO.IOException">Forwards all writer exceptions.</exception>
        private void DeclareUsedNamespaces(XMPNode node, HashSet<string> usedPrefixes, int indent)
		{
			if (node.GetOptions().IsSchemaNode())
			{
				// The schema node name is the URI, the value is the prefix.
				string prefix = Sharpen.Runtime.Substring(node.GetValue(), 0, node.GetValue().Length - 1);
				DeclareNamespace(prefix, node.GetName(), usedPrefixes, indent);
			}
			else
			{
				if (node.GetOptions().IsStruct())
				{
					for (Iterator it = node.IterateChildren(); it.HasNext(); )
					{
						XMPNode field = (XMPNode)it.Next();
						DeclareNamespace(field.GetName(), null, usedPrefixes, indent);
					}
				}
			}
			for (Iterator it_1 = node.IterateChildren(); it_1.HasNext(); )
			{
				XMPNode child = (XMPNode)it_1.Next();
				DeclareUsedNamespaces(child, usedPrefixes, indent);
			}
			for (Iterator it_2 = node.IterateQualifier(); it_2.HasNext(); )
			{
				XMPNode qualifier = (XMPNode)it_2.Next();
				DeclareNamespace(qualifier.GetName(), null, usedPrefixes, indent);
				DeclareUsedNamespaces(qualifier, usedPrefixes, indent);
			}
		}
Exemple #45
0
        /// <seealso cref="Com.Adobe.Xmp.XMPUtils.RemoveProperties(Com.Adobe.Xmp.XMPMeta, string, string, bool, bool)"/>
        /// <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="Com.Adobe.Xmp.XMPException">If metadata processing fails</exception>
        public static void RemoveProperties(XMPMeta xmp, string schemaNS, string propName, bool doAllProperties, bool includeAliases)
        {
            ParameterAsserts.AssertImplementation(xmp);
            XMPMetaImpl xmpImpl = (XMPMetaImpl)xmp;

            if (propName != null && propName.Length > 0)
            {
                // 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 (schemaNS == null || schemaNS.Length == 0)
                {
                    throw new XMPException("Property name requires schema namespace", XMPErrorConstants.Badparam);
                }
                XMPPath expPath  = XMPPathParser.ExpandXPath(schemaNS, propName);
                XMPNode propNode = XMPNodeUtils.FindNode(xmpImpl.GetRoot(), expPath, false, null);
                if (propNode != null)
                {
                    if (doAllProperties || !Utils.IsInternalProperty(expPath.GetSegment(XMPPath.StepSchema).GetName(), expPath.GetSegment(XMPPath.StepRootProp).GetName()))
                    {
                        XMPNode parent = propNode.GetParent();
                        parent.RemoveChild(propNode);
                        if (parent.GetOptions().IsSchemaNode() && !parent.HasChildren())
                        {
                            // remove empty schema node
                            parent.GetParent().RemoveChild(parent);
                        }
                    }
                }
            }
            else
            {
                if (schemaNS != null && schemaNS.Length > 0)
                {
                    // 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.GetRoot(), schemaNS, false);
                    if (schemaNode != null)
                    {
                        if (RemoveSchemaChildren(schemaNode, doAllProperties))
                        {
                            xmpImpl.GetRoot().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.
                        XMPAliasInfo[] aliases = XMPMetaFactory.GetSchemaRegistry().FindAliases(schemaNS);
                        for (int i = 0; i < aliases.Length; i++)
                        {
                            XMPAliasInfo info       = aliases[i];
                            XMPPath      path       = XMPPathParser.ExpandXPath(info.GetNamespace(), info.GetPropName());
                            XMPNode      actualProp = XMPNodeUtils.FindNode(xmpImpl.GetRoot(), path, false, null);
                            if (actualProp != null)
                            {
                                XMPNode parent = actualProp.GetParent();
                                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.
                    for (Iterator it = xmpImpl.GetRoot().IterateChildren(); it.HasNext();)
                    {
                        XMPNode schema = (XMPNode)it.Next();
                        if (RemoveSchemaChildren(schema, doAllProperties))
                        {
                            it.Remove();
                        }
                    }
                }
            }
        }
		/// <summary>Serializes an array property.</summary>
		/// <param name="node">an XMPNode</param>
		/// <param name="indent">the current indent level</param>
		/// <exception cref="System.IO.IOException">Forwards the writer exceptions.</exception>
		/// <exception cref="Com.Adobe.Xmp.XMPException">If qualifier and element fields are mixed.</exception>
		private void SerializeCompactRDFArrayProp(XMPNode node, int indent)
		{
			// This is an array.
			Write('>');
			WriteNewline();
			EmitRDFArrayTag(node, true, indent + 1);
			if (node.GetOptions().IsArrayAltText())
			{
				XMPNodeUtils.NormalizeLangArray(node);
			}
			SerializeCompactRDFElementProps(node, indent + 2);
			EmitRDFArrayTag(node, false, indent + 1);
		}
Exemple #47
0
        /// <seealso cref="AppendProperties(Com.Adobe.Xmp.XMPMeta, Com.Adobe.Xmp.XMPMeta, bool, bool, bool)"/>
        /// <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="Com.Adobe.Xmp.XMPException"/>
        private static void AppendSubtree(XMPMetaImpl destXMP, XMPNode sourceNode, XMPNode destParent, bool replaceOldValues, bool deleteEmptyValues)
        {
            XMPNode destNode     = XMPNodeUtils.FindChildNode(destParent, sourceNode.GetName(), false);
            bool    valueIsEmpty = false;

            if (deleteEmptyValues)
            {
                valueIsEmpty = sourceNode.GetOptions().IsSimple() ? sourceNode.GetValue() == null || sourceNode.GetValue().Length == 0 : !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.GetValue(), sourceNode.GetOptions(), 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.GetOptions();
                        PropertyOptions destForm   = destNode.GetOptions();
                        if (sourceForm != destForm)
                        {
                            return;
                        }
                        if (sourceForm.IsStruct())
                        {
                            // 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 (Iterator it = sourceNode.IterateChildren(); it.HasNext();)
                            {
                                XMPNode sourceField = (XMPNode)it.Next();
                                AppendSubtree(destXMP, sourceField, destNode, replaceOldValues, deleteEmptyValues);
                                if (deleteEmptyValues && !destNode.HasChildren())
                                {
                                    destParent.RemoveChild(destNode);
                                }
                            }
                        }
                        else
                        {
                            if (sourceForm.IsArrayAltText())
                            {
                                // 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 (Iterator it = sourceNode.IterateChildren(); it.HasNext();)
                                {
                                    XMPNode sourceItem = (XMPNode)it.Next();
                                    if (!sourceItem.HasQualifier() || !XMPConstConstants.XmlLang.Equals(sourceItem.GetQualifier(1).GetName()))
                                    {
                                        continue;
                                    }
                                    int destIndex = XMPNodeUtils.LookupLanguageItem(destNode, sourceItem.GetQualifier(1).GetValue());
                                    if (deleteEmptyValues && (sourceItem.GetValue() == null || sourceItem.GetValue().Length == 0))
                                    {
                                        if (destIndex != -1)
                                        {
                                            destNode.RemoveChild(destIndex);
                                            if (!destNode.HasChildren())
                                            {
                                                destParent.RemoveChild(destNode);
                                            }
                                        }
                                    }
                                    else
                                    {
                                        if (destIndex == -1)
                                        {
                                            // Not replacing, keep the existing item.
                                            if (!XMPConstConstants.XDefault.Equals(sourceItem.GetQualifier(1).GetValue()) || !destNode.HasChildren())
                                            {
                                                sourceItem.CloneSubtree(destNode);
                                            }
                                            else
                                            {
                                                XMPNode destItem = new XMPNode(sourceItem.GetName(), sourceItem.GetValue(), sourceItem.GetOptions());
                                                sourceItem.CloneSubtree(destItem);
                                                destNode.AddChild(1, destItem);
                                            }
                                        }
                                    }
                                }
                            }
                            else
                            {
                                if (sourceForm.IsArray())
                                {
                                    // 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 (Iterator @is = sourceNode.IterateChildren(); @is.HasNext();)
                                    {
                                        XMPNode sourceItem = (XMPNode)@is.Next();
                                        bool    match      = false;
                                        for (Iterator id = destNode.IterateChildren(); id.HasNext();)
                                        {
                                            XMPNode destItem = (XMPNode)id.Next();
                                            if (ItemValuesMatch(sourceItem, destItem))
                                            {
                                                match = true;
                                            }
                                        }
                                        if (!match)
                                        {
                                            destNode = (XMPNode)sourceItem.Clone();
                                            destParent.AddChild(destNode);
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
 /// <summary>
 /// <ol>
 /// <li>Look for an exact match with the specific language.
 /// </summary>
 /// <remarks>
 /// <ol>
 /// <li>Look for an exact match with the specific language.
 /// <li>If a generic language is given, look for partial matches.
 /// <li>Look for an "x-default"-item.
 /// <li>Choose the first item.
 /// </ol>
 /// </remarks>
 /// <param name="arrayNode">the alt text array node</param>
 /// <param name="genericLang">the generic language</param>
 /// <param name="specificLang">the specific language</param>
 /// <returns>
 /// Returns the kind of match as an Integer and the found node in an
 /// array.
 /// </returns>
 /// <exception cref="Com.Adobe.Xmp.XMPException"/>
 internal static object[] ChooseLocalizedText(XMPNode arrayNode, string genericLang, string specificLang)
 {
     // See if the array has the right form. Allow empty alt arrays,
     // that is what parsing returns.
     if (!arrayNode.GetOptions().IsArrayAltText())
     {
         throw new XMPException("Localized text array is not alt-text", XMPErrorConstants.Badxpath);
     }
     else
     {
         if (!arrayNode.HasChildren())
         {
             return new object[] { Com.Adobe.Xmp.Impl.XMPNodeUtils.CltNoValues, null };
         }
     }
     int foundGenericMatches = 0;
     XMPNode resultNode = null;
     XMPNode xDefault = null;
     // Look for the first partial match with the generic language.
     for (Iterator it = arrayNode.IterateChildren(); it.HasNext(); )
     {
         XMPNode currItem = (XMPNode)it.Next();
         // perform some checks on the current item
         if (currItem.GetOptions().IsCompositeProperty())
         {
             throw new XMPException("Alt-text array item is not simple", XMPErrorConstants.Badxpath);
         }
         else
         {
             if (!currItem.HasQualifier() || !XMPConstConstants.XmlLang.Equals(currItem.GetQualifier(1).GetName()))
             {
                 throw new XMPException("Alt-text array item has no language qualifier", XMPErrorConstants.Badxpath);
             }
         }
         string currLang = currItem.GetQualifier(1).GetValue();
         // Look for an exact match with the specific language.
         if (specificLang.Equals(currLang))
         {
             return new object[] { Com.Adobe.Xmp.Impl.XMPNodeUtils.CltSpecificMatch, currItem };
         }
         else
         {
             if (genericLang != null && currLang.StartsWith(genericLang))
             {
                 if (resultNode == null)
                 {
                     resultNode = currItem;
                 }
                 // ! Don't return/break, need to look for other matches.
                 foundGenericMatches++;
             }
             else
             {
                 if (XMPConstConstants.XDefault.Equals(currLang))
                 {
                     xDefault = currItem;
                 }
             }
         }
     }
     // evaluate loop
     if (foundGenericMatches == 1)
     {
         return new object[] { Com.Adobe.Xmp.Impl.XMPNodeUtils.CltSingleGeneric, resultNode };
     }
     else
     {
         if (foundGenericMatches > 1)
         {
             return new object[] { Com.Adobe.Xmp.Impl.XMPNodeUtils.CltMultipleGeneric, resultNode };
         }
         else
         {
             if (xDefault != null)
             {
                 return new object[] { Com.Adobe.Xmp.Impl.XMPNodeUtils.CltXdefault, xDefault };
             }
             else
             {
                 // Everything failed, choose the first item.
                 return new object[] { Com.Adobe.Xmp.Impl.XMPNodeUtils.CltFirstItem, arrayNode.GetChild(1) };
             }
         }
     }
 }
Exemple #49
0
            /// <summary>Creates a property info object from an <code>XMPNode</code>.</summary>
            /// <param name="node">an <code>XMPNode</code></param>
            /// <param name="baseNS">the base namespace to report</param>
            /// <param name="path">the full property path</param>
            /// <returns>Returns a <code>XMPProperty</code>-object that serves representation of the node.</returns>
            protected internal virtual XMPPropertyInfo CreatePropertyInfo(XMPNode node, string baseNS, string path)
            {
                string value = node.GetOptions().IsSchemaNode() ? null : node.GetValue();

                return(new _XMPPropertyInfo_450(node, baseNS, path, value));
            }
 /// <summary>Make sure that the array is well-formed AltText.</summary>
 /// <remarks>
 /// Make sure that the array is well-formed AltText. Each item must be simple
 /// and have an "xml:lang" qualifier. If repairs are needed, keep simple
 /// non-empty items by adding the "xml:lang" with value "x-repair".
 /// </remarks>
 /// <param name="arrayNode">the property node of the array to repair.</param>
 /// <exception cref="Com.Adobe.Xmp.XMPException">Forwards unexpected exceptions.</exception>
 private static void RepairAltText(XMPNode arrayNode)
 {
     if (arrayNode == null || !arrayNode.GetOptions().IsArray())
     {
         // Already OK or not even an array.
         return;
     }
     // fix options
     arrayNode.GetOptions().SetArrayOrdered(true).SetArrayAlternate(true).SetArrayAltText(true);
     for (Iterator it = arrayNode.IterateChildren(); it.HasNext(); )
     {
         XMPNode currChild = (XMPNode)it.Next();
         if (currChild.GetOptions().IsCompositeProperty())
         {
             // Delete non-simple children.
             it.Remove();
         }
         else
         {
             if (!currChild.GetOptions().GetHasLanguage())
             {
                 string childValue = currChild.GetValue();
                 if (childValue == null || childValue.Length == 0)
                 {
                     // Delete empty valued children that have no xml:lang.
                     it.Remove();
                 }
                 else
                 {
                     // Add an xml:lang qualifier with the value "x-repair".
                     XMPNode repairLang = new XMPNode(XMPConstConstants.XmlLang, "x-repair", null);
                     currChild.AddQualifier(repairLang);
                 }
             }
         }
     }
 }
		/// <summary>Writes the array start and end tags.</summary>
		/// <param name="arrayNode">an array node</param>
		/// <param name="isStartTag">flag if its the start or end tag</param>
		/// <param name="indent">the current indent level</param>
		/// <exception cref="System.IO.IOException">forwards writer exceptions</exception>
		private void EmitRDFArrayTag(XMPNode arrayNode, bool isStartTag, int indent)
		{
			if (isStartTag || arrayNode.HasChildren())
			{
				WriteIndent(indent);
				Write(isStartTag ? "<rdf:" : "</rdf:");
				if (arrayNode.GetOptions().IsArrayAlternate())
				{
					Write("Alt");
				}
				else
				{
					if (arrayNode.GetOptions().IsArrayOrdered())
					{
						Write("Seq");
					}
					else
					{
						Write("Bag");
					}
				}
				if (isStartTag && !arrayNode.HasChildren())
				{
					Write("/>");
				}
				else
				{
					Write(">");
				}
				WriteNewline();
			}
		}