]> git.proxmox.com Git - ceph.git/blame - ceph/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/protocol/TCompactProtocol.java
update source to Ceph Pacific 16.2.2
[ceph.git] / ceph / src / jaegertracing / thrift / lib / java / src / org / apache / thrift / protocol / TCompactProtocol.java
CommitLineData
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
20
21package org.apache.thrift.protocol;
22
23import java.io.UnsupportedEncodingException;
24import java.nio.ByteBuffer;
25import java.nio.charset.StandardCharsets;
26
27import org.apache.thrift.TException;
28import org.apache.thrift.transport.TTransport;
29
30/**
31 * TCompactProtocol2 is the Java implementation of the compact protocol specified
32 * in THRIFT-110. The fundamental approach to reducing the overhead of
33 * structures is a) use variable-length integers all over the place and b) make
34 * use of unused bits wherever possible. Your savings will obviously vary
35 * based on the specific makeup of your structs, but in general, the more
36 * fields, nested structures, short strings and collections, and low-value i32
37 * and i64 fields you have, the more benefit you'll see.
38 */
39public class TCompactProtocol extends TProtocol {
40 private final static byte[] EMPTY_BYTES = new byte[0];
41 private final static ByteBuffer EMPTY_BUFFER = ByteBuffer.wrap(EMPTY_BYTES);
42
43 private final static long NO_LENGTH_LIMIT = -1;
44
45 private final static TStruct ANONYMOUS_STRUCT = new TStruct("");
46 private final static TField TSTOP = new TField("", TType.STOP, (short)0);
47
48 private final static byte[] ttypeToCompactType = new byte[16];
49
50 static {
51 ttypeToCompactType[TType.STOP] = TType.STOP;
52 ttypeToCompactType[TType.BOOL] = Types.BOOLEAN_TRUE;
53 ttypeToCompactType[TType.BYTE] = Types.BYTE;
54 ttypeToCompactType[TType.I16] = Types.I16;
55 ttypeToCompactType[TType.I32] = Types.I32;
56 ttypeToCompactType[TType.I64] = Types.I64;
57 ttypeToCompactType[TType.DOUBLE] = Types.DOUBLE;
58 ttypeToCompactType[TType.STRING] = Types.BINARY;
59 ttypeToCompactType[TType.LIST] = Types.LIST;
60 ttypeToCompactType[TType.SET] = Types.SET;
61 ttypeToCompactType[TType.MAP] = Types.MAP;
62 ttypeToCompactType[TType.STRUCT] = Types.STRUCT;
63 }
64
65 /**
66 * TProtocolFactory that produces TCompactProtocols.
67 */
68 public static class Factory implements TProtocolFactory {
69 private final long stringLengthLimit_;
70 private final long containerLengthLimit_;
71
72 public Factory() {
73 this(NO_LENGTH_LIMIT, NO_LENGTH_LIMIT);
74 }
75
76 public Factory(long stringLengthLimit) {
77 this(stringLengthLimit, NO_LENGTH_LIMIT);
78 }
79
80 public Factory(long stringLengthLimit, long containerLengthLimit) {
81 this.containerLengthLimit_ = containerLengthLimit;
82 this.stringLengthLimit_ = stringLengthLimit;
83 }
84
85 public TProtocol getProtocol(TTransport trans) {
86 return new TCompactProtocol(trans, stringLengthLimit_, containerLengthLimit_);
87 }
88 }
89
90 private static final byte PROTOCOL_ID = (byte)0x82;
91 private static final byte VERSION = 1;
92 private static final byte VERSION_MASK = 0x1f; // 0001 1111
93 private static final byte TYPE_MASK = (byte)0xE0; // 1110 0000
94 private static final byte TYPE_BITS = 0x07; // 0000 0111
95 private static final int TYPE_SHIFT_AMOUNT = 5;
96
97 /**
98 * All of the on-wire type codes.
99 */
100 private static class Types {
101 public static final byte BOOLEAN_TRUE = 0x01;
102 public static final byte BOOLEAN_FALSE = 0x02;
103 public static final byte BYTE = 0x03;
104 public static final byte I16 = 0x04;
105 public static final byte I32 = 0x05;
106 public static final byte I64 = 0x06;
107 public static final byte DOUBLE = 0x07;
108 public static final byte BINARY = 0x08;
109 public static final byte LIST = 0x09;
110 public static final byte SET = 0x0A;
111 public static final byte MAP = 0x0B;
112 public static final byte STRUCT = 0x0C;
113 }
114
115 /**
116 * Used to keep track of the last field for the current and previous structs,
117 * so we can do the delta stuff.
118 */
119 private ShortStack lastField_ = new ShortStack(15);
120
121 private short lastFieldId_ = 0;
122
123 /**
124 * If we encounter a boolean field begin, save the TField here so it can
125 * have the value incorporated.
126 */
127 private TField booleanField_ = null;
128
129 /**
130 * If we read a field header, and it's a boolean field, save the boolean
131 * value here so that readBool can use it.
132 */
133 private Boolean boolValue_ = null;
134
135 /**
136 * The maximum number of bytes to read from the transport for
137 * variable-length fields (such as strings or binary) or {@link #NO_LENGTH_LIMIT} for
138 * unlimited.
139 */
140 private final long stringLengthLimit_;
141
142 /**
143 * The maximum number of elements to read from the network for
144 * containers (maps, sets, lists), or {@link #NO_LENGTH_LIMIT} for unlimited.
145 */
146 private final long containerLengthLimit_;
147
148 /**
149 * Temporary buffer used for various operations that would otherwise require a
150 * small allocation.
151 */
152 private final byte[] temp = new byte[10];
153
154 /**
155 * Create a TCompactProtocol.
156 *
157 * @param transport the TTransport object to read from or write to.
158 * @param stringLengthLimit the maximum number of bytes to read for
159 * variable-length fields.
160 * @param containerLengthLimit the maximum number of elements to read
161 * for containers.
162 */
163 public TCompactProtocol(TTransport transport, long stringLengthLimit, long containerLengthLimit) {
164 super(transport);
165 this.stringLengthLimit_ = stringLengthLimit;
166 this.containerLengthLimit_ = containerLengthLimit;
167 }
168
169 /**
170 * Create a TCompactProtocol.
171 *
172 * @param transport the TTransport object to read from or write to.
173 * @param stringLengthLimit the maximum number of bytes to read for
174 * variable-length fields.
175 * @deprecated Use constructor specifying both string limit and container limit instead
176 */
177 @Deprecated
178 public TCompactProtocol(TTransport transport, long stringLengthLimit) {
179 this(transport, stringLengthLimit, NO_LENGTH_LIMIT);
180 }
181
182 /**
183 * Create a TCompactProtocol.
184 *
185 * @param transport the TTransport object to read from or write to.
186 */
187 public TCompactProtocol(TTransport transport) {
188 this(transport, NO_LENGTH_LIMIT, NO_LENGTH_LIMIT);
189 }
190
191 @Override
192 public void reset() {
193 lastField_.clear();
194 lastFieldId_ = 0;
195 }
196
197 //
198 // Public Writing methods.
199 //
200
201 /**
202 * Write a message header to the wire. Compact Protocol messages contain the
203 * protocol version so we can migrate forwards in the future if need be.
204 */
205 @Override
206 public void writeMessageBegin(TMessage message) throws TException {
207 writeByteDirect(PROTOCOL_ID);
208 writeByteDirect((VERSION & VERSION_MASK) | ((message.type << TYPE_SHIFT_AMOUNT) & TYPE_MASK));
209 writeVarint32(message.seqid);
210 writeString(message.name);
211 }
212
213 /**
214 * Write a struct begin. This doesn't actually put anything on the wire. We
215 * use it as an opportunity to put special placeholder markers on the field
216 * stack so we can get the field id deltas correct.
217 */
218 @Override
219 public void writeStructBegin(TStruct struct) throws TException {
220 lastField_.push(lastFieldId_);
221 lastFieldId_ = 0;
222 }
223
224 /**
225 * Write a struct end. This doesn't actually put anything on the wire. We use
226 * this as an opportunity to pop the last field from the current struct off
227 * of the field stack.
228 */
229 public void writeStructEnd() throws TException {
230 lastFieldId_ = lastField_.pop();
231 }
232
233 /**
234 * Write a field header containing the field id and field type. If the
235 * difference between the current field id and the last one is small (&lt; 15),
236 * then the field id will be encoded in the 4 MSB as a delta. Otherwise, the
237 * field id will follow the type header as a zigzag varint.
238 */
239 public void writeFieldBegin(TField field) throws TException {
240 if (field.type == TType.BOOL) {
241 // we want to possibly include the value, so we'll wait.
242 booleanField_ = field;
243 } else {
244 writeFieldBeginInternal(field, (byte)-1);
245 }
246 }
247
248 /**
249 * The workhorse of writeFieldBegin. It has the option of doing a
250 * 'type override' of the type header. This is used specifically in the
251 * boolean field case.
252 */
253 private void writeFieldBeginInternal(TField field, byte typeOverride) throws TException {
254 // short lastField = lastField_.pop();
255
256 // if there's a type override, use that.
257 byte typeToWrite = typeOverride == -1 ? getCompactType(field.type) : typeOverride;
258
259 // check if we can use delta encoding for the field id
260 if (field.id > lastFieldId_ && field.id - lastFieldId_ <= 15) {
261 // write them together
262 writeByteDirect((field.id - lastFieldId_) << 4 | typeToWrite);
263 } else {
264 // write them separate
265 writeByteDirect(typeToWrite);
266 writeI16(field.id);
267 }
268
269 lastFieldId_ = field.id;
270 // lastField_.push(field.id);
271 }
272
273 /**
274 * Write the STOP symbol so we know there are no more fields in this struct.
275 */
276 public void writeFieldStop() throws TException {
277 writeByteDirect(TType.STOP);
278 }
279
280 /**
281 * Write a map header. If the map is empty, omit the key and value type
282 * headers, as we don't need any additional information to skip it.
283 */
284 public void writeMapBegin(TMap map) throws TException {
285 if (map.size == 0) {
286 writeByteDirect(0);
287 } else {
288 writeVarint32(map.size);
289 writeByteDirect(getCompactType(map.keyType) << 4 | getCompactType(map.valueType));
290 }
291 }
292
293 /**
294 * Write a list header.
295 */
296 public void writeListBegin(TList list) throws TException {
297 writeCollectionBegin(list.elemType, list.size);
298 }
299
300 /**
301 * Write a set header.
302 */
303 public void writeSetBegin(TSet set) throws TException {
304 writeCollectionBegin(set.elemType, set.size);
305 }
306
307 /**
308 * Write a boolean value. Potentially, this could be a boolean field, in
309 * which case the field header info isn't written yet. If so, decide what the
310 * right type header is for the value and then write the field header.
311 * Otherwise, write a single byte.
312 */
313 public void writeBool(boolean b) throws TException {
314 if (booleanField_ != null) {
315 // we haven't written the field header yet
316 writeFieldBeginInternal(booleanField_, b ? Types.BOOLEAN_TRUE : Types.BOOLEAN_FALSE);
317 booleanField_ = null;
318 } else {
319 // we're not part of a field, so just write the value.
320 writeByteDirect(b ? Types.BOOLEAN_TRUE : Types.BOOLEAN_FALSE);
321 }
322 }
323
324 /**
325 * Write a byte. Nothing to see here!
326 */
327 public void writeByte(byte b) throws TException {
328 writeByteDirect(b);
329 }
330
331 /**
332 * Write an I16 as a zigzag varint.
333 */
334 public void writeI16(short i16) throws TException {
335 writeVarint32(intToZigZag(i16));
336 }
337
338 /**
339 * Write an i32 as a zigzag varint.
340 */
341 public void writeI32(int i32) throws TException {
342 writeVarint32(intToZigZag(i32));
343 }
344
345 /**
346 * Write an i64 as a zigzag varint.
347 */
348 public void writeI64(long i64) throws TException {
349 writeVarint64(longToZigzag(i64));
350 }
351
352 /**
353 * Write a double to the wire as 8 bytes.
354 */
355 public void writeDouble(double dub) throws TException {
356 fixedLongToBytes(Double.doubleToLongBits(dub), temp, 0);
357 trans_.write(temp, 0, 8);
358 }
359
360 /**
361 * Write a string to the wire with a varint size preceding.
362 */
363 public void writeString(String str) throws TException {
364 byte[] bytes = str.getBytes(StandardCharsets.UTF_8);
365 writeBinary(bytes, 0, bytes.length);
366 }
367
368 /**
369 * Write a byte array, using a varint for the size.
370 */
371 public void writeBinary(ByteBuffer bin) throws TException {
372 int length = bin.limit() - bin.position();
373 writeBinary(bin.array(), bin.position() + bin.arrayOffset(), length);
374 }
375
376 private void writeBinary(byte[] buf, int offset, int length) throws TException {
377 writeVarint32(length);
378 trans_.write(buf, offset, length);
379 }
380
381 //
382 // These methods are called by structs, but don't actually have any wire
383 // output or purpose.
384 //
385
386 public void writeMessageEnd() throws TException {}
387 public void writeMapEnd() throws TException {}
388 public void writeListEnd() throws TException {}
389 public void writeSetEnd() throws TException {}
390 public void writeFieldEnd() throws TException {}
391
392 //
393 // Internal writing methods
394 //
395
396 /**
397 * Abstract method for writing the start of lists and sets. List and sets on
398 * the wire differ only by the type indicator.
399 */
400 protected void writeCollectionBegin(byte elemType, int size) throws TException {
401 if (size <= 14) {
402 writeByteDirect(size << 4 | getCompactType(elemType));
403 } else {
404 writeByteDirect(0xf0 | getCompactType(elemType));
405 writeVarint32(size);
406 }
407 }
408
409 /**
410 * Write an i32 as a varint. Results in 1-5 bytes on the wire.
411 * TODO: make a permanent buffer like writeVarint64?
412 */
413 private void writeVarint32(int n) throws TException {
414 int idx = 0;
415 while (true) {
416 if ((n & ~0x7F) == 0) {
417 temp[idx++] = (byte)n;
418 // writeByteDirect((byte)n);
419 break;
420 // return;
421 } else {
422 temp[idx++] = (byte)((n & 0x7F) | 0x80);
423 // writeByteDirect((byte)((n & 0x7F) | 0x80));
424 n >>>= 7;
425 }
426 }
427 trans_.write(temp, 0, idx);
428 }
429
430 /**
431 * Write an i64 as a varint. Results in 1-10 bytes on the wire.
432 */
433 private void writeVarint64(long n) throws TException {
434 int idx = 0;
435 while (true) {
436 if ((n & ~0x7FL) == 0) {
437 temp[idx++] = (byte)n;
438 break;
439 } else {
440 temp[idx++] = ((byte)((n & 0x7F) | 0x80));
441 n >>>= 7;
442 }
443 }
444 trans_.write(temp, 0, idx);
445 }
446
447 /**
448 * Convert l into a zigzag long. This allows negative numbers to be
449 * represented compactly as a varint.
450 */
451 private long longToZigzag(long l) {
452 return (l << 1) ^ (l >> 63);
453 }
454
455 /**
456 * Convert n into a zigzag int. This allows negative numbers to be
457 * represented compactly as a varint.
458 */
459 private int intToZigZag(int n) {
460 return (n << 1) ^ (n >> 31);
461 }
462
463 /**
464 * Convert a long into little-endian bytes in buf starting at off and going
465 * until off+7.
466 */
467 private void fixedLongToBytes(long n, byte[] buf, int off) {
468 buf[off+0] = (byte)( n & 0xff);
469 buf[off+1] = (byte)((n >> 8 ) & 0xff);
470 buf[off+2] = (byte)((n >> 16) & 0xff);
471 buf[off+3] = (byte)((n >> 24) & 0xff);
472 buf[off+4] = (byte)((n >> 32) & 0xff);
473 buf[off+5] = (byte)((n >> 40) & 0xff);
474 buf[off+6] = (byte)((n >> 48) & 0xff);
475 buf[off+7] = (byte)((n >> 56) & 0xff);
476 }
477
478 /**
479 * Writes a byte without any possibility of all that field header nonsense.
480 * Used internally by other writing methods that know they need to write a byte.
481 */
482 private void writeByteDirect(byte b) throws TException {
483 temp[0] = b;
484 trans_.write(temp, 0, 1);
485 }
486
487 /**
488 * Writes a byte without any possibility of all that field header nonsense.
489 */
490 private void writeByteDirect(int n) throws TException {
491 writeByteDirect((byte)n);
492 }
493
494
495 //
496 // Reading methods.
497 //
498
499 /**
500 * Read a message header.
501 */
502 public TMessage readMessageBegin() throws TException {
503 byte protocolId = readByte();
504 if (protocolId != PROTOCOL_ID) {
505 throw new TProtocolException("Expected protocol id " + Integer.toHexString(PROTOCOL_ID) + " but got " + Integer.toHexString(protocolId));
506 }
507 byte versionAndType = readByte();
508 byte version = (byte)(versionAndType & VERSION_MASK);
509 if (version != VERSION) {
510 throw new TProtocolException("Expected version " + VERSION + " but got " + version);
511 }
512 byte type = (byte)((versionAndType >> TYPE_SHIFT_AMOUNT) & TYPE_BITS);
513 int seqid = readVarint32();
514 String messageName = readString();
515 return new TMessage(messageName, type, seqid);
516 }
517
518 /**
519 * Read a struct begin. There's nothing on the wire for this, but it is our
520 * opportunity to push a new struct begin marker onto the field stack.
521 */
522 public TStruct readStructBegin() throws TException {
523 lastField_.push(lastFieldId_);
524 lastFieldId_ = 0;
525 return ANONYMOUS_STRUCT;
526 }
527
528 /**
529 * Doesn't actually consume any wire data, just removes the last field for
530 * this struct from the field stack.
531 */
532 public void readStructEnd() throws TException {
533 // consume the last field we read off the wire.
534 lastFieldId_ = lastField_.pop();
535 }
536
537 /**
538 * Read a field header off the wire.
539 */
540 public TField readFieldBegin() throws TException {
541 byte type = readByte();
542
543 // if it's a stop, then we can return immediately, as the struct is over.
544 if (type == TType.STOP) {
545 return TSTOP;
546 }
547
548 short fieldId;
549
550 // mask off the 4 MSB of the type header. it could contain a field id delta.
551 short modifier = (short)((type & 0xf0) >> 4);
552 if (modifier == 0) {
553 // not a delta. look ahead for the zigzag varint field id.
554 fieldId = readI16();
555 } else {
556 // has a delta. add the delta to the last read field id.
557 fieldId = (short)(lastFieldId_ + modifier);
558 }
559
560 TField field = new TField("", getTType((byte)(type & 0x0f)), fieldId);
561
562 // if this happens to be a boolean field, the value is encoded in the type
563 if (isBoolType(type)) {
564 // save the boolean value in a special instance variable.
565 boolValue_ = (byte)(type & 0x0f) == Types.BOOLEAN_TRUE ? Boolean.TRUE : Boolean.FALSE;
566 }
567
568 // push the new field onto the field stack so we can keep the deltas going.
569 lastFieldId_ = field.id;
570 return field;
571 }
572
573 /**
574 * Read a map header off the wire. If the size is zero, skip reading the key
575 * and value type. This means that 0-length maps will yield TMaps without the
576 * "correct" types.
577 */
578 public TMap readMapBegin() throws TException {
579 int size = readVarint32();
580 checkContainerReadLength(size);
581 byte keyAndValueType = size == 0 ? 0 : readByte();
582 return new TMap(getTType((byte)(keyAndValueType >> 4)), getTType((byte)(keyAndValueType & 0xf)), size);
583 }
584
585 /**
586 * Read a list header off the wire. If the list size is 0-14, the size will
587 * be packed into the element type header. If it's a longer list, the 4 MSB
588 * of the element type header will be 0xF, and a varint will follow with the
589 * true size.
590 */
591 public TList readListBegin() throws TException {
592 byte size_and_type = readByte();
593 int size = (size_and_type >> 4) & 0x0f;
594 if (size == 15) {
595 size = readVarint32();
596 }
597 checkContainerReadLength(size);
598 byte type = getTType(size_and_type);
599 return new TList(type, size);
600 }
601
602 /**
603 * Read a set header off the wire. If the set size is 0-14, the size will
604 * be packed into the element type header. If it's a longer set, the 4 MSB
605 * of the element type header will be 0xF, and a varint will follow with the
606 * true size.
607 */
608 public TSet readSetBegin() throws TException {
609 return new TSet(readListBegin());
610 }
611
612 /**
613 * Read a boolean off the wire. If this is a boolean field, the value should
614 * already have been read during readFieldBegin, so we'll just consume the
615 * pre-stored value. Otherwise, read a byte.
616 */
617 public boolean readBool() throws TException {
618 if (boolValue_ != null) {
619 boolean result = boolValue_.booleanValue();
620 boolValue_ = null;
621 return result;
622 }
623 return readByte() == Types.BOOLEAN_TRUE;
624 }
625
626 /**
627 * Read a single byte off the wire. Nothing interesting here.
628 */
629 public byte readByte() throws TException {
630 byte b;
631 if (trans_.getBytesRemainingInBuffer() > 0) {
632 b = trans_.getBuffer()[trans_.getBufferPosition()];
633 trans_.consumeBuffer(1);
634 } else {
635 trans_.readAll(temp, 0, 1);
636 b = temp[0];
637 }
638 return b;
639 }
640
641 /**
642 * Read an i16 from the wire as a zigzag varint.
643 */
644 public short readI16() throws TException {
645 return (short)zigzagToInt(readVarint32());
646 }
647
648 /**
649 * Read an i32 from the wire as a zigzag varint.
650 */
651 public int readI32() throws TException {
652 return zigzagToInt(readVarint32());
653 }
654
655 /**
656 * Read an i64 from the wire as a zigzag varint.
657 */
658 public long readI64() throws TException {
659 return zigzagToLong(readVarint64());
660 }
661
662 /**
663 * No magic here - just read a double off the wire.
664 */
665 public double readDouble() throws TException {
666 trans_.readAll(temp, 0, 8);
667 return Double.longBitsToDouble(bytesToLong(temp));
668 }
669
670 /**
671 * Reads a byte[] (via readBinary), and then UTF-8 decodes it.
672 */
673 public String readString() throws TException {
674 int length = readVarint32();
675 checkStringReadLength(length);
676
677 if (length == 0) {
678 return "";
679 }
680
681 final String str;
682 if (trans_.getBytesRemainingInBuffer() >= length) {
683 str = new String(trans_.getBuffer(), trans_.getBufferPosition(),
684 length, StandardCharsets.UTF_8);
685 trans_.consumeBuffer(length);
686 } else {
687 str = new String(readBinary(length), StandardCharsets.UTF_8);
688 }
689 return str;
690 }
691
692 /**
693 * Read a byte[] from the wire.
694 */
695 public ByteBuffer readBinary() throws TException {
696 int length = readVarint32();
697 checkStringReadLength(length);
698 if (length == 0) return EMPTY_BUFFER;
699
700 if (trans_.getBytesRemainingInBuffer() >= length) {
701 ByteBuffer bb = ByteBuffer.wrap(trans_.getBuffer(), trans_.getBufferPosition(), length);
702 trans_.consumeBuffer(length);
703 return bb;
704 }
705
706 byte[] buf = new byte[length];
707 trans_.readAll(buf, 0, length);
708 return ByteBuffer.wrap(buf);
709 }
710
711 /**
712 * Read a byte[] of a known length from the wire.
713 */
714 private byte[] readBinary(int length) throws TException {
715 if (length == 0) return EMPTY_BYTES;
716
717 byte[] buf = new byte[length];
718 trans_.readAll(buf, 0, length);
719 return buf;
720 }
721
722 private void checkStringReadLength(int length) throws TProtocolException {
723 if (length < 0) {
724 throw new TProtocolException(TProtocolException.NEGATIVE_SIZE,
725 "Negative length: " + length);
726 }
727 if (stringLengthLimit_ != NO_LENGTH_LIMIT && length > stringLengthLimit_) {
728 throw new TProtocolException(TProtocolException.SIZE_LIMIT,
729 "Length exceeded max allowed: " + length);
730 }
731 }
732
733 private void checkContainerReadLength(int length) throws TProtocolException {
734 if (length < 0) {
735 throw new TProtocolException(TProtocolException.NEGATIVE_SIZE,
736 "Negative length: " + length);
737 }
738 if (containerLengthLimit_ != NO_LENGTH_LIMIT && length > containerLengthLimit_) {
739 throw new TProtocolException(TProtocolException.SIZE_LIMIT,
740 "Length exceeded max allowed: " + length);
741 }
742 }
743
744 //
745 // These methods are here for the struct to call, but don't have any wire
746 // encoding.
747 //
748 public void readMessageEnd() throws TException {}
749 public void readFieldEnd() throws TException {}
750 public void readMapEnd() throws TException {}
751 public void readListEnd() throws TException {}
752 public void readSetEnd() throws TException {}
753
754 //
755 // Internal reading methods
756 //
757
758 /**
759 * Read an i32 from the wire as a varint. The MSB of each byte is set
760 * if there is another byte to follow. This can read up to 5 bytes.
761 */
762 private int readVarint32() throws TException {
763 int result = 0;
764 int shift = 0;
765 if (trans_.getBytesRemainingInBuffer() >= 5) {
766 byte[] buf = trans_.getBuffer();
767 int pos = trans_.getBufferPosition();
768 int off = 0;
769 while (true) {
770 byte b = buf[pos+off];
771 result |= (int) (b & 0x7f) << shift;
772 if ((b & 0x80) != 0x80) break;
773 shift += 7;
774 off++;
775 }
776 trans_.consumeBuffer(off+1);
777 } else {
778 while (true) {
779 byte b = readByte();
780 result |= (int) (b & 0x7f) << shift;
781 if ((b & 0x80) != 0x80) break;
782 shift += 7;
783 }
784 }
785 return result;
786 }
787
788 /**
789 * Read an i64 from the wire as a proper varint. The MSB of each byte is set
790 * if there is another byte to follow. This can read up to 10 bytes.
791 */
792 private long readVarint64() throws TException {
793 int shift = 0;
794 long result = 0;
795 if (trans_.getBytesRemainingInBuffer() >= 10) {
796 byte[] buf = trans_.getBuffer();
797 int pos = trans_.getBufferPosition();
798 int off = 0;
799 while (true) {
800 byte b = buf[pos+off];
801 result |= (long) (b & 0x7f) << shift;
802 if ((b & 0x80) != 0x80) break;
803 shift += 7;
804 off++;
805 }
806 trans_.consumeBuffer(off+1);
807 } else {
808 while (true) {
809 byte b = readByte();
810 result |= (long) (b & 0x7f) << shift;
811 if ((b & 0x80) != 0x80) break;
812 shift +=7;
813 }
814 }
815 return result;
816 }
817
818 //
819 // encoding helpers
820 //
821
822 /**
823 * Convert from zigzag int to int.
824 */
825 private int zigzagToInt(int n) {
826 return (n >>> 1) ^ -(n & 1);
827 }
828
829 /**
830 * Convert from zigzag long to long.
831 */
832 private long zigzagToLong(long n) {
833 return (n >>> 1) ^ -(n & 1);
834 }
835
836 /**
837 * Note that it's important that the mask bytes are long literals,
838 * otherwise they'll default to ints, and when you shift an int left 56 bits,
839 * you just get a messed up int.
840 */
841 private long bytesToLong(byte[] bytes) {
842 return
843 ((bytes[7] & 0xffL) << 56) |
844 ((bytes[6] & 0xffL) << 48) |
845 ((bytes[5] & 0xffL) << 40) |
846 ((bytes[4] & 0xffL) << 32) |
847 ((bytes[3] & 0xffL) << 24) |
848 ((bytes[2] & 0xffL) << 16) |
849 ((bytes[1] & 0xffL) << 8) |
850 ((bytes[0] & 0xffL));
851 }
852
853 //
854 // type testing and converting
855 //
856
857 private boolean isBoolType(byte b) {
858 int lowerNibble = b & 0x0f;
859 return lowerNibble == Types.BOOLEAN_TRUE || lowerNibble == Types.BOOLEAN_FALSE;
860 }
861
862 /**
863 * Given a TCompactProtocol.Types constant, convert it to its corresponding
864 * TType value.
865 */
866 private byte getTType(byte type) throws TProtocolException {
867 switch ((byte)(type & 0x0f)) {
868 case TType.STOP:
869 return TType.STOP;
870 case Types.BOOLEAN_FALSE:
871 case Types.BOOLEAN_TRUE:
872 return TType.BOOL;
873 case Types.BYTE:
874 return TType.BYTE;
875 case Types.I16:
876 return TType.I16;
877 case Types.I32:
878 return TType.I32;
879 case Types.I64:
880 return TType.I64;
881 case Types.DOUBLE:
882 return TType.DOUBLE;
883 case Types.BINARY:
884 return TType.STRING;
885 case Types.LIST:
886 return TType.LIST;
887 case Types.SET:
888 return TType.SET;
889 case Types.MAP:
890 return TType.MAP;
891 case Types.STRUCT:
892 return TType.STRUCT;
893 default:
894 throw new TProtocolException("don't know what type: " + (byte)(type & 0x0f));
895 }
896 }
897
898 /**
899 * Given a TType value, find the appropriate TCompactProtocol.Types constant.
900 */
901 private byte getCompactType(byte ttype) {
902 return ttypeToCompactType[ttype];
903 }
904}