blob: b9299f2fa13c7822cb58a6a4432836caf8d5f473 [file] [log] [blame]
Girish Gowdra631ef3d2020-06-15 10:45:52 -07001/*
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
20package thrift
21
22import (
23 "encoding/binary"
24 "fmt"
25 "io"
26 "math"
27)
28
29const (
30 COMPACT_PROTOCOL_ID = 0x082
31 COMPACT_VERSION = 1
32 COMPACT_VERSION_MASK = 0x1f
33 COMPACT_TYPE_MASK = 0x0E0
34 COMPACT_TYPE_BITS = 0x07
35 COMPACT_TYPE_SHIFT_AMOUNT = 5
36)
37
38type tCompactType byte
39
40const (
41 COMPACT_BOOLEAN_TRUE = 0x01
42 COMPACT_BOOLEAN_FALSE = 0x02
43 COMPACT_BYTE = 0x03
44 COMPACT_I16 = 0x04
45 COMPACT_I32 = 0x05
46 COMPACT_I64 = 0x06
47 COMPACT_DOUBLE = 0x07
48 COMPACT_BINARY = 0x08
49 COMPACT_LIST = 0x09
50 COMPACT_SET = 0x0A
51 COMPACT_MAP = 0x0B
52 COMPACT_STRUCT = 0x0C
53)
54
55var (
56 ttypeToCompactType map[TType]tCompactType
57)
58
59func init() {
60 ttypeToCompactType = map[TType]tCompactType{
61 STOP: STOP,
62 BOOL: COMPACT_BOOLEAN_TRUE,
63 BYTE: COMPACT_BYTE,
64 I16: COMPACT_I16,
65 I32: COMPACT_I32,
66 I64: COMPACT_I64,
67 DOUBLE: COMPACT_DOUBLE,
68 STRING: COMPACT_BINARY,
69 LIST: COMPACT_LIST,
70 SET: COMPACT_SET,
71 MAP: COMPACT_MAP,
72 STRUCT: COMPACT_STRUCT,
73 }
74}
75
76type TCompactProtocolFactory struct{}
77
78func NewTCompactProtocolFactory() *TCompactProtocolFactory {
79 return &TCompactProtocolFactory{}
80}
81
82func (p *TCompactProtocolFactory) GetProtocol(trans TTransport) TProtocol {
83 return NewTCompactProtocol(trans)
84}
85
86type TCompactProtocol struct {
87 trans TRichTransport
88 origTransport TTransport
89
90 // Used to keep track of the last field for the current and previous structs,
91 // so we can do the delta stuff.
92 lastField []int
93 lastFieldId int
94
95 // If we encounter a boolean field begin, save the TField here so it can
96 // have the value incorporated.
97 booleanFieldName string
98 booleanFieldId int16
99 booleanFieldPending bool
100
101 // If we read a field header, and it's a boolean field, save the boolean
102 // value here so that readBool can use it.
103 boolValue bool
104 boolValueIsNotNull bool
105 buffer [64]byte
106}
107
108// Create a TCompactProtocol given a TTransport
109func NewTCompactProtocol(trans TTransport) *TCompactProtocol {
110 p := &TCompactProtocol{origTransport: trans, lastField: []int{}}
111 if et, ok := trans.(TRichTransport); ok {
112 p.trans = et
113 } else {
114 p.trans = NewTRichTransport(trans)
115 }
116
117 return p
118
119}
120
121//
122// Public Writing methods.
123//
124
125// Write a message header to the wire. Compact Protocol messages contain the
126// protocol version so we can migrate forwards in the future if need be.
127func (p *TCompactProtocol) WriteMessageBegin(name string, typeId TMessageType, seqid int32) error {
128 err := p.writeByteDirect(COMPACT_PROTOCOL_ID)
129 if err != nil {
130 return NewTProtocolException(err)
131 }
132 err = p.writeByteDirect((COMPACT_VERSION & COMPACT_VERSION_MASK) | ((byte(typeId) << COMPACT_TYPE_SHIFT_AMOUNT) & COMPACT_TYPE_MASK))
133 if err != nil {
134 return NewTProtocolException(err)
135 }
136 _, err = p.writeVarint32(seqid)
137 if err != nil {
138 return NewTProtocolException(err)
139 }
140 e := p.WriteString(name)
141 return e
142
143}
144
145func (p *TCompactProtocol) WriteMessageEnd() error { return nil }
146
147// Write a struct begin. This doesn't actually put anything on the wire. We
148// use it as an opportunity to put special placeholder markers on the field
149// stack so we can get the field id deltas correct.
150func (p *TCompactProtocol) WriteStructBegin(name string) error {
151 p.lastField = append(p.lastField, p.lastFieldId)
152 p.lastFieldId = 0
153 return nil
154}
155
156// Write a struct end. This doesn't actually put anything on the wire. We use
157// this as an opportunity to pop the last field from the current struct off
158// of the field stack.
159func (p *TCompactProtocol) WriteStructEnd() error {
160 p.lastFieldId = p.lastField[len(p.lastField)-1]
161 p.lastField = p.lastField[:len(p.lastField)-1]
162 return nil
163}
164
165func (p *TCompactProtocol) WriteFieldBegin(name string, typeId TType, id int16) error {
166 if typeId == BOOL {
167 // we want to possibly include the value, so we'll wait.
168 p.booleanFieldName, p.booleanFieldId, p.booleanFieldPending = name, id, true
169 return nil
170 }
171 _, err := p.writeFieldBeginInternal(name, typeId, id, 0xFF)
172 return NewTProtocolException(err)
173}
174
175// The workhorse of writeFieldBegin. It has the option of doing a
176// 'type override' of the type header. This is used specifically in the
177// boolean field case.
178func (p *TCompactProtocol) writeFieldBeginInternal(name string, typeId TType, id int16, typeOverride byte) (int, error) {
179 // short lastField = lastField_.pop();
180
181 // if there's a type override, use that.
182 var typeToWrite byte
183 if typeOverride == 0xFF {
184 typeToWrite = byte(p.getCompactType(typeId))
185 } else {
186 typeToWrite = typeOverride
187 }
188 // check if we can use delta encoding for the field id
189 fieldId := int(id)
190 written := 0
191 if fieldId > p.lastFieldId && fieldId-p.lastFieldId <= 15 {
192 // write them together
193 err := p.writeByteDirect(byte((fieldId-p.lastFieldId)<<4) | typeToWrite)
194 if err != nil {
195 return 0, err
196 }
197 } else {
198 // write them separate
199 err := p.writeByteDirect(typeToWrite)
200 if err != nil {
201 return 0, err
202 }
203 err = p.WriteI16(id)
204 written = 1 + 2
205 if err != nil {
206 return 0, err
207 }
208 }
209
210 p.lastFieldId = fieldId
211 // p.lastField.Push(field.id);
212 return written, nil
213}
214
215func (p *TCompactProtocol) WriteFieldEnd() error { return nil }
216
217func (p *TCompactProtocol) WriteFieldStop() error {
218 err := p.writeByteDirect(STOP)
219 return NewTProtocolException(err)
220}
221
222func (p *TCompactProtocol) WriteMapBegin(keyType TType, valueType TType, size int) error {
223 if size == 0 {
224 err := p.writeByteDirect(0)
225 return NewTProtocolException(err)
226 }
227 _, err := p.writeVarint32(int32(size))
228 if err != nil {
229 return NewTProtocolException(err)
230 }
231 err = p.writeByteDirect(byte(p.getCompactType(keyType))<<4 | byte(p.getCompactType(valueType)))
232 return NewTProtocolException(err)
233}
234
235func (p *TCompactProtocol) WriteMapEnd() error { return nil }
236
237// Write a list header.
238func (p *TCompactProtocol) WriteListBegin(elemType TType, size int) error {
239 _, err := p.writeCollectionBegin(elemType, size)
240 return NewTProtocolException(err)
241}
242
243func (p *TCompactProtocol) WriteListEnd() error { return nil }
244
245// Write a set header.
246func (p *TCompactProtocol) WriteSetBegin(elemType TType, size int) error {
247 _, err := p.writeCollectionBegin(elemType, size)
248 return NewTProtocolException(err)
249}
250
251func (p *TCompactProtocol) WriteSetEnd() error { return nil }
252
253func (p *TCompactProtocol) WriteBool(value bool) error {
254 v := byte(COMPACT_BOOLEAN_FALSE)
255 if value {
256 v = byte(COMPACT_BOOLEAN_TRUE)
257 }
258 if p.booleanFieldPending {
259 // we haven't written the field header yet
260 _, err := p.writeFieldBeginInternal(p.booleanFieldName, BOOL, p.booleanFieldId, v)
261 p.booleanFieldPending = false
262 return NewTProtocolException(err)
263 }
264 // we're not part of a field, so just write the value.
265 err := p.writeByteDirect(v)
266 return NewTProtocolException(err)
267}
268
269// Write a byte. Nothing to see here!
270func (p *TCompactProtocol) WriteByte(value int8) error {
271 err := p.writeByteDirect(byte(value))
272 return NewTProtocolException(err)
273}
274
275// Write an I16 as a zigzag varint.
276func (p *TCompactProtocol) WriteI16(value int16) error {
277 _, err := p.writeVarint32(p.int32ToZigzag(int32(value)))
278 return NewTProtocolException(err)
279}
280
281// Write an i32 as a zigzag varint.
282func (p *TCompactProtocol) WriteI32(value int32) error {
283 _, err := p.writeVarint32(p.int32ToZigzag(value))
284 return NewTProtocolException(err)
285}
286
287// Write an i64 as a zigzag varint.
288func (p *TCompactProtocol) WriteI64(value int64) error {
289 _, err := p.writeVarint64(p.int64ToZigzag(value))
290 return NewTProtocolException(err)
291}
292
293// Write a double to the wire as 8 bytes.
294func (p *TCompactProtocol) WriteDouble(value float64) error {
295 buf := p.buffer[0:8]
296 binary.LittleEndian.PutUint64(buf, math.Float64bits(value))
297 _, err := p.trans.Write(buf)
298 return NewTProtocolException(err)
299}
300
301// Write a string to the wire with a varint size preceding.
302func (p *TCompactProtocol) WriteString(value string) error {
303 _, e := p.writeVarint32(int32(len(value)))
304 if e != nil {
305 return NewTProtocolException(e)
306 }
307 if len(value) > 0 {
308 }
309 _, e = p.trans.WriteString(value)
310 return e
311}
312
313// Write a byte array, using a varint for the size.
314func (p *TCompactProtocol) WriteBinary(bin []byte) error {
315 _, e := p.writeVarint32(int32(len(bin)))
316 if e != nil {
317 return NewTProtocolException(e)
318 }
319 if len(bin) > 0 {
320 _, e = p.trans.Write(bin)
321 return NewTProtocolException(e)
322 }
323 return nil
324}
325
326//
327// Reading methods.
328//
329
330// Read a message header.
331func (p *TCompactProtocol) ReadMessageBegin() (name string, typeId TMessageType, seqId int32, err error) {
332
333 protocolId, err := p.readByteDirect()
334 if err != nil {
335 return
336 }
337
338 if protocolId != COMPACT_PROTOCOL_ID {
339 e := fmt.Errorf("Expected protocol id %02x but got %02x", COMPACT_PROTOCOL_ID, protocolId)
340 return "", typeId, seqId, NewTProtocolExceptionWithType(BAD_VERSION, e)
341 }
342
343 versionAndType, err := p.readByteDirect()
344 if err != nil {
345 return
346 }
347
348 version := versionAndType & COMPACT_VERSION_MASK
349 typeId = TMessageType((versionAndType >> COMPACT_TYPE_SHIFT_AMOUNT) & COMPACT_TYPE_BITS)
350 if version != COMPACT_VERSION {
351 e := fmt.Errorf("Expected version %02x but got %02x", COMPACT_VERSION, version)
352 err = NewTProtocolExceptionWithType(BAD_VERSION, e)
353 return
354 }
355 seqId, e := p.readVarint32()
356 if e != nil {
357 err = NewTProtocolException(e)
358 return
359 }
360 name, err = p.ReadString()
361 return
362}
363
364func (p *TCompactProtocol) ReadMessageEnd() error { return nil }
365
366// Read a struct begin. There's nothing on the wire for this, but it is our
367// opportunity to push a new struct begin marker onto the field stack.
368func (p *TCompactProtocol) ReadStructBegin() (name string, err error) {
369 p.lastField = append(p.lastField, p.lastFieldId)
370 p.lastFieldId = 0
371 return
372}
373
374// Doesn't actually consume any wire data, just removes the last field for
375// this struct from the field stack.
376func (p *TCompactProtocol) ReadStructEnd() error {
377 // consume the last field we read off the wire.
378 p.lastFieldId = p.lastField[len(p.lastField)-1]
379 p.lastField = p.lastField[:len(p.lastField)-1]
380 return nil
381}
382
383// Read a field header off the wire.
384func (p *TCompactProtocol) ReadFieldBegin() (name string, typeId TType, id int16, err error) {
385 t, err := p.readByteDirect()
386 if err != nil {
387 return
388 }
389
390 // if it's a stop, then we can return immediately, as the struct is over.
391 if (t & 0x0f) == STOP {
392 return "", STOP, 0, nil
393 }
394
395 // mask off the 4 MSB of the type header. it could contain a field id delta.
396 modifier := int16((t & 0xf0) >> 4)
397 if modifier == 0 {
398 // not a delta. look ahead for the zigzag varint field id.
399 id, err = p.ReadI16()
400 if err != nil {
401 return
402 }
403 } else {
404 // has a delta. add the delta to the last read field id.
405 id = int16(p.lastFieldId) + modifier
406 }
407 typeId, e := p.getTType(tCompactType(t & 0x0f))
408 if e != nil {
409 err = NewTProtocolException(e)
410 return
411 }
412
413 // if this happens to be a boolean field, the value is encoded in the type
414 if p.isBoolType(t) {
415 // save the boolean value in a special instance variable.
416 p.boolValue = (byte(t)&0x0f == COMPACT_BOOLEAN_TRUE)
417 p.boolValueIsNotNull = true
418 }
419
420 // push the new field onto the field stack so we can keep the deltas going.
421 p.lastFieldId = int(id)
422 return
423}
424
425func (p *TCompactProtocol) ReadFieldEnd() error { return nil }
426
427// Read a map header off the wire. If the size is zero, skip reading the key
428// and value type. This means that 0-length maps will yield TMaps without the
429// "correct" types.
430func (p *TCompactProtocol) ReadMapBegin() (keyType TType, valueType TType, size int, err error) {
431 size32, e := p.readVarint32()
432 if e != nil {
433 err = NewTProtocolException(e)
434 return
435 }
436 if size32 < 0 {
437 err = invalidDataLength
438 return
439 }
440 size = int(size32)
441
442 keyAndValueType := byte(STOP)
443 if size != 0 {
444 keyAndValueType, err = p.readByteDirect()
445 if err != nil {
446 return
447 }
448 }
449 keyType, _ = p.getTType(tCompactType(keyAndValueType >> 4))
450 valueType, _ = p.getTType(tCompactType(keyAndValueType & 0xf))
451 return
452}
453
454func (p *TCompactProtocol) ReadMapEnd() error { return nil }
455
456// Read a list header off the wire. If the list size is 0-14, the size will
457// be packed into the element type header. If it's a longer list, the 4 MSB
458// of the element type header will be 0xF, and a varint will follow with the
459// true size.
460func (p *TCompactProtocol) ReadListBegin() (elemType TType, size int, err error) {
461 size_and_type, err := p.readByteDirect()
462 if err != nil {
463 return
464 }
465 size = int((size_and_type >> 4) & 0x0f)
466 if size == 15 {
467 size2, e := p.readVarint32()
468 if e != nil {
469 err = NewTProtocolException(e)
470 return
471 }
472 if size2 < 0 {
473 err = invalidDataLength
474 return
475 }
476 size = int(size2)
477 }
478 elemType, e := p.getTType(tCompactType(size_and_type))
479 if e != nil {
480 err = NewTProtocolException(e)
481 return
482 }
483 return
484}
485
486func (p *TCompactProtocol) ReadListEnd() error { return nil }
487
488// Read a set header off the wire. If the set size is 0-14, the size will
489// be packed into the element type header. If it's a longer set, the 4 MSB
490// of the element type header will be 0xF, and a varint will follow with the
491// true size.
492func (p *TCompactProtocol) ReadSetBegin() (elemType TType, size int, err error) {
493 return p.ReadListBegin()
494}
495
496func (p *TCompactProtocol) ReadSetEnd() error { return nil }
497
498// Read a boolean off the wire. If this is a boolean field, the value should
499// already have been read during readFieldBegin, so we'll just consume the
500// pre-stored value. Otherwise, read a byte.
501func (p *TCompactProtocol) ReadBool() (value bool, err error) {
502 if p.boolValueIsNotNull {
503 p.boolValueIsNotNull = false
504 return p.boolValue, nil
505 }
506 v, err := p.readByteDirect()
507 return v == COMPACT_BOOLEAN_TRUE, err
508}
509
510// Read a single byte off the wire. Nothing interesting here.
511func (p *TCompactProtocol) ReadByte() (int8, error) {
512 v, err := p.readByteDirect()
513 if err != nil {
514 return 0, NewTProtocolException(err)
515 }
516 return int8(v), err
517}
518
519// Read an i16 from the wire as a zigzag varint.
520func (p *TCompactProtocol) ReadI16() (value int16, err error) {
521 v, err := p.ReadI32()
522 return int16(v), err
523}
524
525// Read an i32 from the wire as a zigzag varint.
526func (p *TCompactProtocol) ReadI32() (value int32, err error) {
527 v, e := p.readVarint32()
528 if e != nil {
529 return 0, NewTProtocolException(e)
530 }
531 value = p.zigzagToInt32(v)
532 return value, nil
533}
534
535// Read an i64 from the wire as a zigzag varint.
536func (p *TCompactProtocol) ReadI64() (value int64, err error) {
537 v, e := p.readVarint64()
538 if e != nil {
539 return 0, NewTProtocolException(e)
540 }
541 value = p.zigzagToInt64(v)
542 return value, nil
543}
544
545// No magic here - just read a double off the wire.
546func (p *TCompactProtocol) ReadDouble() (value float64, err error) {
547 longBits := p.buffer[0:8]
548 _, e := io.ReadFull(p.trans, longBits)
549 if e != nil {
550 return 0.0, NewTProtocolException(e)
551 }
552 return math.Float64frombits(p.bytesToUint64(longBits)), nil
553}
554
555// Reads a []byte (via readBinary), and then UTF-8 decodes it.
556func (p *TCompactProtocol) ReadString() (value string, err error) {
557 length, e := p.readVarint32()
558 if e != nil {
559 return "", NewTProtocolException(e)
560 }
561 if length < 0 {
562 return "", invalidDataLength
563 }
564 if uint64(length) > p.trans.RemainingBytes() {
565 return "", invalidDataLength
566 }
567
568 if length == 0 {
569 return "", nil
570 }
571 var buf []byte
572 if length <= int32(len(p.buffer)) {
573 buf = p.buffer[0:length]
574 } else {
575 buf = make([]byte, length)
576 }
577 _, e = io.ReadFull(p.trans, buf)
578 return string(buf), NewTProtocolException(e)
579}
580
581// Read a []byte from the wire.
582func (p *TCompactProtocol) ReadBinary() (value []byte, err error) {
583 length, e := p.readVarint32()
584 if e != nil {
585 return nil, NewTProtocolException(e)
586 }
587 if length == 0 {
588 return []byte{}, nil
589 }
590 if length < 0 {
591 return nil, invalidDataLength
592 }
593 if uint64(length) > p.trans.RemainingBytes() {
594 return nil, invalidDataLength
595 }
596
597 buf := make([]byte, length)
598 _, e = io.ReadFull(p.trans, buf)
599 return buf, NewTProtocolException(e)
600}
601
602func (p *TCompactProtocol) Flush() (err error) {
603 return NewTProtocolException(p.trans.Flush())
604}
605
606func (p *TCompactProtocol) Skip(fieldType TType) (err error) {
607 return SkipDefaultDepth(p, fieldType)
608}
609
610func (p *TCompactProtocol) Transport() TTransport {
611 return p.origTransport
612}
613
614//
615// Internal writing methods
616//
617
618// Abstract method for writing the start of lists and sets. List and sets on
619// the wire differ only by the type indicator.
620func (p *TCompactProtocol) writeCollectionBegin(elemType TType, size int) (int, error) {
621 if size <= 14 {
622 return 1, p.writeByteDirect(byte(int32(size<<4) | int32(p.getCompactType(elemType))))
623 }
624 err := p.writeByteDirect(0xf0 | byte(p.getCompactType(elemType)))
625 if err != nil {
626 return 0, err
627 }
628 m, err := p.writeVarint32(int32(size))
629 return 1 + m, err
630}
631
632// Write an i32 as a varint. Results in 1-5 bytes on the wire.
633// TODO(pomack): make a permanent buffer like writeVarint64?
634func (p *TCompactProtocol) writeVarint32(n int32) (int, error) {
635 i32buf := p.buffer[0:5]
636 idx := 0
637 for {
638 if (n & ^0x7F) == 0 {
639 i32buf[idx] = byte(n)
640 idx++
641 // p.writeByteDirect(byte(n));
642 break
643 // return;
644 } else {
645 i32buf[idx] = byte((n & 0x7F) | 0x80)
646 idx++
647 // p.writeByteDirect(byte(((n & 0x7F) | 0x80)));
648 u := uint32(n)
649 n = int32(u >> 7)
650 }
651 }
652 return p.trans.Write(i32buf[0:idx])
653}
654
655// Write an i64 as a varint. Results in 1-10 bytes on the wire.
656func (p *TCompactProtocol) writeVarint64(n int64) (int, error) {
657 varint64out := p.buffer[0:10]
658 idx := 0
659 for {
660 if (n & ^0x7F) == 0 {
661 varint64out[idx] = byte(n)
662 idx++
663 break
664 } else {
665 varint64out[idx] = byte((n & 0x7F) | 0x80)
666 idx++
667 u := uint64(n)
668 n = int64(u >> 7)
669 }
670 }
671 return p.trans.Write(varint64out[0:idx])
672}
673
674// Convert l into a zigzag long. This allows negative numbers to be
675// represented compactly as a varint.
676func (p *TCompactProtocol) int64ToZigzag(l int64) int64 {
677 return (l << 1) ^ (l >> 63)
678}
679
680// Convert l into a zigzag long. This allows negative numbers to be
681// represented compactly as a varint.
682func (p *TCompactProtocol) int32ToZigzag(n int32) int32 {
683 return (n << 1) ^ (n >> 31)
684}
685
686func (p *TCompactProtocol) fixedUint64ToBytes(n uint64, buf []byte) {
687 binary.LittleEndian.PutUint64(buf, n)
688}
689
690func (p *TCompactProtocol) fixedInt64ToBytes(n int64, buf []byte) {
691 binary.LittleEndian.PutUint64(buf, uint64(n))
692}
693
694// Writes a byte without any possibility of all that field header nonsense.
695// Used internally by other writing methods that know they need to write a byte.
696func (p *TCompactProtocol) writeByteDirect(b byte) error {
697 return p.trans.WriteByte(b)
698}
699
700// Writes a byte without any possibility of all that field header nonsense.
701func (p *TCompactProtocol) writeIntAsByteDirect(n int) (int, error) {
702 return 1, p.writeByteDirect(byte(n))
703}
704
705//
706// Internal reading methods
707//
708
709// Read an i32 from the wire as a varint. The MSB of each byte is set
710// if there is another byte to follow. This can read up to 5 bytes.
711func (p *TCompactProtocol) readVarint32() (int32, error) {
712 // if the wire contains the right stuff, this will just truncate the i64 we
713 // read and get us the right sign.
714 v, err := p.readVarint64()
715 return int32(v), err
716}
717
718// Read an i64 from the wire as a proper varint. The MSB of each byte is set
719// if there is another byte to follow. This can read up to 10 bytes.
720func (p *TCompactProtocol) readVarint64() (int64, error) {
721 shift := uint(0)
722 result := int64(0)
723 for {
724 b, err := p.readByteDirect()
725 if err != nil {
726 return 0, err
727 }
728 result |= int64(b&0x7f) << shift
729 if (b & 0x80) != 0x80 {
730 break
731 }
732 shift += 7
733 }
734 return result, nil
735}
736
737// Read a byte, unlike ReadByte that reads Thrift-byte that is i8.
738func (p *TCompactProtocol) readByteDirect() (byte, error) {
739 return p.trans.ReadByte()
740}
741
742//
743// encoding helpers
744//
745
746// Convert from zigzag int to int.
747func (p *TCompactProtocol) zigzagToInt32(n int32) int32 {
748 u := uint32(n)
749 return int32(u>>1) ^ -(n & 1)
750}
751
752// Convert from zigzag long to long.
753func (p *TCompactProtocol) zigzagToInt64(n int64) int64 {
754 u := uint64(n)
755 return int64(u>>1) ^ -(n & 1)
756}
757
758// Note that it's important that the mask bytes are long literals,
759// otherwise they'll default to ints, and when you shift an int left 56 bits,
760// you just get a messed up int.
761func (p *TCompactProtocol) bytesToInt64(b []byte) int64 {
762 return int64(binary.LittleEndian.Uint64(b))
763}
764
765// Note that it's important that the mask bytes are long literals,
766// otherwise they'll default to ints, and when you shift an int left 56 bits,
767// you just get a messed up int.
768func (p *TCompactProtocol) bytesToUint64(b []byte) uint64 {
769 return binary.LittleEndian.Uint64(b)
770}
771
772//
773// type testing and converting
774//
775
776func (p *TCompactProtocol) isBoolType(b byte) bool {
777 return (b&0x0f) == COMPACT_BOOLEAN_TRUE || (b&0x0f) == COMPACT_BOOLEAN_FALSE
778}
779
780// Given a tCompactType constant, convert it to its corresponding
781// TType value.
782func (p *TCompactProtocol) getTType(t tCompactType) (TType, error) {
783 switch byte(t) & 0x0f {
784 case STOP:
785 return STOP, nil
786 case COMPACT_BOOLEAN_FALSE, COMPACT_BOOLEAN_TRUE:
787 return BOOL, nil
788 case COMPACT_BYTE:
789 return BYTE, nil
790 case COMPACT_I16:
791 return I16, nil
792 case COMPACT_I32:
793 return I32, nil
794 case COMPACT_I64:
795 return I64, nil
796 case COMPACT_DOUBLE:
797 return DOUBLE, nil
798 case COMPACT_BINARY:
799 return STRING, nil
800 case COMPACT_LIST:
801 return LIST, nil
802 case COMPACT_SET:
803 return SET, nil
804 case COMPACT_MAP:
805 return MAP, nil
806 case COMPACT_STRUCT:
807 return STRUCT, nil
808 }
809 return STOP, TException(fmt.Errorf("don't know what type: %d", t&0x0f))
810}
811
812// Given a TType value, find the appropriate TCompactProtocol.Types constant.
813func (p *TCompactProtocol) getCompactType(t TType) tCompactType {
814 return ttypeToCompactType[t]
815}