Пример #1
0
        /// <seealso cref="Com.Adobe.Xmp.XMPUtils.AppendProperties(Com.Adobe.Xmp.XMPMeta, Com.Adobe.Xmp.XMPMeta, bool, bool)"/>
        /// <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="Com.Adobe.Xmp.XMPException">Forwards the Exceptions from the metadata processing</exception>
        public static void AppendProperties(XMPMeta source, XMPMeta destination, bool doAllProperties, bool replaceOldValues, bool deleteEmptyValues)
        {
            ParameterAsserts.AssertImplementation(source);
            ParameterAsserts.AssertImplementation(destination);
            XMPMetaImpl src  = (XMPMetaImpl)source;
            XMPMetaImpl dest = (XMPMetaImpl)destination;

            for (Iterator it = src.GetRoot().IterateChildren(); it.HasNext();)
            {
                XMPNode sourceSchema = (XMPNode)it.Next();
                // Make sure we have a destination schema node
                XMPNode destSchema    = XMPNodeUtils.FindSchemaNode(dest.GetRoot(), sourceSchema.GetName(), false);
                bool    createdSchema = false;
                if (destSchema == null)
                {
                    destSchema = new XMPNode(sourceSchema.GetName(), sourceSchema.GetValue(), new PropertyOptions().SetSchemaNode(true));
                    dest.GetRoot().AddChild(destSchema);
                    createdSchema = true;
                }
                // Process the source schema's children.
                for (Iterator ic = sourceSchema.IterateChildren(); ic.HasNext();)
                {
                    XMPNode sourceProp = (XMPNode)ic.Next();
                    if (doAllProperties || !Utils.IsInternalProperty(sourceSchema.GetName(), sourceProp.GetName()))
                    {
                        AppendSubtree(dest, sourceProp, destSchema, replaceOldValues, deleteEmptyValues);
                    }
                }
                if (!destSchema.HasChildren() && (createdSchema || deleteEmptyValues))
                {
                    // Don't create an empty schema / remove empty schema.
                    dest.GetRoot().RemoveChild(destSchema);
                }
            }
        }
        // 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="Com.Adobe.Xmp.XMPException">Thrown if parsing or normalisation fails.</exception>
        public static XMPMeta Parse(object input, ParseOptions options)
        {
            ParameterAsserts.AssertNotNull(input);
            options = options != null ? 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] == XmpRdf)
            {
                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));
                }
                else
                {
                    return(xmp);
                }
            }
            else
            {
                // no appropriate root node found, return empty metadata object
                return(new XMPMetaImpl());
            }
        }
