Example #1
0
        /// <param name="arrayNode">an array node</param>
        /// <param name="segment">the segment containing the array index</param>
        /// <param name="createNodes">flag if new nodes are allowed to be created.</param>
        /// <returns>Returns the index or index = -1 if not found</returns>
        /// <exception cref="Com.Adobe.Xmp.XMPException">Throws Exceptions</exception>
        private static int FindIndexedItem(XMPNode arrayNode, string segment, bool createNodes)
        {
            int index = 0;

            try
            {
                segment = Sharpen.Runtime.Substring(segment, 1, segment.Length - 1);
                index   = System.Convert.ToInt32(segment);
                if (index < 1)
                {
                    throw new XMPException("Array index must be larger than zero", XMPErrorConstants.Badxpath);
                }
            }
            catch (FormatException)
            {
                throw new XMPException("Array index not digits.", XMPErrorConstants.Badxpath);
            }
            if (createNodes && index == arrayNode.GetChildrenLength() + 1)
            {
                // Append a new last + 1 node.
                XMPNode newItem = new XMPNode(XMPConstConstants.ArrayItemName, null);
                newItem.SetImplicit(true);
                arrayNode.AddChild(newItem);
            }
            return(index);
        }
Example #2
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;
         }
     }
 }
Example #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);
        }
 /// <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);
                 }
             }
         }
     }
 }
 /// <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);
     }
 }
Example #7
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);
 }
Example #8
0
 /// <summary>
 /// Searches for a qualifier selector in a node:
 /// [?qualName="value"] - an element in an array, chosen by a qualifier value.
 /// </summary>
 /// <remarks>
 /// Searches for a qualifier selector in a node:
 /// [?qualName="value"] - an element in an array, chosen by a qualifier value.
 /// No implicit nodes are created for qualifier selectors,
 /// except for an alias to an x-default item.
 /// </remarks>
 /// <param name="arrayNode">an array node</param>
 /// <param name="qualName">the qualifier name</param>
 /// <param name="qualValue">the qualifier value</param>
 /// <param name="aliasForm">
 /// in case the qual selector results from an alias,
 /// an x-default node is created if there has not been one.
 /// </param>
 /// <returns>Returns the index of th</returns>
 /// <exception cref="Com.Adobe.Xmp.XMPException"></exception>
 private static int LookupQualSelector(XMPNode arrayNode, string qualName, string qualValue, int aliasForm)
 {
     if (XMPConstConstants.XmlLang.Equals(qualName))
     {
         qualValue = Utils.NormalizeLangValue(qualValue);
         int index = Com.Adobe.Xmp.Impl.XMPNodeUtils.LookupLanguageItem(arrayNode, qualValue);
         if (index < 0 && (aliasForm & AliasOptions.PropArrayAltText) > 0)
         {
             XMPNode langNode = new XMPNode(XMPConstConstants.ArrayItemName, null);
             XMPNode xdefault = new XMPNode(XMPConstConstants.XmlLang, XMPConstConstants.XDefault, null);
             langNode.AddQualifier(xdefault);
             arrayNode.AddChild(1, langNode);
             return(1);
         }
         else
         {
             return(index);
         }
     }
     else
     {
         for (int index = 1; index < arrayNode.GetChildrenLength(); index++)
         {
             XMPNode currItem = arrayNode.GetChild(index);
             for (Iterator it = currItem.IterateQualifier(); it.HasNext();)
             {
                 XMPNode qualifier = (XMPNode)it.Next();
                 if (qualName.Equals(qualifier.GetName()) && qualValue.Equals(qualifier.GetValue()))
                 {
                     return(index);
                 }
             }
         }
         return(-1);
     }
 }
 /// <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>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;
		}
