예제 #1
0
		public virtual XMPProperty GetLocalizedText(String schemaNS, String altTextName, 
			String genericLang, String specificLang)
		{
			ParameterAsserts.AssertSchemaNS(schemaNS);
			ParameterAsserts.AssertArrayName(altTextName);
			ParameterAsserts.AssertSpecificLang(specificLang);
			genericLang = genericLang != null ? iText.Kernel.XMP.Impl.Utils.NormalizeLangValue
				(genericLang) : null;
			specificLang = iText.Kernel.XMP.Impl.Utils.NormalizeLangValue(specificLang);
			XMPPath arrayPath = XMPPathParser.ExpandXPath(schemaNS, altTextName);
			XMPNode arrayNode = XMPNodeUtils.FindNode(tree, arrayPath, false, null);
			if (arrayNode == null)
			{
				return null;
			}
			Object[] result = XMPNodeUtils.ChooseLocalizedText(arrayNode, genericLang, specificLang
				);
			int match = (int)result[0];
			XMPNode itemNode = (XMPNode)result[1];
			if (match != XMPNodeUtils.CLT_NO_VALUES)
			{
				return new _XMPProperty_428(itemNode);
			}
			else
			{
				return null;
			}
		}
예제 #2
0
        // EMPTY
        /// <summary>
        /// Parses the input source into an XMP metadata object, including
        /// de-aliasing and normalisation.
        /// </summary>
        /// <param name="input">
        /// the input can be an <code>InputStream</code>, a <code>String</code> or
        /// a byte buffer containing the XMP packet.
        /// </param>
        /// <param name="options">the parse options</param>
        /// <returns>Returns the resulting XMP metadata object</returns>
        /// <exception cref="iText.Kernel.XMP.XMPException">Thrown if parsing or normalisation fails.
        ///     </exception>
        public static XMPMeta Parse(Object input, ParseOptions options)
        {
            ParameterAsserts.AssertNotNull(input);
            options = options ?? new ParseOptions();

            XmlDocument document = ParseXml(input, options);

            bool xmpmetaRequired = options.GetRequireXMPMeta();

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

            if (result != null && result[1] == XMP_RDF)
            {
                XMPMetaImpl xmp = ParseRdf.Parse((XmlNode)result[0]);
                xmp.SetPacketHeader((string)result[2]);

                // Check if the XMP object shall be normalized
                if (!options.GetOmitNormalization())
                {
                    return(XMPNormalizer.Process(xmp, options));
                }
                return(xmp);
            }
            // no appropriate root node found, return empty metadata object
            return(new XMPMetaImpl());
        }
예제 #3
0
		public virtual XMPProperty GetArrayItem(String schemaNS, String arrayName, int itemIndex
			)
		{
			ParameterAsserts.AssertSchemaNS(schemaNS);
			ParameterAsserts.AssertArrayName(arrayName);
			String itemPath = XMPPathFactory.ComposeArrayItemPath(arrayName, itemIndex);
			return GetProperty(schemaNS, itemPath);
		}
예제 #4
0
		public virtual void SetStructField(String schemaNS, String structName, String fieldNS
			, String fieldName, String fieldValue, PropertyOptions options)
		{
			ParameterAsserts.AssertSchemaNS(schemaNS);
			ParameterAsserts.AssertStructName(structName);
			String fieldPath = structName + XMPPathFactory.ComposeStructFieldPath(fieldNS, fieldName
				);
			SetProperty(schemaNS, fieldPath, fieldValue, options);
		}
예제 #5
0
		public virtual XMPProperty GetStructField(String schemaNS, String structName, String
			 fieldNS, String fieldName)
		{
			// fieldNS and fieldName are checked inside composeStructFieldPath
			ParameterAsserts.AssertSchemaNS(schemaNS);
			ParameterAsserts.AssertStructName(structName);
			String fieldPath = structName + XMPPathFactory.ComposeStructFieldPath(fieldNS, fieldName
				);
			return GetProperty(schemaNS, fieldPath);
		}
