📄 xmputilsimpl.java
字号:
// =================================================================================================// ADOBE SYSTEMS INCORPORATED// Copyright 2006-2007 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.xmp.impl;import java.util.Iterator;import com.adobe.xmp.XMPConst;import com.adobe.xmp.XMPError;import com.adobe.xmp.XMPException;import com.adobe.xmp.XMPMeta;import com.adobe.xmp.XMPMetaFactory;import com.adobe.xmp.XMPUtils;import com.adobe.xmp.impl.xpath.XMPPath;import com.adobe.xmp.impl.xpath.XMPPathParser;import com.adobe.xmp.options.PropertyOptions;import com.adobe.xmp.properties.XMPAliasInfo;/** * @since 11.08.2006 */public class XMPUtilsImpl implements XMPConst{ /** */ private static final int UCK_NORMAL = 0; /** */ private static final int UCK_SPACE = 1; /** */ private static final int UCK_COMMA = 2; /** */ private static final int UCK_SEMICOLON = 3; /** */ private static final int UCK_QUOTE = 4; /** */ private static final int UCK_CONTROL = 5; /** * Private constructor, as */ private XMPUtilsImpl() { // EMPTY } /** * @see XMPUtils#catenateArrayItems(XMPMeta, String, String, String, String, * boolean) * * @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 { 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 ""; } else if (!arrayNode.getOptions().isArray() || arrayNode.getOptions().isArrayAlternate()) { throw new XMPException("Named property must be non-alternate array", XMPError.BADPARAM); } // Make sure the separator is OK. checkSeparator(separator); // Make sure the open and close quotes are a legitimate pair. char openQuote = quotes.charAt(0); char closeQuote = checkQuotes(quotes, openQuote); // Build the result, quoting the array items, adding separators. // Hurl if any item isn't simple. StringBuffer catinatedString = new StringBuffer(); for (Iterator it = arrayNode.iterateChildren(); it.hasNext();) { currItem = (XMPNode) it.next(); if (currItem.getOptions().isCompositeProperty()) { throw new XMPException("Array items must be simple", XMPError.BADPARAM); } String str = applyQuotes(currItem.getValue(), openQuote, closeQuote, allowCommas); catinatedString.append(str); if (it.hasNext()) { catinatedString.append(separator); } } return catinatedString.toString(); } /** * see {@link XMPUtils#separateArrayItems(XMPMeta, String, String, String, * PropertyOptions, boolean)} * * @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 { ParameterAsserts.assertSchemaNS(schemaNS); ParameterAsserts.assertArrayName(arrayName); ParameterAsserts.assertNotNull(catedStr); 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, itemEnd; int nextKind = UCK_NORMAL, charKind = UCK_NORMAL; char ch = 0, nextChar = 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.charAt(itemStart); charKind = classifyCharacter(ch); if (charKind == UCK_NORMAL || charKind == UCK_QUOTE) { break; } } if (itemStart >= endPos) { break; } if (charKind != UCK_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.charAt(itemEnd); charKind = classifyCharacter(ch); if (charKind == UCK_NORMAL || charKind == UCK_QUOTE || (charKind == UCK_COMMA && preserveCommas)) { continue; } else if (charKind != UCK_SPACE) { break; } else if ((itemEnd + 1) < endPos) { ch = catedStr.charAt(itemEnd + 1); nextKind = classifyCharacter(ch); if (nextKind == UCK_NORMAL || nextKind == UCK_QUOTE || (nextKind == UCK_COMMA && preserveCommas)) { continue; } } // Anything left? break; // Have multiple spaces, or a space followed by a // separator. } itemValue = catedStr.substring(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 = ""; for (itemEnd = itemStart; itemEnd < endPos; itemEnd++) { ch = catedStr.charAt(itemEnd); charKind = classifyCharacter(ch); if (charKind != UCK_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. if ((itemEnd + 1) < endPos) { nextChar = catedStr.charAt(itemEnd + 1); nextKind = classifyCharacter(nextChar); } else { nextKind = UCK_SEMICOLON; nextChar = 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(ARRAY_ITEM_NAME, itemValue, null); arrayNode.addChild(newItem); } } } /** * Utility to find or create the array used by <code>separateArrayItems()</code>. * @param schemaNS a the namespace fo the array * @param arrayName the name of the array * @param arrayOptions the options for the array if newly created * @param xmp the xmp object * @return Returns the array node. * @throws XMPException Forwards exceptions */ private static XMPNode separateFindCreateArray(String schemaNS, String arrayName, PropertyOptions arrayOptions, XMPMetaImpl xmp) throws XMPException { arrayOptions = XMPNodeUtils.verifySetOptions(arrayOptions, null); if (!arrayOptions.isOnlyArrayOptions()) { throw new XMPException("Options can only provide array form", XMPError.BADOPTIONS); } // Find the array node, make sure it is OK. Move the current children // aside, to be readded later if kept. XMPPath arrayPath = XMPPathParser.expandXPath(schemaNS, arrayName); XMPNode 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. PropertyOptions arrayForm = arrayNode.getOptions(); if (!arrayForm.isArray() || arrayForm.isArrayAlternate()) { throw new XMPException("Named property must be non-alternate array", XMPError.BADXPATH); } if (arrayOptions.equalArrayTypes(arrayForm)) { throw new XMPException("Mismatch of specified and existing array form", XMPError.BADXPATH); // *** Right error? } } else { // The array does not exist, try to create it. // don't modify the options handed into the method arrayNode = XMPNodeUtils.findNode(xmp.getRoot(), arrayPath, true, arrayOptions .setArray(true)); if (arrayNode == null) { throw new XMPException("Failed to create named array", XMPError.BADXPATH); } } return arrayNode; } /** * @see XMPUtils#removeProperties(XMPMeta, String, String, boolean, boolean) * * @param xmp * The XMP object containing the properties to be removed. * * @param schemaNS
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -