diff options
author | eutarass | 2009-07-13 21:57:02 +0000 |
---|---|---|
committer | eutarass | 2009-07-13 21:57:02 +0000 |
commit | 7d81388197cf89b6e8e2f90001d84f54f5904819 (patch) | |
tree | fc662c10e7631cae5b4c5f673156c65fc5037cde /plugins/org.eclipse.tm.tcf.core | |
parent | 57e0537508be9878f45b29d1c5ca51eeda38c0c0 (diff) | |
download | org.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')
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); + } } |