예제 #6
0
		public virtual XMPProperty GetQualifier(String schemaNS, String propName, String 
			qualNS, String qualName)
		{
			// qualNS and qualName are checked inside composeQualfierPath
			ParameterAsserts.AssertSchemaNS(schemaNS);
			ParameterAsserts.AssertPropName(propName);
			String qualPath = propName + XMPPathFactory.ComposeQualifierPath(qualNS, qualName
				);
			return GetProperty(schemaNS, qualPath);
		}
예제 #7
0
		public virtual void AppendArrayItem(String schemaNS, String arrayName, PropertyOptions
			 arrayOptions, String itemValue, PropertyOptions itemOptions)
		{
			ParameterAsserts.AssertSchemaNS(schemaNS);
			ParameterAsserts.AssertArrayName(arrayName);
			if (arrayOptions == null)
			{
				arrayOptions = new PropertyOptions();
			}
			if (!arrayOptions.IsOnlyArrayOptions())
			{
				throw new XMPException("Only array form flags allowed for arrayOptions", XMPError
					.BADOPTIONS);
			}
			// Check if array options are set correctly.
			arrayOptions = XMPNodeUtils.VerifySetOptions(arrayOptions, null);
			// Locate or create the array. If it already exists, make sure the array
			// form from the options
			// parameter is compatible with the current state.
			XMPPath arrayPath = XMPPathParser.ExpandXPath(schemaNS, arrayName);
			// Just lookup, don't try to create.
			XMPNode arrayNode = XMPNodeUtils.FindNode(tree, arrayPath, false, null);
			if (arrayNode != null)
			{
				// The array exists, make sure the form is compatible. Zero
				// arrayForm means take what exists.
				if (!arrayNode.GetOptions().IsArray())
				{
					throw new XMPException("The named property is not an array", XMPError.BADXPATH);
				}
			}
			else
			{
				// if (arrayOptions != null && !arrayOptions.equalArrayTypes(arrayNode.getOptions()))
				// {
				// throw new XMPException("Mismatch of existing and specified array form", BADOPTIONS);
				// }
				// The array does not exist, try to create it.
				if (arrayOptions.IsArray())
				{
					arrayNode = XMPNodeUtils.FindNode(tree, arrayPath, true, arrayOptions);
					if (arrayNode == null)
					{
						throw new XMPException("Failure creating array node", XMPError.BADXPATH);
					}
				}
				else
				{
					// array options missing
					throw new XMPException("Explicit arrayOptions required to create new array", XMPError
						.BADOPTIONS);
				}
			}
			DoSetArrayItem(arrayNode, ARRAY_LAST_ITEM, itemValue, itemOptions, true);
		}
예제 #8
0
		public virtual void SetQualifier(String schemaNS, String propName, String qualNS, 
			String qualName, String qualValue, PropertyOptions options)
		{
			ParameterAsserts.AssertSchemaNS(schemaNS);
			ParameterAsserts.AssertPropName(propName);
			if (!DoesPropertyExist(schemaNS, propName))
			{
				throw new XMPException("Specified property does not exist!", XMPError.BADXPATH);
			}
			String qualPath = propName + XMPPathFactory.ComposeQualifierPath(qualNS, qualName
				);
			SetProperty(schemaNS, qualPath, qualValue, options);
		}
