blob: 2c94c0c546c0d151daa232a75fdaf206850041a6 [file] [log] [blame]
Henrique Mendoncabd5db3a2012-10-03 09:26:32 +00001/**
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 *
19 * Contains some contributions under the Thrift Software License.
20 * Please see doc/old-thrift-license.txt in the Thrift distribution for
21 * details.
Jens Geyerf509df92013-04-25 20:38:55 +020022 */
23
24using System;
25using System.Text;
26using Thrift.Transport;
27using System.Collections;
28using System.IO;
29using System.Collections.Generic;
30
31namespace Thrift.Protocol
32{
33 public class TCompactProtocol : TProtocol
34 {
35 private static TStruct ANONYMOUS_STRUCT = new TStruct("");
36 private static TField TSTOP = new TField("", TType.Stop, (short)0);
37
38 private static byte[] ttypeToCompactType = new byte[16];
39
40 private const byte PROTOCOL_ID = 0x82;
41 private const byte VERSION = 1;
42 private const byte VERSION_MASK = 0x1f; // 0001 1111
43 private const byte TYPE_MASK = 0xE0; // 1110 0000
44 private const int TYPE_SHIFT_AMOUNT = 5;
45
Henrique Mendoncabd5db3a2012-10-03 09:26:32 +000046 /**
47 * All of the on-wire type codes.
Jens Geyerf509df92013-04-25 20:38:55 +020048 */
49 private static class Types
50 {
51 public const byte STOP = 0x00;
52 public const byte BOOLEAN_TRUE = 0x01;
53 public const byte BOOLEAN_FALSE = 0x02;
54 public const byte BYTE = 0x03;
55 public const byte I16 = 0x04;
56 public const byte I32 = 0x05;
57 public const byte I64 = 0x06;
58 public const byte DOUBLE = 0x07;
59 public const byte BINARY = 0x08;
60 public const byte LIST = 0x09;
61 public const byte SET = 0x0A;
62 public const byte MAP = 0x0B;
63 public const byte STRUCT = 0x0C;
64 }
65
Henrique Mendoncabd5db3a2012-10-03 09:26:32 +000066 /**
67 * Used to keep track of the last field for the current and previous structs,
68 * so we can do the delta stuff.
Jens Geyerf509df92013-04-25 20:38:55 +020069 */
70 private Stack<short> lastField_ = new Stack<short>(15);
71
72 private short lastFieldId_ = 0;
73
Henrique Mendoncabd5db3a2012-10-03 09:26:32 +000074 /**
75 * If we encounter a boolean field begin, save the TField here so it can
76 * have the value incorporated.
Jens Geyerf509df92013-04-25 20:38:55 +020077 */
78 private Nullable<TField> booleanField_;
79
Henrique Mendoncabd5db3a2012-10-03 09:26:32 +000080 /**
81 * If we Read a field header, and it's a boolean field, save the boolean
82 * value here so that ReadBool can use it.
Jens Geyerf509df92013-04-25 20:38:55 +020083 */
84 private Nullable<Boolean> boolValue_;
85
86
87 #region CompactProtocol Factory
88
Henrique Mendoncabd5db3a2012-10-03 09:26:32 +000089 /**
90 * Factory
Jens Geyerf509df92013-04-25 20:38:55 +020091 */
92 public class Factory : TProtocolFactory
93 {
94 public Factory() { }
95
96 public TProtocol GetProtocol(TTransport trans)
97 {
98 return new TCompactProtocol(trans);
99 }
100 }
101
102 #endregion
103
104 public TCompactProtocol(TTransport trans)
105 : base(trans)
106 {
107 ttypeToCompactType[(int)TType.Stop] = Types.STOP;
108 ttypeToCompactType[(int)TType.Bool] = Types.BOOLEAN_TRUE;
109 ttypeToCompactType[(int)TType.Byte] = Types.BYTE;
110 ttypeToCompactType[(int)TType.I16] = Types.I16;
111 ttypeToCompactType[(int)TType.I32] = Types.I32;
112 ttypeToCompactType[(int)TType.I64] = Types.I64;
113 ttypeToCompactType[(int)TType.Double] = Types.DOUBLE;
114 ttypeToCompactType[(int)TType.String] = Types.BINARY;
115 ttypeToCompactType[(int)TType.List] = Types.LIST;
116 ttypeToCompactType[(int)TType.Set] = Types.SET;
117 ttypeToCompactType[(int)TType.Map] = Types.MAP;
118 ttypeToCompactType[(int)TType.Struct] = Types.STRUCT;
119 }
120
121 public void reset()
122 {
123 lastField_.Clear();
124 lastFieldId_ = 0;
125 }
126
127 #region Write Methods
128
129
Henrique Mendoncabd5db3a2012-10-03 09:26:32 +0000130 /**
131 * Writes a byte without any possibility of all that field header nonsense.
132 * Used internally by other writing methods that know they need to Write a byte.
Jens Geyerf509df92013-04-25 20:38:55 +0200133 */
134 private byte[] byteDirectBuffer = new byte[1];
135 private void WriteByteDirect(byte b)
136 {
137 byteDirectBuffer[0] = b;
138 trans.Write(byteDirectBuffer);
139 }
140
Henrique Mendoncabd5db3a2012-10-03 09:26:32 +0000141 /**
142 * Writes a byte without any possibility of all that field header nonsense.
Jens Geyerf509df92013-04-25 20:38:55 +0200143 */
144 private void WriteByteDirect(int n)
145 {
146 WriteByteDirect((byte)n);
147 }
148
Henrique Mendoncabd5db3a2012-10-03 09:26:32 +0000149 /**
150 * Write an i32 as a varint. Results in 1-5 bytes on the wire.
151 * TODO: make a permanent buffer like WriteVarint64?
Jens Geyerf509df92013-04-25 20:38:55 +0200152 */
153 byte[] i32buf = new byte[5];
154 private void WriteVarint32(uint n)
155 {
156 int idx = 0;
157 while (true)
158 {
159 if ((n & ~0x7F) == 0)
160 {
161 i32buf[idx++] = (byte)n;
162 // WriteByteDirect((byte)n);
163 break;
164 // return;
165 }
166 else
167 {
168 i32buf[idx++] = (byte)((n & 0x7F) | 0x80);
169 // WriteByteDirect((byte)((n & 0x7F) | 0x80));
170 n >>= 7;
171 }
172 }
173 trans.Write(i32buf, 0, idx);
174 }
175
Henrique Mendoncabd5db3a2012-10-03 09:26:32 +0000176 /**
177 * Write a message header to the wire. Compact Protocol messages contain the
178 * protocol version so we can migrate forwards in the future if need be.
Jens Geyerf509df92013-04-25 20:38:55 +0200179 */
180 public override void WriteMessageBegin(TMessage message)
181 {
182 WriteByteDirect(PROTOCOL_ID);
183 WriteByteDirect((byte)((VERSION & VERSION_MASK) | ((((uint)message.Type) << TYPE_SHIFT_AMOUNT) & TYPE_MASK)));
184 WriteVarint32((uint)message.SeqID);
185 WriteString(message.Name);
186 }
187
Henrique Mendoncabd5db3a2012-10-03 09:26:32 +0000188 /**
189 * Write a struct begin. This doesn't actually put anything on the wire. We
190 * use it as an opportunity to put special placeholder markers on the field
191 * stack so we can get the field id deltas correct.
Jens Geyerf509df92013-04-25 20:38:55 +0200192 */
193 public override void WriteStructBegin(TStruct strct)
194 {
195 lastField_.Push(lastFieldId_);
196 lastFieldId_ = 0;
197 }
198
Henrique Mendoncabd5db3a2012-10-03 09:26:32 +0000199 /**
200 * Write a struct end. This doesn't actually put anything on the wire. We use
201 * this as an opportunity to pop the last field from the current struct off
202 * of the field stack.
Jens Geyerf509df92013-04-25 20:38:55 +0200203 */
204 public override void WriteStructEnd()
205 {
206 lastFieldId_ = lastField_.Pop();
207 }
208
Henrique Mendoncabd5db3a2012-10-03 09:26:32 +0000209 /**
210 * Write a field header containing the field id and field type. If the
211 * difference between the current field id and the last one is small (< 15),
212 * then the field id will be encoded in the 4 MSB as a delta. Otherwise, the
213 * field id will follow the type header as a zigzag varint.
Jens Geyerf509df92013-04-25 20:38:55 +0200214 */
215 public override void WriteFieldBegin(TField field)
216 {
217 if (field.Type == TType.Bool)
218 {
219 // we want to possibly include the value, so we'll wait.
220 booleanField_ = field;
221 }
222 else
223 {
224 WriteFieldBeginInternal(field, 0xFF);
225 }
226 }
227
Henrique Mendoncabd5db3a2012-10-03 09:26:32 +0000228 /**
229 * The workhorse of WriteFieldBegin. It has the option of doing a
230 * 'type override' of the type header. This is used specifically in the
231 * boolean field case.
Jens Geyerf509df92013-04-25 20:38:55 +0200232 */
233 private void WriteFieldBeginInternal(TField field, byte typeOverride)
234 {
235 // short lastField = lastField_.Pop();
236
237 // if there's a type override, use that.
238 byte typeToWrite = typeOverride == 0xFF ? getCompactType(field.Type) : typeOverride;
239
240 // check if we can use delta encoding for the field id
241 if (field.ID > lastFieldId_ && field.ID - lastFieldId_ <= 15)
242 {
243 // Write them together
244 WriteByteDirect((field.ID - lastFieldId_) << 4 | typeToWrite);
245 }
246 else
247 {
248 // Write them separate
249 WriteByteDirect(typeToWrite);
250 WriteI16(field.ID);
251 }
252
253 lastFieldId_ = field.ID;
254 // lastField_.push(field.id);
255 }
256
Henrique Mendoncabd5db3a2012-10-03 09:26:32 +0000257 /**
258 * Write the STOP symbol so we know there are no more fields in this struct.
Jens Geyerf509df92013-04-25 20:38:55 +0200259 */
260 public override void WriteFieldStop()
261 {
262 WriteByteDirect(Types.STOP);
263 }
264
Henrique Mendoncabd5db3a2012-10-03 09:26:32 +0000265 /**
266 * Write a map header. If the map is empty, omit the key and value type
267 * headers, as we don't need any additional information to skip it.
Jens Geyerf509df92013-04-25 20:38:55 +0200268 */
269 public override void WriteMapBegin(TMap map)
270 {
271 if (map.Count == 0)
272 {
273 WriteByteDirect(0);
274 }
275 else
276 {
277 WriteVarint32((uint)map.Count);
278 WriteByteDirect(getCompactType(map.KeyType) << 4 | getCompactType(map.ValueType));
279 }
280 }
281
Henrique Mendoncabd5db3a2012-10-03 09:26:32 +0000282 /**
283 * Write a list header.
Jens Geyerf509df92013-04-25 20:38:55 +0200284 */
285 public override void WriteListBegin(TList list)
286 {
287 WriteCollectionBegin(list.ElementType, list.Count);
288 }
289
Henrique Mendoncabd5db3a2012-10-03 09:26:32 +0000290 /**
291 * Write a set header.
Jens Geyerf509df92013-04-25 20:38:55 +0200292 */
293 public override void WriteSetBegin(TSet set)
294 {
295 WriteCollectionBegin(set.ElementType, set.Count);
296 }
297
Henrique Mendoncabd5db3a2012-10-03 09:26:32 +0000298 /**
299 * Write a boolean value. Potentially, this could be a boolean field, in
300 * which case the field header info isn't written yet. If so, decide what the
301 * right type header is for the value and then Write the field header.
302 * Otherwise, Write a single byte.
Jens Geyerf509df92013-04-25 20:38:55 +0200303 */
304 public override void WriteBool(Boolean b)
305 {
306 if (booleanField_ != null)
307 {
308 // we haven't written the field header yet
309 WriteFieldBeginInternal(booleanField_.Value, b ? Types.BOOLEAN_TRUE : Types.BOOLEAN_FALSE);
310 booleanField_ = null;
311 }
312 else
313 {
314 // we're not part of a field, so just Write the value.
315 WriteByteDirect(b ? Types.BOOLEAN_TRUE : Types.BOOLEAN_FALSE);
316 }
317 }
318
Henrique Mendoncabd5db3a2012-10-03 09:26:32 +0000319 /**
320 * Write a byte. Nothing to see here!
Jens Geyerf509df92013-04-25 20:38:55 +0200321 */
322 public override void WriteByte(sbyte b)
323 {
324 WriteByteDirect((byte)b);
325 }
326
Henrique Mendoncabd5db3a2012-10-03 09:26:32 +0000327 /**
328 * Write an I16 as a zigzag varint.
Jens Geyerf509df92013-04-25 20:38:55 +0200329 */
330 public override void WriteI16(short i16)
331 {
332 WriteVarint32(intToZigZag(i16));
333 }
334
Henrique Mendoncabd5db3a2012-10-03 09:26:32 +0000335 /**
336 * Write an i32 as a zigzag varint.
Jens Geyerf509df92013-04-25 20:38:55 +0200337 */
338 public override void WriteI32(int i32)
339 {
340 WriteVarint32(intToZigZag(i32));
341 }
342
Henrique Mendoncabd5db3a2012-10-03 09:26:32 +0000343 /**
344 * Write an i64 as a zigzag varint.
Jens Geyerf509df92013-04-25 20:38:55 +0200345 */
346 public override void WriteI64(long i64)
347 {
348 WriteVarint64(longToZigzag(i64));
349 }
350
Henrique Mendoncabd5db3a2012-10-03 09:26:32 +0000351 /**
352 * Write a double to the wire as 8 bytes.
Jens Geyerf509df92013-04-25 20:38:55 +0200353 */
354 public override void WriteDouble(double dub)
355 {
356 byte[] data = new byte[] { 0, 0, 0, 0, 0, 0, 0, 0 };
357 fixedLongToBytes(BitConverter.DoubleToInt64Bits(dub), data, 0);
358 trans.Write(data);
359 }
360
Henrique Mendoncabd5db3a2012-10-03 09:26:32 +0000361 /**
362 * Write a string to the wire with a varint size preceding.
Jens Geyerf509df92013-04-25 20:38:55 +0200363 */
364 public override void WriteString(String str)
365 {
366 byte[] bytes = UTF8Encoding.UTF8.GetBytes(str);
367 WriteBinary(bytes, 0, bytes.Length);
368 }
369
Henrique Mendoncabd5db3a2012-10-03 09:26:32 +0000370 /**
371 * Write a byte array, using a varint for the size.
Jens Geyerf509df92013-04-25 20:38:55 +0200372 */
373 public override void WriteBinary(byte[] bin)
374 {
375 WriteBinary(bin, 0, bin.Length);
376 }
377
378 private void WriteBinary(byte[] buf, int offset, int length)
379 {
380 WriteVarint32((uint)length);
381 trans.Write(buf, offset, length);
382 }
383
384 //
385 // These methods are called by structs, but don't actually have any wire
386 // output or purpose.
387 //
388
389 public override void WriteMessageEnd() { }
390 public override void WriteMapEnd() { }
391 public override void WriteListEnd() { }
392 public override void WriteSetEnd() { }
393 public override void WriteFieldEnd() { }
394
395 //
396 // Internal writing methods
397 //
398
Henrique Mendoncabd5db3a2012-10-03 09:26:32 +0000399 /**
400 * Abstract method for writing the start of lists and sets. List and sets on
401 * the wire differ only by the type indicator.
Jens Geyerf509df92013-04-25 20:38:55 +0200402 */
403 protected void WriteCollectionBegin(TType elemType, int size)
404 {
405 if (size <= 14)
406 {
407 WriteByteDirect(size << 4 | getCompactType(elemType));
408 }
409 else
410 {
411 WriteByteDirect(0xf0 | getCompactType(elemType));
412 WriteVarint32((uint)size);
413 }
414 }
415
Henrique Mendoncabd5db3a2012-10-03 09:26:32 +0000416 /**
417 * Write an i64 as a varint. Results in 1-10 bytes on the wire.
Jens Geyerf509df92013-04-25 20:38:55 +0200418 */
419 byte[] varint64out = new byte[10];
420 private void WriteVarint64(ulong n)
421 {
422 int idx = 0;
423 while (true)
424 {
425 if ((n & ~(ulong)0x7FL) == 0)
426 {
427 varint64out[idx++] = (byte)n;
428 break;
429 }
430 else
431 {
432 varint64out[idx++] = ((byte)((n & 0x7F) | 0x80));
433 n >>= 7;
434 }
435 }
436 trans.Write(varint64out, 0, idx);
437 }
438
Henrique Mendoncabd5db3a2012-10-03 09:26:32 +0000439 /**
440 * Convert l into a zigzag long. This allows negative numbers to be
441 * represented compactly as a varint.
Jens Geyerf509df92013-04-25 20:38:55 +0200442 */
443 private ulong longToZigzag(long n)
444 {
Henrique Mendonçada7982e2013-05-31 18:20:42 +0200445 return (ulong)(n << 1) ^ (ulong)(n >> 63);
Jens Geyerf509df92013-04-25 20:38:55 +0200446 }
447
Henrique Mendoncabd5db3a2012-10-03 09:26:32 +0000448 /**
449 * Convert n into a zigzag int. This allows negative numbers to be
450 * represented compactly as a varint.
Jens Geyerf509df92013-04-25 20:38:55 +0200451 */
452 private uint intToZigZag(int n)
453 {
Henrique Mendonçada7982e2013-05-31 18:20:42 +0200454 return (uint)(n << 1) ^ (uint)(n >> 31);
Jens Geyerf509df92013-04-25 20:38:55 +0200455 }
456
Henrique Mendoncabd5db3a2012-10-03 09:26:32 +0000457 /**
458 * Convert a long into little-endian bytes in buf starting at off and going
459 * until off+7.
Jens Geyerf509df92013-04-25 20:38:55 +0200460 */
461 private void fixedLongToBytes(long n, byte[] buf, int off)
462 {
463 buf[off + 0] = (byte)(n & 0xff);
464 buf[off + 1] = (byte)((n >> 8) & 0xff);
465 buf[off + 2] = (byte)((n >> 16) & 0xff);
466 buf[off + 3] = (byte)((n >> 24) & 0xff);
467 buf[off + 4] = (byte)((n >> 32) & 0xff);
468 buf[off + 5] = (byte)((n >> 40) & 0xff);
469 buf[off + 6] = (byte)((n >> 48) & 0xff);
470 buf[off + 7] = (byte)((n >> 56) & 0xff);
471 }
472
473 #endregion
474
475 #region ReadMethods
476
Henrique Mendoncabd5db3a2012-10-03 09:26:32 +0000477 /**
478 * Read a message header.
Jens Geyerf509df92013-04-25 20:38:55 +0200479 */
480 public override TMessage ReadMessageBegin()
Jens Geyer1c99e702014-03-17 22:50:39 +0200481 {
Jens Geyerf509df92013-04-25 20:38:55 +0200482 byte protocolId = (byte)ReadByte();
483 if (protocolId != PROTOCOL_ID)
484 {
485 throw new TProtocolException("Expected protocol id " + PROTOCOL_ID.ToString("X") + " but got " + protocolId.ToString("X"));
Jens Geyer1c99e702014-03-17 22:50:39 +0200486 }
Jens Geyerf509df92013-04-25 20:38:55 +0200487 byte versionAndType = (byte)ReadByte();
488 byte version = (byte)(versionAndType & VERSION_MASK);
489 if (version != VERSION)
490 {
491 throw new TProtocolException("Expected version " + VERSION + " but got " + version);
492 }
493 byte type = (byte)((versionAndType >> TYPE_SHIFT_AMOUNT) & 0x03);
494 int seqid = (int)ReadVarint32();
495 String messageName = ReadString();
496 return new TMessage(messageName, (TMessageType)type, seqid);
497 }
498
Henrique Mendoncabd5db3a2012-10-03 09:26:32 +0000499 /**
500 * Read a struct begin. There's nothing on the wire for this, but it is our
501 * opportunity to push a new struct begin marker onto the field stack.
Jens Geyerf509df92013-04-25 20:38:55 +0200502 */
503 public override TStruct ReadStructBegin()
504 {
505 lastField_.Push(lastFieldId_);
506 lastFieldId_ = 0;
507 return ANONYMOUS_STRUCT;
508 }
509
Henrique Mendoncabd5db3a2012-10-03 09:26:32 +0000510 /**
511 * Doesn't actually consume any wire data, just removes the last field for
512 * this struct from the field stack.
Jens Geyerf509df92013-04-25 20:38:55 +0200513 */
514 public override void ReadStructEnd()
515 {
516 // consume the last field we Read off the wire.
517 lastFieldId_ = lastField_.Pop();
518 }
519
Henrique Mendoncabd5db3a2012-10-03 09:26:32 +0000520 /**
521 * Read a field header off the wire.
Jens Geyerf509df92013-04-25 20:38:55 +0200522 */
523 public override TField ReadFieldBegin()
Jens Geyer1c99e702014-03-17 22:50:39 +0200524 {
Jens Geyerf509df92013-04-25 20:38:55 +0200525 byte type = (byte)ReadByte();
526
527 // if it's a stop, then we can return immediately, as the struct is over.
528 if (type == Types.STOP)
529 {
530 return TSTOP;
531 }
532
533 short fieldId;
534
535 // mask off the 4 MSB of the type header. it could contain a field id delta.
536 short modifier = (short)((type & 0xf0) >> 4);
537 if (modifier == 0)
538 {
539 // not a delta. look ahead for the zigzag varint field id.
540 fieldId = ReadI16();
541 }
542 else
543 {
544 // has a delta. add the delta to the last Read field id.
545 fieldId = (short)(lastFieldId_ + modifier);
546 }
547
548 TField field = new TField("", getTType((byte)(type & 0x0f)), fieldId);
549
550 // if this happens to be a boolean field, the value is encoded in the type
551 if (isBoolType(type))
552 {
553 // save the boolean value in a special instance variable.
554 boolValue_ = (byte)(type & 0x0f) == Types.BOOLEAN_TRUE ? true : false;
555 }
556
557 // push the new field onto the field stack so we can keep the deltas going.
558 lastFieldId_ = field.ID;
559 return field;
560 }
561
Henrique Mendoncabd5db3a2012-10-03 09:26:32 +0000562 /**
563 * Read a map header off the wire. If the size is zero, skip Reading the key
564 * and value type. This means that 0-length maps will yield TMaps without the
565 * "correct" types.
Jens Geyerf509df92013-04-25 20:38:55 +0200566 */
567 public override TMap ReadMapBegin()
568 {
Jens Geyer1c99e702014-03-17 22:50:39 +0200569 int size = (int)ReadVarint32();
Jens Geyerf509df92013-04-25 20:38:55 +0200570 byte keyAndValueType = size == 0 ? (byte)0 : (byte)ReadByte();
571 return new TMap(getTType((byte)(keyAndValueType >> 4)), getTType((byte)(keyAndValueType & 0xf)), size);
572 }
573
Henrique Mendoncabd5db3a2012-10-03 09:26:32 +0000574 /**
575 * Read a list header off the wire. If the list size is 0-14, the size will
576 * be packed into the element type header. If it's a longer list, the 4 MSB
577 * of the element type header will be 0xF, and a varint will follow with the
578 * true size.
Jens Geyerf509df92013-04-25 20:38:55 +0200579 */
580 public override TList ReadListBegin()
Jens Geyer1c99e702014-03-17 22:50:39 +0200581 {
Jens Geyerf509df92013-04-25 20:38:55 +0200582 byte size_and_type = (byte)ReadByte();
583 int size = (size_and_type >> 4) & 0x0f;
584 if (size == 15)
585 {
586 size = (int)ReadVarint32();
587 }
588 TType type = getTType(size_and_type);
589 return new TList(type, size);
590 }
591
Henrique Mendoncabd5db3a2012-10-03 09:26:32 +0000592 /**
593 * Read a set header off the wire. If the set size is 0-14, the size will
594 * be packed into the element type header. If it's a longer set, the 4 MSB
595 * of the element type header will be 0xF, and a varint will follow with the
596 * true size.
Jens Geyerf509df92013-04-25 20:38:55 +0200597 */
598 public override TSet ReadSetBegin()
599 {
600 return new TSet(ReadListBegin());
601 }
602
Henrique Mendoncabd5db3a2012-10-03 09:26:32 +0000603 /**
604 * Read a boolean off the wire. If this is a boolean field, the value should
605 * already have been Read during ReadFieldBegin, so we'll just consume the
606 * pre-stored value. Otherwise, Read a byte.
Jens Geyerf509df92013-04-25 20:38:55 +0200607 */
608 public override Boolean ReadBool()
609 {
610 if (boolValue_ != null)
611 {
612 bool result = boolValue_.Value;
613 boolValue_ = null;
614 return result;
615 }
616 return ReadByte() == Types.BOOLEAN_TRUE;
617 }
618
619 byte[] byteRawBuf = new byte[1];
Henrique Mendoncabd5db3a2012-10-03 09:26:32 +0000620 /**
621 * Read a single byte off the wire. Nothing interesting here.
Jens Geyerf509df92013-04-25 20:38:55 +0200622 */
623 public override sbyte ReadByte()
624 {
625 trans.ReadAll(byteRawBuf, 0, 1);
626 return (sbyte)byteRawBuf[0];
627 }
628
Henrique Mendoncabd5db3a2012-10-03 09:26:32 +0000629 /**
630 * Read an i16 from the wire as a zigzag varint.
Jens Geyerf509df92013-04-25 20:38:55 +0200631 */
632 public override short ReadI16()
633 {
634 return (short)zigzagToInt(ReadVarint32());
635 }
636
Henrique Mendoncabd5db3a2012-10-03 09:26:32 +0000637 /**
638 * Read an i32 from the wire as a zigzag varint.
Jens Geyerf509df92013-04-25 20:38:55 +0200639 */
640 public override int ReadI32()
641 {
642 return zigzagToInt(ReadVarint32());
643 }
644
Henrique Mendoncabd5db3a2012-10-03 09:26:32 +0000645 /**
646 * Read an i64 from the wire as a zigzag varint.
Jens Geyerf509df92013-04-25 20:38:55 +0200647 */
648 public override long ReadI64()
649 {
650 return zigzagToLong(ReadVarint64());
651 }
652
Henrique Mendoncabd5db3a2012-10-03 09:26:32 +0000653 /**
654 * No magic here - just Read a double off the wire.
Jens Geyerf509df92013-04-25 20:38:55 +0200655 */
656 public override double ReadDouble()
657 {
658 byte[] longBits = new byte[8];
659 trans.ReadAll(longBits, 0, 8);
660 return BitConverter.Int64BitsToDouble(bytesToLong(longBits));
661 }
662
Henrique Mendoncabd5db3a2012-10-03 09:26:32 +0000663 /**
664 * Reads a byte[] (via ReadBinary), and then UTF-8 decodes it.
Jens Geyerf509df92013-04-25 20:38:55 +0200665 */
666 public override String ReadString()
667 {
668 int length = (int)ReadVarint32();
669
670 if (length == 0)
671 {
672 return "";
673 }
674
675 return Encoding.UTF8.GetString(ReadBinary(length));
676 }
677
Henrique Mendoncabd5db3a2012-10-03 09:26:32 +0000678 /**
679 * Read a byte[] from the wire.
Jens Geyerf509df92013-04-25 20:38:55 +0200680 */
681 public override byte[] ReadBinary()
682 {
683 int length = (int)ReadVarint32();
684 if (length == 0) return new byte[0];
685
686 byte[] buf = new byte[length];
687 trans.ReadAll(buf, 0, length);
688 return buf;
689 }
690
Henrique Mendoncabd5db3a2012-10-03 09:26:32 +0000691 /**
692 * Read a byte[] of a known length from the wire.
Jens Geyerf509df92013-04-25 20:38:55 +0200693 */
694 private byte[] ReadBinary(int length)
695 {
696 if (length == 0) return new byte[0];
697
698 byte[] buf = new byte[length];
699 trans.ReadAll(buf, 0, length);
700 return buf;
701 }
702
703 //
704 // These methods are here for the struct to call, but don't have any wire
705 // encoding.
706 //
707 public override void ReadMessageEnd() { }
708 public override void ReadFieldEnd() { }
709 public override void ReadMapEnd() { }
710 public override void ReadListEnd() { }
711 public override void ReadSetEnd() { }
712
713 //
714 // Internal Reading methods
715 //
716
Henrique Mendoncabd5db3a2012-10-03 09:26:32 +0000717 /**
718 * Read an i32 from the wire as a varint. The MSB of each byte is set
719 * if there is another byte to follow. This can Read up to 5 bytes.
Jens Geyerf509df92013-04-25 20:38:55 +0200720 */
721 private uint ReadVarint32()
722 {
723 uint result = 0;
724 int shift = 0;
725 while (true)
Jens Geyer1c99e702014-03-17 22:50:39 +0200726 {
Jens Geyerf509df92013-04-25 20:38:55 +0200727 byte b = (byte)ReadByte();
728 result |= (uint)(b & 0x7f) << shift;
729 if ((b & 0x80) != 0x80) break;
730 shift += 7;
731 }
732 return result;
733 }
734
Henrique Mendoncabd5db3a2012-10-03 09:26:32 +0000735 /**
736 * Read an i64 from the wire as a proper varint. The MSB of each byte is set
737 * if there is another byte to follow. This can Read up to 10 bytes.
Jens Geyerf509df92013-04-25 20:38:55 +0200738 */
739 private ulong ReadVarint64()
740 {
741 int shift = 0;
742 ulong result = 0;
743 while (true)
Jens Geyer1c99e702014-03-17 22:50:39 +0200744 {
Jens Geyerf509df92013-04-25 20:38:55 +0200745 byte b = (byte)ReadByte();
746 result |= (ulong)(b & 0x7f) << shift;
747 if ((b & 0x80) != 0x80) break;
748 shift += 7;
Henrique Mendoncabd5db3a2012-10-03 09:26:32 +0000749 }
Jens Geyerf509df92013-04-25 20:38:55 +0200750
751 return result;
752 }
753
754 #endregion
755
756 //
757 // encoding helpers
758 //
759
Henrique Mendoncabd5db3a2012-10-03 09:26:32 +0000760 /**
761 * Convert from zigzag int to int.
Jens Geyerf509df92013-04-25 20:38:55 +0200762 */
763 private int zigzagToInt(uint n)
764 {
765 return (int)(n >> 1) ^ (-(int)(n & 1));
766 }
767
Henrique Mendoncabd5db3a2012-10-03 09:26:32 +0000768 /**
769 * Convert from zigzag long to long.
Jens Geyerf509df92013-04-25 20:38:55 +0200770 */
771 private long zigzagToLong(ulong n)
772 {
773 return (long)(n >> 1) ^ (-(long)(n & 1));
774 }
775
Henrique Mendoncabd5db3a2012-10-03 09:26:32 +0000776 /**
777 * Note that it's important that the mask bytes are long literals,
778 * otherwise they'll default to ints, and when you shift an int left 56 bits,
779 * you just get a messed up int.
Jens Geyerf509df92013-04-25 20:38:55 +0200780 */
781 private long bytesToLong(byte[] bytes)
782 {
783 return
784 ((bytes[7] & 0xffL) << 56) |
785 ((bytes[6] & 0xffL) << 48) |
786 ((bytes[5] & 0xffL) << 40) |
787 ((bytes[4] & 0xffL) << 32) |
788 ((bytes[3] & 0xffL) << 24) |
789 ((bytes[2] & 0xffL) << 16) |
790 ((bytes[1] & 0xffL) << 8) |
791 ((bytes[0] & 0xffL));
792 }
793
794 //
795 // type testing and converting
796 //
797
798 private Boolean isBoolType(byte b)
799 {
800 int lowerNibble = b & 0x0f;
801 return lowerNibble == Types.BOOLEAN_TRUE || lowerNibble == Types.BOOLEAN_FALSE;
802 }
803
Henrique Mendoncabd5db3a2012-10-03 09:26:32 +0000804 /**
805 * Given a TCompactProtocol.Types constant, convert it to its corresponding
806 * TType value.
Jens Geyerf509df92013-04-25 20:38:55 +0200807 */
808 private TType getTType(byte type)
809 {
810 switch ((byte)(type & 0x0f))
811 {
812 case Types.STOP:
813 return TType.Stop;
814 case Types.BOOLEAN_FALSE:
815 case Types.BOOLEAN_TRUE:
816 return TType.Bool;
817 case Types.BYTE:
818 return TType.Byte;
819 case Types.I16:
820 return TType.I16;
821 case Types.I32:
822 return TType.I32;
823 case Types.I64:
824 return TType.I64;
825 case Types.DOUBLE:
826 return TType.Double;
827 case Types.BINARY:
828 return TType.String;
829 case Types.LIST:
830 return TType.List;
831 case Types.SET:
832 return TType.Set;
833 case Types.MAP:
834 return TType.Map;
835 case Types.STRUCT:
836 return TType.Struct;
837 default:
838 throw new TProtocolException("don't know what type: " + (byte)(type & 0x0f));
839 }
840 }
841
Henrique Mendoncabd5db3a2012-10-03 09:26:32 +0000842 /**
843 * Given a TType value, find the appropriate TCompactProtocol.Types constant.
Jens Geyerf509df92013-04-25 20:38:55 +0200844 */
845 private byte getCompactType(TType ttype)
846 {
847 return ttypeToCompactType[(int)ttype];
848 }
849 }
Henrique Mendoncabd5db3a2012-10-03 09:26:32 +0000850}