/// <summary>Find or create a schema node if <c>createNodes</c> is true.</summary>
 /// <param name="tree">the root of the xmp tree.</param>
 /// <param name="namespaceUri">a namespace</param>
 /// <param name="suggestedPrefix">If a prefix is suggested, the namespace is allowed to be registered.</param>
 /// <param name="createNodes">
 /// a flag indicating if the node shall be created if not found.
 /// <em>Note:</em> The namespace must be registered prior to this call.
 /// </param>
 /// <returns>
 /// Returns the schema node if found, <c>null</c> otherwise.
 /// Note: If <c>createNodes</c> is <c>true</c>, it is <b>always</b>
 /// returned a valid node.
 /// </returns>
 /// <exception cref="XmpException">
 /// An exception is only thrown if an error occurred, not if a
 /// node was not found.
 /// </exception>
 internal static XmpNode FindSchemaNode(XmpNode tree, string namespaceUri, string suggestedPrefix, bool createNodes)
 {
     Debug.Assert(tree.Parent == null);
     // make sure that its the root
     var schemaNode = tree.FindChildByName(namespaceUri);
     if (schemaNode == null && createNodes)
     {
         var po = new PropertyOptions { IsSchemaNode = true };
         schemaNode = new XmpNode(namespaceUri, po) { IsImplicit = true };
         // only previously registered schema namespaces are allowed in the XMP tree.
         var prefix = XmpMetaFactory.SchemaRegistry.GetNamespacePrefix(namespaceUri);
         if (prefix == null)
         {
             if (!string.IsNullOrEmpty(suggestedPrefix))
             {
                 prefix = XmpMetaFactory.SchemaRegistry.RegisterNamespace(namespaceUri, suggestedPrefix);
             }
             else
             {
                 throw new XmpException("Unregistered schema namespace URI", XmpErrorCode.BadSchema);
             }
         }
         schemaNode.Value = prefix;
         tree.AddChild(schemaNode);
     }
     return schemaNode;
 }
Beispiel #2
0
 /// <exception cref="XmpException"/>
 public 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", XmpErrorCode.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.
     var arrayPath = XmpPathParser.ExpandXPath(schemaNs, arrayName);
     // Just lookup, don't try to create.
     var 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.Options.IsArray)
         {
             throw new XmpException("The named property is not an array", XmpErrorCode.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", XmpErrorCode.BadXPath);
             }
         }
         else
         {
             // array options missing
             throw new XmpException("Explicit arrayOptions required to create new array", XmpErrorCode.BadOptions);
         }
     }
     DoSetArrayItem(arrayNode, XmpConstants.ArrayLastItem, itemValue, itemOptions, true);
 }
Beispiel #3
0
 /// <exception cref="XmpException"/>
 public void SetPropertyBase64(string schemaNs, string propName, byte[] propValue, PropertyOptions options)
 {
     SetProperty(schemaNs, propName, propValue, options);
 }
Beispiel #4
0
 /// <exception cref="XmpException"/>
 public void SetPropertyCalendar(string schemaNs, string propName, Calendar propValue, PropertyOptions options)
 {
     SetProperty(schemaNs, propName, propValue, options);
 }
Beispiel #5
0
 /// <exception cref="XmpException"/>
 public void SetPropertyDate(string schemaNs, string propName, IXmpDateTime propValue, PropertyOptions options)
 {
     SetProperty(schemaNs, propName, propValue, options);
 }
 /// <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 <c>null</c>.</returns>
 /// <exception cref="XmpException">Thrown if</exception>
 internal static XmpNode FindChildNode(XmpNode parent, string childName, bool createNodes)
 {
     if (!parent.Options.IsSchemaNode && !parent.Options.IsStruct)
     {
         if (!parent.IsImplicit)
         {
             throw new XmpException("Named children only allowed for schemas and structs", XmpErrorCode.BadXPath);
         }
         if (parent.Options.IsArray)
         {
             throw new XmpException("Named children not allowed for arrays", XmpErrorCode.BadXPath);
         }
         if (createNodes)
         {
             parent.Options.IsStruct = true;
         }
     }
     var childNode = parent.FindChildByName(childName);
     if (childNode == null && createNodes)
     {
         var options = new PropertyOptions();
         childNode = new XmpNode(childName, options) { IsImplicit = true };
         parent.AddChild(childNode);
     }
     Debug.Assert(childNode != null || !createNodes);
     return childNode;
 }