예제 #9
0
 /// <summary>Associates an alias name with an actual name.</summary>
 /// <remarks>
 /// Associates an alias name with an actual name.
 /// <para>
 /// Define a alias mapping from one namespace/property to another. Both
 /// property names must be simple names. An alias can be a direct mapping,
 /// where the alias and actual have the same data type. It is also possible
 /// to map a simple alias to an item in an array. This can either be to the
 /// first item in the array, or to the 'x-default' item in an alt-text array.
 /// Multiple alias names may map to the same actual, as long as the forms
 /// match. It is a no-op to reregister an alias in an identical fashion.
 /// Note: This method is not locking because only called by registerStandardAliases
 /// which is only called by the constructor.
 /// Note2: The method is only package-private so that it can be tested with unittests
 /// </para>
 /// </remarks>
 /// <param name="aliasNS">
 /// The namespace URI for the alias. Must not be null or the empty
 /// string.
 /// </param>
 /// <param name="aliasProp">
 /// The name of the alias. Must be a simple name, not null or the
 /// empty string and not a general path expression.
 /// </param>
 /// <param name="actualNS">
 /// The namespace URI for the actual. Must not be null or the
 /// empty string.
 /// </param>
 /// <param name="actualProp">
 /// The name of the actual. Must be a simple name, not null or the
 /// empty string and not a general path expression.
 /// </param>
 /// <param name="aliasForm">
 /// Provides options for aliases for simple aliases to array
 /// items. This is needed to know what kind of array to create if
 /// set for the first time via the simple alias. Pass
 /// <code>XMP_NoOptions</code>, the default value, for all
 /// direct aliases regardless of whether the actual data type is
 /// an array or not (see
 /// <see cref="iText.Kernel.XMP.Options.AliasOptions"/>
 /// ).
 /// </param>
 /// <exception cref="iText.Kernel.XMP.XMPException">for inconsistant aliases.</exception>
 internal void RegisterAlias(String aliasNS, String aliasProp, String actualNS, String
                             actualProp, AliasOptions aliasForm)
 {
     lock (this)
     {
         ParameterAsserts.AssertSchemaNS(aliasNS);
         ParameterAsserts.AssertPropName(aliasProp);
         ParameterAsserts.AssertSchemaNS(actualNS);
         ParameterAsserts.AssertPropName(actualProp);
         // Fix the alias options
         AliasOptions aliasOpts = aliasForm != null ? new AliasOptions(XMPNodeUtils.VerifySetOptions
                                                                           (aliasForm.ToPropertyOptions(), null).GetOptions()) : new AliasOptions();
         if (_regex.IsMatch(aliasProp) || _regex.IsMatch(actualProp))
         {
             throw new XMPException("Alias and actual property names must be simple", XMPError.BADXPATH);
         }
         // check if both namespaces are registered
         String aliasPrefix  = GetNamespacePrefix(aliasNS);
         String actualPrefix = GetNamespacePrefix(actualNS);
         if (aliasPrefix == null)
         {
             throw new XMPException("Alias namespace is not registered", XMPError.BADSCHEMA);
         }
         else
         {
             if (actualPrefix == null)
             {
                 throw new XMPException("Actual namespace is not registered", XMPError.BADSCHEMA);
             }
         }
         String key = aliasPrefix + aliasProp;
         // check if alias is already existing
         if (aliasMap.Contains(key))
         {
             throw new XMPException("Alias is already existing", XMPError.BADPARAM);
         }
         else
         {
             if (aliasMap.Contains(actualPrefix + actualProp))
             {
                 throw new XMPException("Actual property is already an alias, use the base property"
                                        , XMPError.BADPARAM);
             }
         }
         XMPAliasInfo aliasInfo = new _XMPAliasInfo_409(actualNS, actualPrefix, actualProp
                                                        , aliasOpts);
         aliasMap[key] = aliasInfo;
     }
 }
예제 #10
0
		public virtual void DeleteArrayItem(String schemaNS, String arrayName, int itemIndex
			)
		{
			try
			{
				ParameterAsserts.AssertSchemaNS(schemaNS);
				ParameterAsserts.AssertArrayName(arrayName);
				String itemPath = XMPPathFactory.ComposeArrayItemPath(arrayName, itemIndex);
				DeleteProperty(schemaNS, itemPath);
			}
			catch (XMPException)
			{
				// EMPTY, exceptions are ignored within delete
			}
		}
