]>
Commit | Line | Data |
---|---|---|
f67539c2 TL |
1 | /** |
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. | |
22 | */ | |
23 | ||
24 | using System; | |
25 | using System.Text; | |
26 | using Thrift.Transport; | |
27 | using System.Collections; | |
28 | using System.IO; | |
29 | using System.Collections.Generic; | |
30 | ||
31 | namespace 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 byte TYPE_BITS = 0x07; // 0000 0111 | |
45 | private const int TYPE_SHIFT_AMOUNT = 5; | |
46 | ||
47 | /// <summary> | |
48 | /// All of the on-wire type codes. | |
49 | /// </summary> | |
50 | private static class Types | |
51 | { | |
52 | public const byte STOP = 0x00; | |
53 | public const byte BOOLEAN_TRUE = 0x01; | |
54 | public const byte BOOLEAN_FALSE = 0x02; | |
55 | public const byte BYTE = 0x03; | |
56 | public const byte I16 = 0x04; | |
57 | public const byte I32 = 0x05; | |
58 | public const byte I64 = 0x06; | |
59 | public const byte DOUBLE = 0x07; | |
60 | public const byte BINARY = 0x08; | |
61 | public const byte LIST = 0x09; | |
62 | public const byte SET = 0x0A; | |
63 | public const byte MAP = 0x0B; | |
64 | public const byte STRUCT = 0x0C; | |
65 | } | |
66 | ||
67 | /// <summary> | |
68 | /// Used to keep track of the last field for the current and previous structs, | |
69 | /// so we can do the delta stuff. | |
70 | /// </summary> | |
71 | private Stack<short> lastField_ = new Stack<short>(15); | |
72 | ||
73 | private short lastFieldId_ = 0; | |
74 | ||
75 | /// <summary> | |
76 | /// If we encounter a boolean field begin, save the TField here so it can | |
77 | /// have the value incorporated. | |
78 | /// </summary> | |
79 | private Nullable<TField> booleanField_; | |
80 | ||
81 | /// <summary> | |
82 | /// If we Read a field header, and it's a boolean field, save the boolean | |
83 | /// value here so that ReadBool can use it. | |
84 | /// </summary> | |
85 | private Nullable<Boolean> boolValue_; | |
86 | ||
87 | ||
88 | #region CompactProtocol Factory | |
89 | ||
90 | public class Factory : TProtocolFactory | |
91 | { | |
92 | public Factory() { } | |
93 | ||
94 | public TProtocol GetProtocol(TTransport trans) | |
95 | { | |
96 | return new TCompactProtocol(trans); | |
97 | } | |
98 | } | |
99 | ||
100 | #endregion | |
101 | ||
102 | public TCompactProtocol(TTransport trans) | |
103 | : base(trans) | |
104 | { | |
105 | ttypeToCompactType[(int)TType.Stop] = Types.STOP; | |
106 | ttypeToCompactType[(int)TType.Bool] = Types.BOOLEAN_TRUE; | |
107 | ttypeToCompactType[(int)TType.Byte] = Types.BYTE; | |
108 | ttypeToCompactType[(int)TType.I16] = Types.I16; | |
109 | ttypeToCompactType[(int)TType.I32] = Types.I32; | |
110 | ttypeToCompactType[(int)TType.I64] = Types.I64; | |
111 | ttypeToCompactType[(int)TType.Double] = Types.DOUBLE; | |
112 | ttypeToCompactType[(int)TType.String] = Types.BINARY; | |
113 | ttypeToCompactType[(int)TType.List] = Types.LIST; | |
114 | ttypeToCompactType[(int)TType.Set] = Types.SET; | |
115 | ttypeToCompactType[(int)TType.Map] = Types.MAP; | |
116 | ttypeToCompactType[(int)TType.Struct] = Types.STRUCT; | |
117 | } | |
118 | ||
119 | public void reset() | |
120 | { | |
121 | lastField_.Clear(); | |
122 | lastFieldId_ = 0; | |
123 | } | |
124 | ||
125 | #region Write Methods | |
126 | ||
127 | /// <summary> | |
128 | /// Writes a byte without any possibility of all that field header nonsense. | |
129 | /// Used internally by other writing methods that know they need to Write a byte. | |
130 | /// </summary> | |
131 | private byte[] byteDirectBuffer = new byte[1]; | |
132 | ||
133 | private void WriteByteDirect(byte b) | |
134 | { | |
135 | byteDirectBuffer[0] = b; | |
136 | trans.Write(byteDirectBuffer); | |
137 | } | |
138 | ||
139 | /// <summary> | |
140 | /// Writes a byte without any possibility of all that field header nonsense. | |
141 | /// </summary> | |
142 | private void WriteByteDirect(int n) | |
143 | { | |
144 | WriteByteDirect((byte)n); | |
145 | } | |
146 | ||
147 | /// <summary> | |
148 | /// Write an i32 as a varint. Results in 1-5 bytes on the wire. | |
149 | /// TODO: make a permanent buffer like WriteVarint64? | |
150 | /// </summary> | |
151 | byte[] i32buf = new byte[5]; | |
152 | ||
153 | private void WriteVarint32(uint n) | |
154 | { | |
155 | int idx = 0; | |
156 | while (true) | |
157 | { | |
158 | if ((n & ~0x7F) == 0) | |
159 | { | |
160 | i32buf[idx++] = (byte)n; | |
161 | // WriteByteDirect((byte)n); | |
162 | break; | |
163 | // return; | |
164 | } | |
165 | else | |
166 | { | |
167 | i32buf[idx++] = (byte)((n & 0x7F) | 0x80); | |
168 | // WriteByteDirect((byte)((n & 0x7F) | 0x80)); | |
169 | n >>= 7; | |
170 | } | |
171 | } | |
172 | trans.Write(i32buf, 0, idx); | |
173 | } | |
174 | ||
175 | /// <summary> | |
176 | /// Write a message header to the wire. Compact Protocol messages contain the | |
177 | /// protocol version so we can migrate forwards in the future if need be. | |
178 | /// </summary> | |
179 | public override void WriteMessageBegin(TMessage message) | |
180 | { | |
181 | WriteByteDirect(PROTOCOL_ID); | |
182 | WriteByteDirect((byte)((VERSION & VERSION_MASK) | ((((uint)message.Type) << TYPE_SHIFT_AMOUNT) & TYPE_MASK))); | |
183 | WriteVarint32((uint)message.SeqID); | |
184 | WriteString(message.Name); | |
185 | } | |
186 | ||
187 | /// <summary> | |
188 | /// Write a struct begin. This doesn't actually put anything on the wire. We | |
189 | /// use it as an opportunity to put special placeholder markers on the field | |
190 | /// stack so we can get the field id deltas correct. | |
191 | /// </summary> | |
192 | public override void WriteStructBegin(TStruct strct) | |
193 | { | |
194 | lastField_.Push(lastFieldId_); | |
195 | lastFieldId_ = 0; | |
196 | } | |
197 | ||
198 | /// <summary> | |
199 | /// Write a struct end. This doesn't actually put anything on the wire. We use | |
200 | /// this as an opportunity to pop the last field from the current struct off | |
201 | /// of the field stack. | |
202 | /// </summary> | |
203 | public override void WriteStructEnd() | |
204 | { | |
205 | lastFieldId_ = lastField_.Pop(); | |
206 | } | |
207 | ||
208 | /// <summary> | |
209 | /// Write a field header containing the field id and field type. If the | |
210 | /// difference between the current field id and the last one is small (< 15), | |
211 | /// then the field id will be encoded in the 4 MSB as a delta. Otherwise, the | |
212 | /// field id will follow the type header as a zigzag varint. | |
213 | /// </summary> | |
214 | public override void WriteFieldBegin(TField field) | |
215 | { | |
216 | if (field.Type == TType.Bool) | |
217 | { | |
218 | // we want to possibly include the value, so we'll wait. | |
219 | booleanField_ = field; | |
220 | } | |
221 | else | |
222 | { | |
223 | WriteFieldBeginInternal(field, 0xFF); | |
224 | } | |
225 | } | |
226 | ||
227 | /// <summary> | |
228 | /// The workhorse of WriteFieldBegin. It has the option of doing a | |
229 | /// 'type override' of the type header. This is used specifically in the | |
230 | /// boolean field case. | |
231 | /// </summary> | |
232 | private void WriteFieldBeginInternal(TField field, byte typeOverride) | |
233 | { | |
234 | // short lastField = lastField_.Pop(); | |
235 | ||
236 | // if there's a type override, use that. | |
237 | byte typeToWrite = typeOverride == 0xFF ? getCompactType(field.Type) : typeOverride; | |
238 | ||
239 | // check if we can use delta encoding for the field id | |
240 | if (field.ID > lastFieldId_ && field.ID - lastFieldId_ <= 15) | |
241 | { | |
242 | // Write them together | |
243 | WriteByteDirect((field.ID - lastFieldId_) << 4 | typeToWrite); | |
244 | } | |
245 | else | |
246 | { | |
247 | // Write them separate | |
248 | WriteByteDirect(typeToWrite); | |
249 | WriteI16(field.ID); | |
250 | } | |
251 | ||
252 | lastFieldId_ = field.ID; | |
253 | // lastField_.push(field.id); | |
254 | } | |
255 | ||
256 | /// <summary> | |
257 | /// Write the STOP symbol so we know there are no more fields in this struct. | |
258 | /// </summary> | |
259 | public override void WriteFieldStop() | |
260 | { | |
261 | WriteByteDirect(Types.STOP); | |
262 | } | |
263 | ||
264 | /// <summary> | |
265 | /// Write a map header. If the map is empty, omit the key and value type | |
266 | /// headers, as we don't need any additional information to skip it. | |
267 | /// </summary> | |
268 | public override void WriteMapBegin(TMap map) | |
269 | { | |
270 | if (map.Count == 0) | |
271 | { | |
272 | WriteByteDirect(0); | |
273 | } | |
274 | else | |
275 | { | |
276 | WriteVarint32((uint)map.Count); | |
277 | WriteByteDirect(getCompactType(map.KeyType) << 4 | getCompactType(map.ValueType)); | |
278 | } | |
279 | } | |
280 | ||
281 | /// <summary> | |
282 | /// Write a list header. | |
283 | /// </summary> | |
284 | public override void WriteListBegin(TList list) | |
285 | { | |
286 | WriteCollectionBegin(list.ElementType, list.Count); | |
287 | } | |
288 | ||
289 | /// <summary> | |
290 | /// Write a set header. | |
291 | /// </summary> | |
292 | public override void WriteSetBegin(TSet set) | |
293 | { | |
294 | WriteCollectionBegin(set.ElementType, set.Count); | |
295 | } | |
296 | ||
297 | /// <summary> | |
298 | /// Write a boolean value. Potentially, this could be a boolean field, in | |
299 | /// which case the field header info isn't written yet. If so, decide what the | |
300 | /// right type header is for the value and then Write the field header. | |
301 | /// Otherwise, Write a single byte. | |
302 | /// </summary> | |
303 | public override void WriteBool(Boolean b) | |
304 | { | |
305 | if (booleanField_ != null) | |
306 | { | |
307 | // we haven't written the field header yet | |
308 | WriteFieldBeginInternal(booleanField_.Value, b ? Types.BOOLEAN_TRUE : Types.BOOLEAN_FALSE); | |
309 | booleanField_ = null; | |
310 | } | |
311 | else | |
312 | { | |
313 | // we're not part of a field, so just Write the value. | |
314 | WriteByteDirect(b ? Types.BOOLEAN_TRUE : Types.BOOLEAN_FALSE); | |
315 | } | |
316 | } | |
317 | ||
318 | /// <summary> | |
319 | /// Write a byte. Nothing to see here! | |
320 | /// </summary> | |
321 | public override void WriteByte(sbyte b) | |
322 | { | |
323 | WriteByteDirect((byte)b); | |
324 | } | |
325 | ||
326 | /// <summary> | |
327 | /// Write an I16 as a zigzag varint. | |
328 | /// </summary> | |
329 | public override void WriteI16(short i16) | |
330 | { | |
331 | WriteVarint32(intToZigZag(i16)); | |
332 | } | |
333 | ||
334 | /// <summary> | |
335 | /// Write an i32 as a zigzag varint. | |
336 | /// </summary> | |
337 | public override void WriteI32(int i32) | |
338 | { | |
339 | WriteVarint32(intToZigZag(i32)); | |
340 | } | |
341 | ||
342 | /// <summary> | |
343 | /// Write an i64 as a zigzag varint. | |
344 | /// </summary> | |
345 | public override void WriteI64(long i64) | |
346 | { | |
347 | WriteVarint64(longToZigzag(i64)); | |
348 | } | |
349 | ||
350 | /// <summary> | |
351 | /// Write a double to the wire as 8 bytes. | |
352 | /// </summary> | |
353 | public override void WriteDouble(double dub) | |
354 | { | |
355 | byte[] data = new byte[] { 0, 0, 0, 0, 0, 0, 0, 0 }; | |
356 | fixedLongToBytes(BitConverter.DoubleToInt64Bits(dub), data, 0); | |
357 | trans.Write(data); | |
358 | } | |
359 | ||
360 | /// <summary> | |
361 | /// Write a string to the wire with a varint size preceding. | |
362 | /// </summary> | |
363 | public override void WriteString(string str) | |
364 | { | |
365 | byte[] bytes = UTF8Encoding.UTF8.GetBytes(str); | |
366 | WriteBinary(bytes, 0, bytes.Length); | |
367 | } | |
368 | ||
369 | /// <summary> | |
370 | /// Write a byte array, using a varint for the size. | |
371 | /// </summary> | |
372 | public override void WriteBinary(byte[] bin) | |
373 | { | |
374 | WriteBinary(bin, 0, bin.Length); | |
375 | } | |
376 | ||
377 | private void WriteBinary(byte[] buf, int offset, int length) | |
378 | { | |
379 | WriteVarint32((uint)length); | |
380 | trans.Write(buf, offset, length); | |
381 | } | |
382 | ||
383 | // | |
384 | // These methods are called by structs, but don't actually have any wire | |
385 | // output or purpose. | |
386 | // | |
387 | ||
388 | public override void WriteMessageEnd() { } | |
389 | public override void WriteMapEnd() { } | |
390 | public override void WriteListEnd() { } | |
391 | public override void WriteSetEnd() { } | |
392 | public override void WriteFieldEnd() { } | |
393 | ||
394 | // | |
395 | // Internal writing methods | |
396 | // | |
397 | ||
398 | /// <summary> | |
399 | /// Abstract method for writing the start of lists and sets. List and sets on | |
400 | /// the wire differ only by the type indicator. | |
401 | /// </summary> | |
402 | protected void WriteCollectionBegin(TType elemType, int size) | |
403 | { | |
404 | if (size <= 14) | |
405 | { | |
406 | WriteByteDirect(size << 4 | getCompactType(elemType)); | |
407 | } | |
408 | else | |
409 | { | |
410 | WriteByteDirect(0xf0 | getCompactType(elemType)); | |
411 | WriteVarint32((uint)size); | |
412 | } | |
413 | } | |
414 | ||
415 | /// <summary> | |
416 | /// Write an i64 as a varint. Results in 1-10 bytes on the wire. | |
417 | /// </summary> | |
418 | byte[] varint64out = new byte[10]; | |
419 | private void WriteVarint64(ulong n) | |
420 | { | |
421 | int idx = 0; | |
422 | while (true) | |
423 | { | |
424 | if ((n & ~(ulong)0x7FL) == 0) | |
425 | { | |
426 | varint64out[idx++] = (byte)n; | |
427 | break; | |
428 | } | |
429 | else | |
430 | { | |
431 | varint64out[idx++] = ((byte)((n & 0x7F) | 0x80)); | |
432 | n >>= 7; | |
433 | } | |
434 | } | |
435 | trans.Write(varint64out, 0, idx); | |
436 | } | |
437 | ||
438 | /// <summary> | |
439 | /// Convert l into a zigzag long. This allows negative numbers to be | |
440 | /// represented compactly as a varint. | |
441 | /// </summary> | |
442 | private ulong longToZigzag(long n) | |
443 | { | |
444 | return (ulong)(n << 1) ^ (ulong)(n >> 63); | |
445 | } | |
446 | ||
447 | /// <summary> | |
448 | /// Convert n into a zigzag int. This allows negative numbers to be | |
449 | /// represented compactly as a varint. | |
450 | /// </summary> | |
451 | private uint intToZigZag(int n) | |
452 | { | |
453 | return (uint)(n << 1) ^ (uint)(n >> 31); | |
454 | } | |
455 | ||
456 | /// <summary> | |
457 | /// Convert a long into little-endian bytes in buf starting at off and going | |
458 | /// until off+7. | |
459 | /// </summary> | |
460 | private void fixedLongToBytes(long n, byte[] buf, int off) | |
461 | { | |
462 | buf[off + 0] = (byte)(n & 0xff); | |
463 | buf[off + 1] = (byte)((n >> 8) & 0xff); | |
464 | buf[off + 2] = (byte)((n >> 16) & 0xff); | |
465 | buf[off + 3] = (byte)((n >> 24) & 0xff); | |
466 | buf[off + 4] = (byte)((n >> 32) & 0xff); | |
467 | buf[off + 5] = (byte)((n >> 40) & 0xff); | |
468 | buf[off + 6] = (byte)((n >> 48) & 0xff); | |
469 | buf[off + 7] = (byte)((n >> 56) & 0xff); | |
470 | } | |
471 | ||
472 | #endregion | |
473 | ||
474 | #region ReadMethods | |
475 | ||
476 | /// <summary> | |
477 | /// Read a message header. | |
478 | /// </summary> | |
479 | public override TMessage ReadMessageBegin() | |
480 | { | |
481 | byte protocolId = (byte)ReadByte(); | |
482 | if (protocolId != PROTOCOL_ID) | |
483 | { | |
484 | throw new TProtocolException("Expected protocol id " + PROTOCOL_ID.ToString("X") + " but got " + protocolId.ToString("X")); | |
485 | } | |
486 | byte versionAndType = (byte)ReadByte(); | |
487 | byte version = (byte)(versionAndType & VERSION_MASK); | |
488 | if (version != VERSION) | |
489 | { | |
490 | throw new TProtocolException("Expected version " + VERSION + " but got " + version); | |
491 | } | |
492 | byte type = (byte)((versionAndType >> TYPE_SHIFT_AMOUNT) & TYPE_BITS); | |
493 | int seqid = (int)ReadVarint32(); | |
494 | string messageName = ReadString(); | |
495 | return new TMessage(messageName, (TMessageType)type, seqid); | |
496 | } | |
497 | ||
498 | /// <summary> | |
499 | /// Read a struct begin. There's nothing on the wire for this, but it is our | |
500 | /// opportunity to push a new struct begin marker onto the field stack. | |
501 | /// </summary> | |
502 | public override TStruct ReadStructBegin() | |
503 | { | |
504 | lastField_.Push(lastFieldId_); | |
505 | lastFieldId_ = 0; | |
506 | return ANONYMOUS_STRUCT; | |
507 | } | |
508 | ||
509 | /// <summary> | |
510 | /// Doesn't actually consume any wire data, just removes the last field for | |
511 | /// this struct from the field stack. | |
512 | /// </summary> | |
513 | public override void ReadStructEnd() | |
514 | { | |
515 | // consume the last field we Read off the wire. | |
516 | lastFieldId_ = lastField_.Pop(); | |
517 | } | |
518 | ||
519 | /// <summary> | |
520 | /// Read a field header off the wire. | |
521 | /// </summary> | |
522 | public override TField ReadFieldBegin() | |
523 | { | |
524 | byte type = (byte)ReadByte(); | |
525 | ||
526 | // if it's a stop, then we can return immediately, as the struct is over. | |
527 | if (type == Types.STOP) | |
528 | { | |
529 | return TSTOP; | |
530 | } | |
531 | ||
532 | short fieldId; | |
533 | ||
534 | // mask off the 4 MSB of the type header. it could contain a field id delta. | |
535 | short modifier = (short)((type & 0xf0) >> 4); | |
536 | if (modifier == 0) | |
537 | { | |
538 | // not a delta. look ahead for the zigzag varint field id. | |
539 | fieldId = ReadI16(); | |
540 | } | |
541 | else | |
542 | { | |
543 | // has a delta. add the delta to the last Read field id. | |
544 | fieldId = (short)(lastFieldId_ + modifier); | |
545 | } | |
546 | ||
547 | TField field = new TField("", getTType((byte)(type & 0x0f)), fieldId); | |
548 | ||
549 | // if this happens to be a boolean field, the value is encoded in the type | |
550 | if (isBoolType(type)) | |
551 | { | |
552 | // save the boolean value in a special instance variable. | |
553 | boolValue_ = (byte)(type & 0x0f) == Types.BOOLEAN_TRUE ? true : false; | |
554 | } | |
555 | ||
556 | // push the new field onto the field stack so we can keep the deltas going. | |
557 | lastFieldId_ = field.ID; | |
558 | return field; | |
559 | } | |
560 | ||
561 | /// <summary> | |
562 | /// Read a map header off the wire. If the size is zero, skip Reading the key | |
563 | /// and value type. This means that 0-length maps will yield TMaps without the | |
564 | /// "correct" types. | |
565 | /// </summary> | |
566 | public override TMap ReadMapBegin() | |
567 | { | |
568 | int size = (int)ReadVarint32(); | |
569 | byte keyAndValueType = size == 0 ? (byte)0 : (byte)ReadByte(); | |
570 | return new TMap(getTType((byte)(keyAndValueType >> 4)), getTType((byte)(keyAndValueType & 0xf)), size); | |
571 | } | |
572 | ||
573 | /// <summary> | |
574 | /// Read a list header off the wire. If the list size is 0-14, the size will | |
575 | /// be packed into the element type header. If it's a longer list, the 4 MSB | |
576 | /// of the element type header will be 0xF, and a varint will follow with the | |
577 | /// true size. | |
578 | /// </summary> | |
579 | public override TList ReadListBegin() | |
580 | { | |
581 | byte size_and_type = (byte)ReadByte(); | |
582 | int size = (size_and_type >> 4) & 0x0f; | |
583 | if (size == 15) | |
584 | { | |
585 | size = (int)ReadVarint32(); | |
586 | } | |
587 | TType type = getTType(size_and_type); | |
588 | return new TList(type, size); | |
589 | } | |
590 | ||
591 | /// <summary> | |
592 | /// Read a set header off the wire. If the set size is 0-14, the size will | |
593 | /// be packed into the element type header. If it's a longer set, the 4 MSB | |
594 | /// of the element type header will be 0xF, and a varint will follow with the | |
595 | /// true size. | |
596 | /// </summary> | |
597 | public override TSet ReadSetBegin() | |
598 | { | |
599 | return new TSet(ReadListBegin()); | |
600 | } | |
601 | ||
602 | /// <summary> | |
603 | /// Read a boolean off the wire. If this is a boolean field, the value should | |
604 | /// already have been Read during ReadFieldBegin, so we'll just consume the | |
605 | /// pre-stored value. Otherwise, Read a byte. | |
606 | /// </summary> | |
607 | public override Boolean ReadBool() | |
608 | { | |
609 | if (boolValue_ != null) | |
610 | { | |
611 | bool result = boolValue_.Value; | |
612 | boolValue_ = null; | |
613 | return result; | |
614 | } | |
615 | return ReadByte() == Types.BOOLEAN_TRUE; | |
616 | } | |
617 | ||
618 | byte[] byteRawBuf = new byte[1]; | |
619 | /// <summary> | |
620 | /// Read a single byte off the wire. Nothing interesting here. | |
621 | /// </summary> | |
622 | public override sbyte ReadByte() | |
623 | { | |
624 | trans.ReadAll(byteRawBuf, 0, 1); | |
625 | return (sbyte)byteRawBuf[0]; | |
626 | } | |
627 | ||
628 | /// <summary> | |
629 | /// Read an i16 from the wire as a zigzag varint. | |
630 | /// </summary> | |
631 | public override short ReadI16() | |
632 | { | |
633 | return (short)zigzagToInt(ReadVarint32()); | |
634 | } | |
635 | ||
636 | /// <summary> | |
637 | /// Read an i32 from the wire as a zigzag varint. | |
638 | /// </summary> | |
639 | public override int ReadI32() | |
640 | { | |
641 | return zigzagToInt(ReadVarint32()); | |
642 | } | |
643 | ||
644 | /// <summary> | |
645 | /// Read an i64 from the wire as a zigzag varint. | |
646 | /// </summary> | |
647 | public override long ReadI64() | |
648 | { | |
649 | return zigzagToLong(ReadVarint64()); | |
650 | } | |
651 | ||
652 | /// <summary> | |
653 | /// No magic here - just Read a double off the wire. | |
654 | /// </summary> | |
655 | public override double ReadDouble() | |
656 | { | |
657 | byte[] longBits = new byte[8]; | |
658 | trans.ReadAll(longBits, 0, 8); | |
659 | return BitConverter.Int64BitsToDouble(bytesToLong(longBits)); | |
660 | } | |
661 | ||
662 | /// <summary> | |
663 | /// Reads a byte[] (via ReadBinary), and then UTF-8 decodes it. | |
664 | /// </summary> | |
665 | public override string ReadString() | |
666 | { | |
667 | int length = (int)ReadVarint32(); | |
668 | ||
669 | if (length == 0) | |
670 | { | |
671 | return ""; | |
672 | } | |
673 | ||
674 | return Encoding.UTF8.GetString(ReadBinary(length)); | |
675 | } | |
676 | ||
677 | /// <summary> | |
678 | /// Read a byte[] from the wire. | |
679 | /// </summary> | |
680 | public override byte[] ReadBinary() | |
681 | { | |
682 | int length = (int)ReadVarint32(); | |
683 | if (length == 0) return new byte[0]; | |
684 | ||
685 | byte[] buf = new byte[length]; | |
686 | trans.ReadAll(buf, 0, length); | |
687 | return buf; | |
688 | } | |
689 | ||
690 | /// <summary> | |
691 | /// Read a byte[] of a known length from the wire. | |
692 | /// </summary> | |
693 | private byte[] ReadBinary(int length) | |
694 | { | |
695 | if (length == 0) return new byte[0]; | |
696 | ||
697 | byte[] buf = new byte[length]; | |
698 | trans.ReadAll(buf, 0, length); | |
699 | return buf; | |
700 | } | |
701 | ||
702 | // | |
703 | // These methods are here for the struct to call, but don't have any wire | |
704 | // encoding. | |
705 | // | |
706 | public override void ReadMessageEnd() { } | |
707 | public override void ReadFieldEnd() { } | |
708 | public override void ReadMapEnd() { } | |
709 | public override void ReadListEnd() { } | |
710 | public override void ReadSetEnd() { } | |
711 | ||
712 | // | |
713 | // Internal Reading methods | |
714 | // | |
715 | ||
716 | /// <summary> | |
717 | /// Read an i32 from the wire as a varint. The MSB of each byte is set | |
718 | /// if there is another byte to follow. This can Read up to 5 bytes. | |
719 | /// </summary> | |
720 | private uint ReadVarint32() | |
721 | { | |
722 | uint result = 0; | |
723 | int shift = 0; | |
724 | while (true) | |
725 | { | |
726 | byte b = (byte)ReadByte(); | |
727 | result |= (uint)(b & 0x7f) << shift; | |
728 | if ((b & 0x80) != 0x80) break; | |
729 | shift += 7; | |
730 | } | |
731 | return result; | |
732 | } | |
733 | ||
734 | /// <summary> | |
735 | /// Read an i64 from the wire as a proper varint. The MSB of each byte is set | |
736 | /// if there is another byte to follow. This can Read up to 10 bytes. | |
737 | /// </summary> | |
738 | private ulong ReadVarint64() | |
739 | { | |
740 | int shift = 0; | |
741 | ulong result = 0; | |
742 | while (true) | |
743 | { | |
744 | byte b = (byte)ReadByte(); | |
745 | result |= (ulong)(b & 0x7f) << shift; | |
746 | if ((b & 0x80) != 0x80) break; | |
747 | shift += 7; | |
748 | } | |
749 | ||
750 | return result; | |
751 | } | |
752 | ||
753 | #endregion | |
754 | ||
755 | // | |
756 | // encoding helpers | |
757 | // | |
758 | ||
759 | /// <summary> | |
760 | /// Convert from zigzag int to int. | |
761 | /// </summary> | |
762 | private int zigzagToInt(uint n) | |
763 | { | |
764 | return (int)(n >> 1) ^ (-(int)(n & 1)); | |
765 | } | |
766 | ||
767 | /// <summary> | |
768 | /// Convert from zigzag long to long. | |
769 | /// </summary> | |
770 | private long zigzagToLong(ulong n) | |
771 | { | |
772 | return (long)(n >> 1) ^ (-(long)(n & 1)); | |
773 | } | |
774 | ||
775 | /// <summary> | |
776 | /// Note that it's important that the mask bytes are long literals, | |
777 | /// otherwise they'll default to ints, and when you shift an int left 56 bits, | |
778 | /// you just get a messed up int. | |
779 | /// </summary> | |
780 | private long bytesToLong(byte[] bytes) | |
781 | { | |
782 | return | |
783 | ((bytes[7] & 0xffL) << 56) | | |
784 | ((bytes[6] & 0xffL) << 48) | | |
785 | ((bytes[5] & 0xffL) << 40) | | |
786 | ((bytes[4] & 0xffL) << 32) | | |
787 | ((bytes[3] & 0xffL) << 24) | | |
788 | ((bytes[2] & 0xffL) << 16) | | |
789 | ((bytes[1] & 0xffL) << 8) | | |
790 | ((bytes[0] & 0xffL)); | |
791 | } | |
792 | ||
793 | // | |
794 | // type testing and converting | |
795 | // | |
796 | ||
797 | private Boolean isBoolType(byte b) | |
798 | { | |
799 | int lowerNibble = b & 0x0f; | |
800 | return lowerNibble == Types.BOOLEAN_TRUE || lowerNibble == Types.BOOLEAN_FALSE; | |
801 | } | |
802 | ||
803 | /// <summary> | |
804 | /// Given a TCompactProtocol.Types constant, convert it to its corresponding | |
805 | /// TType value. | |
806 | /// </summary> | |
807 | private TType getTType(byte type) | |
808 | { | |
809 | switch ((byte)(type & 0x0f)) | |
810 | { | |
811 | case Types.STOP: | |
812 | return TType.Stop; | |
813 | case Types.BOOLEAN_FALSE: | |
814 | case Types.BOOLEAN_TRUE: | |
815 | return TType.Bool; | |
816 | case Types.BYTE: | |
817 | return TType.Byte; | |
818 | case Types.I16: | |
819 | return TType.I16; | |
820 | case Types.I32: | |
821 | return TType.I32; | |
822 | case Types.I64: | |
823 | return TType.I64; | |
824 | case Types.DOUBLE: | |
825 | return TType.Double; | |
826 | case Types.BINARY: | |
827 | return TType.String; | |
828 | case Types.LIST: | |
829 | return TType.List; | |
830 | case Types.SET: | |
831 | return TType.Set; | |
832 | case Types.MAP: | |
833 | return TType.Map; | |
834 | case Types.STRUCT: | |
835 | return TType.Struct; | |
836 | default: | |
837 | throw new TProtocolException("don't know what type: " + (byte)(type & 0x0f)); | |
838 | } | |
839 | } | |
840 | ||
841 | /// <summary> | |
842 | /// Given a TType value, find the appropriate TCompactProtocol.Types constant. | |
843 | /// </summary> | |
844 | private byte getCompactType(TType ttype) | |
845 | { | |
846 | return ttypeToCompactType[(int)ttype]; | |
847 | } | |
848 | } | |
849 | } |