Beispiel #7
0
 /// <summary>Separate a single edit string into an array of strings.</summary>
 /// <param name="xmp">The XMP object containing the array to be updated.</param>
 /// <param name="schemaNs">
 /// The schema namespace URI for the array. Must not be null or
 /// the empty string.
 /// </param>
 /// <param name="arrayName">
 /// The name of the array. May be a general path expression, must
 /// not be null or the empty string. Each item in the array must
 /// be a simple string value.
 /// </param>
 /// <param name="catedStr">The string to be separated into the array items.</param>
 /// <param name="arrayOptions">Option flags to control the separation.</param>
 /// <param name="preserveCommas">Flag if commas shall be preserved</param>
 /// <exception cref="XmpException">Forwards the Exceptions from the metadata processing</exception>
 /// <exception cref="XmpException"/>
 public static void SeparateArrayItems(IXmpMeta xmp, string schemaNs, string arrayName, string catedStr, PropertyOptions arrayOptions, bool preserveCommas)
 {
     Impl.XmpUtils.SeparateArrayItems(xmp, schemaNs, arrayName, catedStr, arrayOptions, preserveCommas);
 }
Beispiel #8
0
 /// <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="XmpException"/>
 private void DoSetArrayItem(XmpNode arrayNode, int itemIndex, string itemValue, PropertyOptions itemOptions, bool insert)
 {
     var itemNode = new XmpNode(XmpConstants.ArrayItemName, null);
     itemOptions = XmpNodeUtils.VerifySetOptions(itemOptions, itemValue);
     // in insert mode the index after the last is allowed,
     // even ARRAY_LAST_ITEM points to the index *after* the last.
     var maxIndex = insert ? arrayNode.GetChildrenLength() + 1 : arrayNode.GetChildrenLength();
     if (itemIndex == XmpConstants.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", XmpErrorCode.BadIndex);
     }
 }
Beispiel #9
0
 /// <exception cref="XmpException"/>
 public 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!", XmpErrorCode.BadXPath);
     }
     var qualPath = propName + XmpPathFactory.ComposeQualifierPath(qualNs, qualName);
     SetProperty(schemaNs, qualPath, qualValue, options);
 }
Beispiel #10
0
 /// <exception cref="XmpException"/>
 public void SetPropertyBoolean(string schemaNs, string propName, bool propValue, PropertyOptions options)
 {
     SetProperty(schemaNs, propName, propValue ? XmpConstants.TrueString : XmpConstants.FalseString, options);
 }