예제 #11
0
		public virtual bool DoesArrayItemExist(String schemaNS, String arrayName, int itemIndex
			)
		{
			try
			{
				ParameterAsserts.AssertSchemaNS(schemaNS);
				ParameterAsserts.AssertArrayName(arrayName);
				String path = XMPPathFactory.ComposeArrayItemPath(arrayName, itemIndex);
				return DoesPropertyExist(schemaNS, path);
			}
			catch (XMPException)
			{
				return false;
			}
		}
예제 #12
0
		public virtual bool DoesPropertyExist(String schemaNS, String propName)
		{
			try
			{
				ParameterAsserts.AssertSchemaNS(schemaNS);
				ParameterAsserts.AssertPropName(propName);
				XMPPath expPath = XMPPathParser.ExpandXPath(schemaNS, propName);
				XMPNode propNode = XMPNodeUtils.FindNode(tree, expPath, false, null);
				return propNode != null;
			}
			catch (XMPException)
			{
				return false;
			}
		}
예제 #13
0
		public virtual bool DoesQualifierExist(String schemaNS, String propName, String qualNS
			, String qualName)
		{
			try
			{
				// qualNS and qualName are checked inside composeQualifierPath()
				ParameterAsserts.AssertSchemaNS(schemaNS);
				ParameterAsserts.AssertPropName(propName);
				String path = XMPPathFactory.ComposeQualifierPath(qualNS, qualName);
				return DoesPropertyExist(schemaNS, propName + path);
			}
			catch (XMPException)
			{
				return false;
			}
		}
예제 #14
0
		public virtual bool DoesStructFieldExist(String schemaNS, String structName, String
			 fieldNS, String fieldName)
		{
			try
			{
				// fieldNS and fieldName are checked inside composeStructFieldPath()
				ParameterAsserts.AssertSchemaNS(schemaNS);
				ParameterAsserts.AssertStructName(structName);
				String path = XMPPathFactory.ComposeStructFieldPath(fieldNS, fieldName);
				return DoesPropertyExist(schemaNS, structName + path);
			}
			catch (XMPException)
			{
				return false;
			}
		}
예제 #15
0
		public virtual void SetProperty(String schemaNS, String propName, Object propValue
			, PropertyOptions options)
		{
			ParameterAsserts.AssertSchemaNS(schemaNS);
			ParameterAsserts.AssertPropName(propName);
			options = XMPNodeUtils.VerifySetOptions(options, propValue);
			XMPPath expPath = XMPPathParser.ExpandXPath(schemaNS, propName);
			XMPNode propNode = XMPNodeUtils.FindNode(tree, expPath, true, options);
			if (propNode != null)
			{
				SetNode(propNode, propValue, options, false);
			}
			else
			{
				throw new XMPException("Specified property does not exist", XMPError.BADXPATH);
			}
		}
예제 #16
0
		public virtual void InsertArrayItem(String schemaNS, String arrayName, int itemIndex
			, String itemValue, PropertyOptions options)
		{
			ParameterAsserts.AssertSchemaNS(schemaNS);
			ParameterAsserts.AssertArrayName(arrayName);
			// Just lookup, don't try to create.
			XMPPath arrayPath = XMPPathParser.ExpandXPath(schemaNS, arrayName);
			XMPNode arrayNode = XMPNodeUtils.FindNode(tree, arrayPath, false, null);
			if (arrayNode != null)
			{
				DoSetArrayItem(arrayNode, itemIndex, itemValue, options, true);
			}
			else
			{
				throw new XMPException("Specified array does not exist", XMPError.BADXPATH);
			}
		}
예제 #17
0
		public virtual void DeleteStructField(String schemaNS, String structName, String 
			fieldNS, String fieldName)
		{
			try
			{
				// fieldNS and fieldName are checked inside composeStructFieldPath
				ParameterAsserts.AssertSchemaNS(schemaNS);
				ParameterAsserts.AssertStructName(structName);
				String fieldPath = structName + XMPPathFactory.ComposeStructFieldPath(fieldNS, fieldName
					);
				DeleteProperty(schemaNS, fieldPath);
			}
			catch (XMPException)
			{
				// EMPTY, exceptions within delete are ignored
			}
		}