Example #11
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);
        }
 /// <param name="arrayNode">an array node</param>
 /// <param name="segment">the segment containing the array index</param>
 /// <param name="createNodes">flag if new nodes are allowed to be created.</param>
 /// <returns>Returns the index or index = -1 if not found</returns>
 /// <exception cref="Com.Adobe.Xmp.XMPException">Throws Exceptions</exception>
 private static int FindIndexedItem(XMPNode arrayNode, string segment, bool createNodes)
 {
     int index = 0;
     try
     {
         segment = Sharpen.Runtime.Substring(segment, 1, segment.Length - 1);
         index = System.Convert.ToInt32(segment);
         if (index < 1)
         {
             throw new XMPException("Array index must be larger than zero", XMPErrorConstants.Badxpath);
         }
     }
     catch (FormatException)
     {
         throw new XMPException("Array index not digits.", XMPErrorConstants.Badxpath);
     }
     if (createNodes && index == arrayNode.GetChildrenLength() + 1)
     {
         // Append a new last + 1 node.
         XMPNode newItem = new XMPNode(XMPConstConstants.ArrayItemName, null);
         newItem.SetImplicit(true);
         arrayNode.AddChild(newItem);
     }
     return index;
 }
 /// <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;
 }
		// -------------------------------------------------------------------------------------
		// private
		/// <summary>Locate or create the item node and set the value.</summary>
		/// <remarks>
		/// Locate or create the item node and set the value. Note the index
		/// parameter is one-based! The index can be in the range [1..size + 1] or
		/// "last()", normalize it and check the insert flags. The order of the
		/// normalization checks is important. If the array is empty we end up with
		/// an index and location to set item size + 1.
		/// </remarks>
		/// <param name="arrayNode">an array node</param>
		/// <param name="itemIndex">the index where to insert the item</param>
		/// <param name="itemValue">the item value</param>
		/// <param name="itemOptions">the options for the new item</param>
		/// <param name="insert">insert oder overwrite at index position?</param>
		/// <exception cref="Com.Adobe.Xmp.XMPException"/>
		private void DoSetArrayItem(XMPNode arrayNode, int itemIndex, string itemValue, PropertyOptions itemOptions, bool insert)
		{
			XMPNode itemNode = new XMPNode(XMPConstConstants.ArrayItemName, null);
			itemOptions = XMPNodeUtils.VerifySetOptions(itemOptions, itemValue);
			// in insert mode the index after the last is allowed,
			// even ArrayLastItem points to the index *after* the last.
			int maxIndex = insert ? arrayNode.GetChildrenLength() + 1 : arrayNode.GetChildrenLength();
			if (itemIndex == XMPConstConstants.ArrayLastItem)
			{
				itemIndex = maxIndex;
			}
			if (1 <= itemIndex && itemIndex <= maxIndex)
			{
				if (!insert)
				{
					arrayNode.RemoveChild(itemIndex);
				}
				arrayNode.AddChild(itemIndex, itemNode);
				SetNode(itemNode, itemValue, itemOptions, false);
			}
			else
			{
				throw new XMPException("Array index out of bounds", XMPErrorConstants.Badindex);
			}
		}
 /// <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;
 }
Example #16
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>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>
 /// Searches for a qualifier selector in a node:
 /// [?qualName="value"] - an element in an array, chosen by a qualifier value.
 /// </summary>
 /// <remarks>
 /// Searches for a qualifier selector in a node:
 /// [?qualName="value"] - an element in an array, chosen by a qualifier value.
 /// No implicit nodes are created for qualifier selectors,
 /// except for an alias to an x-default item.
 /// </remarks>
 /// <param name="arrayNode">an array node</param>
 /// <param name="qualName">the qualifier name</param>
 /// <param name="qualValue">the qualifier value</param>
 /// <param name="aliasForm">
 /// in case the qual selector results from an alias,
 /// an x-default node is created if there has not been one.
 /// </param>
 /// <returns>Returns the index of th</returns>
 /// <exception cref="Com.Adobe.Xmp.XMPException"></exception>
 private static int LookupQualSelector(XMPNode arrayNode, string qualName, string qualValue, int aliasForm)
 {
     if (XMPConstConstants.XmlLang.Equals(qualName))
     {
         qualValue = Utils.NormalizeLangValue(qualValue);
         int index = Com.Adobe.Xmp.Impl.XMPNodeUtils.LookupLanguageItem(arrayNode, qualValue);
         if (index < 0 && (aliasForm & AliasOptions.PropArrayAltText) > 0)
         {
             XMPNode langNode = new XMPNode(XMPConstConstants.ArrayItemName, null);
             XMPNode xdefault = new XMPNode(XMPConstConstants.XmlLang, XMPConstConstants.XDefault, null);
             langNode.AddQualifier(xdefault);
             arrayNode.AddChild(1, langNode);
             return 1;
         }
         else
         {
             return index;
         }
     }
     else
     {
         for (int index = 1; index < arrayNode.GetChildrenLength(); index++)
         {
             XMPNode currItem = arrayNode.GetChild(index);
             for (Iterator it = currItem.IterateQualifier(); it.HasNext(); )
             {
                 XMPNode qualifier = (XMPNode)it.Next();
                 if (qualName.Equals(qualifier.GetName()) && qualValue.Equals(qualifier.GetValue()))
                 {
                     return index;
                 }
             }
         }
         return -1;
     }
 }
 /// <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);
                 }
             }
         }
     }
 }
