blob: b9167d24d9025f7ba6feef08be619e909b03bef0 [file] [log] [blame]
Mark Slee7eb0d632007-03-01 00:00:27 +00001// Copyright (c) 2006- Facebook
2// Distributed under the Thrift Software License
3//
4// See accompanying file LICENSE or visit the Thrift site at:
5// http://developers.facebook.com/thrift/
6
Mark Slee83c52a82006-06-07 06:51:18 +00007package com.facebook.thrift.protocol;
8
9import com.facebook.thrift.TException;
10import com.facebook.thrift.transport.TTransport;
David Reiss4a15eb72007-12-14 22:14:47 +000011import com.facebook.thrift.transport.TTransportException;
12
Mark Slee6eb58922007-11-07 00:48:47 +000013import java.io.UnsupportedEncodingException;
Mark Slee83c52a82006-06-07 06:51:18 +000014
15/**
16 * Binary protocol implementation for thrift.
17 *
18 * @author Mark Slee <mcslee@facebook.com>
19 */
Mark Slee456b7a82006-10-25 20:53:37 +000020public class TBinaryProtocol extends TProtocol {
Mark Slee78f58e22006-09-02 04:17:07 +000021
Mark Slee808454e2007-06-20 21:51:57 +000022 protected static final int VERSION_MASK = 0xffff0000;
23 protected static final int VERSION_1 = 0x80010000;
24
25 protected boolean strictRead_ = false;
26 protected boolean strictWrite_ = true;
27
David Reiss4a15eb72007-12-14 22:14:47 +000028 protected int readLength_;
29 protected boolean checkReadLength_ = false;
30
Mark Slee456b7a82006-10-25 20:53:37 +000031 /**
32 * Factory
33 */
34 public static class Factory implements TProtocolFactory {
Mark Slee808454e2007-06-20 21:51:57 +000035 protected boolean strictRead_ = false;
36 protected boolean strictWrite_ = true;
Mark Slee6eb58922007-11-07 00:48:47 +000037
Mark Slee808454e2007-06-20 21:51:57 +000038 public Factory() {
Mark Sleea1d4cab2007-11-20 04:58:16 +000039 this(false, true);
Mark Slee808454e2007-06-20 21:51:57 +000040 }
41
42 public Factory(boolean strictRead, boolean strictWrite) {
43 strictRead_ = strictRead;
44 strictWrite_ = strictWrite;
45 }
46
Aditya Agarwal5a429582007-02-06 02:51:15 +000047 public TProtocol getProtocol(TTransport trans) {
Mark Slee808454e2007-06-20 21:51:57 +000048 return new TBinaryProtocol(trans, strictRead_, strictWrite_);
Mark Slee456b7a82006-10-25 20:53:37 +000049 }
Mark Slee78f58e22006-09-02 04:17:07 +000050 }
51
Mark Slee456b7a82006-10-25 20:53:37 +000052 /**
53 * Constructor
54 */
Aditya Agarwal5a429582007-02-06 02:51:15 +000055 public TBinaryProtocol(TTransport trans) {
Mark Sleea1d4cab2007-11-20 04:58:16 +000056 this(trans, false, true);
Mark Slee83c52a82006-06-07 06:51:18 +000057 }
58
Mark Slee808454e2007-06-20 21:51:57 +000059 public TBinaryProtocol(TTransport trans, boolean strictRead, boolean strictWrite) {
60 super(trans);
61 strictRead_ = strictRead;
62 strictWrite_ = strictWrite;
63 }
64
Mark Slee456b7a82006-10-25 20:53:37 +000065 public void writeMessageBegin(TMessage message) throws TException {
Mark Slee808454e2007-06-20 21:51:57 +000066 if (strictWrite_) {
67 int version = VERSION_1 | message.type;
68 writeI32(version);
69 writeString(message.name);
70 writeI32(message.seqid);
71 } else {
72 writeString(message.name);
73 writeByte(message.type);
74 writeI32(message.seqid);
75 }
Mark Slee83c52a82006-06-07 06:51:18 +000076 }
77
Mark Slee456b7a82006-10-25 20:53:37 +000078 public void writeMessageEnd() {}
79
80 public void writeStructBegin(TStruct struct) {}
81
82 public void writeStructEnd() {}
83
84 public void writeFieldBegin(TField field) throws TException {
85 writeByte(field.type);
86 writeI16(field.id);
Mark Slee83c52a82006-06-07 06:51:18 +000087 }
88
Mark Slee456b7a82006-10-25 20:53:37 +000089 public void writeFieldEnd() {}
Mark Slee530fd662006-08-09 00:05:18 +000090
Mark Slee456b7a82006-10-25 20:53:37 +000091 public void writeFieldStop() throws TException {
92 writeByte(TType.STOP);
Mark Slee83c52a82006-06-07 06:51:18 +000093 }
94
Mark Slee456b7a82006-10-25 20:53:37 +000095 public void writeMapBegin(TMap map) throws TException {
96 writeByte(map.keyType);
97 writeByte(map.valueType);
98 writeI32(map.size);
Mark Slee83c52a82006-06-07 06:51:18 +000099 }
100
Mark Slee456b7a82006-10-25 20:53:37 +0000101 public void writeMapEnd() {}
Mark Slee530fd662006-08-09 00:05:18 +0000102
Mark Slee456b7a82006-10-25 20:53:37 +0000103 public void writeListBegin(TList list) throws TException {
104 writeByte(list.elemType);
105 writeI32(list.size);
Mark Slee78f58e22006-09-02 04:17:07 +0000106 }
107
Mark Slee456b7a82006-10-25 20:53:37 +0000108 public void writeListEnd() {}
109
110 public void writeSetBegin(TSet set) throws TException {
111 writeByte(set.elemType);
112 writeI32(set.size);
113 }
114
115 public void writeSetEnd() {}
116
117 public void writeBool(boolean b) throws TException {
118 writeByte(b ? (byte)1 : (byte)0);
119 }
120
121 private byte [] bout = new byte[1];
122 public void writeByte(byte b) throws TException {
Mark Slee530fd662006-08-09 00:05:18 +0000123 bout[0] = b;
Aditya Agarwal5a429582007-02-06 02:51:15 +0000124 trans_.write(bout, 0, 1);
Mark Slee83c52a82006-06-07 06:51:18 +0000125 }
126
Mark Slee456b7a82006-10-25 20:53:37 +0000127 private byte[] i16out = new byte[2];
128 public void writeI16(short i16) throws TException {
Mark Slee78f58e22006-09-02 04:17:07 +0000129 i16out[0] = (byte)(0xff & (i16 >> 8));
130 i16out[1] = (byte)(0xff & (i16));
Aditya Agarwal5a429582007-02-06 02:51:15 +0000131 trans_.write(i16out, 0, 2);
Mark Slee83c52a82006-06-07 06:51:18 +0000132 }
133
Mark Slee456b7a82006-10-25 20:53:37 +0000134 private byte[] i32out = new byte[4];
135 public void writeI32(int i32) throws TException {
Mark Slee530fd662006-08-09 00:05:18 +0000136 i32out[0] = (byte)(0xff & (i32 >> 24));
137 i32out[1] = (byte)(0xff & (i32 >> 16));
138 i32out[2] = (byte)(0xff & (i32 >> 8));
139 i32out[3] = (byte)(0xff & (i32));
Aditya Agarwal5a429582007-02-06 02:51:15 +0000140 trans_.write(i32out, 0, 4);
Mark Slee83c52a82006-06-07 06:51:18 +0000141 }
142
Mark Slee456b7a82006-10-25 20:53:37 +0000143 private byte[] i64out = new byte[8];
144 public void writeI64(long i64) throws TException {
Mark Slee530fd662006-08-09 00:05:18 +0000145 i64out[0] = (byte)(0xff & (i64 >> 56));
146 i64out[1] = (byte)(0xff & (i64 >> 48));
147 i64out[2] = (byte)(0xff & (i64 >> 40));
148 i64out[3] = (byte)(0xff & (i64 >> 32));
149 i64out[4] = (byte)(0xff & (i64 >> 24));
150 i64out[5] = (byte)(0xff & (i64 >> 16));
151 i64out[6] = (byte)(0xff & (i64 >> 8));
152 i64out[7] = (byte)(0xff & (i64));
Aditya Agarwal5a429582007-02-06 02:51:15 +0000153 trans_.write(i64out, 0, 8);
Mark Slee83c52a82006-06-07 06:51:18 +0000154 }
155
Mark Slee456b7a82006-10-25 20:53:37 +0000156 public void writeDouble(double dub) throws TException {
157 writeI64(Double.doubleToLongBits(dub));
Mark Sleec98d0502006-09-06 02:42:25 +0000158 }
159
Mark Slee456b7a82006-10-25 20:53:37 +0000160 public void writeString(String str) throws TException {
Mark Slee6eb58922007-11-07 00:48:47 +0000161 try {
162 byte[] dat = str.getBytes("UTF-8");
163 writeI32(dat.length);
164 trans_.write(dat, 0, dat.length);
165 } catch (UnsupportedEncodingException uex) {
166 throw new TException("JVM DOES NOT SUPPORT UTF-8");
167 }
Mark Slee83c52a82006-06-07 06:51:18 +0000168 }
169
Mark Slee8d725a22007-04-13 01:57:12 +0000170 public void writeBinary(byte[] bin) throws TException {
171 writeI32(bin.length);
172 trans_.write(bin, 0, bin.length);
173 }
174
Mark Slee83c52a82006-06-07 06:51:18 +0000175 /**
176 * Reading methods.
177 */
178
Mark Slee456b7a82006-10-25 20:53:37 +0000179 public TMessage readMessageBegin() throws TException {
Mark Slee78f58e22006-09-02 04:17:07 +0000180 TMessage message = new TMessage();
Mark Slee808454e2007-06-20 21:51:57 +0000181
182 int size = readI32();
183 if (size < 0) {
184 int version = size & VERSION_MASK;
185 if (version != VERSION_1) {
186 throw new TProtocolException(TProtocolException.BAD_VERSION, "Bad version in readMessageBegin");
187 }
David Reiss5ddd2f12007-12-17 09:49:10 +0000188 message.type = (byte)(size & 0x000000ff);
Mark Slee808454e2007-06-20 21:51:57 +0000189 message.name = readString();
190 message.seqid = readI32();
191 } else {
192 if (strictRead_) {
193 throw new TProtocolException(TProtocolException.BAD_VERSION, "Missing version in readMessageBegin, old client?");
194 }
195 message.name = readStringBody(size);
196 message.type = readByte();
197 message.seqid = readI32();
198 }
Mark Slee78f58e22006-09-02 04:17:07 +0000199 return message;
200 }
201
Mark Slee456b7a82006-10-25 20:53:37 +0000202 public void readMessageEnd() {}
Mark Slee78f58e22006-09-02 04:17:07 +0000203
Mark Slee456b7a82006-10-25 20:53:37 +0000204 public TStruct readStructBegin() {
Mark Slee530fd662006-08-09 00:05:18 +0000205 return new TStruct();
Mark Slee83c52a82006-06-07 06:51:18 +0000206 }
207
Mark Slee456b7a82006-10-25 20:53:37 +0000208 public void readStructEnd() {}
Mark Slee83c52a82006-06-07 06:51:18 +0000209
Mark Slee456b7a82006-10-25 20:53:37 +0000210 public TField readFieldBegin() throws TException {
Mark Slee530fd662006-08-09 00:05:18 +0000211 TField field = new TField();
Mark Slee456b7a82006-10-25 20:53:37 +0000212 field.type = readByte();
Mark Slee530fd662006-08-09 00:05:18 +0000213 if (field.type != TType.STOP) {
Mark Slee456b7a82006-10-25 20:53:37 +0000214 field.id = readI16();
Mark Slee83c52a82006-06-07 06:51:18 +0000215 }
Mark Slee530fd662006-08-09 00:05:18 +0000216 return field;
Mark Slee83c52a82006-06-07 06:51:18 +0000217 }
Mark Slee6eb58922007-11-07 00:48:47 +0000218
Mark Slee456b7a82006-10-25 20:53:37 +0000219 public void readFieldEnd() {}
Mark Slee6eb58922007-11-07 00:48:47 +0000220
Mark Slee456b7a82006-10-25 20:53:37 +0000221 public TMap readMapBegin() throws TException {
Mark Slee530fd662006-08-09 00:05:18 +0000222 TMap map = new TMap();
Mark Slee456b7a82006-10-25 20:53:37 +0000223 map.keyType = readByte();
224 map.valueType = readByte();
225 map.size = readI32();
Mark Slee530fd662006-08-09 00:05:18 +0000226 return map;
Mark Slee83c52a82006-06-07 06:51:18 +0000227 }
228
Mark Slee456b7a82006-10-25 20:53:37 +0000229 public void readMapEnd() {}
Mark Slee530fd662006-08-09 00:05:18 +0000230
Mark Slee456b7a82006-10-25 20:53:37 +0000231 public TList readListBegin() throws TException {
Mark Slee530fd662006-08-09 00:05:18 +0000232 TList list = new TList();
Mark Slee456b7a82006-10-25 20:53:37 +0000233 list.elemType = readByte();
234 list.size = readI32();
Mark Slee530fd662006-08-09 00:05:18 +0000235 return list;
Mark Slee83c52a82006-06-07 06:51:18 +0000236 }
237
Mark Slee456b7a82006-10-25 20:53:37 +0000238 public void readListEnd() {}
Mark Slee530fd662006-08-09 00:05:18 +0000239
Mark Slee456b7a82006-10-25 20:53:37 +0000240 public TSet readSetBegin() throws TException {
Mark Slee530fd662006-08-09 00:05:18 +0000241 TSet set = new TSet();
Mark Slee456b7a82006-10-25 20:53:37 +0000242 set.elemType = readByte();
243 set.size = readI32();
Mark Slee530fd662006-08-09 00:05:18 +0000244 return set;
Mark Slee83c52a82006-06-07 06:51:18 +0000245 }
246
Mark Slee456b7a82006-10-25 20:53:37 +0000247 public void readSetEnd() {}
Mark Slee530fd662006-08-09 00:05:18 +0000248
Mark Slee456b7a82006-10-25 20:53:37 +0000249 public boolean readBool() throws TException {
250 return (readByte() == 1);
Mark Slee78f58e22006-09-02 04:17:07 +0000251 }
252
Mark Slee456b7a82006-10-25 20:53:37 +0000253 private byte[] bin = new byte[1];
254 public byte readByte() throws TException {
David Reiss4a15eb72007-12-14 22:14:47 +0000255 readAll(bin, 0, 1);
Mark Slee530fd662006-08-09 00:05:18 +0000256 return bin[0];
Mark Slee83c52a82006-06-07 06:51:18 +0000257 }
258
Mark Slee456b7a82006-10-25 20:53:37 +0000259 private byte[] i16rd = new byte[2];
260 public short readI16() throws TException {
David Reiss4a15eb72007-12-14 22:14:47 +0000261 readAll(i16rd, 0, 2);
Mark Slee78f58e22006-09-02 04:17:07 +0000262 return
263 (short)
264 (((i16rd[0] & 0xff) << 8) |
265 ((i16rd[1] & 0xff)));
Mark Slee83c52a82006-06-07 06:51:18 +0000266 }
267
Mark Slee456b7a82006-10-25 20:53:37 +0000268 private byte[] i32rd = new byte[4];
269 public int readI32() throws TException {
David Reiss4a15eb72007-12-14 22:14:47 +0000270 readAll(i32rd, 0, 4);
Mark Slee530fd662006-08-09 00:05:18 +0000271 return
272 ((i32rd[0] & 0xff) << 24) |
273 ((i32rd[1] & 0xff) << 16) |
274 ((i32rd[2] & 0xff) << 8) |
275 ((i32rd[3] & 0xff));
Mark Slee83c52a82006-06-07 06:51:18 +0000276 }
Mark Slee6eb58922007-11-07 00:48:47 +0000277
Mark Slee456b7a82006-10-25 20:53:37 +0000278 private byte[] i64rd = new byte[8];
279 public long readI64() throws TException {
David Reiss4a15eb72007-12-14 22:14:47 +0000280 readAll(i64rd, 0, 8);
Mark Slee530fd662006-08-09 00:05:18 +0000281 return
282 ((long)(i64rd[0] & 0xff) << 56) |
283 ((long)(i64rd[1] & 0xff) << 48) |
284 ((long)(i64rd[2] & 0xff) << 40) |
285 ((long)(i64rd[3] & 0xff) << 32) |
286 ((long)(i64rd[4] & 0xff) << 24) |
287 ((long)(i64rd[5] & 0xff) << 16) |
288 ((long)(i64rd[6] & 0xff) << 8) |
289 ((long)(i64rd[7] & 0xff));
Mark Slee83c52a82006-06-07 06:51:18 +0000290 }
291
Mark Slee456b7a82006-10-25 20:53:37 +0000292 public double readDouble() throws TException {
293 return Double.longBitsToDouble(readI64());
Mark Sleec98d0502006-09-06 02:42:25 +0000294 }
295
Mark Slee456b7a82006-10-25 20:53:37 +0000296 public String readString() throws TException {
297 int size = readI32();
Mark Slee808454e2007-06-20 21:51:57 +0000298 return readStringBody(size);
299 }
300
301 public String readStringBody(int size) throws TException {
Mark Slee6eb58922007-11-07 00:48:47 +0000302 try {
David Reiss4a15eb72007-12-14 22:14:47 +0000303 checkReadLength(size);
Mark Slee6eb58922007-11-07 00:48:47 +0000304 byte[] buf = new byte[size];
305 trans_.readAll(buf, 0, size);
306 return new String(buf, "UTF-8");
307 } catch (UnsupportedEncodingException uex) {
308 throw new TException("JVM DOES NOT SUPPORT UTF-8");
309 }
Mark Slee83c52a82006-06-07 06:51:18 +0000310 }
Mark Slee8d725a22007-04-13 01:57:12 +0000311
312 public byte[] readBinary() throws TException {
313 int size = readI32();
David Reiss4a15eb72007-12-14 22:14:47 +0000314 checkReadLength(size);
Mark Slee8d725a22007-04-13 01:57:12 +0000315 byte[] buf = new byte[size];
316 trans_.readAll(buf, 0, size);
317 return buf;
318 }
319
David Reiss4a15eb72007-12-14 22:14:47 +0000320 private int readAll(byte[] buf, int off, int len) throws TException {
321 checkReadLength(len);
322 return trans_.readAll(buf, off, len);
323 }
324
325 public void setReadLength(int readLength) {
326 readLength_ = readLength;
327 checkReadLength_ = true;
328 }
329
330 protected void checkReadLength(int length) throws TException {
331 if (checkReadLength_) {
332 readLength_ -= length;
333 if (readLength_ < 0) {
334 throw new TException("Message length exceeded: " + length);
335 }
336 }
337 }
338
Mark Slee83c52a82006-06-07 06:51:18 +0000339}