예제 #18
0
		public virtual void DeleteQualifier(String schemaNS, String propName, String qualNS
			, String qualName)
		{
			try
			{
				// Note: qualNS and qualName are checked inside composeQualfierPath
				ParameterAsserts.AssertSchemaNS(schemaNS);
				ParameterAsserts.AssertPropName(propName);
				String qualPath = propName + XMPPathFactory.ComposeQualifierPath(qualNS, qualName
					);
				DeleteProperty(schemaNS, qualPath);
			}
			catch (XMPException)
			{
				// EMPTY, exceptions within delete are ignored
			}
		}
예제 #19
0
		public virtual void DeleteProperty(String schemaNS, String propName)
		{
			try
			{
				ParameterAsserts.AssertSchemaNS(schemaNS);
				ParameterAsserts.AssertPropName(propName);
				XMPPath expPath = XMPPathParser.ExpandXPath(schemaNS, propName);
				XMPNode propNode = XMPNodeUtils.FindNode(tree, expPath, false, null);
				if (propNode != null)
				{
					XMPNodeUtils.DeleteNode(propNode);
				}
			}
			catch (XMPException)
			{
				// EMPTY, exceptions are ignored within delete
			}
		}
예제 #20
0
		public virtual int CountArrayItems(String schemaNS, String arrayName)
		{
			ParameterAsserts.AssertSchemaNS(schemaNS);
			ParameterAsserts.AssertArrayName(arrayName);
			XMPPath arrayPath = XMPPathParser.ExpandXPath(schemaNS, arrayName);
			XMPNode arrayNode = XMPNodeUtils.FindNode(tree, arrayPath, false, null);
			if (arrayNode == null)
			{
				return 0;
			}
			if (arrayNode.GetOptions().IsArray())
			{
				return arrayNode.GetChildrenLength();
			}
			else
			{
				throw new XMPException("The named property is not an array", XMPError.BADXPATH);
			}
		}
예제 #21
0
 // ---------------------------------------------------------------------------------------------
 // Namespace Functions
 /// <seealso cref="iText.Kernel.XMP.XMPSchemaRegistry.RegisterNamespace(System.String, System.String)
 ///     "/>
 /// <exception cref="iText.Kernel.XMP.XMPException"/>
 public String RegisterNamespace(String namespaceURI, String suggestedPrefix)
 {
     lock (this)
     {
         ParameterAsserts.AssertSchemaNS(namespaceURI);
         ParameterAsserts.AssertPrefix(suggestedPrefix);
         if (suggestedPrefix[suggestedPrefix.Length - 1] != ':')
         {
             suggestedPrefix += ':';
         }
         if (!Utils.IsXMLNameNS(suggestedPrefix.JSubstring(0, suggestedPrefix.Length - 1)))
         {
             throw new XMPException("The prefix is a bad XML name", XMPError.BADXML);
         }
         String registeredPrefix = (String)namespaceToPrefixMap[namespaceURI];
         String registeredNS     = (String)prefixToNamespaceMap[suggestedPrefix];
         if (registeredPrefix != null)
         {
             // Return the actual prefix
             return(registeredPrefix);
         }
         else
         {
             if (registeredNS != null)
             {
                 // the namespace is new, but the prefix is already engaged,
                 // we generate a new prefix out of the suggested
                 String generatedPrefix = suggestedPrefix;
                 for (int i = 1; prefixToNamespaceMap.Contains(generatedPrefix); i++)
                 {
                     generatedPrefix = suggestedPrefix.JSubstring(0, suggestedPrefix.Length - 1) + "_"
                                       + i + "_:";
                 }
                 suggestedPrefix = generatedPrefix;
             }
             prefixToNamespaceMap[suggestedPrefix] = namespaceURI;
             namespaceToPrefixMap[namespaceURI]    = suggestedPrefix;
             // Return the suggested prefix
             return(suggestedPrefix);
         }
     }
 }