Beispiel #11
0
        /// <exception cref="XmpException"/>
        public 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 ? Utils.NormalizeLangValue(genericLang) : null;
            specificLang = Utils.NormalizeLangValue(specificLang);
            var arrayPath = XmpPathParser.ExpandXPath(schemaNs, altTextName);
            // Find the array node and set the options if it was just created.
            var arrayNode = XmpNodeUtils.FindNode(_tree, arrayPath, true, new PropertyOptions(PropertyOptions.ArrayFlag | PropertyOptions.ArrayOrderedFlag | PropertyOptions.ArrayAlternateFlag | PropertyOptions.ArrayAltTextFlag));
            if (arrayNode == null)
            {
                throw new XmpException("Failed to find or create array node", XmpErrorCode.BadXPath);
            }
            if (!arrayNode.Options.IsArrayAltText)
            {
                if (!arrayNode.HasChildren && arrayNode.Options.IsArrayAlternate)
                {
                    arrayNode.Options.IsArrayAltText = true;
                }
                else
                {
                    throw new XmpException("Specified property is no alt-text array", XmpErrorCode.BadXPath);
                }
            }
            // Make sure the x-default item, if any, is first.
            var haveXDefault = false;
            XmpNode xdItem = null;
            for (var it = arrayNode.IterateChildren(); it.HasNext(); )
            {
                var currItem = (XmpNode)it.Next();
                if (!currItem.HasQualifier || !XmpConstants.XmlLang.Equals(currItem.GetQualifier(1).Name))
                {
                    throw new XmpException("Language qualifier must be first", XmpErrorCode.BadXPath);
                }
                if (XmpConstants.XDefault.Equals(currItem.GetQualifier(1).Value))
                {
                    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.
            var result = XmpNodeUtils.ChooseLocalizedText(arrayNode, genericLang, specificLang);
            var match = (int)result[0];
            var itemNode = (XmpNode)result[1];
            var specificXDefault = XmpConstants.XDefault.Equals(specificLang);
            switch (match)
            {
                case XmpNodeUtils.CltNoValues:
                {
                    // Create the array items for the specificLang and x-default, with
                    // x-default first.
                    XmpNodeUtils.AppendLangItem(arrayNode, XmpConstants.XDefault, itemValue);
                    haveXDefault = true;
                    if (!specificXDefault)
                    {
                        XmpNodeUtils.AppendLangItem(arrayNode, specificLang, itemValue);
                    }
                    break;
                }

                case XmpNodeUtils.CltSpecificMatch:
                {
                    if (!specificXDefault)
                    {
                        // Update the specific item, update x-default if it matches the
                        // old value.
                        if (haveXDefault && xdItem != itemNode && xdItem != null && xdItem.Value.Equals(itemNode.Value))
                        {
                            xdItem.Value = itemValue;
                        }
                        // ! Do this after the x-default check!
                        itemNode.Value = itemValue;
                    }
                    else
                    {
                        // Update all items whose values match the old x-default value.
                        Debug.Assert(haveXDefault && xdItem == itemNode);
                        for (var it1 = arrayNode.IterateChildren(); it1.HasNext(); )
                        {
                            var currItem = (XmpNode)it1.Next();
                            if (currItem == xdItem || !currItem.Value.Equals(xdItem != null ? xdItem.Value : null))
                            {
                                continue;
                            }
                            currItem.Value = itemValue;
                        }
                        // And finally do the x-default item.
                        if (xdItem != null)
                        {
                            xdItem.Value = itemValue;
                        }
                    }
                    break;
                }

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

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

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

                case XmpNodeUtils.CltFirstItem:
                {
                    // 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", XmpErrorCode.InternalFailure);
                }
            }
            // Add an x-default at the front if needed.
            if (!haveXDefault && arrayNode.GetChildrenLength() == 1)
            {
                XmpNodeUtils.AppendLangItem(arrayNode, XmpConstants.XDefault, itemValue);
            }
        }
Beispiel #12
0
        /// <summary>Utility to find or create the array used by <c>separateArrayItems()</c>.</summary>
        /// <param name="schemaNs">a the namespace fo the array</param>
        /// <param name="arrayName">the name of the array</param>
        /// <param name="arrayOptions">the options for the array if newly created</param>
        /// <param name="xmp">the xmp object</param>
        /// <returns>Returns the array node.</returns>
        /// <exception cref="XmpException">Forwards exceptions</exception>
        private static XmpNode SeparateFindCreateArray(string schemaNs, string arrayName, PropertyOptions arrayOptions, XmpMeta xmp)
        {
            arrayOptions = XmpNodeUtils.VerifySetOptions(arrayOptions, null);

            if (!arrayOptions.IsOnlyArrayOptions)
                throw new XmpException("Options can only provide array form", XmpErrorCode.BadOptions);

            // Find the array node, make sure it is OK. Move the current children
            // aside, to be readded later if kept.
            var arrayPath = XmpPathParser.ExpandXPath(schemaNs, arrayName);
            var 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.
                var arrayForm = arrayNode.Options;

                if (!arrayForm.IsArray || arrayForm.IsArrayAlternate)
                    throw new XmpException("Named property must be non-alternate array", XmpErrorCode.BadXPath);
                if (arrayOptions.EqualArrayTypes(arrayForm))
                    throw new XmpException("Mismatch of specified and existing array form", XmpErrorCode.BadXPath);
            }
            else
            {
                // *** Right error?
                // The array does not exist, try to create it.
                // don't modify the options handed into the method
                arrayOptions.IsArray = true;
                arrayNode = XmpNodeUtils.FindNode(xmp.GetRoot(), arrayPath, true, arrayOptions);
                if (arrayNode == null)
                    throw new XmpException("Failed to create named array", XmpErrorCode.BadXPath);
            }
            return arrayNode;
        }
