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