Author: mreutegg Date: Fri Feb 9 05:44:04 2007 New Revision: 505286 URL: http://svn.apache.org/viewvc?view=rev&rev=505286 Log: JCR-739: Predefined entity references are not decoded in string literal Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/xpath/XPathQueryBuilder.java Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/xpath/XPathQueryBuilder.java URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/xpath/XPathQueryBuilder.java?view=diff&rev=505286&r1=505285&r2=505286 ============================================================================== --- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/xpath/XPathQueryBuilder.java (original) +++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/xpath/XPathQueryBuilder.java Fri Feb 9 05:44:04 2007 @@ -666,7 +666,8 @@ */ private void assignValue(SimpleNode node, RelationQueryNode queryNode) { if (node.getId() == JJTSTRINGLITERAL) { - queryNode.setStringValue(unescapeQuotes(node.getValue())); + queryNode.setStringValue(unescapeQuotes( + decodePredefinedEntities(node.getValue()))); } else if (node.getId() == JJTDECIMALLITERAL) { queryNode.setDoubleValue(Double.parseDouble(node.getValue())); } else if (node.getId() == JJTDOUBLELITERAL) { @@ -744,8 +745,10 @@ if (queryNode instanceof NAryQueryNode) { SimpleNode literal = (SimpleNode) node.jjtGetChild(2).jjtGetChild(0); if (literal.getId() == JJTSTRINGLITERAL) { - TextsearchQueryNode contains = new TextsearchQueryNode(queryNode, - unescapeQuotes(literal.getValue())); + TextsearchQueryNode contains = new TextsearchQueryNode( + queryNode, + unescapeQuotes(decodePredefinedEntities( + literal.getValue()))); // assign property name SimpleNode path = (SimpleNode) node.jjtGetChild(1); path.jjtAccept(this, contains); @@ -774,7 +777,8 @@ SimpleNode literal = (SimpleNode) node.jjtGetChild(2).jjtGetChild(0); if (literal.getId() == JJTSTRINGLITERAL) { - like.setStringValue(unescapeQuotes(literal.getValue())); + like.setStringValue(unescapeQuotes( + decodePredefinedEntities(literal.getValue()))); } else { exceptions.add(new InvalidQueryException("Wrong second argument type for jcr:like")); } @@ -856,6 +860,7 @@ String value = literal.getValue(); // strip quotes value = value.substring(1, value.length() - 1); + value = decodePredefinedEntities(value); if (!value.equals("*")) { QName name = null; try { @@ -1022,5 +1027,57 @@ value = value.replaceAll("''", "'"); } return value; + } + + /** + * Decodes a string literal with predefined entities. Predefined entities + * are: + * + * @param literal a string literal that may contain predefined entities. + * @return the decoded string. + * @throws IllegalArgumentException if the string literal is + * malformed. + */ + private String decodePredefinedEntities(String literal) throws IllegalArgumentException { + int idx = literal.indexOf('&'); + if (idx == -1) { + return literal; + } + int endIndex = -1; + StringBuffer buf = new StringBuffer(); + buf.append(literal.substring(0, idx)); + while (idx != -1) { + endIndex = literal.indexOf(';', idx); + if (endIndex == -1) { + throw new IllegalArgumentException(literal); + } + String entity = literal.substring(idx + 1, endIndex); + if (entity.equals("lt")) { + buf.append('<'); + } else if (entity.equals("gt")) { + buf.append('>'); + } else if (entity.equals("amp")) { + buf.append('&'); + } else if (entity.equals("quot")) { + buf.append('"'); + } else if (entity.equals("apos")) { + buf.append('\''); + } else { + throw new IllegalArgumentException(literal); + } + idx = literal.indexOf('&', idx + 1); + if (idx != -1) { + buf.append(literal.substring(endIndex + 1, idx)); + } + } + // write remaining + buf.append(literal.substring(endIndex + 1)); + return buf.toString(); } }