Beispiel #13
0
        /// <summary>
        /// See <see cref="XmpCore.XmpUtils.SeparateArrayItems(IXmpMeta, string, string, string, 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="XmpException">Forwards the Exceptions from the metadata processing</exception>
        public static void SeparateArrayItems(IXmpMeta xmp, string schemaNs, string arrayName, string catedStr, PropertyOptions arrayOptions, bool preserveCommas)
        {
            ParameterAsserts.AssertSchemaNs(schemaNs);
            ParameterAsserts.AssertArrayName(arrayName);

            if (catedStr == null)
                throw new XmpException("Parameter must not be null", XmpErrorCode.BadParam);

            ParameterAsserts.AssertImplementation(xmp);
            var xmpImpl = (XmpMeta)xmp;

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

            // Extract the item values one at a time, until the whole input string is done.
            var charKind = UnicodeKind.Normal;
            var ch = (char)0;
            var itemEnd = 0;
            var 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.
                int itemStart;
                for (itemStart = itemEnd; itemStart < endPos; itemStart++)
                {
                    ch = catedStr[itemStart];
                    charKind = ClassifyCharacter(ch);
                    if (charKind == UnicodeKind.Normal || charKind == UnicodeKind.Quote)
                        break;
                }

                if (itemStart >= endPos)
                    break;

                string itemValue;
                if (charKind != UnicodeKind.Quote)
                {
                    // This is not a quoted value. Scan for the end, create an array
                    // item from the substring.
                    for (itemEnd = itemStart; itemEnd < endPos; itemEnd++)
                    {
                        ch = catedStr[itemEnd];
                        charKind = ClassifyCharacter(ch);

                        if (charKind == UnicodeKind.Normal || charKind == UnicodeKind.Quote || (charKind == UnicodeKind.Comma && preserveCommas))
                            continue;

                        if (charKind != UnicodeKind.Space)
                            break;

                        if ((itemEnd + 1) < endPos)
                        {
                            ch = catedStr[itemEnd + 1];
                            var nextKind = ClassifyCharacter(ch);
                            if (nextKind == UnicodeKind.Normal || nextKind == UnicodeKind.Quote || (nextKind == UnicodeKind.Comma && preserveCommas))
                                continue;
                        }
                        // Anything left?
                        break;
                    }
                    // Have multiple spaces, or a space followed by a
                    // separator.
                    itemValue = catedStr.Substring (itemStart, itemEnd - itemStart);
                }
                else
                {
                    // Accumulate quoted values into a local string, undoubling
                    // internal quotes that
                    // match the surrounding quotes. Do not undouble "unmatching"
                    // quotes.
                    var openQuote = ch;
                    var 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 != UnicodeKind.Quote || !IsSurroundingQuote(ch, openQuote, closeQuote))
                        {
                            // This is not a matching quote, just append it to the
                            // item value.
                            itemValue += ch;
                        }
                        else
                        {
                            // This is a "matching" quote. Is it doubled, or the
                            // final closing quote?
                            // Tolerate various edge cases like undoubled opening
                            // (non-closing) quotes,
                            // or end of input.
                            char nextChar;
                            if ((itemEnd + 1) < endPos)
                                nextChar = catedStr[itemEnd + 1];
                            else
                                nextChar = (char)0x3B;

                            if (ch == nextChar)
                            {
                                // This is doubled, copy it and skip the double.
                                itemValue += ch;
                                // Loop will add in charSize.
                                itemEnd++;
                            }
                            else
                            {
                                if (!IsClosingQuote(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.
                var foundIndex = -1;
                for (var oldChild = 1; oldChild <= arrayNode.GetChildrenLength(); oldChild++)
                {
                    if (itemValue.Equals(arrayNode.GetChild(oldChild).Value))
                    {
                        foundIndex = oldChild;
                        break;
                    }
                }

                if (foundIndex < 0)
                    arrayNode.AddChild(new XmpNode(XmpConstants.ArrayItemName, itemValue, null));
            }
        }
Beispiel #14
0
 /// <summary>Verifies the PropertyOptions for consistancy and updates them as needed.</summary>
 /// <remarks>
 /// Verifies the PropertyOptions for consistancy and updates them as needed.
 /// If options are <c>null</c> they are created with default values.
 /// </remarks>
 /// <param name="options">the <c>PropertyOptions</c></param>
 /// <param name="itemValue">the node value to set</param>
 /// <returns>Returns the updated options.</returns>
 /// <exception cref="XmpException">If the options are not consistant.</exception>
 internal static PropertyOptions VerifySetOptions(PropertyOptions options, object itemValue)
 {
     // create empty and fix existing options
     if (options == null)
     {
         // set default options
         options = new PropertyOptions();
     }
     if (options.IsArrayAltText)
     {
         options.IsArrayAlternate = true;
     }
     if (options.IsArrayAlternate)
     {
         options.IsArrayOrdered = true;
     }
     if (options.IsArrayOrdered)
     {
         options.IsArray = true;
     }
     if (options.IsCompositeProperty && itemValue != null && itemValue.ToString().Length > 0)
     {
         throw new XmpException("Structs and arrays can't have values", XmpErrorCode.BadOptions);
     }
     options.AssertConsistency(options.GetOptions());
     return options;
 }
Beispiel #15
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 <c>setProperty()</c>)
 /// </param>
 /// <param name="leafOptions">
 /// the options for the created leaf nodes (only when
 /// <c>createNodes == true</c>).
 /// </param>
 /// <returns>Returns the node if found or created or <c>null</c>.</returns>
 /// <exception cref="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", XmpErrorCode.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).Name, createNodes);
     if (currNode == null)
     {
         return null;
     }
     if (currNode.IsImplicit)
     {
         currNode.IsImplicit = 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 (var 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;
             }
             if (currNode.IsImplicit)
             {
                 // clear the implicit node flag
                 currNode.IsImplicit = 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).AliasForm != 0)
                 {
                     currNode.Options.SetOption(xpath.GetSegment(i).AliasForm, true);
                 }
                 else
                 {
                     // "CheckImplicitStruct" in C++
                     if (i < xpath.Size() - 1 && xpath.GetSegment(i).Kind == XmpPath.StructFieldStep && !currNode.Options.IsCompositeProperty)
                     {
                         currNode.Options.IsStruct = true;
                     }
                 }
                 if (rootImplicitNode == null)
                 {
                     rootImplicitNode = currNode;
                 }
             }
         }
     }
     catch (XmpException)
     {
         // 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.Options.MergeWith(leafOptions);
         currNode.Options = currNode.Options;
     }
     return currNode;
 }
