summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndroid (Google) Code Review <android-gerrit@google.com>2009-12-21 18:39:19 -0800
committerAndroid (Google) Code Review <android-gerrit@google.com>2009-12-21 18:39:19 -0800
commitf966afa1461c602fb5b50aeb5d6429dc525014be (patch)
treeb35042dffb3a4882fe99a24f3ee0770910a27171
parentee0511d76ce0ceae2f54782ca33e400e62d08137 (diff)
parentf41de2a4a1c22e3f3ee9a8cd65ec7997c9587cdb (diff)
downloadframeworks_base-f966afa1461c602fb5b50aeb5d6429dc525014be.zip
frameworks_base-f966afa1461c602fb5b50aeb5d6429dc525014be.tar.gz
frameworks_base-f966afa1461c602fb5b50aeb5d6429dc525014be.tar.bz2
Merge change I34a427a5
* changes: Adding support for LoggingPrintStream.write(byte[]) and friends.
-rw-r--r--core/java/com/android/internal/os/LoggingPrintStream.java81
-rw-r--r--tests/framework-tests/src/com/android/internal/os/LoggingPrintStreamTest.java61
2 files changed, 124 insertions, 18 deletions
diff --git a/core/java/com/android/internal/os/LoggingPrintStream.java b/core/java/com/android/internal/os/LoggingPrintStream.java
index b3d6f20..451340b 100644
--- a/core/java/com/android/internal/os/LoggingPrintStream.java
+++ b/core/java/com/android/internal/os/LoggingPrintStream.java
@@ -16,11 +16,17 @@
package com.android.internal.os;
-import java.io.PrintStream;
-import java.io.OutputStream;
import java.io.IOException;
-import java.util.Locale;
+import java.io.OutputStream;
+import java.io.PrintStream;
+import java.nio.ByteBuffer;
+import java.nio.CharBuffer;
+import java.nio.charset.Charset;
+import java.nio.charset.CharsetDecoder;
+import java.nio.charset.CoderResult;
+import java.nio.charset.CodingErrorAction;
import java.util.Formatter;
+import java.util.Locale;
/**
* A print stream which logs output line by line.
@@ -31,6 +37,27 @@ abstract class LoggingPrintStream extends PrintStream {
private final StringBuilder builder = new StringBuilder();
+ /**
+ * A buffer that is initialized when raw bytes are first written to this
+ * stream. It may contain the leading bytes of multi-byte characters.
+ * Between writes this buffer is always ready to receive data; ie. the
+ * position is at the first unassigned byte and the limit is the capacity.
+ */
+ private ByteBuffer encodedBytes;
+
+ /**
+ * A buffer that is initialized when raw bytes are first written to this
+ * stream. Between writes this buffer is always clear; ie. the position is
+ * zero and the limit is the capacity.
+ */
+ private CharBuffer decodedChars;
+
+ /**
+ * Decodes bytes to characters using the system default charset. Initialized
+ * when raw bytes are first written to this stream.
+ */
+ private CharsetDecoder decoder;
+
protected LoggingPrintStream() {
super(new OutputStream() {
public void write(int oneByte) throws IOException {
@@ -80,20 +107,48 @@ abstract class LoggingPrintStream extends PrintStream {
}
}
- /*
- * We have no idea of how these bytes are encoded, so just ignore them.
- */
-
- /** Ignored. */
- public void write(int oneByte) {}
+ public void write(int oneByte) {
+ write(new byte[] { (byte) oneByte }, 0, 1);
+ }
- /** Ignored. */
@Override
- public void write(byte buffer[]) {}
+ public void write(byte[] buffer) {
+ write(buffer, 0, buffer.length);
+ }
- /** Ignored. */
@Override
- public void write(byte bytes[], int start, int count) {}
+ public synchronized void write(byte bytes[], int start, int count) {
+ if (decoder == null) {
+ encodedBytes = ByteBuffer.allocate(80);
+ decodedChars = CharBuffer.allocate(80);
+ decoder = Charset.defaultCharset().newDecoder()
+ .onMalformedInput(CodingErrorAction.REPLACE)
+ .onUnmappableCharacter(CodingErrorAction.REPLACE);
+ }
+
+ int end = start + count;
+ while (start < end) {
+ // copy some bytes from the array to the long-lived buffer. This
+ // way, if we end with a partial character we don't lose it.
+ int numBytes = Math.min(encodedBytes.remaining(), end - start);
+ encodedBytes.put(bytes, start, numBytes);
+ start += numBytes;
+
+ encodedBytes.flip();
+ CoderResult coderResult;
+ do {
+ // decode bytes from the byte buffer into the char buffer
+ coderResult = decoder.decode(encodedBytes, decodedChars, false);
+
+ // copy chars from the char buffer into our string builder
+ decodedChars.flip();
+ builder.append(decodedChars);
+ decodedChars.clear();
+ } while (coderResult.isOverflow());
+ encodedBytes.compact();
+ }
+ flush(false);
+ }
/** Always returns false. */
@Override
diff --git a/tests/framework-tests/src/com/android/internal/os/LoggingPrintStreamTest.java b/tests/framework-tests/src/com/android/internal/os/LoggingPrintStreamTest.java
index 8e3a034..4d016d1 100644
--- a/tests/framework-tests/src/com/android/internal/os/LoggingPrintStreamTest.java
+++ b/tests/framework-tests/src/com/android/internal/os/LoggingPrintStreamTest.java
@@ -18,12 +18,12 @@ package com.android.internal.os;
import junit.framework.TestCase;
-import java.util.Arrays;
-import java.util.List;
+import java.io.PrintWriter;
+import java.io.StringWriter;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Collections;
-import java.io.StringWriter;
-import java.io.PrintWriter;
+import java.util.List;
public class LoggingPrintStreamTest extends TestCase {
@@ -121,6 +121,58 @@ public class LoggingPrintStreamTest extends TestCase {
assertEquals(Arrays.asList("Foo", "4", "a"), out.lines);
}
+ public void testMultiByteCharactersSpanningBuffers() throws Exception {
+ // assume 3*1000 bytes won't fit in LoggingPrintStream's internal buffer
+ StringBuilder builder = new StringBuilder();
+ for (int i = 0; i < 1000; i++) {
+ builder.append("\u20AC"); // a Euro character; 3 bytes in UTF-8
+ }
+ String expected = builder.toString();
+
+ out.write(expected.getBytes("UTF-8"));
+ out.flush();
+ assertEquals(Arrays.asList(expected), out.lines);
+ }
+
+ public void testWriteOneByteAtATimeMultibyteCharacters() throws Exception {
+ String expected = " \u20AC \u20AC \u20AC \u20AC ";
+ for (byte b : expected.getBytes()) {
+ out.write(b);
+ }
+ out.flush();
+ assertEquals(Arrays.asList(expected), out.lines);
+ }
+
+ public void testWriteByteArrayAtATimeMultibyteCharacters() throws Exception {
+ String expected = " \u20AC \u20AC \u20AC \u20AC ";
+ out.write(expected.getBytes());
+ out.flush();
+ assertEquals(Arrays.asList(expected), out.lines);
+ }
+
+ public void testWriteWithOffsetsMultibyteCharacters() throws Exception {
+ String expected = " \u20AC \u20AC \u20AC \u20AC ";
+ byte[] bytes = expected.getBytes();
+ int i = 0;
+ while (i < bytes.length - 5) {
+ out.write(bytes, i, 5);
+ i += 5;
+ }
+ out.write(bytes, i, bytes.length - i);
+ out.flush();
+ assertEquals(Arrays.asList(expected), out.lines);
+ }
+
+ public void testWriteFlushesOnNewlines() throws Exception {
+ String a = " \u20AC \u20AC ";
+ String b = " \u20AC \u20AC ";
+ String c = " ";
+ String toWrite = a + "\n" + b + "\n" + c;
+ out.write(toWrite.getBytes());
+ out.flush();
+ assertEquals(Arrays.asList(a, b, c), out.lines);
+ }
+
static class TestPrintStream extends LoggingPrintStream {
final List<String> lines = new ArrayList<String>();
@@ -129,5 +181,4 @@ public class LoggingPrintStreamTest extends TestCase {
lines.add(line);
}
}
-
}