Пример #3
0
        // EMPTY
        /// <seealso cref="Com.Adobe.Xmp.XMPUtils.CatenateArrayItems(Com.Adobe.Xmp.XMPMeta, string, string, string, string, bool)"/>
        /// <param name="xmp">The XMP object containing the array to be catenated.</param>
        /// <param name="schemaNS">
        /// The schema namespace URI for the array. Must not be null or
        /// the empty string.
        /// </param>
        /// <param name="arrayName">
        /// The name of the array. May be a general path expression, must
        /// not be null or the empty string. Each item in the array must
        /// be a simple string value.
        /// </param>
        /// <param name="separator">
        /// The string to be used to separate the items in the catenated
        /// string. Defaults to &quot;; &quot;, ASCII semicolon and space
        /// (U+003B, U+0020).
        /// </param>
        /// <param name="quotes">
        /// The characters to be used as quotes around array items that
        /// contain a separator. Defaults to &apos;&quot;&apos;
        /// </param>
        /// <param name="allowCommas">Option flag to control the catenation.</param>
        /// <returns>Returns the string containing the catenated array items.</returns>
        /// <exception cref="Com.Adobe.Xmp.XMPException">Forwards the Exceptions from the metadata processing</exception>
        public static string CatenateArrayItems(XMPMeta xmp, string schemaNS, string arrayName, string separator, string quotes, bool allowCommas)
        {
            ParameterAsserts.AssertSchemaNS(schemaNS);
            ParameterAsserts.AssertArrayName(arrayName);
            ParameterAsserts.AssertImplementation(xmp);
            if (separator == null || separator.Length == 0)
            {
                separator = "; ";
            }
            if (quotes == null || quotes.Length == 0)
            {
                quotes = "\"";
            }
            XMPMetaImpl xmpImpl   = (XMPMetaImpl)xmp;
            XMPNode     arrayNode = null;
            XMPNode     currItem  = null;
            // Return an empty result if the array does not exist,
            // hurl if it isn't the right form.
            XMPPath arrayPath = XMPPathParser.ExpandXPath(schemaNS, arrayName);

            arrayNode = XMPNodeUtils.FindNode(xmpImpl.GetRoot(), arrayPath, false, null);
            if (arrayNode == null)
            {
                return(string.Empty);
            }
            else
            {
                if (!arrayNode.GetOptions().IsArray() || arrayNode.GetOptions().IsArrayAlternate())
                {
                    throw new XMPException("Named property must be non-alternate array", XMPErrorConstants.Badparam);
                }
            }
            // Make sure the separator is OK.
            CheckSeparator(separator);
            // Make sure the open and close quotes are a legitimate pair.
            char openQuote  = quotes[0];
            char closeQuote = CheckQuotes(quotes, openQuote);
            // Build the result, quoting the array items, adding separators.
            // Hurl if any item isn't simple.
            StringBuilder catinatedString = new StringBuilder();

            for (Iterator it = arrayNode.IterateChildren(); it.HasNext();)
            {
                currItem = (XMPNode)it.Next();
                if (currItem.GetOptions().IsCompositeProperty())
                {
                    throw new XMPException("Array items must be simple", XMPErrorConstants.Badparam);
                }
                string str = ApplyQuotes(currItem.GetValue(), openQuote, closeQuote, allowCommas);
                catinatedString.Append(str);
                if (it.HasNext())
                {
                    catinatedString.Append(separator);
                }
            }
            return(catinatedString.ToString());
        }
 /// <summary>Associates an alias name with an actual name.</summary>
 /// <remarks>
 /// Associates an alias name with an actual name.
 /// <p>
 /// 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
 /// </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="Com.Adobe.Xmp.Options.AliasOptions"/>
 /// ).
 /// </param>
 /// <exception cref="Com.Adobe.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 (p.Matcher(aliasProp).Find() || p.Matcher(actualProp).Find())
         {
             throw new XMPException("Alias and actual property names must be simple", XMPErrorConstants.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", XMPErrorConstants.Badschema);
         }
         else
         {
             if (actualPrefix == null)
             {
                 throw new XMPException("Actual namespace is not registered", XMPErrorConstants.Badschema);
             }
         }
         string key = aliasPrefix + aliasProp;
         // check if alias is already existing
         if (aliasMap.ContainsKey(key))
         {
             throw new XMPException("Alias is already existing", XMPErrorConstants.Badparam);
         }
         else
         {
             if (aliasMap.ContainsKey(actualPrefix + actualProp))
             {
                 throw new XMPException("Actual property is already an alias, use the base property", XMPErrorConstants.Badparam);
             }
         }
         XMPAliasInfo aliasInfo = new _XMPAliasInfo_390(actualNS, actualPrefix, actualProp, aliasOpts);
         aliasMap.Put(key, aliasInfo);
     }
 }
 // ---------------------------------------------------------------------------------------------
 // Namespace Functions
 /// <seealso cref="Com.Adobe.Xmp.XMPSchemaRegistry.RegisterNamespace(string, string)"/>
 /// <exception cref="Com.Adobe.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(Sharpen.Runtime.Substring(suggestedPrefix, 0, suggestedPrefix.Length - 1)))
         {
             throw new XMPException("The prefix is a bad XML name", XMPErrorConstants.Badxml);
         }
         string registeredPrefix = (string)namespaceToPrefixMap.Get(namespaceURI);
         string registeredNS     = (string)prefixToNamespaceMap.Get(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.ContainsKey(generatedPrefix); i++)
                 {
                     generatedPrefix = Sharpen.Runtime.Substring(suggestedPrefix, 0, suggestedPrefix.Length - 1) + "_" + i + "_:";
                 }
                 suggestedPrefix = generatedPrefix;
             }
             prefixToNamespaceMap.Put(suggestedPrefix, namespaceURI);
             namespaceToPrefixMap.Put(namespaceURI, suggestedPrefix);
             // Return the suggested prefix
             return(suggestedPrefix);
         }
     }
 }
