All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.adobe.internal.xmp.XMPUtils Maven / Gradle / Ivy

// =================================================================================================
// ADOBE SYSTEMS INCORPORATED
// Copyright 2006 Adobe Systems Incorporated
// All Rights Reserved
//
// NOTICE:  Adobe permits you to use, modify, and distribute this file in accordance with the terms
// of the Adobe license agreement accompanying it.
// =================================================================================================

package com.adobe.internal.xmp;

import java.security.NoSuchAlgorithmException;
import com.adobe.internal.xmp.impl.Base64;
import com.adobe.internal.xmp.impl.ISO8601Converter;
import com.adobe.internal.xmp.impl.XMPUtilsImpl;
import com.adobe.internal.xmp.options.PropertyOptions;
import com.adobe.internal.xmp.options.TemplateOptions;


/**
 * Utility methods for XMP. I included only those that are different from the
 * Java default conversion utilities.
 *
 * @author Stefan Makswit
 * @version $Revision$
 * @since 21.02.2006
 */
public class XMPUtils
{
	/** Private constructor */
	private XMPUtils()
	{
		// EMPTY
	}


	/**
	 * Create a single edit string from an array of strings.
	 *
	 * @param xmp
	 *            The XMP object containing the array to be catenated.
	 * @param schemaNS
	 *            The schema namespace URI for the array. Must not be null or
	 *            the empty string.
	 * @param 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 separator
	 *            The string to be used to separate the items in the catenated
	 *            string. Defaults to "; ", ASCII semicolon and space
	 *            (U+003B, U+0020).
	 * @param quotes
	 *            The characters to be used as quotes around array items that
	 *            contain a separator. Defaults to '"'
	 * @param allowCommas
	 *            Option flag to control the catenation.
	 * @return Returns the string containing the catenated array items.
	 * @throws XMPException Forwards the Exceptions from the metadata processing
	 */
	public static String catenateArrayItems(XMPMeta xmp, String schemaNS, String arrayName,
			String separator, String quotes, boolean allowCommas) throws XMPException
	{
		return XMPUtilsImpl
				.catenateArrayItems(xmp, schemaNS, arrayName, separator, quotes, allowCommas);
	}


	/**
	 * Separate a single edit string into an array of strings.
	 *
	 * @param xmp
	 *            The XMP object containing the array to be updated.
	 * @param schemaNS
	 *            The schema namespace URI for the array. Must not be null or
	 *            the empty string.
	 * @param 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 catedStr
	 *            The string to be separated into the array items.
	 * @param arrayOptions Option flags to control the separation.
	 * @param preserveCommas Flag if commas shall be preserved
	 * @throws XMPException Forwards the Exceptions from the metadata processing
	 */
	public static void separateArrayItems(XMPMeta xmp, String schemaNS, String arrayName,
			String catedStr, PropertyOptions arrayOptions, boolean preserveCommas)
				throws XMPException
	{
		XMPUtilsImpl.separateArrayItems(xmp, schemaNS, arrayName, catedStr, arrayOptions,
				preserveCommas);
	}


