diff --git a/teavm-classlib/src/main/java/org/teavm/classlib/impl/charset/ByteBuffer.java b/teavm-classlib/src/main/java/org/teavm/classlib/impl/charset/ByteBuffer.java index aa161983f..0f07a668c 100644 --- a/teavm-classlib/src/main/java/org/teavm/classlib/impl/charset/ByteBuffer.java +++ b/teavm-classlib/src/main/java/org/teavm/classlib/impl/charset/ByteBuffer.java @@ -54,6 +54,10 @@ public class ByteBuffer { return pos == end; } + public void skip(int count) { + pos += count; + } + public byte get() { return data[pos++]; } diff --git a/teavm-classlib/src/main/java/org/teavm/classlib/impl/charset/UTF16Helper.java b/teavm-classlib/src/main/java/org/teavm/classlib/impl/charset/UTF16Helper.java index 163be31fd..29afb680e 100644 --- a/teavm-classlib/src/main/java/org/teavm/classlib/impl/charset/UTF16Helper.java +++ b/teavm-classlib/src/main/java/org/teavm/classlib/impl/charset/UTF16Helper.java @@ -34,7 +34,7 @@ public class UTF16Helper { } public static char lowSurrogate(int codePoint) { - return (char)(HIGH_SURROGATE_BITS | codePoint & SURROGATE_BIT_INV_MASK); + return (char)(LOW_SURROGATE_BITS | codePoint & SURROGATE_BIT_INV_MASK); } public static boolean isHighSurrogate(char c) { diff --git a/teavm-classlib/src/main/java/org/teavm/classlib/impl/charset/UTF8Charset.java b/teavm-classlib/src/main/java/org/teavm/classlib/impl/charset/UTF8Charset.java index 55c7c2ec4..84e595d6a 100644 --- a/teavm-classlib/src/main/java/org/teavm/classlib/impl/charset/UTF8Charset.java +++ b/teavm-classlib/src/main/java/org/teavm/classlib/impl/charset/UTF8Charset.java @@ -53,6 +53,40 @@ public class UTF8Charset extends Charset { @Override public void decode(ByteBuffer source, CharBuffer dest) { - + while (!source.end() && dest.available() >= 2) { + int b = source.get() & 0xFF; + if ((b & 0x80) == 0) { + dest.put((char)b); + } else if ((b & 0xE0) == 0xC0) { + if (source.end()) { + dest.put((char)b); + return; + } + dest.put((char)(((b & 0x1F) << 6) | (source.get() & 0x3F))); + } else if ((b & 0xF0) == 0xE0) { + if (source.available() < 2) { + source.skip(source.available()); + dest.put((char)b); + return; + } + byte b2 = source.get(); + byte b3 = source.get(); + char c = (char)(((b & 0x0F) << 12) | ((b2 & 0x3f) << 6) | (b3 & 0x3F)); + dest.put(!UTF16Helper.isHighSurrogate(c) ? c : '?'); + } else if ((b & 0xF8) == 0xF0) { + if (source.available() < 3) { + source.skip(source.available()); + dest.put((char)b); + return; + } + byte b2 = source.get(); + byte b3 = source.get(); + byte b4 = source.get(); + int code = (((b & 0x07) << 18) | ((b2 & 0x3f) << 12) | ((b3 & 0x3F) << 6) | (b4 & 0x3F)) - + UTF16Helper.SUPPLEMENTARY_PLANE; + dest.put(UTF16Helper.highSurrogate(code)); + dest.put(UTF16Helper.lowSurrogate(code)); + } + } } } diff --git a/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TAbstractStringBuilder.java b/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TAbstractStringBuilder.java index 3a3056f10..61b1c1565 100644 --- a/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TAbstractStringBuilder.java +++ b/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TAbstractStringBuilder.java @@ -46,7 +46,7 @@ class TAbstractStringBuilder extends TObject implements TSerializable, TCharSequ private static final int FLOAT_MAX_POS = 1000000; private static final long DOUBLE_MAX_POS = 1000000000000000L; char[] buffer; - int length; + private int length; public TAbstractStringBuilder() { this(16); @@ -490,6 +490,11 @@ class TAbstractStringBuilder extends TObject implements TSerializable, TCharSequ return this; } + protected TAbstractStringBuilder append(TObject obj) { + append(TString.wrap(obj != null ? obj.toString() : "null")); + return this; + } + private void ensureCapacity(int capacity) { if (buffer.length >= capacity) { return; @@ -522,7 +527,7 @@ class TAbstractStringBuilder extends TObject implements TSerializable, TCharSequ return buffer[index]; } - public TAbstractStringBuilder append(TCharSequence s, int start, int end) { + protected TAbstractStringBuilder append(TCharSequence s, int start, int end) { if (start > end || end > s.length() || start < 0) { throw new TIndexOutOfBoundsException(); } @@ -533,10 +538,19 @@ class TAbstractStringBuilder extends TObject implements TSerializable, TCharSequ return this; } - public TAbstractStringBuilder append(TCharSequence s) { + protected TAbstractStringBuilder append(TCharSequence s) { return append(s, 0, s.length()); } + protected TAbstractStringBuilder append(char[] chars, int offset, int len) { + ensureCapacity(length + len); + len += offset; + while (offset < len) { + buffer[length++] = chars[offset++]; + } + return this; + } + @Override public TCharSequence subSequence(int start, int end) { // TODO: implement diff --git a/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TString.java b/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TString.java index d394b2b6a..576959afd 100644 --- a/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TString.java +++ b/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TString.java @@ -15,8 +15,12 @@ */ package org.teavm.classlib.java.lang; +import org.teavm.classlib.impl.charset.ByteBuffer; +import org.teavm.classlib.impl.charset.CharBuffer; +import org.teavm.classlib.impl.charset.Charset; import org.teavm.classlib.impl.charset.UTF16Helper; import org.teavm.classlib.java.io.TSerializable; +import org.teavm.classlib.java.io.TUnsupportedEncodingException; import org.teavm.javascript.ni.GeneratedBy; import org.teavm.javascript.ni.Rename; @@ -24,8 +28,7 @@ import org.teavm.javascript.ni.Rename; * * @author Alexey Andreev */ -public class TString extends TObject implements TSerializable, TComparable, - TCharSequence { +public class TString extends TObject implements TSerializable, TComparable, TCharSequence { private char[] characters; private transient int hashCode; @@ -51,8 +54,43 @@ public class TString extends TObject implements TSerializable, TComparable