Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authoreutarass2009-07-13 21:57:02 +0000
committereutarass2009-07-13 21:57:02 +0000
commit7d81388197cf89b6e8e2f90001d84f54f5904819 (patch)
treefc662c10e7631cae5b4c5f673156c65fc5037cde /plugins/org.eclipse.tm.tcf.core
parent57e0537508be9878f45b29d1c5ca51eeda38c0c0 (diff)
downloadorg.eclipse.tcf-7d81388197cf89b6e8e2f90001d84f54f5904819.tar.gz
org.eclipse.tcf-7d81388197cf89b6e8e2f90001d84f54f5904819.tar.xz
org.eclipse.tcf-7d81388197cf89b6e8e2f90001d84f54f5904819.zip
Bug 282840: Zero copy transfer
Diffstat (limited to 'plugins/org.eclipse.tm.tcf.core')
-rw-r--r--plugins/org.eclipse.tm.tcf.core/src/org/eclipse/tm/internal/tcf/core/ServiceManager.java6
-rw-r--r--plugins/org.eclipse.tm.tcf.core/src/org/eclipse/tm/internal/tcf/services/remote/ExpressionsProxy.java5
-rw-r--r--plugins/org.eclipse.tm.tcf.core/src/org/eclipse/tm/internal/tcf/services/remote/FileSystemProxy.java7
-rw-r--r--plugins/org.eclipse.tm.tcf.core/src/org/eclipse/tm/internal/tcf/services/remote/MemoryProxy.java6
-rw-r--r--plugins/org.eclipse.tm.tcf.core/src/org/eclipse/tm/internal/tcf/services/remote/RegistersProxy.java15
-rw-r--r--plugins/org.eclipse.tm.tcf.core/src/org/eclipse/tm/internal/tcf/services/remote/StreamsProxy.java6
-rw-r--r--plugins/org.eclipse.tm.tcf.core/src/org/eclipse/tm/internal/tcf/services/remote/SymbolsProxy.java10
-rw-r--r--plugins/org.eclipse.tm.tcf.core/src/org/eclipse/tm/tcf/core/AbstractChannel.java6
-rw-r--r--plugins/org.eclipse.tm.tcf.core/src/org/eclipse/tm/tcf/core/ChannelTCP.java6
-rw-r--r--plugins/org.eclipse.tm.tcf.core/src/org/eclipse/tm/tcf/core/Command.java3
-rw-r--r--plugins/org.eclipse.tm.tcf.core/src/org/eclipse/tm/tcf/core/StreamChannel.java67
-rw-r--r--plugins/org.eclipse.tm.tcf.core/src/org/eclipse/tm/tcf/protocol/JSON.java169
12 files changed, 208 insertions, 98 deletions
diff --git a/plugins/org.eclipse.tm.tcf.core/src/org/eclipse/tm/internal/tcf/core/ServiceManager.java b/plugins/org.eclipse.tm.tcf.core/src/org/eclipse/tm/internal/tcf/core/ServiceManager.java
index 8389e355e..360dac927 100644
--- a/plugins/org.eclipse.tm.tcf.core/src/org/eclipse/tm/internal/tcf/core/ServiceManager.java
+++ b/plugins/org.eclipse.tm.tcf.core/src/org/eclipse/tm/internal/tcf/core/ServiceManager.java
@@ -58,6 +58,12 @@ public class ServiceManager {
}
public static void onChannelCreated(IChannel channel, Map<String,IService> services) {
+ IService zero_copy = new IService() {
+ public String getName() {
+ return "ZeroCopy";
+ }
+ };
+ services.put(zero_copy.getName(), zero_copy);
for (IServiceProvider provider : providers) {
IService[] arr = provider.getLocalService(channel);
if (arr == null) continue;
diff --git a/plugins/org.eclipse.tm.tcf.core/src/org/eclipse/tm/internal/tcf/services/remote/ExpressionsProxy.java b/plugins/org.eclipse.tm.tcf.core/src/org/eclipse/tm/internal/tcf/services/remote/ExpressionsProxy.java
index 9e31ea558..02fb12acf 100644
--- a/plugins/org.eclipse.tm.tcf.core/src/org/eclipse/tm/internal/tcf/services/remote/ExpressionsProxy.java
+++ b/plugins/org.eclipse.tm.tcf.core/src/org/eclipse/tm/internal/tcf/services/remote/ExpressionsProxy.java
@@ -15,7 +15,6 @@ import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
-import org.eclipse.tm.tcf.core.Base64;
import org.eclipse.tm.tcf.core.Command;
import org.eclipse.tm.tcf.protocol.IChannel;
import org.eclipse.tm.tcf.protocol.IToken;
@@ -136,7 +135,7 @@ public class ExpressionsProxy implements IExpressions {
}
public IToken assign(String id, byte[] value, final DoneAssign done) {
- return new Command(channel, this, "assign", new Object[]{ id, Base64.toBase64(value, 0, value.length) }) {
+ return new Command(channel, this, "assign", new Object[]{ id, new JSON.Binary(value, 0, value.length) }) {
@Override
public void done(Exception error, Object[] args) {
if (error == null) {
@@ -186,7 +185,7 @@ public class ExpressionsProxy implements IExpressions {
Map<String,Object> props = null;
if (error == null) {
assert args.length == 3;
- if (args[0] != null) value = Base64.toByteArray(((String)args[0]).toCharArray());
+ value = JSON.toByteArray(args[0]);
error = toError(args[1]);
props = (Map<String,Object>)args[2];
}
diff --git a/plugins/org.eclipse.tm.tcf.core/src/org/eclipse/tm/internal/tcf/services/remote/FileSystemProxy.java b/plugins/org.eclipse.tm.tcf.core/src/org/eclipse/tm/internal/tcf/services/remote/FileSystemProxy.java
index 0f6a64144..13e6bbcf7 100644
--- a/plugins/org.eclipse.tm.tcf.core/src/org/eclipse/tm/internal/tcf/services/remote/FileSystemProxy.java
+++ b/plugins/org.eclipse.tm.tcf.core/src/org/eclipse/tm/internal/tcf/services/remote/FileSystemProxy.java
@@ -14,11 +14,11 @@ import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
-import org.eclipse.tm.tcf.core.Base64;
import org.eclipse.tm.tcf.core.Command;
import org.eclipse.tm.tcf.protocol.IChannel;
import org.eclipse.tm.tcf.protocol.IErrorReport;
import org.eclipse.tm.tcf.protocol.IToken;
+import org.eclipse.tm.tcf.protocol.JSON;
import org.eclipse.tm.tcf.services.IFileSystem;
@@ -294,8 +294,7 @@ public class FileSystemProxy implements IFileSystem {
assert args.length == 3;
s = toFSError(args[1]);
if (s == null) {
- String str = (String)args[0];
- if (str != null) b = Base64.toByteArray(str.toCharArray());
+ b = JSON.toByteArray(args[0]);
eof = ((Boolean)args[2]).booleanValue();
}
}
@@ -451,7 +450,7 @@ public class FileSystemProxy implements IFileSystem {
assert handle.getService() == this;
String id = ((FileHandle)handle).id;
return new FileSystemCommand("write", new Object[]{
- id, Long.valueOf(offset), Base64.toBase64(data, data_pos, data_size) }) {
+ id, Long.valueOf(offset), new JSON.Binary(data, data_pos, data_size) }) {
public void done(Exception error, Object[] args) {
Status s = null;
if (error != null) {
diff --git a/plugins/org.eclipse.tm.tcf.core/src/org/eclipse/tm/internal/tcf/services/remote/MemoryProxy.java b/plugins/org.eclipse.tm.tcf.core/src/org/eclipse/tm/internal/tcf/services/remote/MemoryProxy.java
index a82649110..e8dd8b948 100644
--- a/plugins/org.eclipse.tm.tcf.core/src/org/eclipse/tm/internal/tcf/services/remote/MemoryProxy.java
+++ b/plugins/org.eclipse.tm.tcf.core/src/org/eclipse/tm/internal/tcf/services/remote/MemoryProxy.java
@@ -18,7 +18,6 @@ import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
-import org.eclipse.tm.tcf.core.Base64;
import org.eclipse.tm.tcf.core.Command;
import org.eclipse.tm.tcf.protocol.IChannel;
import org.eclipse.tm.tcf.protocol.IErrorReport;
@@ -225,8 +224,7 @@ public class MemoryProxy implements IMemory {
}
else {
assert args.length == 3;
- String str = (String)args[0];
- if (str != null) Base64.toByteArray(buf, offs, size, str.toCharArray());
+ JSON.toByteArray(buf, offs, size, args[0]);
e = toMemoryError(addr, args[1], args[2]);
}
done.doneMemory(token, e);
@@ -237,7 +235,7 @@ public class MemoryProxy implements IMemory {
public IToken set(final Number addr, int word_size,
byte[] buf, int offs, int size, int mode, final DoneMemory done) {
return new MemoryCommand("set", new Object[] {
- getID(), addr, word_size, size, mode, Base64.toBase64(buf, offs, size)
+ getID(), addr, word_size, size, mode, new JSON.Binary(buf, offs, size)
} ) {
public void done(Exception error, Object[] args) {
MemoryError e = null;
diff --git a/plugins/org.eclipse.tm.tcf.core/src/org/eclipse/tm/internal/tcf/services/remote/RegistersProxy.java b/plugins/org.eclipse.tm.tcf.core/src/org/eclipse/tm/internal/tcf/services/remote/RegistersProxy.java
index bdeb91af3..947852ccb 100644
--- a/plugins/org.eclipse.tm.tcf.core/src/org/eclipse/tm/internal/tcf/services/remote/RegistersProxy.java
+++ b/plugins/org.eclipse.tm.tcf.core/src/org/eclipse/tm/internal/tcf/services/remote/RegistersProxy.java
@@ -15,7 +15,6 @@ import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
-import org.eclipse.tm.tcf.core.Base64;
import org.eclipse.tm.tcf.core.Command;
import org.eclipse.tm.tcf.protocol.IChannel;
import org.eclipse.tm.tcf.protocol.IToken;
@@ -162,8 +161,7 @@ public class RegistersProxy implements IRegisters {
if (error == null) {
assert args.length == 2;
error = toError(args[0]);
- String str = (String)args[1];
- if (str != null) val = Base64.toByteArray(str.toCharArray());
+ val = JSON.toByteArray(args[1]);
}
done.doneGet(token, error, val);
}
@@ -172,7 +170,7 @@ public class RegistersProxy implements IRegisters {
public IToken set(byte[] value, final DoneSet done) {
return new Command(channel, RegistersProxy.this, "set",
- new Object[]{ getID(), Base64.toBase64(value, 0, value.length) }) {
+ new Object[]{ getID(), new JSON.Binary(value, 0, value.length) }) {
@Override
public void done(Exception error, Object[] args) {
if (error == null) {
@@ -252,8 +250,7 @@ public class RegistersProxy implements IRegisters {
if (error == null) {
assert args.length == 2;
error = toError(args[0]);
- String str = (String)args[1];
- if (str != null) val = Base64.toByteArray(str.toCharArray());
+ val = JSON.toByteArray(args[1]);
}
done.doneGet(token, error, val);
}
@@ -262,7 +259,7 @@ public class RegistersProxy implements IRegisters {
public IToken setm(Location[] locs, byte[] value, final DoneSet done) {
return new Command(channel, this, "setm",
- new Object[]{ locs, Base64.toBase64(value, 0, value.length) }) {
+ new Object[]{ locs, new JSON.Binary(value, 0, value.length) }) {
@Override
public void done(Exception error, Object[] args) {
if (error == null) {
@@ -343,9 +340,7 @@ public class RegistersProxy implements IRegisters {
NamedValueInfo(Map<String,Object> m) {
desc = (String)m.get("Description");
name = (String)m.get("Name");
- String str = (String)m.get("Value");
- if (str == null) value = null;
- else value = Base64.toByteArray(str.toCharArray());
+ value = JSON.toByteArray(m.get("Value"));
}
public String getDescription() {
diff --git a/plugins/org.eclipse.tm.tcf.core/src/org/eclipse/tm/internal/tcf/services/remote/StreamsProxy.java b/plugins/org.eclipse.tm.tcf.core/src/org/eclipse/tm/internal/tcf/services/remote/StreamsProxy.java
index f785def30..dd9a7b9ad 100644
--- a/plugins/org.eclipse.tm.tcf.core/src/org/eclipse/tm/internal/tcf/services/remote/StreamsProxy.java
+++ b/plugins/org.eclipse.tm.tcf.core/src/org/eclipse/tm/internal/tcf/services/remote/StreamsProxy.java
@@ -14,7 +14,6 @@ import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
-import org.eclipse.tm.tcf.core.Base64;
import org.eclipse.tm.tcf.core.Command;
import org.eclipse.tm.tcf.protocol.IChannel;
import org.eclipse.tm.tcf.protocol.IToken;
@@ -79,11 +78,10 @@ public class StreamsProxy implements IStreams {
boolean eos = false;
if (error == null) {
assert args.length == 4;
- String str = (String)args[0];
+ data = JSON.toByteArray(args[0]);
error = toError(args[1]);
lost_size = ((Number)args[2]).intValue();
eos = ((Boolean)args[3]).booleanValue();
- if (str != null) data = Base64.toByteArray(str.toCharArray());
}
done.doneRead(token, error, lost_size, data, eos);
}
@@ -147,7 +145,7 @@ public class StreamsProxy implements IStreams {
}
public IToken write(String stream_id, byte[] buf, int offset, int size, final DoneWrite done) {
- return new Command(channel, this, "write", new Object[]{ stream_id, size, Base64.toBase64(buf, offset, size) }) {
+ return new Command(channel, this, "write", new Object[]{ stream_id, size, new JSON.Binary(buf, offset, size) }) {
@Override
public void done(Exception error, Object[] args) {
if (error == null) {
diff --git a/plugins/org.eclipse.tm.tcf.core/src/org/eclipse/tm/internal/tcf/services/remote/SymbolsProxy.java b/plugins/org.eclipse.tm.tcf.core/src/org/eclipse/tm/internal/tcf/services/remote/SymbolsProxy.java
index b211887ac..6f21f5536 100644
--- a/plugins/org.eclipse.tm.tcf.core/src/org/eclipse/tm/internal/tcf/services/remote/SymbolsProxy.java
+++ b/plugins/org.eclipse.tm.tcf.core/src/org/eclipse/tm/internal/tcf/services/remote/SymbolsProxy.java
@@ -3,10 +3,10 @@ package org.eclipse.tm.internal.tcf.services.remote;
import java.util.Collection;
import java.util.Map;
-import org.eclipse.tm.tcf.core.Base64;
import org.eclipse.tm.tcf.core.Command;
import org.eclipse.tm.tcf.protocol.IChannel;
import org.eclipse.tm.tcf.protocol.IToken;
+import org.eclipse.tm.tcf.protocol.JSON;
import org.eclipse.tm.tcf.services.ISymbols;
public class SymbolsProxy implements ISymbols {
@@ -20,13 +20,7 @@ public class SymbolsProxy implements ISymbols {
Context(Map<String,Object> props) {
this.props = props;
- String s = (String)props.get(PROP_VALUE);
- if (s == null) {
- value = null;
- }
- else {
- value = Base64.toByteArray(s.toCharArray());
- }
+ value = JSON.toByteArray(props.get(PROP_VALUE));
}
public Number getAddress() {
diff --git a/plugins/org.eclipse.tm.tcf.core/src/org/eclipse/tm/tcf/core/AbstractChannel.java b/plugins/org.eclipse.tm.tcf.core/src/org/eclipse/tm/tcf/core/AbstractChannel.java
index a5ef733e0..4ae31c499 100644
--- a/plugins/org.eclipse.tm.tcf.core/src/org/eclipse/tm/tcf/core/AbstractChannel.java
+++ b/plugins/org.eclipse.tm.tcf.core/src/org/eclipse/tm/tcf/core/AbstractChannel.java
@@ -138,6 +138,7 @@ public abstract class AbstractChannel implements IChannel {
private final IPeer local_peer;
private IPeer remote_peer;
private Proxy proxy;
+ private boolean zero_copy;
private static final int pending_command_limit = 32;
private int local_congestion_level = -100;
@@ -770,6 +771,10 @@ public abstract class AbstractChannel implements IChannel {
addToOutQueue(msg);
}
+ public boolean isZeroCopySupported() {
+ return zero_copy;
+ }
+
@SuppressWarnings("unchecked")
private void handleInput(Message msg) {
assert Protocol.isDispatchThread();
@@ -836,6 +841,7 @@ public abstract class AbstractChannel implements IChannel {
remote_service_by_class.clear();
ServiceManager.onChannelOpened(this, (Collection<String>)JSON.parseSequence(msg.data)[0], remote_service_by_name);
makeServiceByClassMap(remote_service_by_name, remote_service_by_class);
+ zero_copy = remote_service_by_name.containsKey("ZeroCopy");
}
if (proxy != null && state == STATE_OPEN) {
proxy.onEvent(msg.service, msg.name, msg.data);
diff --git a/plugins/org.eclipse.tm.tcf.core/src/org/eclipse/tm/tcf/core/ChannelTCP.java b/plugins/org.eclipse.tm.tcf.core/src/org/eclipse/tm/tcf/core/ChannelTCP.java
index cdf889206..d4918858f 100644
--- a/plugins/org.eclipse.tm.tcf.core/src/org/eclipse/tm/tcf/core/ChannelTCP.java
+++ b/plugins/org.eclipse.tm.tcf.core/src/org/eclipse/tm/tcf/core/ChannelTCP.java
@@ -126,6 +126,12 @@ public class ChannelTCP extends StreamChannel {
}
@Override
+ protected final void put(byte[] buf) throws IOException {
+ if (closed) return;
+ out.write(buf);
+ }
+
+ @Override
protected final void flush() throws IOException {
if (closed) return;
out.flush();
diff --git a/plugins/org.eclipse.tm.tcf.core/src/org/eclipse/tm/tcf/core/Command.java b/plugins/org.eclipse.tm.tcf.core/src/org/eclipse/tm/tcf/core/Command.java
index 7748e15c7..886a1a793 100644
--- a/plugins/org.eclipse.tm.tcf.core/src/org/eclipse/tm/tcf/core/Command.java
+++ b/plugins/org.eclipse.tm.tcf.core/src/org/eclipse/tm/tcf/core/Command.java
@@ -74,7 +74,8 @@ public abstract class Command implements IChannel.ICommandListener {
this.args = args;
IToken t = null;
try {
- t = channel.sendCommand(service, command, JSON.toJSONSequence(args), this);
+ boolean zero_copy = ((AbstractChannel)channel).isZeroCopySupported();
+ t = channel.sendCommand(service, command, JSON.toJSONSequence(args, zero_copy), this);
}
catch (Throwable y) {
t = new Token();
diff --git a/plugins/org.eclipse.tm.tcf.core/src/org/eclipse/tm/tcf/core/StreamChannel.java b/plugins/org.eclipse.tm.tcf.core/src/org/eclipse/tm/tcf/core/StreamChannel.java
index b9020729a..14d2e0cf5 100644
--- a/plugins/org.eclipse.tm.tcf.core/src/org/eclipse/tm/tcf/core/StreamChannel.java
+++ b/plugins/org.eclipse.tm.tcf.core/src/org/eclipse/tm/tcf/core/StreamChannel.java
@@ -28,6 +28,8 @@ import org.eclipse.tm.tcf.protocol.IPeer;
public abstract class StreamChannel extends AbstractChannel {
public static final int ESC = 3;
+
+ private int bin_data_size;
public StreamChannel(IPeer remote_peer) {
super(remote_peer);
@@ -39,22 +41,38 @@ public abstract class StreamChannel extends AbstractChannel {
protected abstract int get() throws IOException;
protected abstract void put(int n) throws IOException;
+
+ protected void put(byte[] buf) throws IOException {
+ for (byte b : buf) put(b & 0xff);
+ }
@Override
protected final int read() throws IOException {
- int res = get();
- if (res < 0) return EOS;
- assert res >= 0 && res <= 0xff;
- if (res != ESC) return res;
- int n = get();
- switch (n) {
- case 0: return ESC;
- case 1: return EOM;
- case 2: return EOS;
- default:
- if (n < 0) return EOS;
- assert false;
- return 0;
+ for (;;) {
+ int res = get();
+ if (res < 0) return EOS;
+ assert res >= 0 && res <= 0xff;
+ if (bin_data_size > 0) {
+ bin_data_size--;
+ return res;
+ }
+ if (res != ESC) return res;
+ int n = get();
+ switch (n) {
+ case 0: return ESC;
+ case 1: return EOM;
+ case 2: return EOS;
+ case 3:
+ for (int i = 0;; i += 7) {
+ res = get();
+ bin_data_size |= (res & 0x7f) << i;
+ if ((res & 0x80) == 0) break;
+ }
+ break;
+ default:
+ if (n < 0) return EOS;
+ assert false;
+ }
}
}
@@ -72,10 +90,25 @@ public abstract class StreamChannel extends AbstractChannel {
@Override
protected void write(byte[] buf) throws IOException {
- for (int i = 0; i < buf.length; i++) {
- int n = buf[i] & 0xff;
- put(n);
- if (n == ESC) put(0);
+ if (buf.length > 32 && isZeroCopySupported()) {
+ put(ESC); put(3);
+ int n = buf.length;
+ for (;;) {
+ if (n <= 0x7f) {
+ put(n);
+ break;
+ }
+ put((n & 0x7f) | 0x80);
+ n = n >> 7;
+ }
+ put(buf);
+ }
+ else {
+ for (byte b : buf) {
+ int n = b & 0xff;
+ put(n);
+ if (n == ESC) put(0);
+ }
}
}
}
diff --git a/plugins/org.eclipse.tm.tcf.core/src/org/eclipse/tm/tcf/protocol/JSON.java b/plugins/org.eclipse.tm.tcf.core/src/org/eclipse/tm/tcf/protocol/JSON.java
index 0b4f1f51b..c63cc0c05 100644
--- a/plugins/org.eclipse.tm.tcf.core/src/org/eclipse/tm/tcf/protocol/JSON.java
+++ b/plugins/org.eclipse.tm.tcf.core/src/org/eclipse/tm/tcf/protocol/JSON.java
@@ -10,11 +10,7 @@
*******************************************************************************/
package org.eclipse.tm.tcf.protocol;
-import java.io.ByteArrayInputStream;
import java.io.IOException;
-import java.io.InputStreamReader;
-import java.io.Reader;
-import java.io.StringReader;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.ArrayList;
@@ -25,6 +21,8 @@ import java.util.Iterator;
import java.util.List;
import java.util.Map;
+import org.eclipse.tm.tcf.core.Base64;
+
/**
* JSON is TCF preferred marshaling. This class implements generation and parsing of JSON strings.
@@ -54,14 +52,28 @@ public final class JSON {
private static final Map<Class<?>,ObjectWriter> object_writers = new HashMap<Class<?>,ObjectWriter>();
+ /** Wrapper class for binary byte blocs */
+ public final static class Binary {
+ public final byte[] bytes;
+ public final int offs;
+ public final int size;
+
+ public Binary(byte[] bytes, int offs, int size) {
+ this.bytes = bytes;
+ this.offs = offs;
+ this.size = size;
+ }
+ }
+
private static char[] tmp_buf = new char[0x1000];
private static byte[] tmp_bbf = new byte[0x1000];
private static int tmp_buf_pos;
+ private static boolean zero_copy;
+ private static Binary[] bin_buf = new Binary[0x10];
+ private static int bin_buf_pos;
- private static Reader reader;
- private static final char[] cur_buf = new char[0x1000];
- private static int cur_buf_pos;
- private static int cur_buf_len;
+ private static byte[] inp;
+ private static int inp_pos;
private static int cur_ch;
// This buffer is used to create nice error reports
@@ -117,18 +129,32 @@ public final class JSON {
if (n >= 10) writeUInt(n / 10);
write((char)('0' + n % 10));
}
-
- private static void read() throws IOException {
- if (cur_buf_pos >= cur_buf_len) {
- cur_buf_len = reader.read(cur_buf);
- cur_buf_pos = 0;
- if (cur_buf_len < 0) {
- cur_buf_len = 0;
- cur_ch = -1;
- return;
+
+ private static int readUTF8Char() {
+ if (inp_pos >= inp.length) return -1;
+ int ch = inp[inp_pos++];
+ if (ch < 0) {
+ if ((ch & 0xe0) == 0xc0) {
+ ch = (ch & 0x1f) << 6;
+ ch |= inp[inp_pos++] & 0x3f;
+ }
+ else if ((ch & 0xf0) == 0xe0) {
+ ch = (ch & 0x0f) << 12;
+ ch |= (inp[inp_pos++] & 0x3f) << 6;
+ ch |= inp[inp_pos++] & 0x3f;
+ }
+ else if ((ch & 0xf0) == 0xf0) {
+ ch = (ch & 0x0f) << 18;
+ ch |= (inp[inp_pos++] & 0x3f) << 12;
+ ch |= (inp[inp_pos++] & 0x3f) << 6;
+ ch |= inp[inp_pos++] & 0x3f;
}
}
- cur_ch = cur_buf[cur_buf_pos++];
+ return ch;
+ }
+
+ private static void read() throws IOException {
+ cur_ch = readUTF8Char();
err_buf[err_buf_pos++] = (char)cur_ch;
if (err_buf_pos >= err_buf.length) {
err_buf_pos = 0;
@@ -154,7 +180,7 @@ public final class JSON {
ch = err_buf[(err_buf_pos + i) % err_buf.length];
}
else {
- int n = reader.read();
+ int n = readUTF8Char();
if (n < 0) break;
ch = (char)n;
}
@@ -214,6 +240,19 @@ public final class JSON {
private static Object readNestedObject() throws IOException {
switch (cur_ch) {
+ case '(':
+ read();
+ int len = 0;
+ while (cur_ch >= '0' && cur_ch <= '9') {
+ len = len * 10 + (cur_ch - '0');
+ read();
+ }
+ if (cur_ch != ')') error();
+ byte[] res = new byte[len];
+ System.arraycopy(inp, inp_pos, res, 0, len);
+ inp_pos += len;
+ read();
+ return res;
case '"':
read();
tmp_buf_pos = 0;
@@ -263,17 +302,7 @@ public final class JSON {
else {
tmp_buf[tmp_buf_pos++] = (char)cur_ch;
}
- if (cur_buf_pos >= cur_buf_len) {
- read();
- }
- else {
- cur_ch = cur_buf[cur_buf_pos++];
- err_buf[err_buf_pos++] = (char)cur_ch;
- if (err_buf_pos >= err_buf.length) {
- err_buf_pos = 0;
- err_buf_cnt++;
- }
- }
+ read();
}
read();
return new String(tmp_buf, 0, tmp_buf_pos);
@@ -435,6 +464,9 @@ public final class JSON {
case 0:
write("\\u0000");
break;
+ case 1:
+ write("\\u0001");
+ break;
case '\r':
write("\\r");
break;
@@ -460,6 +492,19 @@ public final class JSON {
}
write('"');
}
+ else if (o instanceof Binary) {
+ Binary b = (Binary)o;
+ if (zero_copy) {
+ write('(');
+ write(Integer.toString(b.size));
+ write(')');
+ write((char)1);
+ bin_buf[bin_buf_pos++] = b;
+ }
+ else {
+ writeObject(Base64.toBase64(b.bytes, b.offs, b.size));
+ }
+ }
else if (o instanceof byte[]) {
write('[');
byte[] arr = (byte[])o;
@@ -520,14 +565,25 @@ public final class JSON {
private static byte[] toBytes() {
int inp_pos = 0;
int out_pos = 0;
+ int blc_pos = 0;
while (inp_pos < tmp_buf_pos) {
- if (out_pos >= tmp_bbf.length - 4) {
+ if (out_pos > tmp_bbf.length - 4) {
byte[] tmp = new byte[tmp_bbf.length * 2];
System.arraycopy(tmp_bbf, 0, tmp, 0, out_pos);
tmp_bbf = tmp;
}
int ch = tmp_buf[inp_pos++];
- if (ch < 0x80) {
+ if (ch == 1) {
+ Binary b = bin_buf[blc_pos++];
+ while (out_pos > tmp_bbf.length - b.size) {
+ byte[] tmp = new byte[tmp_bbf.length * 2];
+ System.arraycopy(tmp_bbf, 0, tmp, 0, out_pos);
+ tmp_bbf = tmp;
+ }
+ System.arraycopy(b.bytes, b.offs, tmp_bbf, out_pos, b.size);
+ out_pos += b.size;
+ }
+ else if (ch < 0x80) {
tmp_bbf[out_pos++] = (byte)ch;
}
else if (ch < 0x800) {
@@ -554,6 +610,8 @@ public final class JSON {
public static String toJSON(Object o) throws IOException {
assert Protocol.isDispatchThread();
tmp_buf_pos = 0;
+ bin_buf_pos = 0;
+ zero_copy = false;
writeObject(o);
return new String(tmp_buf, 0, tmp_buf_pos);
}
@@ -561,6 +619,8 @@ public final class JSON {
public static byte[] toJASONBytes(Object o) throws IOException {
assert Protocol.isDispatchThread();
tmp_buf_pos = 0;
+ bin_buf_pos = 0;
+ zero_copy = false;
writeObject(o);
return toBytes();
}
@@ -569,6 +629,8 @@ public final class JSON {
assert Protocol.isDispatchThread();
if (o == null || o.length == 0) return null;
tmp_buf_pos = 0;
+ bin_buf_pos = 0;
+ zero_copy = false;
for (int i = 0; i < o.length; i++) {
writeObject(o[i]);
write((char)0);
@@ -576,38 +638,51 @@ public final class JSON {
return toBytes();
}
- public static Object parseOne(String s) throws IOException {
+ public static byte[] toJSONSequence(Object[] o, boolean zero_copy) throws IOException {
assert Protocol.isDispatchThread();
- if (s.length() == 0) return null;
- reader = new StringReader(s);
- err_buf_pos = 0;
- err_buf_cnt = 0;
- cur_buf_pos = 0;
- cur_buf_len = 0;
- read();
- return readObject();
+ if (o == null || o.length == 0) return null;
+ tmp_buf_pos = 0;
+ bin_buf_pos = 0;
+ JSON.zero_copy = zero_copy;
+ for (int i = 0; i < o.length; i++) {
+ writeObject(o[i]);
+ write((char)0);
+ }
+ return toBytes();
}
public static Object parseOne(byte[] b) throws IOException {
assert Protocol.isDispatchThread();
if (b.length == 0) return null;
- reader = new InputStreamReader(new ByteArrayInputStream(b), "UTF8");
+ inp = b;
+ inp_pos = 0;
err_buf_pos = 0;
err_buf_cnt = 0;
- cur_buf_pos = 0;
- cur_buf_len = 0;
read();
return readObject();
}
public static Object[] parseSequence(byte[] b) throws IOException {
assert Protocol.isDispatchThread();
- reader = new InputStreamReader(new ByteArrayInputStream(b), "UTF8");
+ inp = b;
+ inp_pos = 0;
err_buf_pos = 0;
err_buf_cnt = 0;
- cur_buf_pos = 0;
- cur_buf_len = 0;
read();
return readSequence();
}
+
+ public static byte[] toByteArray(Object o) {
+ if (o == null) return null;
+ if (o instanceof byte[]) return (byte[])o;
+ if (o instanceof char[]) return Base64.toByteArray((char[])o);
+ if (o instanceof String) return Base64.toByteArray(((String)o).toCharArray());
+ throw new Error();
+ }
+
+ public static void toByteArray(byte[] buf, int offs, int size, Object o) {
+ if (o instanceof char[]) Base64.toByteArray(buf, offs, size, (char[])o);
+ else if (o instanceof String) Base64.toByteArray(buf, offs, size, ((String)o).toCharArray());
+ else if (o != null) System.arraycopy(toByteArray(o), 0, buf, offs, size);
+ }
}

Back to the top