# HG changeset patch # User Jaroslav Tulach # Date 1359371904 -3600 # Node ID 784aaf9ee1790cf2ea816e9921515ae37fe0076a # Parent 5e13b1ac2886784f88afb07eedc2cc0e52b4c52b String.getBytes and InputStreamReader support UTF-8 encoding diff -r 5e13b1ac2886 -r 784aaf9ee179 emul/compact/src/main/java/java/io/InputStreamReader.java --- a/emul/compact/src/main/java/java/io/InputStreamReader.java Sat Jan 26 08:47:05 2013 +0100 +++ b/emul/compact/src/main/java/java/io/InputStreamReader.java Mon Jan 28 12:18:24 2013 +0100 @@ -156,9 +156,39 @@ * @exception IOException If an I/O error occurs */ public int read() throws IOException { - return ((InputStream)lock).read(); + final InputStream is = (InputStream)lock; + int c = is.read(); + if (c == -1) { + return -1; + } + c = (int) c & 0xff; + switch (c >> 4) { + case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7: + /* 0xxxxxxx*/ + return c; + case 12: case 13: { + /* 110x xxxx 10xx xxxx*/ + int char2 = (int) is.read(); + if ((char2 & 0xC0) != 0x80) + throw new UTFDataFormatException("malformed input"); + return (((c & 0x1F) << 6) | (char2 & 0x3F)); + } + case 14: { + /* 1110 xxxx 10xx xxxx 10xx xxxx */ + int char2 = is.read(); + int char3 = is.read(); + if (((char2 & 0xC0) != 0x80) || ((char3 & 0xC0) != 0x80)) + throw new UTFDataFormatException("malformed input"); + return (((c & 0x0F) << 12) | + ((char2 & 0x3F) << 6) | + ((char3 & 0x3F) << 0)); + } + default: + /* 10xx xxxx, 1111 xxxx */ + throw new UTFDataFormatException("malformed input"); + } } - + /** * Reads characters into a portion of an array. * diff -r 5e13b1ac2886 -r 784aaf9ee179 emul/compact/src/test/java/org/apidesign/bck2brwsr/compact/tck/ReaderTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/emul/compact/src/test/java/org/apidesign/bck2brwsr/compact/tck/ReaderTest.java Mon Jan 28 12:18:24 2013 +0100 @@ -0,0 +1,60 @@ +/** + * Back 2 Browser Bytecode Translator + * Copyright (C) 2012 Jaroslav Tulach + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. Look for COPYING file in the top folder. + * If not, see http://opensource.org/licenses/GPL-2.0. + */ +package org.apidesign.bck2brwsr.compact.tck; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStreamReader; +import java.util.Arrays; +import org.apidesign.bck2brwsr.vmtest.Compare; +import org.apidesign.bck2brwsr.vmtest.VMTest; +import org.testng.annotations.Factory; + +/** + * + * @author Jaroslav Tulach + */ +public class ReaderTest { + @Compare public String readUTFString() throws IOException { + byte[] arr = { + (byte)-59, (byte)-67, (byte)108, (byte)117, (byte)-59, (byte)-91, + (byte)111, (byte)117, (byte)-60, (byte)-115, (byte)107, (byte)-61, + (byte)-67, (byte)32, (byte)107, (byte)-59, (byte)-81, (byte)-59, + (byte)-120 + }; + ByteArrayInputStream is = new ByteArrayInputStream(arr); + InputStreamReader r = new InputStreamReader(is); + + StringBuilder sb = new StringBuilder(); + for (;;) { + int ch = r.read(); + if (ch == -1) { + break; + } + sb.append((char)ch); + } + return sb.toString().toString(); + } + @Compare public String stringToBytes() { + return Arrays.toString("Žluťoučký kůň".getBytes()); + } + + @Factory public static Object[] create() { + return VMTest.create(ReaderTest.class); + } +} diff -r 5e13b1ac2886 -r 784aaf9ee179 emul/mini/src/main/java/java/lang/String.java --- a/emul/mini/src/main/java/java/lang/String.java Sat Jan 26 08:47:05 2013 +0100 +++ b/emul/mini/src/main/java/java/lang/String.java Mon Jan 28 12:18:24 2013 +0100 @@ -971,10 +971,24 @@ * @since JDK1.1 */ public byte[] getBytes() { - byte[] arr = new byte[length()]; - for (int i = 0; i < arr.length; i++) { - final char v = charAt(i); - arr[i] = (byte)v; + int len = length(); + byte[] arr = new byte[len]; + for (int i = 0, j = 0; j < len; j++) { + final int v = charAt(j); + if (v < 128) { + arr[i++] = (byte) v; + continue; + } + if (v < 0x0800) { + arr = System.expandArray(arr, i + 1); + arr[i++] = (byte) (0xC0 | (v >> 6)); + arr[i++] = (byte) (0x80 | (0x3F & v)); + continue; + } + arr = System.expandArray(arr, i + 2); + arr[i++] = (byte) (0xE0 | (v >> 12)); + arr[i++] = (byte) (0x80 | ((v >> 6) & 0x7F)); + arr[i++] = (byte) (0x80 | (0x3F & v)); } return arr; } diff -r 5e13b1ac2886 -r 784aaf9ee179 emul/mini/src/main/java/org/apidesign/bck2brwsr/emul/lang/System.java --- a/emul/mini/src/main/java/org/apidesign/bck2brwsr/emul/lang/System.java Sat Jan 26 08:47:05 2013 +0100 +++ b/emul/mini/src/main/java/org/apidesign/bck2brwsr/emul/lang/System.java Mon Jan 28 12:18:24 2013 +0100 @@ -39,4 +39,10 @@ "}" ) public static native void arraycopy(Object value, int srcBegin, Object dst, int dstBegin, int count); + + @JavaScriptBody(args = { "arr", "expectedSize" }, body = + "while (expectedSize-- > arr.length) { arr.push(0); }; return arr;" + ) + public static native byte[] expandArray(byte[] arr, int expectedSize); + } diff -r 5e13b1ac2886 -r 784aaf9ee179 launcher/src/main/java/org/apidesign/bck2brwsr/launcher/JSLauncher.java --- a/launcher/src/main/java/org/apidesign/bck2brwsr/launcher/JSLauncher.java Sat Jan 26 08:47:05 2013 +0100 +++ b/launcher/src/main/java/org/apidesign/bck2brwsr/launcher/JSLauncher.java Mon Jan 28 12:18:24 2013 +0100 @@ -23,6 +23,7 @@ import java.util.Enumeration; import java.util.LinkedHashSet; import java.util.Set; +import java.util.logging.Level; import java.util.logging.Logger; import javax.script.Invocable; import javax.script.ScriptEngine; @@ -46,10 +47,15 @@ loaders.add(clazz.getClassLoader()); MethodInvocation mi = new MethodInvocation(clazz.getName(), method, html); try { - mi.result(code.invokeMethod( + long time = System.currentTimeMillis(); + LOG.log(Level.FINE, "Invoking {0}.{1}", new Object[]{mi.className, mi.methodName}); + String res = code.invokeMethod( console, "invoke__Ljava_lang_String_2Ljava_lang_String_2Ljava_lang_String_2", - mi.className, mi.methodName).toString(), null); + mi.className, mi.methodName).toString(); + time = System.currentTimeMillis() - time; + LOG.log(Level.FINE, "Resut of {0}.{1} = {2} in {3} ms", new Object[]{mi.className, mi.methodName, res, time}); + mi.result(res, null); } catch (ScriptException | NoSuchMethodException ex) { mi.result(null, ex); } diff -r 5e13b1ac2886 -r 784aaf9ee179 vm/src/test/java/org/apidesign/vm4brwsr/StringSample.java --- a/vm/src/test/java/org/apidesign/vm4brwsr/StringSample.java Sat Jan 26 08:47:05 2013 +0100 +++ b/vm/src/test/java/org/apidesign/vm4brwsr/StringSample.java Mon Jan 28 12:18:24 2013 +0100 @@ -68,6 +68,15 @@ return chars('a', (char)30, 'b') instanceof String; } + public static String getBytes(String s) { + byte[] arr = s.getBytes(); + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < arr.length; i++) { + sb.append(arr[i]).append(" "); + } + return sb.toString().toString(); + } + public static String insertBuffer() { StringBuilder sb = new StringBuilder(); sb.append("Jardo!"); diff -r 5e13b1ac2886 -r 784aaf9ee179 vm/src/test/java/org/apidesign/vm4brwsr/StringTest.java --- a/vm/src/test/java/org/apidesign/vm4brwsr/StringTest.java Sat Jan 26 08:47:05 2013 +0100 +++ b/vm/src/test/java/org/apidesign/vm4brwsr/StringTest.java Mon Jan 28 12:18:24 2013 +0100 @@ -75,6 +75,16 @@ ); } + @Test public void getBytes() throws Exception { + final String horse = "Žluťoučký kůň"; + final String expected = StringSample.getBytes(horse); + assertExec( + "Bytes look simplar", + StringSample.class, "getBytes__Ljava_lang_String_2Ljava_lang_String_2", + expected, horse + ); + } + @Test(timeOut=10000) public void toStringConcatenation() throws Exception { assertExec( "Five executions should generate 5Hello World!", diff -r 5e13b1ac2886 -r 784aaf9ee179 vmtest/src/main/java/org/apidesign/bck2brwsr/vmtest/impl/Bck2BrwsrCase.java --- a/vmtest/src/main/java/org/apidesign/bck2brwsr/vmtest/impl/Bck2BrwsrCase.java Sat Jan 26 08:47:05 2013 +0100 +++ b/vmtest/src/main/java/org/apidesign/bck2brwsr/vmtest/impl/Bck2BrwsrCase.java Mon Jan 28 12:18:24 2013 +0100 @@ -23,8 +23,6 @@ import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; -import java.util.Map; -import java.util.WeakHashMap; import org.apidesign.bck2brwsr.launcher.Launcher; import org.apidesign.bck2brwsr.launcher.MethodInvocation; import org.testng.ITest;