Beispiel #16
0
 /// <exception cref="XmpException"/>
 public 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.
     var arrayPath = XmpPathParser.ExpandXPath(schemaNs, arrayName);
     var 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", XmpErrorCode.BadXPath);
     }
 }
Beispiel #17
0
 /// <exception cref="XmpException"/>
 public void SetProperty(string schemaNs, string propName, object propValue, PropertyOptions options)
 {
     ParameterAsserts.AssertSchemaNs(schemaNs);
     ParameterAsserts.AssertPropName(propName);
     options = XmpNodeUtils.VerifySetOptions(options, propValue);
     var expPath = XmpPathParser.ExpandXPath(schemaNs, propName);
     var propNode = XmpNodeUtils.FindNode(_tree, expPath, true, options);
     if (propNode != null)
     {
         SetNode(propNode, propValue, options, false);
     }
     else
     {
         throw new XmpException("Specified property does not exist", XmpErrorCode.BadXPath);
     }
 }
Beispiel #18
0
 /// <exception cref="XmpException"/>
 public void SetPropertyInteger(string schemaNs, string propName, int propValue, PropertyOptions options)
 {
     SetProperty(schemaNs, propName, propValue, options);
 }
Beispiel #19
0
 /// <exception cref="XmpException"/>
 public void SetStructField(string schemaNs, string structName, string fieldNs, string fieldName, string fieldValue, PropertyOptions options)
 {
     ParameterAsserts.AssertSchemaNs(schemaNs);
     ParameterAsserts.AssertStructName(structName);
     var fieldPath = structName + XmpPathFactory.ComposeStructFieldPath(fieldNs, fieldName);
     SetProperty(schemaNs, fieldPath, fieldValue, options);
 }
Beispiel #20
0
 /// <exception cref="XmpException"/>
 public void SetPropertyLong(string schemaNs, string propName, long propValue, PropertyOptions options)
 {
     SetProperty(schemaNs, propName, propValue, options);
 }
Beispiel #21
0
 /// <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 <c>null</c></param>
 /// <param name="newOptions">options for the new node, must not be <c>null</c>.</param>
 /// <param name="deleteExisting">flag if the existing value is to be overwritten</param>
 /// <exception cref="XmpException">thrown if options and value do not correspond</exception>
 internal 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.Options.MergeWith(newOptions);
     if (!node.Options.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", XmpErrorCode.BadXPath);
         }
         node.RemoveChildren();
     }
 }