	/**
	 * Remove multiple properties from an XMP object.
	 *
	 * RemoveProperties was created to support the File Info dialog's Delete
	 * button, and has been been generalized somewhat from those specific needs.
	 * It operates in one of three main modes depending on the schemaNS and
	 * propName parameters:
	 *
	 * 
    *
  • Non-empty schemaNS and propName - The named property is * removed if it is an external property, or if the * flag doAllProperties option is true. It does not matter whether the * named property is an actual property or an alias. * *
  • Non-empty schemaNS and empty propName - The all external * properties in the named schema are removed. Internal properties are also * removed if the flag doAllProperties option is set. In addition, * aliases from the named schema will be removed if the flag includeAliases * option is set. * *
  • Empty schemaNS and empty propName - All external properties in * all schema are removed. Internal properties are also removed if the * flag doAllProperties option is passed. Aliases are implicitly handled * because the associated actuals are internal if the alias is. *
* * It is an error to pass an empty schemaNS and non-empty propName. * * @param xmp * The XMP object containing the properties to be removed. * * @param schemaNS * Optional schema namespace URI for the properties to be * removed. * * @param propName * Optional path expression for the property to be removed. * * @param doAllProperties Option flag to control the deletion: do internal properties in * addition to external properties. * * @param includeAliases Option flag to control the deletion: * Include aliases in the "named schema" case above. * Note: Currently not supported. * @throws XMPException Forwards the Exceptions from the metadata processing */ public static void removeProperties(XMPMeta xmp, String schemaNS, String propName, boolean doAllProperties, boolean includeAliases) throws XMPException { XMPUtilsImpl.removeProperties(xmp, schemaNS, propName, doAllProperties, includeAliases); } /** * Alias without the new option deleteEmptyValues. * @param source The source XMP object. * @param dest The destination XMP object. * @param doAllProperties Do internal properties in addition to external properties. * @param replaceOldValues Replace the values of existing properties. * @throws XMPException Forwards the Exceptions from the metadata processing */ public static void appendProperties(XMPMeta source, XMPMeta dest, boolean doAllProperties, boolean replaceOldValues) throws XMPException { appendProperties(source, dest, doAllProperties, replaceOldValues, false); } /** *

Append properties from one XMP object to another. * *

XMPUtils#appendProperties was created to support the File Info dialog's Append button, and * has been been generalized somewhat from those specific needs. It appends information from one * XMP object (source) to another (dest). The default operation is to append only external * properties that do not already exist in the destination. The flag * doAllProperties can be used to operate on all properties, external and internal. * The flag replaceOldValues option can be used to replace the values * of existing properties. The notion of external * versus internal applies only to top level properties. The keep-or-replace-old notion applies * within structs and arrays as described below. *

    *
  • If replaceOldValues is true then the processing is restricted to the top * level properties. The processed properties from the source (according to * doAllProperties) are propagated to the destination, * replacing any existing values.Properties in the destination that are not in the source * are left alone. * *
  • If replaceOldValues is not passed then the processing is more complicated. * Top level properties are added to the destination if they do not already exist. * If they do exist but differ in form (simple/struct/array) then the destination is left alone. * If the forms match, simple properties are left unchanged while structs and arrays are merged. * *
  • If deleteEmptyValues is passed then an empty value in the source XMP causes * the corresponding destination XMP property to be deleted. The default is to treat empty * values the same as non-empty values. An empty value is any of a simple empty string, an array * with no items, or a struct with no fields. Qualifiers are ignored. *
* *

The detailed behavior is defined by the following pseudo-code: *

*
     *    appendProperties ( sourceXMP, destXMP, doAllProperties,
     *    			replaceOldValues, deleteEmptyValues ):
     *       for all source schema (top level namespaces):
     *          for all top level properties in sourceSchema:
     *             if doAllProperties or prop is external:
     *                appendSubtree ( sourceNode, destSchema, replaceOldValues, deleteEmptyValues )
     *
     *    appendSubtree ( sourceNode, destParent, replaceOldValues, deleteEmptyValues ):
     *        if deleteEmptyValues and source value is empty:
     *            delete the corresponding child from destParent
     *        else if sourceNode not in destParent (by name):
     *           copy sourceNode's subtree to destParent
     *        else if replaceOld:
     *            delete subtree from destParent
     *            copy sourceNode's subtree to destParent
     *        else:
     *            // Already exists in dest and not replacing, merge structs and arrays
     *            if sourceNode and destNode forms differ:
     *                return, leave the destNode alone
     *            else if form is a struct:
     *                for each field in sourceNode:
     *                    AppendSubtree ( sourceNode.field, destNode, replaceOldValues )
     *            else if form is an alt-text array:
     *                copy new items by "xml:lang" value into the destination
     *            else if form is an array:
     *                copy new items by value into the destination, ignoring order and duplicates
     * 
*
* *

Note: appendProperties can be expensive if replaceOldValues is not passed and * the XMP contains large arrays. The array item checking described above is n-squared. * Each source item is checked to see if it already exists in the destination, * without regard to order or duplicates. *

Simple items are compared by value and "xml:lang" qualifier, other qualifiers are ignored. * Structs are recursively compared by field names, without regard to field order. Arrays are * compared by recursively comparing all items. * * @param source The source XMP object. * @param dest The destination XMP object. * @param doAllProperties Do internal properties in addition to external properties. * @param replaceOldValues Replace the values of existing properties. * @param deleteEmptyValues Delete destination values if source property is empty. * @throws XMPException Forwards the Exceptions from the metadata processing */ public static void appendProperties(XMPMeta source, XMPMeta dest, boolean doAllProperties, boolean replaceOldValues, boolean deleteEmptyValues) throws XMPException { XMPUtilsImpl.appendProperties(source, dest, doAllProperties, replaceOldValues, deleteEmptyValues); } /** * Convert from string to Boolean. * * @param value * The string representation of the Boolean. * @return The appropriate boolean value for the string. The checked values * for true and false are: *

    *
  • {@link XMPConst#TRUESTR} and {@link XMPConst#FALSESTR} *
  • "t" and "f" *
  • "on" and "off" *
  • "yes" and "no" *
  • "value != 0" and "value == 0" *
* @throws XMPException If an empty string is passed. */ public static boolean convertToBoolean(String value) throws XMPException { if (value == null || value.length() == 0) { throw new XMPException("Empty convert-string", XMPError.BADVALUE); } value = value.toLowerCase(); try { // First try interpretation as Integer (anything not 0 is true) return Integer.parseInt(value) != 0; } catch (NumberFormatException e) { return "true".equals(value) || "t".equals(value) || "on".equals(value) || "yes".equals(value); } } /** * Convert from boolean to string. * * @param value * a boolean value * @return The XMP string representation of the boolean. The values used are * given by the constnts {@link XMPConst#TRUESTR} and * {@link XMPConst#FALSESTR}. */ public static String convertFromBoolean(boolean value) { return value ? XMPConst.TRUESTR : XMPConst.FALSESTR; } /** * Converts a string value to an int. * * @param rawValue * the string value * @return Returns an int. * @throws XMPException * If the rawValue is null or empty or the * conversion fails. */ public static int convertToInteger(String rawValue) throws XMPException { try { if (rawValue == null || rawValue.length() == 0) { throw new XMPException("Empty convert-string", XMPError.BADVALUE); } if (rawValue.startsWith("0x")) { return Integer.parseInt(rawValue.substring(2), 16); } else { return Integer.parseInt(rawValue); } } catch (NumberFormatException e) { throw new XMPException("Invalid integer string", XMPError.BADVALUE); } } /** * Convert from int to string. * * @param value * an int value * @return The string representation of the int. */ public static String convertFromInteger(int value) { return String.valueOf(value); } /** * Converts a string value to a long. * * @param rawValue * the string value * @return Returns a long. * @throws XMPException * If the rawValue is null or empty or the * conversion fails. */ public static long convertToLong(String rawValue) throws XMPException { try { if (rawValue == null || rawValue.length() == 0) { throw new XMPException("Empty convert-string", XMPError.BADVALUE); } if (rawValue.startsWith("0x")) { return Long.parseLong(rawValue.substring(2), 16); } else { return Long.parseLong(rawValue); } } catch (NumberFormatException e) { throw new XMPException("Invalid long string", XMPError.BADVALUE); } } /** * Convert from long to string. * * @param value * a long value * @return The string representation of the long. */ public static String convertFromLong(long value) { return String.valueOf(value); } /** * Converts a string value to a double. * * @param rawValue * the string value * @return Returns a double. * @throws XMPException * If the rawValue is null or empty or the * conversion fails. */ public static double convertToDouble(String rawValue) throws XMPException { try { if (rawValue == null || rawValue.length() == 0) { throw new XMPException("Empty convert-string", XMPError.BADVALUE); } else { return Double.parseDouble(rawValue); } } catch (NumberFormatException e) { throw new XMPException("Invalid double string", XMPError.BADVALUE); } } /** * Convert from long to string. * * @param value * a long value * @return The string representation of the long. */ public static String convertFromDouble(double value) { return String.valueOf(value); } /** * Converts a string value to an XMPDateTime. * * @param rawValue * the string value * @return Returns an XMPDateTime-object. * @throws XMPException * If the rawValue is null or empty or the * conversion fails. */ public static XMPDateTime convertToDate(String rawValue) throws XMPException { if (rawValue == null || rawValue.length() == 0) { throw new XMPException("Empty convert-string", XMPError.BADVALUE); } else { return ISO8601Converter.parse(rawValue); } } /** * Convert from XMPDateTime to string. * * @param value * an XMPDateTime * @return The string representation of the long. */ public static String convertFromDate(XMPDateTime value) { return ISO8601Converter.render(value); } /** * Convert from a byte array to a base64 encoded string. * * @param buffer * the byte array to be converted * @return Returns the base64 string. */ public static String encodeBase64(byte[] buffer) { return new String(Base64.encode(buffer)); } /** * Decode from Base64 encoded string to raw data. * * @param base64String * a base64 encoded string * @return Returns a byte array containg the decoded string. * @throws XMPException Thrown if the given string is not property base64 encoded */ public static byte[] decodeBase64(String base64String) throws XMPException { try { return Base64.decode(base64String.getBytes()); } catch (Throwable e) { throw new XMPException("Invalid base64 string", XMPError.BADVALUE, e); } } /** * creates XMP serializations appropriate for a JPEG file. * * The standard XMP in a JPEG file is limited to 64K bytes. This function * serializes the XMP metadata in an XMP object into a string of RDF . If * the data does not fit into the 64K byte limit, it creates a second packet * string with the extended data. * * @param origXMP * The XMP object containing the metadata. * * @param stdStr * A string builder object in which to return the full standard XMP * packet. * * @param extStr * A string builder object in which to return the serialized extended * XMP, empty if not needed. * * @param digestStr * A string builder object in which to return an MD5 digest of the * serialized extended XMP, empty if not needed. * * @throws NoSuchAlgorithmException if fail to find algorithm for MD5 * @throws XMPException in case of internal error occurs. * */ public static void packageForJPEG(XMPMeta origXMP, StringBuilder stdStr, StringBuilder extStr, StringBuilder digestStr) throws NoSuchAlgorithmException, XMPException{ XMPUtilsImpl.packageForJPEG(origXMP,stdStr,extStr,digestStr); } /** * merges standard and extended XMP retrieved from a JPEG file. * * When an extended partition stores properties that do not fit into the * JPEG file limitation of 64K bytes, this function integrates those * properties back into the same XMP object with those from the standard XMP * packet. * * @param fullXMP * An XMP object which the caller has initialized from the * standard XMP packet in a JPEG file. The extended XMP is added * to this object. * * @param extendedXMP * An XMP object which the caller has initialized from the * extended XMP packet in a JPEG file. * * @throws XMPException * in case of internal error occurs. */ public static void mergeFromJPEG(XMPMeta fullXMP, XMPMeta extendedXMP) throws XMPException{ XMPUtilsImpl.mergeFromJPEG(fullXMP,extendedXMP); } /** * modifies a working XMP object according to a template object. *

* The XMP template can be used to add, replace or delete properties from * the working XMP object. The actions that you specify determine how the * template is applied. Each action can be applied individually or combined; * if you do not specify any actions, the properties and values in the * working XMP object do not change. *

* These actions are available: *

    *
  • Clear CLEAR_UNNAMED_PROPERTIES : Deletes top-level * properties. Any top-level property that is present in the template (even * with empty value) is retained. All other top-level properties in the * working object are deleted * *
  • Add ADD_NEW_PROPERTIES : Adds new properties to the * working object if the template properties have values. See additional * detail below. * *
  • Replace REPLACE_EXISTING_PROPERTIES : Replaces the * values of existing top-level properties in the working XMP if the value * forms match those in the template. Properties with empty values in the * template are ignored. If combined with Clear or Add actions, those take * precedence; values are cleared or added, rather than replaced. * *
  • Replace/Delete empty REPLACE_WITH_DELETE_EMPTY : * Replaces values in the same way as the simple Replace action, and also * deletes properties if the value in the template is empty. If combined * with Clear or Add actions, those take precedence; values are cleared or * added, rather than replaced. * *
  • Include internal INCLUDE_INTERNAL_PROPERTIES : Performs * specified action on internal properties as well as external properties. * By default, internal properties are ignored for all actions. *

* * The Add behavior depends on the type of property: *

    *
  • If a top-level property is not in the working XMP, and has a value in * the template, the property and value are added. Empty properties are not * added. *
  • If a property is in both the working XMP and template, the value * forms must match, otherwise the template is ignored for that property. *
  • If a struct is present in both the working XMP and template, the * individual fields of the template struct are added as appropriate; that * is, the logic is recursively applied to the fields. Struct values are * equivalent if they have the same fields with equivalent values. *
  • If an array is present in both the working XMP and template, items * from the template are added if the value forms match. Array values match * if they have sets of equivalent items, regardless of order. *
  • Alt-text arrays use the \c xml:lang qualifier as a key, adding * languages that are missing. *

* Array item checking is n-squared; this can be time-intensive if the * Replace option is not specified. Each source item is checked to see if it * already exists in the destination, without regard to order or duplicates. * Simple items are compared by value and xml:lang qualifier; * other qualifiers are ignored. Structs are recursively compared by field * names, without regard to field order. Arrays are compared by recursively * comparing all items. * * @param workingXMP * The destination XMP object. * * @param templateXMP * The template to apply to the destination XMP object. * * @param options * Option flags to control the copying. If none are specified, * the properties and values in the working XMP do not change. A * logical OR of these bit-flag constants: *

    *
  • CLEAR_UNNAMED_PROPERTIES Delete anything * that is not in the template *
  • ADD_NEW_PROPERTIES Add properties; see * detailed description. *
  • REPLACE_EXISTING_PROPERTIES Replace the * values of existing properties. *
  • REPLACE_WITH_DELETE_EMPTY Replace the * values of existing properties and delete properties if the new * value is empty. *
  • INCLUDE_INTERNAL_PROPERTIES Operate on * internal properties as well as external properties. *
* * @throws XMPException * in case of internal error occurs. */ static public void applyTemplate ( XMPMeta workingXMP, XMPMeta templateXMP, TemplateOptions options) throws XMPException{ XMPUtilsImpl.applyTemplate(workingXMP,templateXMP,options); } /** * * Replicate a subtree from one XMP object into another, possibly at a * different location. * * * @param source * The source XMP object. * * @param dest * The destination XMP object. * * @param sourceNS * The schema namespace URI for the source subtree. * * @param sourceRoot * The root location for the source subtree. May be a general * path expression, must not be null or the empty string. * * @param destNS * The schema namespace URI for the destination. Defaults to the * source namespace. * * @param destRoot * The root location for the destination. May be a general path * expression. Defaults to the source location. * * @param options * Option flags to control the separation. (For now, this argument is ignored. * 0 should be passed. * @throws XMPException throws an XMPException */ public static void duplicateSubtree(XMPMeta source, XMPMeta dest, String sourceNS, String sourceRoot, String destNS, String destRoot, PropertyOptions options) throws XMPException { XMPUtilsImpl.duplicateSubtree(source, dest, sourceNS, sourceRoot, destNS, destRoot, options); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy