diff --git a/src/org/joni/ast/StringNode.java b/src/org/joni/ast/StringNode.java index 4a3c27b..57e87cc 100644 --- a/src/org/joni/ast/StringNode.java +++ b/src/org/joni/ast/StringNode.java @@ -22,6 +22,8 @@ import org.jcodings.Encoding; import org.joni.Config; import org.joni.constants.internal.StringType; +import org.joni.exception.ErrorMessages; +import org.joni.exception.ValueException; public final class StringNode extends Node implements StringType { private static final int NODE_STR_MARGIN = 16; @@ -138,7 +140,14 @@ public void catByte(byte c) { public void catCode(int code, Encoding enc) { modifyEnsure(Config.ENC_CODE_TO_MBC_MAXLEN); + int oldEnd = end; end += enc.codeToMbc(code, bytes, end); + if (enc.length(bytes, oldEnd, end) < 0) { + throw new ValueException(ErrorMessages.ERR_INVALID_UNICODE, code <= 0xFFFF + ? String.format("\\\\u%04X", code) + : String.format("\\\\u%04X\\\\u%04X", Character.highSurrogate(code), Character.lowSurrogate(code)) + ); + } } public void setRaw() { diff --git a/src/org/joni/exception/ErrorMessages.java b/src/org/joni/exception/ErrorMessages.java index b80340b..4d3cace 100644 --- a/src/org/joni/exception/ErrorMessages.java +++ b/src/org/joni/exception/ErrorMessages.java @@ -85,5 +85,6 @@ public interface ErrorMessages extends org.jcodings.exception.ErrorMessages { String INVALID_COMBINATION_OF_OPTIONS = "invalid combination of options"; String OVER_THREAD_PASS_LIMIT_COUNT = "over thread pass limit count"; String TOO_BIG_SB_CHAR_VALUE = "too big singlebyte char value"; + String ERR_INVALID_UNICODE = "invalid unicode: %n"; } diff --git a/test/org/joni/test/TestInvalidUnicode.java b/test/org/joni/test/TestInvalidUnicode.java new file mode 100644 index 0000000..aac14bf --- /dev/null +++ b/test/org/joni/test/TestInvalidUnicode.java @@ -0,0 +1,54 @@ +/* + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is furnished to do + * so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package org.joni.test; + +import org.jcodings.Encoding; +import org.jcodings.specific.UTF8Encoding; +import org.joni.Option; +import org.joni.Syntax; + +public class TestInvalidUnicode extends Test { + + @Override + public int option() { + return Option.DEFAULT; + } + + @Override + public Encoding encoding() { + return UTF8Encoding.INSTANCE; + } + + @Override + public String testEncoding() { + return "utf-8"; + } + + @Override + public Syntax syntax() { + return Syntax.Java; + } + + @Override + public void test() throws Exception { + // see https://github.com/jruby/joni/issues/17 + xerrs("A\\uD800", "invalid unicode: \\uD800"); + } +}