]> git.proxmox.com Git - ceph.git/blame - ceph/src/jaegertracing/thrift/lib/java/src/org/apache/thrift/protocol/TProtocolUtil.java
buildsys: switch source download to quincy
[ceph.git] / ceph / src / jaegertracing / thrift / lib / java / src / org / apache / thrift / protocol / TProtocolUtil.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
20package org.apache.thrift.protocol;
21
22import org.apache.thrift.TException;
23
24/**
25 * Utility class with static methods for interacting with protocol data
26 * streams.
27 *
28 */
29public class TProtocolUtil {
30
31 /**
32 * The maximum recursive depth the skip() function will traverse before
33 * throwing a TException.
34 */
35 private static int maxSkipDepth = Integer.MAX_VALUE;
36
37 /**
38 * Specifies the maximum recursive depth that the skip function will
39 * traverse before throwing a TException. This is a global setting, so
40 * any call to skip in this JVM will enforce this value.
41 *
42 * @param depth the maximum recursive depth. A value of 2 would allow
43 * the skip function to skip a structure or collection with basic children,
44 * but it would not permit skipping a struct that had a field containing
45 * a child struct. A value of 1 would only allow skipping of simple
46 * types and empty structs/collections.
47 */
48 public static void setMaxSkipDepth(int depth) {
49 maxSkipDepth = depth;
50 }
51
52 /**
53 * Skips over the next data element from the provided input TProtocol object.
54 *
55 * @param prot the protocol object to read from
56 * @param type the next value will be interpreted as this TType value.
57 */
58 public static void skip(TProtocol prot, byte type)
59 throws TException {
60 skip(prot, type, maxSkipDepth);
61 }
62
63 /**
64 * Skips over the next data element from the provided input TProtocol object.
65 *
66 * @param prot the protocol object to read from
67 * @param type the next value will be interpreted as this TType value.
68 * @param maxDepth this function will only skip complex objects to this
69 * recursive depth, to prevent Java stack overflow.
70 */
71 public static void skip(TProtocol prot, byte type, int maxDepth)
72 throws TException {
73 if (maxDepth <= 0) {
74 throw new TException("Maximum skip depth exceeded");
75 }
76 switch (type) {
77 case TType.BOOL:
78 prot.readBool();
79 break;
80
81 case TType.BYTE:
82 prot.readByte();
83 break;
84
85 case TType.I16:
86 prot.readI16();
87 break;
88
89 case TType.I32:
90 prot.readI32();
91 break;
92
93 case TType.I64:
94 prot.readI64();
95 break;
96
97 case TType.DOUBLE:
98 prot.readDouble();
99 break;
100
101 case TType.STRING:
102 prot.readBinary();
103 break;
104
105 case TType.STRUCT:
106 prot.readStructBegin();
107 while (true) {
108 TField field = prot.readFieldBegin();
109 if (field.type == TType.STOP) {
110 break;
111 }
112 skip(prot, field.type, maxDepth - 1);
113 prot.readFieldEnd();
114 }
115 prot.readStructEnd();
116 break;
117
118 case TType.MAP:
119 TMap map = prot.readMapBegin();
120 for (int i = 0; i < map.size; i++) {
121 skip(prot, map.keyType, maxDepth - 1);
122 skip(prot, map.valueType, maxDepth - 1);
123 }
124 prot.readMapEnd();
125 break;
126
127 case TType.SET:
128 TSet set = prot.readSetBegin();
129 for (int i = 0; i < set.size; i++) {
130 skip(prot, set.elemType, maxDepth - 1);
131 }
132 prot.readSetEnd();
133 break;
134
135 case TType.LIST:
136 TList list = prot.readListBegin();
137 for (int i = 0; i < list.size; i++) {
138 skip(prot, list.elemType, maxDepth - 1);
139 }
140 prot.readListEnd();
141 break;
142
143 default:
144 throw new TProtocolException(TProtocolException.INVALID_DATA,
145 "Unrecognized type " + type);
146 }
147 }
148
149 /**
150 * Attempt to determine the protocol used to serialize some data.
151 *
152 * The guess is based on known specificities of supported protocols.
153 * In some cases, no guess can be done, in that case we return the
154 * fallback TProtocolFactory.
155 * To be certain to correctly detect the protocol, the first encoded
156 * field should have a field id &lt; 256
157 *
158 * @param data The serialized data to guess the protocol for.
159 * @param fallback The TProtocol to return if no guess can be made.
160 * @return a Class implementing TProtocolFactory which can be used to create a deserializer.
161 */
162 public static TProtocolFactory guessProtocolFactory(byte[] data, TProtocolFactory fallback) {
163 //
164 // If the first and last bytes are opening/closing curly braces we guess the protocol as
165 // being TJSONProtocol.
166 // It could not be a TCompactBinary encoding for a field of type 0xb (Map)
167 // with delta id 7 as the last byte for TCompactBinary is always 0.
168 //
169
170 if ('{' == data[0] && '}' == data[data.length - 1]) {
171 return new TJSONProtocol.Factory();
172 }
173
174 //
175 // If the last byte is not 0, then it cannot be TCompactProtocol, it must be
176 // TBinaryProtocol.
177 //
178
179 if (data[data.length - 1] != 0) {
180 return new TBinaryProtocol.Factory();
181 }
182
183 //
184 // A first byte of value > 16 indicates TCompactProtocol was used, and the first byte
185 // encodes a delta field id (id <= 15) and a field type.
186 //
187
188 if (data[0] > 0x10) {
189 return new TCompactProtocol.Factory();
190 }
191
192 //
193 // If the second byte is 0 then it is a field id < 256 encoded by TBinaryProtocol.
194 // It cannot possibly be TCompactProtocol since a value of 0 would imply a field id
195 // of 0 as the zig zag varint encoding would end.
196 //
197
198 if (data.length > 1 && 0 == data[1]) {
199 return new TBinaryProtocol.Factory();
200 }
201
202 //
203 // If bit 7 of the first byte of the field id is set then we have two choices:
204 // 1. A field id > 63 was encoded with TCompactProtocol.
205 // 2. A field id > 0x7fff (32767) was encoded with TBinaryProtocol and the last byte of the
206 // serialized data is 0.
207 // Option 2 is impossible since field ids are short and thus limited to 32767.
208 //
209
210 if (data.length > 1 && (data[1] & 0x80) != 0) {
211 return new TCompactProtocol.Factory();
212 }
213
214 //
215 // The remaining case is either a field id <= 63 encoded as TCompactProtocol,
216 // one >= 256 encoded with TBinaryProtocol with a last byte at 0, or an empty structure.
217 // As we cannot really decide, we return the fallback protocol.
218 //
219 return fallback;
220 }
221}