Пример #6
0
        /// <seealso cref="Com.Adobe.Xmp.XMPUtils.RemoveProperties(Com.Adobe.Xmp.XMPMeta, string, string, bool, bool)"/>
        /// <param name="xmp">The XMP object containing the properties to be removed.</param>
        /// <param name="schemaNS">
        /// Optional schema namespace URI for the properties to be
        /// removed.
        /// </param>
        /// <param name="propName">Optional path expression for the property to be removed.</param>
        /// <param name="doAllProperties">
        /// Option flag to control the deletion: do internal properties in
        /// addition to external properties.
        /// </param>
        /// <param name="includeAliases">
        /// Option flag to control the deletion: Include aliases in the
        /// "named schema" case above.
        /// </param>
        /// <exception cref="Com.Adobe.Xmp.XMPException">If metadata processing fails</exception>
        public static void RemoveProperties(XMPMeta xmp, string schemaNS, string propName, bool doAllProperties, bool includeAliases)
        {
            ParameterAsserts.AssertImplementation(xmp);
            XMPMetaImpl xmpImpl = (XMPMetaImpl)xmp;

            if (propName != null && propName.Length > 0)
            {
                // Remove just the one indicated property. This might be an alias,
                // the named schema might not actually exist. So don't lookup the
                // schema node.
                if (schemaNS == null || schemaNS.Length == 0)
                {
                    throw new XMPException("Property name requires schema namespace", XMPErrorConstants.Badparam);
                }
                XMPPath expPath  = XMPPathParser.ExpandXPath(schemaNS, propName);
                XMPNode propNode = XMPNodeUtils.FindNode(xmpImpl.GetRoot(), expPath, false, null);
                if (propNode != null)
                {
                    if (doAllProperties || !Utils.IsInternalProperty(expPath.GetSegment(XMPPath.StepSchema).GetName(), expPath.GetSegment(XMPPath.StepRootProp).GetName()))
                    {
                        XMPNode parent = propNode.GetParent();
                        parent.RemoveChild(propNode);
                        if (parent.GetOptions().IsSchemaNode() && !parent.HasChildren())
                        {
                            // remove empty schema node
                            parent.GetParent().RemoveChild(parent);
                        }
                    }
                }
            }
            else
            {
                if (schemaNS != null && schemaNS.Length > 0)
                {
                    // Remove all properties from the named schema. Optionally include
                    // aliases, in which case
                    // there might not be an actual schema node.
                    // XMP_NodePtrPos schemaPos;
                    XMPNode schemaNode = XMPNodeUtils.FindSchemaNode(xmpImpl.GetRoot(), schemaNS, false);
                    if (schemaNode != null)
                    {
                        if (RemoveSchemaChildren(schemaNode, doAllProperties))
                        {
                            xmpImpl.GetRoot().RemoveChild(schemaNode);
                        }
                    }
                    if (includeAliases)
                    {
                        // We're removing the aliases also. Look them up by their
                        // namespace prefix.
                        // But that takes more code and the extra speed isn't worth it.
                        // Lookup the XMP node
                        // from the alias, to make sure the actual exists.
                        XMPAliasInfo[] aliases = XMPMetaFactory.GetSchemaRegistry().FindAliases(schemaNS);
                        for (int i = 0; i < aliases.Length; i++)
                        {
                            XMPAliasInfo info       = aliases[i];
                            XMPPath      path       = XMPPathParser.ExpandXPath(info.GetNamespace(), info.GetPropName());
                            XMPNode      actualProp = XMPNodeUtils.FindNode(xmpImpl.GetRoot(), path, false, null);
                            if (actualProp != null)
                            {
                                XMPNode parent = actualProp.GetParent();
                                parent.RemoveChild(actualProp);
                            }
                        }
                    }
                }
                else
                {
                    // Remove all appropriate properties from all schema. In this case
                    // we don't have to be
                    // concerned with aliases, they are handled implicitly from the
                    // actual properties.
                    for (Iterator it = xmpImpl.GetRoot().IterateChildren(); it.HasNext();)
                    {
                        XMPNode schema = (XMPNode)it.Next();
                        if (RemoveSchemaChildren(schema, doAllProperties))
                        {
                            it.Remove();
                        }
                    }
                }
            }
        }
Пример #7
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);
                }
            }
        }