Example #20
0
        /// <summary>
        /// see
        /// <see cref="Com.Adobe.Xmp.XMPUtils.SeparateArrayItems(Com.Adobe.Xmp.XMPMeta, string, string, string, Com.Adobe.Xmp.Options.PropertyOptions, bool)"/>
        /// </summary>
        /// <param name="xmp">The XMP object containing the array to be updated.</param>
        /// <param name="schemaNS">
        /// The schema namespace URI for the array. Must not be null or
        /// the empty string.
        /// </param>
        /// <param name="arrayName">
        /// The name of the array. May be a general path expression, must
        /// not be null or the empty string. Each item in the array must
        /// be a simple string value.
        /// </param>
        /// <param name="catedStr">The string to be separated into the array items.</param>
        /// <param name="arrayOptions">Option flags to control the separation.</param>
        /// <param name="preserveCommas">Flag if commas shall be preserved</param>
        /// <exception cref="Com.Adobe.Xmp.XMPException">Forwards the Exceptions from the metadata processing</exception>
        public static void SeparateArrayItems(XMPMeta xmp, string schemaNS, string arrayName, string catedStr, PropertyOptions arrayOptions, bool preserveCommas)
        {
            ParameterAsserts.AssertSchemaNS(schemaNS);
            ParameterAsserts.AssertArrayName(arrayName);
            if (catedStr == null)
            {
                throw new XMPException("Parameter must not be null", XMPErrorConstants.Badparam);
            }
            ParameterAsserts.AssertImplementation(xmp);
            XMPMetaImpl xmpImpl = (XMPMetaImpl)xmp;
            // Keep a zero value, has special meaning below.
            XMPNode arrayNode = SeparateFindCreateArray(schemaNS, arrayName, arrayOptions, xmpImpl);
            // Extract the item values one at a time, until the whole input string is done.
            string itemValue;
            int    itemStart;
            int    itemEnd;
            int    nextKind = UckNormal;
            int    charKind = UckNormal;
            char   ch       = (char)0;
            char   nextChar = (char)0;

            itemEnd = 0;
            int endPos = catedStr.Length;

            while (itemEnd < endPos)
            {
                // Skip any leading spaces and separation characters. Always skip commas here.
                // They can be kept when within a value, but not when alone between values.
                for (itemStart = itemEnd; itemStart < endPos; itemStart++)
                {
                    ch       = catedStr[itemStart];
                    charKind = ClassifyCharacter(ch);
                    if (charKind == UckNormal || charKind == UckQuote)
                    {
                        break;
                    }
                }
                if (itemStart >= endPos)
                {
                    break;
                }
                if (charKind != UckQuote)
                {
                    // This is not a quoted value. Scan for the end, create an array
                    // item from the substring.
                    for (itemEnd = itemStart; itemEnd < endPos; itemEnd++)
                    {
                        ch       = catedStr[itemEnd];
                        charKind = ClassifyCharacter(ch);
                        if (charKind == UckNormal || charKind == UckQuote || (charKind == UckComma && preserveCommas))
                        {
                            continue;
                        }
                        else
                        {
                            if (charKind != UckSpace)
                            {
                                break;
                            }
                            else
                            {
                                if ((itemEnd + 1) < endPos)
                                {
                                    ch       = catedStr[itemEnd + 1];
                                    nextKind = ClassifyCharacter(ch);
                                    if (nextKind == UckNormal || nextKind == UckQuote || (nextKind == UckComma && preserveCommas))
                                    {
                                        continue;
                                    }
                                }
                            }
                        }
                        // Anything left?
                        break;
                    }
                    // Have multiple spaces, or a space followed by a
                    // separator.
                    itemValue = Sharpen.Runtime.Substring(catedStr, itemStart, itemEnd);
                }
                else
                {
                    // Accumulate quoted values into a local string, undoubling
                    // internal quotes that
                    // match the surrounding quotes. Do not undouble "unmatching"
                    // quotes.
                    char openQuote  = ch;
                    char closeQuote = GetClosingQuote(openQuote);
                    itemStart++;
                    // Skip the opening quote;
                    itemValue = string.Empty;
                    for (itemEnd = itemStart; itemEnd < endPos; itemEnd++)
                    {
                        ch       = catedStr[itemEnd];
                        charKind = ClassifyCharacter(ch);
                        if (charKind != UckQuote || !IsSurroundingQuote(ch, openQuote, closeQuote))
                        {
                            // This is not a matching quote, just append it to the
                            // item value.
                            itemValue += ch;
                        }
                        else
                        {
                            // This is a "matching" quote. Is it doubled, or the
                            // final closing quote?
                            // Tolerate various edge cases like undoubled opening
                            // (non-closing) quotes,
                            // or end of input.
                            if ((itemEnd + 1) < endPos)
                            {
                                nextChar = catedStr[itemEnd + 1];
                                nextKind = ClassifyCharacter(nextChar);
                            }
                            else
                            {
                                nextKind = UckSemicolon;
                                nextChar = (char)unchecked ((int)(0x3B));
                            }
                            if (ch == nextChar)
                            {
                                // This is doubled, copy it and skip the double.
                                itemValue += ch;
                                // Loop will add in charSize.
                                itemEnd++;
                            }
                            else
                            {
                                if (!IsClosingingQuote(ch, openQuote, closeQuote))
                                {
                                    // This is an undoubled, non-closing quote, copy it.
                                    itemValue += ch;
                                }
                                else
                                {
                                    // This is an undoubled closing quote, skip it and
                                    // exit the loop.
                                    itemEnd++;
                                    break;
                                }
                            }
                        }
                    }
                }
                // Add the separated item to the array.
                // Keep a matching old value in case it had separators.
                int foundIndex = -1;
                for (int oldChild = 1; oldChild <= arrayNode.GetChildrenLength(); oldChild++)
                {
                    if (itemValue.Equals(arrayNode.GetChild(oldChild).GetValue()))
                    {
                        foundIndex = oldChild;
                        break;
                    }
                }
                XMPNode newItem = null;
                if (foundIndex < 0)
                {
                    newItem = new XMPNode(XMPConstConstants.ArrayItemName, itemValue, null);
                    arrayNode.AddChild(newItem);
                }
            }
        }
 /// <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);
     }
 }