示例#1
0
        /// <param name="source">The source XMP object.</param>
        /// <param name="destination">The destination XMP object.</param>
        /// <param name="doAllProperties">Do internal properties in addition to external properties.</param>
        /// <param name="replaceOldValues">Replace the values of existing properties.</param>
        /// <param name="deleteEmptyValues">Delete destination values if source property is empty.</param>
        /// <exception cref="XmpException">Forwards the Exceptions from the metadata processing</exception>
        public static void AppendProperties(IXmpMeta source, IXmpMeta destination, bool doAllProperties, bool replaceOldValues, bool deleteEmptyValues)
        {
            ParameterAsserts.AssertImplementation(source);
            ParameterAsserts.AssertImplementation(destination);

            var src  = (XmpMeta)source;
            var dest = (XmpMeta)destination;

            for (var it = src.GetRoot().IterateChildren(); it.HasNext();)
            {
                var sourceSchema = (XmpNode)it.Next();

                // Make sure we have a destination schema node
                var destSchema    = XmpNodeUtils.FindSchemaNode(dest.GetRoot(), sourceSchema.Name, false);
                var createdSchema = false;

                if (destSchema == null)
                {
                    destSchema = new XmpNode(sourceSchema.Name, sourceSchema.Value, new PropertyOptions {
                        IsSchemaNode = true
                    });
                    dest.GetRoot().AddChild(destSchema);
                    createdSchema = true;
                }

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

                if (!destSchema.HasChildren && (createdSchema || deleteEmptyValues))
                {
                    // Don't create an empty schema / remove empty schema.
                    dest.GetRoot().RemoveChild(destSchema);
                }
            }
        }
示例#2
0
        /// <param name="xmp">The XMP object containing the array to be catenated.</param>
        /// <param name="schemaNs">
        /// The schema namespace URI for the array. Must not be null or
        /// the empty string.
        /// </param>
        /// <param name="arrayName">
        /// The name of the array. May be a general path expression, must
        /// not be null or the empty string. Each item in the array must
        /// be a simple string value.
        /// </param>
        /// <param name="separator">
        /// The string to be used to separate the items in the catenated
        /// string. Defaults to &quot;; &quot;, ASCII semicolon and space
        /// (U+003B, U+0020).
        /// </param>
        /// <param name="quotes">
        /// The characters to be used as quotes around array items that
        /// contain a separator. Defaults to &apos;&quot;&apos;
        /// </param>
        /// <param name="allowCommas">Option flag to control the catenation.</param>
        /// <returns>Returns the string containing the catenated array items.</returns>
        /// <exception cref="XmpException">Forwards the Exceptions from the metadata processing</exception>
        public static string CatenateArrayItems(IXmpMeta xmp, string schemaNs, string arrayName, string separator, string quotes, bool allowCommas)
        {
            ParameterAsserts.AssertSchemaNs(schemaNs);
            ParameterAsserts.AssertArrayName(arrayName);
            ParameterAsserts.AssertImplementation(xmp);

            if (string.IsNullOrEmpty(separator))
            {
                separator = "; ";
            }
            if (string.IsNullOrEmpty(quotes))
            {
                quotes = "\"";
            }

            var xmpImpl = (XmpMeta)xmp;

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

            if (arrayNode == null)
            {
                return(string.Empty);
            }
            if (!arrayNode.Options.IsArray || arrayNode.Options.IsArrayAlternate)
            {
                throw new XmpException("Named property must be non-alternate array", XmpErrorCode.BadParam);
            }

            // Make sure the separator is OK.
            CheckSeparator(separator);

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

            // Build the result, quoting the array items, adding separators.
            // Hurl if any item isn't simple.
            var catenatedString = new StringBuilder();

            for (var it = arrayNode.IterateChildren(); it.HasNext();)
            {
                var currItem = (XmpNode)it.Next();

                if (currItem.Options.IsCompositeProperty)
                {
                    throw new XmpException("Array items must be simple", XmpErrorCode.BadParam);
                }

                var str = ApplyQuotes(currItem.Value, openQuote, closeQuote, allowCommas);
                catenatedString.Append(str);

                if (it.HasNext())
                {
                    catenatedString.Append(separator);
                }
            }
            return(catenatedString.ToString());
        }
