String.getBytes and InputStreamReader support UTF-8 encoding
authorJaroslav Tulach <jaroslav.tulach@apidesign.org>
Mon, 28 Jan 2013 12:18:24 +0100
changeset 595784aaf9ee179
parent 592 5e13b1ac2886
child 598 41b8defdf158
String.getBytes and InputStreamReader support UTF-8 encoding
emul/compact/src/main/java/java/io/InputStreamReader.java
emul/compact/src/test/java/org/apidesign/bck2brwsr/compact/tck/ReaderTest.java
emul/mini/src/main/java/java/lang/String.java
emul/mini/src/main/java/org/apidesign/bck2brwsr/emul/lang/System.java
launcher/src/main/java/org/apidesign/bck2brwsr/launcher/JSLauncher.java
vm/src/test/java/org/apidesign/vm4brwsr/StringSample.java
vm/src/test/java/org/apidesign/vm4brwsr/StringTest.java
vmtest/src/main/java/org/apidesign/bck2brwsr/vmtest/impl/Bck2BrwsrCase.java
     1.1 --- a/emul/compact/src/main/java/java/io/InputStreamReader.java	Sat Jan 26 08:47:05 2013 +0100
     1.2 +++ b/emul/compact/src/main/java/java/io/InputStreamReader.java	Mon Jan 28 12:18:24 2013 +0100
     1.3 @@ -156,9 +156,39 @@
     1.4       * @exception  IOException  If an I/O error occurs
     1.5       */
     1.6      public int read() throws IOException {
     1.7 -        return ((InputStream)lock).read();
     1.8 +        final InputStream is = (InputStream)lock;
     1.9 +        int c = is.read();
    1.10 +        if (c == -1) {
    1.11 +            return -1;
    1.12 +        }
    1.13 +        c = (int) c & 0xff;
    1.14 +        switch (c >> 4) {
    1.15 +            case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7:
    1.16 +                /* 0xxxxxxx*/
    1.17 +                return c;
    1.18 +            case 12: case 13: {
    1.19 +                /* 110x xxxx   10xx xxxx*/
    1.20 +                int char2 = (int) is.read();
    1.21 +                if ((char2 & 0xC0) != 0x80)
    1.22 +                    throw new UTFDataFormatException("malformed input");
    1.23 +                return (((c & 0x1F) << 6) | (char2 & 0x3F));
    1.24 +            }
    1.25 +            case 14: {
    1.26 +                /* 1110 xxxx  10xx xxxx  10xx xxxx */
    1.27 +                int char2 = is.read();
    1.28 +                int char3 = is.read();
    1.29 +                if (((char2 & 0xC0) != 0x80) || ((char3 & 0xC0) != 0x80))
    1.30 +                    throw new UTFDataFormatException("malformed input");
    1.31 +                return (((c    & 0x0F) << 12) |
    1.32 +                       ((char2 & 0x3F) << 6)  |
    1.33 +                       ((char3 & 0x3F) << 0));
    1.34 +            }
    1.35 +            default:
    1.36 +                /* 10xx xxxx,  1111 xxxx */
    1.37 +                throw new UTFDataFormatException("malformed input");
    1.38 +        }
    1.39      }
    1.40 -
    1.41 +    
    1.42      /**
    1.43       * Reads characters into a portion of an array.
    1.44       *
     2.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     2.2 +++ b/emul/compact/src/test/java/org/apidesign/bck2brwsr/compact/tck/ReaderTest.java	Mon Jan 28 12:18:24 2013 +0100
     2.3 @@ -0,0 +1,60 @@
     2.4 +/**
     2.5 + * Back 2 Browser Bytecode Translator
     2.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
     2.7 + *
     2.8 + * This program is free software: you can redistribute it and/or modify
     2.9 + * it under the terms of the GNU General Public License as published by
    2.10 + * the Free Software Foundation, version 2 of the License.
    2.11 + *
    2.12 + * This program is distributed in the hope that it will be useful,
    2.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
    2.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    2.15 + * GNU General Public License for more details.
    2.16 + *
    2.17 + * You should have received a copy of the GNU General Public License
    2.18 + * along with this program. Look for COPYING file in the top folder.
    2.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
    2.20 + */
    2.21 +package org.apidesign.bck2brwsr.compact.tck;
    2.22 +
    2.23 +import java.io.ByteArrayInputStream;
    2.24 +import java.io.IOException;
    2.25 +import java.io.InputStreamReader;
    2.26 +import java.util.Arrays;
    2.27 +import org.apidesign.bck2brwsr.vmtest.Compare;
    2.28 +import org.apidesign.bck2brwsr.vmtest.VMTest;
    2.29 +import org.testng.annotations.Factory;
    2.30 +
    2.31 +/**
    2.32 + *
    2.33 + * @author Jaroslav Tulach <jtulach@netbeans.org>
    2.34 + */
    2.35 +public class ReaderTest {
    2.36 +    @Compare public String readUTFString() throws IOException {
    2.37 +        byte[] arr = { 
    2.38 +            (byte)-59, (byte)-67, (byte)108, (byte)117, (byte)-59, (byte)-91, 
    2.39 +            (byte)111, (byte)117, (byte)-60, (byte)-115, (byte)107, (byte)-61, 
    2.40 +            (byte)-67, (byte)32, (byte)107, (byte)-59, (byte)-81, (byte)-59, 
    2.41 +            (byte)-120 
    2.42 +        };
    2.43 +        ByteArrayInputStream is = new ByteArrayInputStream(arr);
    2.44 +        InputStreamReader r = new InputStreamReader(is);
    2.45 +        
    2.46 +        StringBuilder sb = new StringBuilder();
    2.47 +        for (;;) {
    2.48 +            int ch = r.read();
    2.49 +            if (ch == -1) {
    2.50 +                break;
    2.51 +            }
    2.52 +            sb.append((char)ch);
    2.53 +        }
    2.54 +        return sb.toString().toString();
    2.55 +    }
    2.56 +    @Compare public String stringToBytes() {
    2.57 +        return Arrays.toString("Žluťoučký kůň".getBytes());
    2.58 +    }
    2.59 +    
    2.60 +    @Factory public static Object[] create() {
    2.61 +        return VMTest.create(ReaderTest.class);
    2.62 +    }
    2.63 +}
     3.1 --- a/emul/mini/src/main/java/java/lang/String.java	Sat Jan 26 08:47:05 2013 +0100
     3.2 +++ b/emul/mini/src/main/java/java/lang/String.java	Mon Jan 28 12:18:24 2013 +0100
     3.3 @@ -971,10 +971,24 @@
     3.4       * @since      JDK1.1
     3.5       */
     3.6      public byte[] getBytes() {
     3.7 -        byte[] arr = new byte[length()];
     3.8 -        for (int i = 0; i < arr.length; i++) {
     3.9 -            final char v = charAt(i);
    3.10 -            arr[i] = (byte)v;
    3.11 +        int len = length();
    3.12 +        byte[] arr = new byte[len];
    3.13 +        for (int i = 0, j = 0; j < len; j++) {
    3.14 +            final int v = charAt(j);
    3.15 +            if (v < 128) {
    3.16 +                arr[i++] = (byte) v;
    3.17 +                continue;
    3.18 +            }
    3.19 +            if (v < 0x0800) {
    3.20 +                arr = System.expandArray(arr, i + 1);
    3.21 +                arr[i++] = (byte) (0xC0 | (v >> 6));
    3.22 +                arr[i++] = (byte) (0x80 | (0x3F & v));
    3.23 +                continue;
    3.24 +            }
    3.25 +            arr = System.expandArray(arr, i + 2);
    3.26 +            arr[i++] = (byte) (0xE0 | (v >> 12));
    3.27 +            arr[i++] = (byte) (0x80 | ((v >> 6) & 0x7F));
    3.28 +            arr[i++] = (byte) (0x80 | (0x3F & v));
    3.29          }
    3.30          return arr;
    3.31      }
     4.1 --- a/emul/mini/src/main/java/org/apidesign/bck2brwsr/emul/lang/System.java	Sat Jan 26 08:47:05 2013 +0100
     4.2 +++ b/emul/mini/src/main/java/org/apidesign/bck2brwsr/emul/lang/System.java	Mon Jan 28 12:18:24 2013 +0100
     4.3 @@ -39,4 +39,10 @@
     4.4          "}"
     4.5      )
     4.6      public static native void arraycopy(Object value, int srcBegin, Object dst, int dstBegin, int count);
     4.7 +
     4.8 +    @JavaScriptBody(args = { "arr", "expectedSize" }, body = 
     4.9 +        "while (expectedSize-- > arr.length) { arr.push(0); }; return arr;"
    4.10 +    )
    4.11 +    public static native byte[] expandArray(byte[] arr, int expectedSize);
    4.12 +    
    4.13  }
     5.1 --- a/launcher/src/main/java/org/apidesign/bck2brwsr/launcher/JSLauncher.java	Sat Jan 26 08:47:05 2013 +0100
     5.2 +++ b/launcher/src/main/java/org/apidesign/bck2brwsr/launcher/JSLauncher.java	Mon Jan 28 12:18:24 2013 +0100
     5.3 @@ -23,6 +23,7 @@
     5.4  import java.util.Enumeration;
     5.5  import java.util.LinkedHashSet;
     5.6  import java.util.Set;
     5.7 +import java.util.logging.Level;
     5.8  import java.util.logging.Logger;
     5.9  import javax.script.Invocable;
    5.10  import javax.script.ScriptEngine;
    5.11 @@ -46,10 +47,15 @@
    5.12          loaders.add(clazz.getClassLoader());
    5.13          MethodInvocation mi = new MethodInvocation(clazz.getName(), method, html);
    5.14          try {
    5.15 -            mi.result(code.invokeMethod(
    5.16 +            long time = System.currentTimeMillis();
    5.17 +            LOG.log(Level.FINE, "Invoking {0}.{1}", new Object[]{mi.className, mi.methodName});
    5.18 +            String res = code.invokeMethod(
    5.19                  console,
    5.20                  "invoke__Ljava_lang_String_2Ljava_lang_String_2Ljava_lang_String_2",
    5.21 -                mi.className, mi.methodName).toString(), null);
    5.22 +                mi.className, mi.methodName).toString();
    5.23 +            time = System.currentTimeMillis() - time;
    5.24 +            LOG.log(Level.FINE, "Resut of {0}.{1} = {2} in {3} ms", new Object[]{mi.className, mi.methodName, res, time});
    5.25 +            mi.result(res, null);
    5.26          } catch (ScriptException | NoSuchMethodException ex) {
    5.27              mi.result(null, ex);
    5.28          }
     6.1 --- a/vm/src/test/java/org/apidesign/vm4brwsr/StringSample.java	Sat Jan 26 08:47:05 2013 +0100
     6.2 +++ b/vm/src/test/java/org/apidesign/vm4brwsr/StringSample.java	Mon Jan 28 12:18:24 2013 +0100
     6.3 @@ -68,6 +68,15 @@
     6.4          return chars('a', (char)30, 'b') instanceof String;
     6.5      }
     6.6      
     6.7 +    public static String getBytes(String s) {
     6.8 +        byte[] arr = s.getBytes();
     6.9 +        StringBuilder sb = new StringBuilder();
    6.10 +        for (int i = 0; i < arr.length; i++) {
    6.11 +            sb.append(arr[i]).append(" ");
    6.12 +        }
    6.13 +        return sb.toString().toString();
    6.14 +    }
    6.15 +    
    6.16      public static String insertBuffer() {
    6.17          StringBuilder sb = new StringBuilder();
    6.18          sb.append("Jardo!");
     7.1 --- a/vm/src/test/java/org/apidesign/vm4brwsr/StringTest.java	Sat Jan 26 08:47:05 2013 +0100
     7.2 +++ b/vm/src/test/java/org/apidesign/vm4brwsr/StringTest.java	Mon Jan 28 12:18:24 2013 +0100
     7.3 @@ -75,6 +75,16 @@
     7.4          );
     7.5      }
     7.6  
     7.7 +    @Test public void getBytes() throws Exception {
     7.8 +        final String horse = "Žluťoučký kůň";
     7.9 +        final String expected = StringSample.getBytes(horse);
    7.10 +        assertExec(
    7.11 +            "Bytes look simplar",
    7.12 +            StringSample.class, "getBytes__Ljava_lang_String_2Ljava_lang_String_2",
    7.13 +            expected, horse
    7.14 +        );
    7.15 +    }
    7.16 +
    7.17      @Test(timeOut=10000) public void toStringConcatenation() throws Exception {
    7.18          assertExec(
    7.19              "Five executions should generate 5Hello World!",
     8.1 --- a/vmtest/src/main/java/org/apidesign/bck2brwsr/vmtest/impl/Bck2BrwsrCase.java	Sat Jan 26 08:47:05 2013 +0100
     8.2 +++ b/vmtest/src/main/java/org/apidesign/bck2brwsr/vmtest/impl/Bck2BrwsrCase.java	Mon Jan 28 12:18:24 2013 +0100
     8.3 @@ -23,8 +23,6 @@
     8.4  import java.lang.reflect.Constructor;
     8.5  import java.lang.reflect.InvocationTargetException;
     8.6  import java.lang.reflect.Method;
     8.7 -import java.util.Map;
     8.8 -import java.util.WeakHashMap;
     8.9  import org.apidesign.bck2brwsr.launcher.Launcher;
    8.10  import org.apidesign.bck2brwsr.launcher.MethodInvocation;
    8.11  import org.testng.ITest;