Beispiel #22
0
 /// <exception cref="XmpException"/>
 public void SetPropertyDouble(string schemaNs, string propName, double propValue, PropertyOptions options)
 {
     SetProperty(schemaNs, propName, propValue, options);
 }
        // Don't let failures (like a bad dc:rights form) stop other
        // cleanup.
        /// <summary>
        /// Initializes the map that contains the known arrays, that are fixed by <see cref="NormalizeDcArrays"/>.
        /// </summary>
        private static void InitDcArrays()
        {
            var bagForm = new PropertyOptions { IsArray = true };
            var seqForm = new PropertyOptions { IsArray = true, IsArrayOrdered = true };
            var altTextForm = new PropertyOptions { IsArray = true, IsArrayOrdered = true, IsArrayAlternate = true, IsArrayAltText = true };

            _dcArrayForms = new Dictionary<string, PropertyOptions>();
            // Properties supposed to be a "Bag".
            _dcArrayForms["dc:contributor"] = bagForm;
            _dcArrayForms["dc:language"] = bagForm;
            _dcArrayForms["dc:publisher"] = bagForm;
            _dcArrayForms["dc:relation"] = bagForm;
            _dcArrayForms["dc:subject"] = bagForm;
            _dcArrayForms["dc:type"] = bagForm;
            // Properties supposed to be a "Seq".
            _dcArrayForms["dc:creator"] = seqForm;
            _dcArrayForms["dc:date"] = seqForm;
            // Properties supposed to be an "Alt" in alternative-text form.
            _dcArrayForms["dc:description"] = altTextForm;
            _dcArrayForms["dc:rights"] = altTextForm;
            _dcArrayForms["dc:title"] = altTextForm;
        }
Beispiel #24
0
 private static XmpNode AddChildNode(XmpMeta xmp, XmpNode xmpParent, XName nodeName, string nodeNamespacePrefix, string value, bool isTopLevel)
 {
     var registry = XmpMetaFactory.SchemaRegistry;
     var ns = nodeName.NamespaceName;
     string childName;
     if (ns != string.Empty)
     {
         if (XmpConstants.NsDcDeprecated.Equals(ns))
         {
             // Fix a legacy DC namespace
             ns = XmpConstants.NsDC;
         }
         var prefix = registry.GetNamespacePrefix(ns);
         if (prefix == null)
         {
             prefix = nodeNamespacePrefix ?? DefaultPrefix;
             prefix = registry.RegisterNamespace(ns, prefix);
         }
         childName = prefix + nodeName.LocalName;
     }
     else
     {
         throw new XmpException("XML namespace required for all elements and attributes", XmpErrorCode.BadRdf);
     }
     // create schema node if not already there
     var childOptions = new PropertyOptions();
     var isAlias = false;
     if (isTopLevel)
     {
         // Lookup the schema node, adjust the XMP parent pointer.
         // Incoming parent must be the tree root.
         var schemaNode = XmpNodeUtils.FindSchemaNode(xmp.GetRoot(), ns, DefaultPrefix, true);
         schemaNode.IsImplicit = 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().HasAliases = true;
             schemaNode.HasAliases = true;
         }
     }
     // Make sure that this is not a duplicate of a named node.
     var isArrayItem = "rdf:li".Equals(childName);
     var isValueNode = "rdf:value".Equals(childName);
     // Create XMP node and so some checks
     var newChild = new XmpNode(childName, value, childOptions) { IsAlias = isAlias };
     // Add the new child to the XMP parent node, a value node first.
     if (!isValueNode)
     {
         xmpParent.AddChild(newChild);
     }
     else
     {
         xmpParent.AddChild(1, newChild);
     }
     if (isValueNode)
     {
         if (isTopLevel || !xmpParent.Options.IsStruct)
         {
             throw new XmpException("Misplaced rdf:value element", XmpErrorCode.BadRdf);
         }
         xmpParent.HasValueChild = true;
     }
     if (isArrayItem)
     {
         if (!xmpParent.Options.IsArray)
         {
             throw new XmpException("Misplaced rdf:li element", XmpErrorCode.BadRdf);
         }
         newChild.Name = XmpConstants.ArrayItemName;
     }
     return newChild;
 }