📄 xmputilsimpl.java
字号:
XMPNode rightField = XMPNodeUtils.findChildNode(rightNode, leftField.getName(), false); if (rightField == null || !itemValuesMatch(leftField, rightField)) { return false; } } } else { // Array nodes, see if the "leftNode" values are present in the // "rightNode", ignoring order, duplicates, // and extra values in the rightNode-> The rightNode is the // destination for AppendProperties. assert leftForm.isArray(); for (Iterator il = leftNode.iterateChildren(); il.hasNext();) { XMPNode leftItem = (XMPNode) il.next(); boolean match = false; for (Iterator ir = leftNode.iterateChildren(); ir.hasNext();) { XMPNode rightItem = (XMPNode) ir.next(); if (itemValuesMatch(leftItem, rightItem)) { match = true; break; } } if (!match) { return false; } } } return true; // All of the checks passed. } /** * Make sure the separator is OK. It must be one semicolon surrounded by * zero or more spaces. Any of the recognized semicolons or spaces are * allowed. * * @param separator * @throws XMPException */ private static void checkSeparator(String separator) throws XMPException { boolean haveSemicolon = false; for (int i = 0; i < separator.length(); i++) { int charKind = classifyCharacter(separator.charAt(i)); if (charKind == UCK_SEMICOLON) { if (haveSemicolon) { throw new XMPException("Separator can have only one semicolon", XMPError.BADPARAM); } haveSemicolon = true; } else if (charKind != UCK_SPACE) { throw new XMPException("Separator can have only spaces and one semicolon", XMPError.BADPARAM); } } if (!haveSemicolon) { throw new XMPException("Separator must have one semicolon", XMPError.BADPARAM); } } /** * Make sure the open and close quotes are a legitimate pair and return the * correct closing quote or an exception. * * @param quotes * opened and closing quote in a string * @param openQuote * the open quote * @return Returns a corresponding closing quote. * @throws XMPException */ private static char checkQuotes(String quotes, char openQuote) throws XMPException { char closeQuote; int charKind = classifyCharacter(openQuote); if (charKind != UCK_QUOTE) { throw new XMPException("Invalid quoting character", XMPError.BADPARAM); } if (quotes.length() == 1) { closeQuote = openQuote; } else { closeQuote = quotes.charAt(1); charKind = classifyCharacter(closeQuote); if (charKind != UCK_QUOTE) { throw new XMPException("Invalid quoting character", XMPError.BADPARAM); } } if (closeQuote != getClosingQuote(openQuote)) { throw new XMPException("Mismatched quote pair", XMPError.BADPARAM); } return closeQuote; } /** * Classifies the character into normal chars, spaces, semicola, quotes, * control chars. * * @param ch * a char * @return Return the character kind. */ private static int classifyCharacter(char ch) { if (SPACES.indexOf(ch) >= 0 || (0x2000 <= ch && ch <= 0x200B)) { return UCK_SPACE; } else if (COMMAS.indexOf(ch) >= 0) { return UCK_COMMA; } else if (SEMICOLA.indexOf(ch) >= 0) { return UCK_SEMICOLON; } else if (QUOTES.indexOf(ch) >= 0 || (0x3008 <= ch && ch <= 0x300F) || (0x2018 <= ch && ch <= 0x201F)) { return UCK_QUOTE; } else if (ch < 0x0020 || CONTROLS.indexOf(ch) >= 0) { return UCK_CONTROL; } else { // Assume typical case. return UCK_NORMAL; } } /** * @param openQuote * the open quote char * @return Returns the matching closing quote for an open quote. */ private static char getClosingQuote(char openQuote) { switch (openQuote) { case 0x0022: return 0x0022; // ! U+0022 is both opening and closing. case 0x005B: return 0x005D; case 0x00AB: return 0x00BB; // ! U+00AB and U+00BB are reversible. case 0x00BB: return 0x00AB; case 0x2015: return 0x2015; // ! U+2015 is both opening and closing. case 0x2018: return 0x2019; case 0x201A: return 0x201B; case 0x201C: return 0x201D; case 0x201E: return 0x201F; case 0x2039: return 0x203A; // ! U+2039 and U+203A are reversible. case 0x203A: return 0x2039; case 0x3008: return 0x3009; case 0x300A: return 0x300B; case 0x300C: return 0x300D; case 0x300E: return 0x300F; case 0x301D: return 0x301F; // ! U+301E also closes U+301D. default: return 0; } } /** * Add quotes to the item. * * @param item * the array item * @param openQuote * the open quote character * @param closeQuote * the closing quote character * @param allowCommas * flag if commas are allowed * @return Returns the value in quotes. */ private static String applyQuotes(String item, char openQuote, char closeQuote, boolean allowCommas) { if (item == null) { item = ""; } boolean prevSpace = false; int charOffset; int charKind; // See if there are any separators in the value. Stop at the first // occurrance. This is a bit // tricky in order to make typical typing work conveniently. The purpose // of applying quotes // is to preserve the values when splitting them back apart. That is // CatenateContainerItems // and SeparateContainerItems must round trip properly. For the most // part we only look for // separators here. Internal quotes, as in -- Irving "Bud" Jones -- // won't cause problems in // the separation. An initial quote will though, it will make the value // look quoted. int i; for (i = 0; i < item.length(); i++) { char ch = item.charAt(i); charKind = classifyCharacter(ch); if (i == 0 && charKind == UCK_QUOTE) { break; } if (charKind == UCK_SPACE) { // Multiple spaces are a separator. if (prevSpace) { break; } prevSpace = true; } else { prevSpace = false; if ((charKind == UCK_SEMICOLON || charKind == UCK_CONTROL) || (charKind == UCK_COMMA && !allowCommas)) { break; } } } if (i < item.length()) { // Create a quoted copy, doubling any internal quotes that match the // outer ones. Internal quotes did not stop the "needs quoting" // search, but they do need // doubling. So we have to rescan the front of the string for // quotes. Handle the special // case of U+301D being closed by either U+301E or U+301F. StringBuffer newItem = new StringBuffer(item.length() + 2); int splitPoint; for (splitPoint = 0; splitPoint <= i; splitPoint++) { if (classifyCharacter(item.charAt(i)) == UCK_QUOTE) { break; } } // Copy the leading "normal" portion. newItem.append(openQuote).append(item.substring(0, splitPoint)); for (charOffset = splitPoint; charOffset < item.length(); charOffset++) { newItem.append(item.charAt(charOffset)); if (classifyCharacter(item.charAt(charOffset)) == UCK_QUOTE && isSurroundingQuote(item.charAt(charOffset), openQuote, closeQuote)) { newItem.append(item.charAt(charOffset)); } } newItem.append(closeQuote); item = newItem.toString(); } return item; } /** * @param ch a character * @param openQuote the opening quote char * @param closeQuote the closing quote char * @return Return it the character is a surrounding quote. */ private static boolean isSurroundingQuote(char ch, char openQuote, char closeQuote) { return ch == openQuote || isClosingingQuote(ch, openQuote, closeQuote); } /** * @param ch a character * @param openQuote the opening quote char * @param closeQuote the closing quote char * @return Returns true if the character is a closing quote. */ private static boolean isClosingingQuote(char ch, char openQuote, char closeQuote) { return ch == closeQuote || (openQuote == 0x301D && ch == 0x301E || ch == 0x301F); } /** * U+0022 ASCII space<br> * U+3000, ideographic space<br> * U+303F, ideographic half fill space<br> * U+2000..U+200B, en quad through zero width space */ private static final String SPACES = "\u0020\u3000\u303F"; /** * U+002C, ASCII comma<br> * U+FF0C, full width comma<br> * U+FF64, half width ideographic comma<br> * U+FE50, small comma<br> * U+FE51, small ideographic comma<br> * U+3001, ideographic comma<br> * U+060C, Arabic comma<br> * U+055D, Armenian comma */ private static final String COMMAS = "\u002C\uFF0C\uFF64\uFE50\uFE51\u3001\u060C\u055D"; /** * U+003B, ASCII semicolon<br> * U+FF1B, full width semicolon<br> * U+FE54, small semicolon<br> * U+061B, Arabic semicolon<br> * U+037E, Greek "semicolon" (really a question mark) */ private static final String SEMICOLA = "\u003B\uFF1B\uFE54\u061B\u037E"; /** * U+0022 ASCII quote<br> * ASCII '[' (0x5B) and ']' (0x5D) are used as quotes in Chinese and * Korean.<br> * U+00AB and U+00BB, guillemet quotes<br> * U+3008..U+300F, various quotes.<br> * U+301D..U+301F, double prime quotes.<br> * U+2015, dash quote.<br> * U+2018..U+201F, various quotes.<br> * U+2039 and U+203A, guillemet quotes. */ private static final String QUOTES = "\"\u005B\u005D\u00AB\u00BB\u301D\u301E\u301F\u2015\u2039\u203A"; /** * U+0000..U+001F ASCII controls<br> * U+2028, line separator.<br> * U+2029, paragraph separator. */ private static final String CONTROLS = "\u2028\u2029"; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -