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	"errors"
25	"fmt"
26)
27
28const (
29	VERSION_MASK = 0xffff0000
30	VERSION_1    = 0x80010000
31)
32
33type TProtocol interface {
34	WriteMessageBegin(ctx context.Context, name string, typeId TMessageType, seqid int32) error
35	WriteMessageEnd(ctx context.Context) error
36	WriteStructBegin(ctx context.Context, name string) error
37	WriteStructEnd(ctx context.Context) error
38	WriteFieldBegin(ctx context.Context, name string, typeId TType, id int16) error
39	WriteFieldEnd(ctx context.Context) error
40	WriteFieldStop(ctx context.Context) error
41	WriteMapBegin(ctx context.Context, keyType TType, valueType TType, size int) error
42	WriteMapEnd(ctx context.Context) error
43	WriteListBegin(ctx context.Context, elemType TType, size int) error
44	WriteListEnd(ctx context.Context) error
45	WriteSetBegin(ctx context.Context, elemType TType, size int) error
46	WriteSetEnd(ctx context.Context) error
47	WriteBool(ctx context.Context, value bool) error
48	WriteByte(ctx context.Context, value int8) error
49	WriteI16(ctx context.Context, value int16) error
50	WriteI32(ctx context.Context, value int32) error
51	WriteI64(ctx context.Context, value int64) error
52	WriteDouble(ctx context.Context, value float64) error
53	WriteString(ctx context.Context, value string) error
54	WriteBinary(ctx context.Context, value []byte) error
55
56	ReadMessageBegin(ctx context.Context) (name string, typeId TMessageType, seqid int32, err error)
57	ReadMessageEnd(ctx context.Context) error
58	ReadStructBegin(ctx context.Context) (name string, err error)
59	ReadStructEnd(ctx context.Context) error
60	ReadFieldBegin(ctx context.Context) (name string, typeId TType, id int16, err error)
61	ReadFieldEnd(ctx context.Context) error
62	ReadMapBegin(ctx context.Context) (keyType TType, valueType TType, size int, err error)
63	ReadMapEnd(ctx context.Context) error
64	ReadListBegin(ctx context.Context) (elemType TType, size int, err error)
65	ReadListEnd(ctx context.Context) error
66	ReadSetBegin(ctx context.Context) (elemType TType, size int, err error)
67	ReadSetEnd(ctx context.Context) error
68	ReadBool(ctx context.Context) (value bool, err error)
69	ReadByte(ctx context.Context) (value int8, err error)
70	ReadI16(ctx context.Context) (value int16, err error)
71	ReadI32(ctx context.Context) (value int32, err error)
72	ReadI64(ctx context.Context) (value int64, err error)
73	ReadDouble(ctx context.Context) (value float64, err error)
74	ReadString(ctx context.Context) (value string, err error)
75	ReadBinary(ctx context.Context) (value []byte, err error)
76
77	Skip(ctx context.Context, fieldType TType) (err error)
78	Flush(ctx context.Context) (err error)
79
80	Transport() TTransport
81}
82
83// The maximum recursive depth the skip() function will traverse
84const DEFAULT_RECURSION_DEPTH = 64
85
86// Skips over the next data element from the provided input TProtocol object.
87func SkipDefaultDepth(ctx context.Context, prot TProtocol, typeId TType) (err error) {
88	return Skip(ctx, prot, typeId, DEFAULT_RECURSION_DEPTH)
89}
90
91// Skips over the next data element from the provided input TProtocol object.
92func Skip(ctx context.Context, self TProtocol, fieldType TType, maxDepth int) (err error) {
93
94	if maxDepth <= 0 {
95		return NewTProtocolExceptionWithType(DEPTH_LIMIT, errors.New("Depth limit exceeded"))
96	}
97
98	switch fieldType {
99	case BOOL:
100		_, err = self.ReadBool(ctx)
101		return
102	case BYTE:
103		_, err = self.ReadByte(ctx)
104		return
105	case I16:
106		_, err = self.ReadI16(ctx)
107		return
108	case I32:
109		_, err = self.ReadI32(ctx)
110		return
111	case I64:
112		_, err = self.ReadI64(ctx)
113		return
114	case DOUBLE:
115		_, err = self.ReadDouble(ctx)
116		return
117	case STRING:
118		_, err = self.ReadString(ctx)
119		return
120	case STRUCT:
121		if _, err = self.ReadStructBegin(ctx); err != nil {
122			return err
123		}
124		for {
125			_, typeId, _, _ := self.ReadFieldBegin(ctx)
126			if typeId == STOP {
127				break
128			}
129			err := Skip(ctx, self, typeId, maxDepth-1)
130			if err != nil {
131				return err
132			}
133			self.ReadFieldEnd(ctx)
134		}
135		return self.ReadStructEnd(ctx)
136	case MAP:
137		keyType, valueType, size, err := self.ReadMapBegin(ctx)
138		if err != nil {
139			return err
140		}
141		for i := 0; i < size; i++ {
142			err := Skip(ctx, self, keyType, maxDepth-1)
143			if err != nil {
144				return err
145			}
146			self.Skip(ctx, valueType)
147		}
148		return self.ReadMapEnd(ctx)
149	case SET:
150		elemType, size, err := self.ReadSetBegin(ctx)
151		if err != nil {
152			return err
153		}
154		for i := 0; i < size; i++ {
155			err := Skip(ctx, self, elemType, maxDepth-1)
156			if err != nil {
157				return err
158			}
159		}
160		return self.ReadSetEnd(ctx)
161	case LIST:
162		elemType, size, err := self.ReadListBegin(ctx)
163		if err != nil {
164			return err
165		}
166		for i := 0; i < size; i++ {
167			err := Skip(ctx, self, elemType, maxDepth-1)
168			if err != nil {
169				return err
170			}
171		}
172		return self.ReadListEnd(ctx)
173	default:
174		return NewTProtocolExceptionWithType(INVALID_DATA, errors.New(fmt.Sprintf("Unknown data type %d", fieldType)))
175	}
176	return nil
177}
178