示例#3
0
        /// <param name="xmp">The XMP object containing the properties to be removed.</param>
        /// <param name="schemaNs">
        /// Optional schema namespace URI for the properties to be
        /// removed.
        /// </param>
        /// <param name="propName">Optional path expression for the property to be removed.</param>
        /// <param name="doAllProperties">
        /// Option flag to control the deletion: do internal properties in
        /// addition to external properties.
        /// </param>
        /// <param name="includeAliases">
        /// Option flag to control the deletion: Include aliases in the
        /// "named schema" case above.
        /// </param>
        /// <exception cref="XmpException">If metadata processing fails</exception>
        public static void RemoveProperties(IXmpMeta xmp, string schemaNs, string propName, bool doAllProperties, bool includeAliases)
        {
            ParameterAsserts.AssertImplementation(xmp);

            var xmpImpl = (XmpMeta)xmp;

            if (!string.IsNullOrEmpty(propName))
            {
                // Remove just the one indicated property. This might be an alias,
                // the named schema might not actually exist. So don't lookup the
                // schema node.
                if (string.IsNullOrEmpty(schemaNs))
                {
                    throw new XmpException("Property name requires schema namespace", XmpErrorCode.BadParam);
                }

                var expPath  = XmpPathParser.ExpandXPath(schemaNs, propName);
                var propNode = XmpNodeUtils.FindNode(xmpImpl.GetRoot(), expPath, false, null);
                if (propNode != null)
                {
                    if (doAllProperties || !Utils.IsInternalProperty(expPath.GetSegment(XmpPath.StepSchema).Name, expPath.GetSegment(XmpPath.StepRootProp).Name))
                    {
                        var parent = propNode.Parent;
                        parent.RemoveChild(propNode);
                        if (parent.Options.IsSchemaNode && !parent.HasChildren)
                        {
                            // remove empty schema node
                            parent.Parent.RemoveChild(parent);
                        }
                    }
                }
            }
            else
            {
                if (!string.IsNullOrEmpty(schemaNs))
                {
                    // Remove all properties from the named schema. Optionally include
                    // aliases, in which case
                    // there might not be an actual schema node.
                    // XMP_NodePtrPos schemaPos;
                    var schemaNode = XmpNodeUtils.FindSchemaNode(xmpImpl.GetRoot(), schemaNs, false);

                    if (schemaNode != null && RemoveSchemaChildren(schemaNode, doAllProperties))
                    {
                        xmpImpl.GetRoot().RemoveChild(schemaNode);
                    }

                    if (includeAliases)
                    {
                        // We're removing the aliases also. Look them up by their namespace prefix.
                        // But that takes more code and the extra speed isn't worth it.
                        // Lookup the XMP node from the alias, to make sure the actual exists.
                        foreach (var info in XmpMetaFactory.SchemaRegistry.FindAliases(schemaNs))
                        {
                            var path       = XmpPathParser.ExpandXPath(info.Namespace, info.PropName);
                            var actualProp = XmpNodeUtils.FindNode(xmpImpl.GetRoot(), path, false, null);
                            if (actualProp != null)
                            {
                                actualProp.Parent.RemoveChild(actualProp);
                            }
                        }
                    }
                }
                else
                {
                    // Remove all appropriate properties from all schema. In this case
                    // we don't have to be
                    // concerned with aliases, they are handled implicitly from the
                    // actual properties.
                    for (var it = xmpImpl.GetRoot().IterateChildren(); it.HasNext();)
                    {
                        var schema = (XmpNode)it.Next();
                        if (RemoveSchemaChildren(schema, doAllProperties))
                        {
                            it.Remove();
                        }
                    }
                }
            }
        }
示例#4
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));
                }
            }
        }