예제 #22
0
		/// <summary>Returns a property, but the result value can be requested.</summary>
		/// <seealso cref="iText.Kernel.XMP.XMPMeta.GetProperty(System.String, System.String)
		/// 	"/>
		/// <param name="schemaNS">a schema namespace</param>
		/// <param name="propName">a property name or path</param>
		/// <param name="valueType">the type of the value, see VALUE_...</param>
		/// <returns>
		/// Returns the node value as an object according to the
		/// <code>valueType</code>.
		/// </returns>
		/// <exception cref="iText.Kernel.XMP.XMPException">Collects any exception that occurs.</exception>
		protected internal virtual Object GetPropertyObject(String schemaNS, String propName
			, int valueType)
		{
			ParameterAsserts.AssertSchemaNS(schemaNS);
			ParameterAsserts.AssertPropName(propName);
			XMPPath expPath = XMPPathParser.ExpandXPath(schemaNS, propName);
			XMPNode propNode = XMPNodeUtils.FindNode(tree, expPath, false, null);
			if (propNode != null)
			{
				if (valueType != VALUE_STRING && propNode.GetOptions().IsCompositeProperty())
				{
					throw new XMPException("Property must be simple when a value type is requested", 
						XMPError.BADXPATH);
				}
				return EvaluateNodeValue(valueType, propNode);
			}
			else
			{
				return null;
			}
		}
