diff --git a/src/main/java/org/codehaus/plexus/util/xml/pull/MXParser.java b/src/main/java/org/codehaus/plexus/util/xml/pull/MXParser.java index 5a119719..e03d6bda 100644 --- a/src/main/java/org/codehaus/plexus/util/xml/pull/MXParser.java +++ b/src/main/java/org/codehaus/plexus/util/xml/pull/MXParser.java @@ -2664,13 +2664,16 @@ protected char[] parseEntityRef() entityRefName = null; posStart = pos; char ch = more(); - StringBuilder sb = new StringBuilder(); if ( ch == '#' ) { // parse character reference + char charRef = 0; ch = more(); - if ( ch == 'x' ) + StringBuilder sb = new StringBuilder(); + boolean isHex = ( ch == 'x' ); + + if ( isHex ) { // encoded in hex while ( true ) @@ -2710,6 +2713,7 @@ else if ( ch >= 'A' && ch <= 'F' ) if ( ch >= '0' && ch <= '9' ) { charRef = (char) ( charRef * 10 + ( ch - '0' ) ); + sb.append( ch ); } else if ( ch == ';' ) { @@ -2724,20 +2728,19 @@ else if ( ch >= 'A' && ch <= 'F' ) } } posEnd = pos - 1; - if ( sb.length() > 0 ) + try { - char[] tmp = toChars( Integer.parseInt( sb.toString(), 16 ) ); - charRefOneCharBuf = tmp; - if ( tokenize ) - { - text = newString( charRefOneCharBuf, 0, charRefOneCharBuf.length ); - } - return charRefOneCharBuf; + charRefOneCharBuf = toChars( Integer.parseInt( sb.toString(), isHex ? 16 : 10 ) ); } - charRefOneCharBuf[0] = charRef; + catch ( IllegalArgumentException e ) + { + throw new XmlPullParserException( "character reference (with " + ( isHex ? "hex" : "decimal" ) + + " value " + sb.toString() + ") is invalid", this, null ); + } + if ( tokenize ) { - text = newString( charRefOneCharBuf, 0, 1 ); + text = newString( charRefOneCharBuf, 0, charRefOneCharBuf.length ); } return charRefOneCharBuf; } @@ -3996,15 +3999,21 @@ private static boolean isHighSurrogate( char ch ) return ( MIN_HIGH_SURROGATE <= ch && MAX_HIGH_SURROGATE >= ch ); } - private static final int MIN_CODE_POINT = 0x000000; - private static final int MAX_CODE_POINT = 0x10FFFF; private static final int MIN_SUPPLEMENTARY_CODE_POINT = 0x10000; + /** + * Check if the provided parameter is a valid Char, according to: {@link https://www.w3.org/TR/REC-xml/#NT-Char} + * + * @param codePoint the numeric value to check + * @return true if it is a valid numeric character reference. False otherwise. + */ private static boolean isValidCodePoint( int codePoint ) { - return ( MIN_CODE_POINT <= codePoint && MAX_CODE_POINT >= codePoint ); + // Char ::= #x9 | #xA | #xD | [#x20-#xD7FF] | [#xE000-#xFFFD] | [#x10000-#x10FFFF] + return codePoint == 0x9 || codePoint == 0xA || codePoint == 0xD || ( 0x20 <= codePoint && codePoint <= 0xD7FF ) + || ( 0xE000 <= codePoint && codePoint <= 0xFFFD ) || ( 0x10000 <= codePoint && codePoint <= 0x10FFFF ); } private static boolean isSupplementaryCodePoint( int codePoint ) diff --git a/src/test/java/org/codehaus/plexus/util/xml/pull/MXParserTest.java b/src/test/java/org/codehaus/plexus/util/xml/pull/MXParserTest.java index a50b4507..d26afe5b 100644 --- a/src/test/java/org/codehaus/plexus/util/xml/pull/MXParserTest.java +++ b/src/test/java/org/codehaus/plexus/util/xml/pull/MXParserTest.java @@ -17,6 +17,8 @@ */ import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; import java.io.IOException; import java.io.StringReader; @@ -156,6 +158,133 @@ public void testUnicodeEntities() assertEquals( XmlPullParser.END_TAG, parser.nextToken() ); } + @Test + public void testInvalidCharacterReferenceHexa() + throws Exception + { + MXParser parser = new MXParser(); + String input = ""; + parser.setInput( new StringReader( input ) ); + + try + { + assertEquals( XmlPullParser.START_TAG, parser.nextToken() ); + assertEquals( XmlPullParser.ENTITY_REF, parser.nextToken() ); + fail( "Should fail since � is an illegal character reference" ); + } + catch ( XmlPullParserException e ) + { + assertTrue( e.getMessage().contains( "character reference (with hex value 110000) is invalid" ) ); + } + } + + @Test + public void testValidCharacterReferenceHexa() + throws Exception + { + MXParser parser = new MXParser(); + String input = " Ȁ퟿ᄁ�𐀀􏿽􏿿"; + parser.setInput( new StringReader( input ) ); + + try + { + assertEquals( XmlPullParser.START_TAG, parser.nextToken() ); + assertEquals( XmlPullParser.ENTITY_REF, parser.nextToken() ); + assertEquals( 0x9, parser.getText().codePointAt( 0 ) ); + assertEquals( XmlPullParser.ENTITY_REF, parser.nextToken() ); + assertEquals( 0xA, parser.getText().codePointAt( 0 ) ); + assertEquals( XmlPullParser.ENTITY_REF, parser.nextToken() ); + assertEquals( 0xD, parser.getText().codePointAt( 0 ) ); + assertEquals( XmlPullParser.ENTITY_REF, parser.nextToken() ); + assertEquals( 0x20, parser.getText().codePointAt( 0 ) ); + assertEquals( XmlPullParser.ENTITY_REF, parser.nextToken() ); + assertEquals( 0x200, parser.getText().codePointAt( 0 ) ); + assertEquals( XmlPullParser.ENTITY_REF, parser.nextToken() ); + assertEquals( 0xD7FF, parser.getText().codePointAt( 0 ) ); + assertEquals( XmlPullParser.ENTITY_REF, parser.nextToken() ); + assertEquals( 0xE000, parser.getText().codePointAt( 0 ) ); + assertEquals( XmlPullParser.ENTITY_REF, parser.nextToken() ); + assertEquals( 0xFFA2, parser.getText().codePointAt( 0 ) ); + assertEquals( XmlPullParser.ENTITY_REF, parser.nextToken() ); + assertEquals( 0xFFFD, parser.getText().codePointAt( 0 ) ); + assertEquals( XmlPullParser.ENTITY_REF, parser.nextToken() ); + assertEquals( 0x10000, parser.getText().codePointAt( 0 ) ); + assertEquals( XmlPullParser.ENTITY_REF, parser.nextToken() ); + assertEquals( 0x10FFFD, parser.getText().codePointAt( 0 ) ); + assertEquals( XmlPullParser.ENTITY_REF, parser.nextToken() ); + assertEquals( 0x10FFFF, parser.getText().codePointAt( 0 ) ); + assertEquals( XmlPullParser.END_TAG, parser.nextToken() ); + } + catch ( XmlPullParserException e ) + { + fail( "Should success since the input represents all legal character references" ); + } + } + + @Test + public void testInvalidCharacterReferenceDecimal() + throws Exception + { + MXParser parser = new MXParser(); + String input = ""; + parser.setInput( new StringReader( input ) ); + + try + { + assertEquals( XmlPullParser.START_TAG, parser.nextToken() ); + assertEquals( XmlPullParser.ENTITY_REF, parser.nextToken() ); + fail( "Should fail since � is an illegal character reference" ); + } + catch ( XmlPullParserException e ) + { + assertTrue( e.getMessage().contains( "character reference (with decimal value 1114112) is invalid" ) ); + } + } + + @Test + public void testValidCharacterReferenceDecimal() + throws Exception + { + MXParser parser = new MXParser(); + String input = + " Ȁ퟿ᄁ�𐀀􏿽􏿿"; + parser.setInput( new StringReader( input ) ); + + try + { + assertEquals( XmlPullParser.START_TAG, parser.nextToken() ); + assertEquals( XmlPullParser.ENTITY_REF, parser.nextToken() ); + assertEquals( 9, parser.getText().codePointAt( 0 ) ); + assertEquals( XmlPullParser.ENTITY_REF, parser.nextToken() ); + assertEquals( 10, parser.getText().codePointAt( 0 ) ); + assertEquals( XmlPullParser.ENTITY_REF, parser.nextToken() ); + assertEquals( 13, parser.getText().codePointAt( 0 ) ); + assertEquals( XmlPullParser.ENTITY_REF, parser.nextToken() ); + assertEquals( 32, parser.getText().codePointAt( 0 ) ); + assertEquals( XmlPullParser.ENTITY_REF, parser.nextToken() ); + assertEquals( 512, parser.getText().codePointAt( 0 ) ); + assertEquals( XmlPullParser.ENTITY_REF, parser.nextToken() ); + assertEquals( 55295, parser.getText().codePointAt( 0 ) ); + assertEquals( XmlPullParser.ENTITY_REF, parser.nextToken() ); + assertEquals( 57344, parser.getText().codePointAt( 0 ) ); + assertEquals( XmlPullParser.ENTITY_REF, parser.nextToken() ); + assertEquals( 65442, parser.getText().codePointAt( 0 ) ); + assertEquals( XmlPullParser.ENTITY_REF, parser.nextToken() ); + assertEquals( 65533, parser.getText().codePointAt( 0 ) ); + assertEquals( XmlPullParser.ENTITY_REF, parser.nextToken() ); + assertEquals( 65536, parser.getText().codePointAt( 0 ) ); + assertEquals( XmlPullParser.ENTITY_REF, parser.nextToken() ); + assertEquals( 1114109, parser.getText().codePointAt( 0 ) ); + assertEquals( XmlPullParser.ENTITY_REF, parser.nextToken() ); + assertEquals( 1114111, parser.getText().codePointAt( 0 ) ); + assertEquals( XmlPullParser.END_TAG, parser.nextToken() ); + } + catch ( XmlPullParserException e ) + { + fail( "Should success since the input represents all legal character references" ); + } + } + @Test public void testProcessingInstruction() throws Exception