예제 #23
0
		public virtual void SetLocalizedText(String schemaNS, String altTextName, String 
			genericLang, String specificLang, String itemValue, PropertyOptions options)
		{
			ParameterAsserts.AssertSchemaNS(schemaNS);
			ParameterAsserts.AssertArrayName(altTextName);
			ParameterAsserts.AssertSpecificLang(specificLang);
			genericLang = genericLang != null ? iText.Kernel.XMP.Impl.Utils.NormalizeLangValue
				(genericLang) : null;
			specificLang = iText.Kernel.XMP.Impl.Utils.NormalizeLangValue(specificLang);
			XMPPath arrayPath = XMPPathParser.ExpandXPath(schemaNS, altTextName);
			// Find the array node and set the options if it was just created.
			XMPNode arrayNode = XMPNodeUtils.FindNode(tree, arrayPath, true, new PropertyOptions
				(PropertyOptions.ARRAY | PropertyOptions.ARRAY_ORDERED | PropertyOptions.ARRAY_ALTERNATE
				 | PropertyOptions.ARRAY_ALT_TEXT));
			if (arrayNode == null)
			{
				throw new XMPException("Failed to find or create array node", XMPError.BADXPATH);
			}
			else
			{
				if (!arrayNode.GetOptions().IsArrayAltText())
				{
					if (!arrayNode.HasChildren() && arrayNode.GetOptions().IsArrayAlternate())
					{
						arrayNode.GetOptions().SetArrayAltText(true);
					}
					else
					{
						throw new XMPException("Specified property is no alt-text array", XMPError.BADXPATH
							);
					}
				}
			}
			// Make sure the x-default item, if any, is first.
			bool haveXDefault = false;
			XMPNode xdItem = null;
			foreach (XMPNode currItem in arrayNode.GetChildren())
			{
				if (!currItem.HasQualifier() || !XMPConst.XML_LANG.Equals(currItem.GetQualifier(1
					).GetName()))
				{
					throw new XMPException("Language qualifier must be first", XMPError.BADXPATH);
				}
				else
				{
					if (XMPConst.X_DEFAULT.Equals(currItem.GetQualifier(1).GetValue()))
					{
						xdItem = currItem;
						haveXDefault = true;
						break;
					}
				}
			}
			// Moves x-default to the beginning of the array
			if (xdItem != null && arrayNode.GetChildrenLength() > 1)
			{
				arrayNode.RemoveChild(xdItem);
				arrayNode.AddChild(1, xdItem);
			}
			// Find the appropriate item.
			// chooseLocalizedText will make sure the array is a language
			// alternative.
			Object[] result = XMPNodeUtils.ChooseLocalizedText(arrayNode, genericLang, specificLang
				);
			int match = (int)result[0];
			XMPNode itemNode = (XMPNode)result[1];
			bool specificXDefault = XMPConst.X_DEFAULT.Equals(specificLang);
			switch (match)
			{
				case XMPNodeUtils.CLT_NO_VALUES:
				{
					// Create the array items for the specificLang and x-default, with
					// x-default first.
					XMPNodeUtils.AppendLangItem(arrayNode, XMPConst.X_DEFAULT, itemValue);
					haveXDefault = true;
					if (!specificXDefault)
					{
						XMPNodeUtils.AppendLangItem(arrayNode, specificLang, itemValue);
					}
					break;
				}

				case XMPNodeUtils.CLT_SPECIFIC_MATCH:
				{
					if (!specificXDefault)
					{
						// Update the specific item, update x-default if it matches the
						// old value.
						if (haveXDefault && xdItem != itemNode && xdItem != null && xdItem.GetValue().Equals
							(itemNode.GetValue()))
						{
							xdItem.SetValue(itemValue);
						}
						// ! Do this after the x-default check!
						itemNode.SetValue(itemValue);
					}
					else
					{
						// Update all items whose values match the old x-default value.
						System.Diagnostics.Debug.Assert(haveXDefault && xdItem == itemNode);
						for (IEnumerator it_1 = arrayNode.IterateChildren(); it_1.MoveNext(); )
						{
							XMPNode currItem = (XMPNode)it_1.Current;
							if (currItem == xdItem || !currItem.GetValue().Equals(xdItem != null ? xdItem.GetValue
								() : null))
							{
								continue;
							}
							currItem.SetValue(itemValue);
						}
						// And finally do the x-default item.
						if (xdItem != null)
						{
							xdItem.SetValue(itemValue);
						}
					}
					break;
				}

				case XMPNodeUtils.CLT_SINGLE_GENERIC:
				{
					// Update the generic item, update x-default if it matches the old
					// value.
					if (haveXDefault && xdItem != itemNode && xdItem != null && xdItem.GetValue().Equals
						(itemNode.GetValue()))
					{
						xdItem.SetValue(itemValue);
					}
					itemNode.SetValue(itemValue);
					// ! Do this after
					// the x-default
					// check!
					break;
				}

				case XMPNodeUtils.CLT_MULTIPLE_GENERIC:
				{
					// Create the specific language, ignore x-default.
					XMPNodeUtils.AppendLangItem(arrayNode, specificLang, itemValue);
					if (specificXDefault)
					{
						haveXDefault = true;
					}
					break;
				}

				case XMPNodeUtils.CLT_XDEFAULT:
				{
					// Create the specific language, update x-default if it was the only
					// item.
					if (xdItem != null && arrayNode.GetChildrenLength() == 1)
					{
						xdItem.SetValue(itemValue);
					}
					XMPNodeUtils.AppendLangItem(arrayNode, specificLang, itemValue);
					break;
				}

				case XMPNodeUtils.CLT_FIRST_ITEM:
				{
					// Create the specific language, don't add an x-default item.
					XMPNodeUtils.AppendLangItem(arrayNode, specificLang, itemValue);
					if (specificXDefault)
					{
						haveXDefault = true;
					}
					break;
				}

				default:
				{
					// does not happen under normal circumstances
					throw new XMPException("Unexpected result from ChooseLocalizedText", XMPError.INTERNALFAILURE
						);
				}
			}
			// Add an x-default at the front if needed.
			if (!haveXDefault && arrayNode.GetChildrenLength() == 1)
			{
				XMPNodeUtils.AppendLangItem(arrayNode, XMPConst.X_DEFAULT, itemValue);
			}
		}