blob: 9b0ebb2a78a516f8070f76ab3302a6e1fdf6a9fd [file] [log] [blame]
Jens Geyerdc799ca2015-04-27 22:56:54 +02001/*
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#import "TCompactProtocol.h"
Jens Geyer56e5b9b2015-10-09 22:01:55 +020021#import "TProtocolError.h"
Jens Geyerdc799ca2015-04-27 22:56:54 +020022
Jens Geyer56e5b9b2015-10-09 22:01:55 +020023static const UInt8 COMPACT_PROTOCOL_ID = 0x82;
24static const UInt8 COMPACT_VERSION = 1;
25static const UInt8 COMPACT_VERSION_MASK = 0x1F; // 0001 1111
26static const UInt8 COMPACT_TYPE_MASK = 0xE0; // 1110 0000
27static const UInt8 COMPACT_TYPE_BITS = 0x07; // 0000 0111
Jens Geyerdc799ca2015-04-27 22:56:54 +020028static const int COMPACT_TYPE_SHIFT_AMOUNT = 5;
29
30enum {
31 TCType_STOP = 0x00,
32 TCType_BOOLEAN_TRUE = 0x01,
33 TCType_BOOLEAN_FALSE = 0x02,
34 TCType_BYTE = 0x03,
35 TCType_I16 = 0x04,
36 TCType_I32 = 0x05,
37 TCType_I64 = 0x06,
38 TCType_DOUBLE = 0x07,
39 TCType_BINARY = 0x08,
40 TCType_LIST = 0x09,
41 TCType_SET = 0x0A,
42 TCType_MAP = 0x0B,
43 TCType_STRUCT = 0x0C,
44};
45
46@implementation TCompactProtocolFactory
47
Jens Geyer56e5b9b2015-10-09 22:01:55 +020048+(TCompactProtocolFactory *) sharedFactory
Jens Geyerdc799ca2015-04-27 22:56:54 +020049{
Jens Geyer56e5b9b2015-10-09 22:01:55 +020050 static TCompactProtocolFactory *gSharedFactory = nil;
Jens Geyerdc799ca2015-04-27 22:56:54 +020051 if (gSharedFactory == nil) {
52 gSharedFactory = [[TCompactProtocolFactory alloc] init];
53 }
Jens Geyer56e5b9b2015-10-09 22:01:55 +020054
Jens Geyerdc799ca2015-04-27 22:56:54 +020055 return gSharedFactory;
56}
57
Jens Geyer56e5b9b2015-10-09 22:01:55 +020058-(NSString *) protocolName
Jens Geyerdc799ca2015-04-27 22:56:54 +020059{
Jens Geyer56e5b9b2015-10-09 22:01:55 +020060 return @"compact";
61}
62
63-(TCompactProtocol *) newProtocolOnTransport:(id <TTransport>)transport
64{
65 return [[TCompactProtocol alloc] initWithTransport:transport];
Jens Geyerdc799ca2015-04-27 22:56:54 +020066}
67
68@end
69
Jens Geyerdc799ca2015-04-27 22:56:54 +020070
Jens Geyer56e5b9b2015-10-09 22:01:55 +020071@interface TCompactProtocol ()
72
73@property(strong, nonatomic) id <TTransport> transport;
74
75@property(strong, nonatomic) NSMutableArray *lastField;
76@property(assign, nonatomic) short lastFieldId;
77
78@property(strong, nonatomic) NSString *boolFieldName;
79@property(strong, nonatomic) NSNumber *boolFieldType;
80@property(strong, nonatomic) NSNumber *boolFieldId;
81@property(strong, nonatomic) NSNumber *booleanValue;
82
83@property(strong, nonatomic) NSString *currentMessageName;
84
85@end
86
87
88@implementation TCompactProtocol
89
90-(id) init
Jens Geyerdc799ca2015-04-27 22:56:54 +020091{
92 self = [super init];
Jens Geyer56e5b9b2015-10-09 22:01:55 +020093
Jens Geyerdc799ca2015-04-27 22:56:54 +020094 if (self != nil) {
Jens Geyer56e5b9b2015-10-09 22:01:55 +020095 _lastField = [[NSMutableArray alloc] init];
Jens Geyerdc799ca2015-04-27 22:56:54 +020096 }
Jens Geyer56e5b9b2015-10-09 22:01:55 +020097
Jens Geyerdc799ca2015-04-27 22:56:54 +020098 return self;
99}
100
Jens Geyer56e5b9b2015-10-09 22:01:55 +0200101-(id) initWithTransport:(id <TTransport>)aTransport
Jens Geyerdc799ca2015-04-27 22:56:54 +0200102{
103 self = [self init];
Jens Geyer56e5b9b2015-10-09 22:01:55 +0200104
Jens Geyerdc799ca2015-04-27 22:56:54 +0200105 if (self != nil) {
Jens Geyer56e5b9b2015-10-09 22:01:55 +0200106 _transport = aTransport;
Jens Geyerdc799ca2015-04-27 22:56:54 +0200107 }
Jens Geyer56e5b9b2015-10-09 22:01:55 +0200108
Jens Geyerdc799ca2015-04-27 22:56:54 +0200109 return self;
110}
111
Jens Geyer56e5b9b2015-10-09 22:01:55 +0200112-(id <TTransport>) transport
Jens Geyerdc799ca2015-04-27 22:56:54 +0200113{
Jens Geyer56e5b9b2015-10-09 22:01:55 +0200114 return _transport;
Jens Geyerdc799ca2015-04-27 22:56:54 +0200115}
116
Jens Geyer56e5b9b2015-10-09 22:01:55 +0200117-(BOOL) writeByteDirect:(UInt8)n error:(NSError *__autoreleasing *)error
Jens Geyerdc799ca2015-04-27 22:56:54 +0200118{
Jens Geyer56e5b9b2015-10-09 22:01:55 +0200119 if (![_transport write:(UInt8 *)&n offset:0 length:1 error:error]) {
120 PROTOCOL_TRANSPORT_ERROR(NO, error, @"Transport write failed");
121 }
122 return YES;
Jens Geyerdc799ca2015-04-27 22:56:54 +0200123}
124
Jens Geyer56e5b9b2015-10-09 22:01:55 +0200125-(BOOL) writeVarint32:(UInt32)n error:(NSError *__autoreleasing *)error
Jens Geyerdc799ca2015-04-27 22:56:54 +0200126{
Jens Geyer56e5b9b2015-10-09 22:01:55 +0200127 UInt8 i32buf[5] = {0};
128 UInt32 idx = 0;
Jens Geyerdc799ca2015-04-27 22:56:54 +0200129
Jens Geyerdc799ca2015-04-27 22:56:54 +0200130 while (true) {
131 if ((n & ~0x7F) == 0) {
Jens Geyer56e5b9b2015-10-09 22:01:55 +0200132 i32buf[idx++] = (UInt8)n;
Jens Geyerdc799ca2015-04-27 22:56:54 +0200133 break;
Jens Geyer56e5b9b2015-10-09 22:01:55 +0200134 }
135 else {
136 i32buf[idx++] = (UInt8)((n & 0x7F) | 0x80);
Jens Geyerdc799ca2015-04-27 22:56:54 +0200137 n >>= 7;
138 }
139 }
Jens Geyer56e5b9b2015-10-09 22:01:55 +0200140
141 if (![_transport write:i32buf offset:0 length:idx error:error]) {
142 PROTOCOL_TRANSPORT_ERROR(NO, error, @"Transport write failed");
143 }
144
145 return YES;
Jens Geyerdc799ca2015-04-27 22:56:54 +0200146}
147
Jens Geyer56e5b9b2015-10-09 22:01:55 +0200148-(BOOL) writeMessageBeginWithName:(NSString *)name
149 type:(SInt32)messageType
150 sequenceID:(SInt32)sequenceID
151 error:(NSError *__autoreleasing *)error
Jens Geyerdc799ca2015-04-27 22:56:54 +0200152{
Jens Geyer56e5b9b2015-10-09 22:01:55 +0200153 if (![self writeByteDirect:COMPACT_PROTOCOL_ID error:error]) {
154 return NO;
155 }
156 if (![self writeByteDirect:(UInt8)((COMPACT_VERSION & COMPACT_VERSION_MASK) |
157 ((((UInt32)messageType) << COMPACT_TYPE_SHIFT_AMOUNT) & COMPACT_TYPE_MASK)) error:error])
158 {
159 return NO;
160 }
161 if (![self writeVarint32:(UInt32)sequenceID error:error]) {
162 return NO;
163 }
164 if (![self writeString:name error:error]) {
165 return NO;
166 }
167
168 _currentMessageName = name;
169
170 return YES;
Jens Geyerdc799ca2015-04-27 22:56:54 +0200171}
172
Jens Geyer56e5b9b2015-10-09 22:01:55 +0200173-(BOOL) writeStructBeginWithName:(NSString *)name error:(NSError *__autoreleasing *)error
Jens Geyerdc799ca2015-04-27 22:56:54 +0200174{
Jens Geyer56e5b9b2015-10-09 22:01:55 +0200175 [_lastField addObject:@(_lastFieldId)];
176 _lastFieldId = 0;
177 return YES;
Jens Geyerdc799ca2015-04-27 22:56:54 +0200178}
179
Jens Geyer56e5b9b2015-10-09 22:01:55 +0200180-(BOOL) writeStructEnd:(NSError *__autoreleasing *)error
Jens Geyerdc799ca2015-04-27 22:56:54 +0200181{
Jens Geyer56e5b9b2015-10-09 22:01:55 +0200182 _lastFieldId = [_lastField.lastObject shortValue];
183 [_lastField removeLastObject];
184 return YES;
Jens Geyerdc799ca2015-04-27 22:56:54 +0200185}
186
Jens Geyer56e5b9b2015-10-09 22:01:55 +0200187-(BOOL) writeFieldBeginWithName:(NSString *)name
188 type:(SInt32)fieldType
189 fieldID:(SInt32)fieldID
190 error:(NSError *__autoreleasing *)error
Jens Geyerdc799ca2015-04-27 22:56:54 +0200191{
Jens Geyer56e5b9b2015-10-09 22:01:55 +0200192 if (fieldType == TTypeBOOL) {
193 _boolFieldName = [name copy];
194 _boolFieldType = @(fieldType);
195 _boolFieldId = @(fieldID);
196 return YES;
197 }
198 else {
199 return [self writeFieldBeginInternalWithName:name
200 type:fieldType
201 fieldID:fieldID
202 typeOverride:0xFF
203 error:error];
Jens Geyerdc799ca2015-04-27 22:56:54 +0200204 }
205}
206
Jens Geyer56e5b9b2015-10-09 22:01:55 +0200207-(BOOL) writeFieldBeginInternalWithName:(NSString *)name
208 type:(SInt32)fieldType
209 fieldID:(SInt32)fieldID
210 typeOverride:(UInt8)typeOverride
211 error:(NSError *__autoreleasing *)error
Jens Geyerdc799ca2015-04-27 22:56:54 +0200212{
Jens Geyer56e5b9b2015-10-09 22:01:55 +0200213 UInt8 typeToWrite = typeOverride == 0xFF ? [self compactTypeForTType:fieldType] : typeOverride;
214
Jens Geyerdc799ca2015-04-27 22:56:54 +0200215 // check if we can use delta encoding for the field id
Jens Geyer56e5b9b2015-10-09 22:01:55 +0200216 if (fieldID > _lastFieldId && fieldID - _lastFieldId <= 15) {
Jens Geyerdc799ca2015-04-27 22:56:54 +0200217 // Write them together
Jens Geyer56e5b9b2015-10-09 22:01:55 +0200218 if (![self writeByteDirect:(fieldID - _lastFieldId) << 4 | typeToWrite error:error]) {
219 return NO;
220 }
Jens Geyerdc799ca2015-04-27 22:56:54 +0200221 }
Jens Geyer56e5b9b2015-10-09 22:01:55 +0200222 else {
223 // Write them separate
224 if (![self writeByteDirect:typeToWrite error:error]) {
225 return NO;
226 }
227 if (![self writeI16:fieldID error:error]) {
228 return NO;
229 }
230 }
231
232 _lastFieldId = fieldID;
233
234 return YES;
Jens Geyerdc799ca2015-04-27 22:56:54 +0200235}
236
Jens Geyer56e5b9b2015-10-09 22:01:55 +0200237-(BOOL) writeFieldStop:(NSError *__autoreleasing *)error
Jens Geyerdc799ca2015-04-27 22:56:54 +0200238{
Jens Geyer56e5b9b2015-10-09 22:01:55 +0200239 return [self writeByteDirect:TCType_STOP error:error];
Jens Geyerdc799ca2015-04-27 22:56:54 +0200240}
241
Jens Geyer56e5b9b2015-10-09 22:01:55 +0200242-(BOOL) writeMapBeginWithKeyType:(SInt32)keyType
243 valueType:(SInt32)valueType
244 size:(SInt32)size
245 error:(NSError *__autoreleasing *)error
Jens Geyerdc799ca2015-04-27 22:56:54 +0200246{
247 if (size == 0) {
Jens Geyer56e5b9b2015-10-09 22:01:55 +0200248 if (![self writeByteDirect:0 error:error]) {
249 return NO;
250 }
Jens Geyerdc799ca2015-04-27 22:56:54 +0200251 }
Jens Geyer56e5b9b2015-10-09 22:01:55 +0200252 else {
253 if (![self writeVarint32:(UInt32)size error:error]) {
254 return NO;
255 }
256 if (![self writeByteDirect:[self compactTypeForTType:keyType] << 4 | [self compactTypeForTType:valueType] error:error]) {
257 return NO;
258 }
259 }
260 return YES;
Jens Geyerdc799ca2015-04-27 22:56:54 +0200261}
262
Jens Geyer56e5b9b2015-10-09 22:01:55 +0200263-(BOOL) writeListBeginWithElementType:(SInt32)elementType
264 size:(SInt32)size
265 error:(NSError *__autoreleasing *)error
Jens Geyerdc799ca2015-04-27 22:56:54 +0200266{
Jens Geyer56e5b9b2015-10-09 22:01:55 +0200267 return [self writeCollectionBeginWithElementType:elementType size:size error:error];
Jens Geyerdc799ca2015-04-27 22:56:54 +0200268}
269
Jens Geyer56e5b9b2015-10-09 22:01:55 +0200270-(BOOL) writeSetBeginWithElementType:(SInt32)elementType
271 size:(SInt32)size
272 error:(NSError *__autoreleasing *)error
Jens Geyerdc799ca2015-04-27 22:56:54 +0200273{
Jens Geyer56e5b9b2015-10-09 22:01:55 +0200274 return [self writeCollectionBeginWithElementType:elementType size:size error:error];
Jens Geyerdc799ca2015-04-27 22:56:54 +0200275}
276
Jens Geyer56e5b9b2015-10-09 22:01:55 +0200277-(BOOL) writeBool:(BOOL)b error:(NSError *__autoreleasing *)error
Jens Geyerdc799ca2015-04-27 22:56:54 +0200278{
Jens Geyer56e5b9b2015-10-09 22:01:55 +0200279 BOOL result;
280 if (_boolFieldId != nil && _boolFieldName != nil && _boolFieldType != nil) {
Jens Geyerdc799ca2015-04-27 22:56:54 +0200281 // we haven't written the field header yet
Jens Geyer56e5b9b2015-10-09 22:01:55 +0200282 result = [self writeFieldBeginInternalWithName:_boolFieldName
283 type:_boolFieldType.intValue
284 fieldID:_boolFieldId.intValue
285 typeOverride:b ? TCType_BOOLEAN_TRUE : TCType_BOOLEAN_FALSE
286 error:error];
287 _boolFieldId = nil;
288 _boolFieldName = nil;
289 _boolFieldType = nil;
290 }
291 else {
Jens Geyerdc799ca2015-04-27 22:56:54 +0200292 // we're not part of a field, so just Write the value.
Jens Geyer56e5b9b2015-10-09 22:01:55 +0200293 result = [self writeByteDirect:b ? TCType_BOOLEAN_TRUE : TCType_BOOLEAN_FALSE error:error];
Jens Geyerdc799ca2015-04-27 22:56:54 +0200294 }
Jens Geyer56e5b9b2015-10-09 22:01:55 +0200295 return result;
Jens Geyerdc799ca2015-04-27 22:56:54 +0200296}
297
Jens Geyer56e5b9b2015-10-09 22:01:55 +0200298-(BOOL) writeByte:(UInt8)value error:(NSError *__autoreleasing *)error
Jens Geyerdc799ca2015-04-27 22:56:54 +0200299{
Jens Geyer56e5b9b2015-10-09 22:01:55 +0200300 return [self writeByteDirect:value error:error];
Jens Geyerdc799ca2015-04-27 22:56:54 +0200301}
302
Jens Geyer56e5b9b2015-10-09 22:01:55 +0200303-(BOOL) writeI16:(SInt16)value error:(NSError *__autoreleasing *)error
Jens Geyerdc799ca2015-04-27 22:56:54 +0200304{
Jens Geyer56e5b9b2015-10-09 22:01:55 +0200305 return [self writeVarint32:[self i32ToZigZag:value] error:error];
Jens Geyerdc799ca2015-04-27 22:56:54 +0200306}
307
Jens Geyer56e5b9b2015-10-09 22:01:55 +0200308-(BOOL) writeI32:(SInt32)value error:(NSError *__autoreleasing *)error
Jens Geyerdc799ca2015-04-27 22:56:54 +0200309{
Jens Geyer56e5b9b2015-10-09 22:01:55 +0200310 return [self writeVarint32:[self i32ToZigZag:value] error:error];
Jens Geyerdc799ca2015-04-27 22:56:54 +0200311}
312
Jens Geyer56e5b9b2015-10-09 22:01:55 +0200313-(BOOL) writeI64:(SInt64)value error:(NSError *__autoreleasing *)error
Jens Geyerdc799ca2015-04-27 22:56:54 +0200314{
Jens Geyer56e5b9b2015-10-09 22:01:55 +0200315 return [self writeVarint64:[self i64ToZigZag:value] error:error];
Jens Geyerdc799ca2015-04-27 22:56:54 +0200316}
317
Jens Geyer56e5b9b2015-10-09 22:01:55 +0200318-(BOOL) writeDouble:(double)value error:(NSError *__autoreleasing *)error
Jens Geyerdc799ca2015-04-27 22:56:54 +0200319{
Jens Geyer56e5b9b2015-10-09 22:01:55 +0200320 // Safe bit-casting double->uint64
321
322 UInt64 bits = 0;
Jens Geyerdc799ca2015-04-27 22:56:54 +0200323 memcpy(&bits, &value, 8);
Jens Geyer56e5b9b2015-10-09 22:01:55 +0200324
Jens Geyerdc799ca2015-04-27 22:56:54 +0200325 bits = OSSwapHostToLittleInt64(bits);
Jens Geyerdc799ca2015-04-27 22:56:54 +0200326
Jens Geyer56e5b9b2015-10-09 22:01:55 +0200327 if (![_transport write:(UInt8 *)&bits offset:0 length:8 error:error]) {
328 PROTOCOL_TRANSPORT_ERROR(NO, error, @"Transport write failed");
Jens Geyerdc799ca2015-04-27 22:56:54 +0200329 }
Jens Geyer56e5b9b2015-10-09 22:01:55 +0200330
331 return YES;
Jens Geyerdc799ca2015-04-27 22:56:54 +0200332}
333
Jens Geyer56e5b9b2015-10-09 22:01:55 +0200334-(BOOL) writeString:(NSString *)value error:(NSError *__autoreleasing *)error
Jens Geyerdc799ca2015-04-27 22:56:54 +0200335{
Jens Geyer56e5b9b2015-10-09 22:01:55 +0200336 return [self writeBinary:[value dataUsingEncoding:NSUTF8StringEncoding] error:error];
337}
338
339-(BOOL) writeBinary:(NSData *)data error:(NSError *__autoreleasing *)error
340{
341 if (![self writeVarint32:(UInt32)data.length error:error]) {
342 return NO;
343 }
344 if (![_transport write:data.bytes offset:0 length:(UInt32)data.length error:error]) {
345 PROTOCOL_TRANSPORT_ERROR(NO, error, @"Transport write failed");
346 }
347 return YES;
348}
349
350-(BOOL) writeMessageEnd:(NSError *__autoreleasing *)error
351{
352 _currentMessageName = nil;
353 return YES;
354}
355
356-(BOOL) writeMapEnd:(NSError *__autoreleasing *)error
357{
358 return YES;
359}
360
361-(BOOL) writeListEnd:(NSError *__autoreleasing *)error
362{
363 return YES;
364}
365
366-(BOOL) writeSetEnd:(NSError *__autoreleasing *)error
367{
368 return YES;
369}
370
371-(BOOL) writeFieldEnd:(NSError *__autoreleasing *)error
372{
373 return YES;
374}
375
376-(BOOL) writeCollectionBeginWithElementType:(SInt32)elementType
377 size:(SInt32)size
378 error:(NSError *__autoreleasing *)error
379{
380 UInt8 ctypeElement = [self compactTypeForTType:elementType];
381
382 if (size <= 14) {
383 if (![self writeByteDirect:size << 4 | ctypeElement error:error]) {
384 return NO;
385 }
386 }
387 else {
388 if (![self writeByteDirect:0xf0 | ctypeElement error:error]) {
389 return NO;
390 }
391 if (![self writeVarint32:(UInt32)size error:error]) {
392 return NO;
393 }
394 }
395 return YES;
396}
397
398-(BOOL) writeVarint64:(UInt64)n error:(NSError *__autoreleasing *)error
399{
400 UInt8 varint64out[10] = {0};
Jens Geyerdc799ca2015-04-27 22:56:54 +0200401 int idx = 0;
Jens Geyer56e5b9b2015-10-09 22:01:55 +0200402
Jens Geyerdc799ca2015-04-27 22:56:54 +0200403 while (true) {
404 if ((n & ~0x7FL) == 0) {
Jens Geyer56e5b9b2015-10-09 22:01:55 +0200405 varint64out[idx++] = (UInt8)n;
Jens Geyerdc799ca2015-04-27 22:56:54 +0200406 break;
Jens Geyer56e5b9b2015-10-09 22:01:55 +0200407 }
408 else {
409 varint64out[idx++] = (UInt8)((n & 0x7F) | 0x80);
Jens Geyerdc799ca2015-04-27 22:56:54 +0200410 n >>= 7;
411 }
412 }
Jens Geyer56e5b9b2015-10-09 22:01:55 +0200413
414 if (![_transport write:varint64out offset:0 length:idx error:error]) {
415 PROTOCOL_TRANSPORT_ERROR(NO, error, @"Transport write failed");
416 }
417
418 return YES;
Jens Geyerdc799ca2015-04-27 22:56:54 +0200419}
420
Jens Geyer56e5b9b2015-10-09 22:01:55 +0200421-(UInt32) i32ToZigZag:(SInt32)n
Jens Geyerdc799ca2015-04-27 22:56:54 +0200422{
423 /*
Jens Geyer56e5b9b2015-10-09 22:01:55 +0200424 ZigZag encoding maps signed integers to unsigned integers so that
425 numbers with a small absolute value (for instance, -1) have
426 a small varint encoded value too. It does this in a way that
427 "zig-zags" back and forth through the positive and negative integers,
428 so that -1 is encoded as 1, 1 is encoded as 2, -2 is encoded as 3, and so
429 on
Jens Geyerdc799ca2015-04-27 22:56:54 +0200430 */
Jens Geyer56e5b9b2015-10-09 22:01:55 +0200431 return (UInt32)(n << 1) ^ (UInt32)(n >> 31);
Jens Geyerdc799ca2015-04-27 22:56:54 +0200432}
433
Jens Geyer56e5b9b2015-10-09 22:01:55 +0200434-(UInt64) i64ToZigZag:(SInt64)n
Jens Geyerdc799ca2015-04-27 22:56:54 +0200435{
Jens Geyer56e5b9b2015-10-09 22:01:55 +0200436 return (UInt64)(n << 1) ^ (UInt64)(n >> 63);
Jens Geyerdc799ca2015-04-27 22:56:54 +0200437}
438
Jens Geyer56e5b9b2015-10-09 22:01:55 +0200439-(BOOL) readMessageBeginReturningName:(NSString **)pname
440 type:(SInt32 *)ptype
441 sequenceID:(SInt32 *)psequenceID
442 error:(NSError *__autoreleasing *)error
Jens Geyerdc799ca2015-04-27 22:56:54 +0200443{
Jens Geyer56e5b9b2015-10-09 22:01:55 +0200444 UInt8 protocolId;
445 if (![self readByte:&protocolId error:error]) {
446 return NO;
447 }
448
Jens Geyerdc799ca2015-04-27 22:56:54 +0200449 if (protocolId != COMPACT_PROTOCOL_ID) {
Jens Geyer56e5b9b2015-10-09 22:01:55 +0200450 if (error) {
451 *error = [NSError errorWithDomain:TProtocolErrorDomain
452 code:TProtocolErrorUnknown
453 userInfo:@{TProtocolErrorExtendedErrorKey: @(TProtocolExtendedErrorMismatchedProtocol),
454 TProtocolErrorExpectedIdKey: @(COMPACT_PROTOCOL_ID)}];
455 }
456 return NO;
Jens Geyerdc799ca2015-04-27 22:56:54 +0200457 }
Jens Geyer56e5b9b2015-10-09 22:01:55 +0200458
459 UInt8 versionAndType;
460 if (![self readByte:&versionAndType error:error]) {
461 return NO;
462 }
463
464 UInt8 version = versionAndType & COMPACT_VERSION_MASK;
Jens Geyerdc799ca2015-04-27 22:56:54 +0200465 if (version != COMPACT_VERSION) {
Jens Geyer56e5b9b2015-10-09 22:01:55 +0200466 if (error) {
467 *error = [NSError errorWithDomain:TProtocolErrorDomain
468 code:TProtocolErrorBadVersion
469 userInfo:@{TProtocolErrorExpectedVersionKey: @(COMPACT_VERSION)}];
470 }
471 return NO;
Jens Geyerdc799ca2015-04-27 22:56:54 +0200472 }
Jens Geyer56e5b9b2015-10-09 22:01:55 +0200473
Jens Geyerdc799ca2015-04-27 22:56:54 +0200474 int type = (versionAndType >> COMPACT_TYPE_SHIFT_AMOUNT) & COMPACT_TYPE_BITS;
Jens Geyer56e5b9b2015-10-09 22:01:55 +0200475 UInt32 sequenceID;
476 if (![self readVarint32:&sequenceID error:error]) {
477 return NO;
478 }
479 NSString *name;
480 if (![self readString:&name error:error]) {
481 return NO;
482 }
483
Jens Geyerdc799ca2015-04-27 22:56:54 +0200484 if (ptype != NULL) {
485 *ptype = type;
486 }
487 if (psequenceID != NULL) {
488 *psequenceID = sequenceID;
489 }
490 if (pname != NULL) {
491 *pname = name;
492 }
Jens Geyer56e5b9b2015-10-09 22:01:55 +0200493 return YES;
Jens Geyerdc799ca2015-04-27 22:56:54 +0200494}
495
Jens Geyer56e5b9b2015-10-09 22:01:55 +0200496-(BOOL) readStructBeginReturningName:(NSString **)pname error:(NSError *__autoreleasing *)error
Jens Geyerdc799ca2015-04-27 22:56:54 +0200497{
Jens Geyer56e5b9b2015-10-09 22:01:55 +0200498 [_lastField addObject:@(_lastFieldId)];
499 _lastFieldId = 0;
500
Jens Geyerdc799ca2015-04-27 22:56:54 +0200501 if (pname != NULL) {
502 *pname = @"";
503 }
Jens Geyer56e5b9b2015-10-09 22:01:55 +0200504
505 return YES;
Jens Geyerdc799ca2015-04-27 22:56:54 +0200506}
507
Jens Geyer56e5b9b2015-10-09 22:01:55 +0200508-(BOOL) readStructEnd:(NSError *__autoreleasing *)error
Jens Geyerdc799ca2015-04-27 22:56:54 +0200509{
Jens Geyer56e5b9b2015-10-09 22:01:55 +0200510 _lastFieldId = [_lastField.lastObject shortValue];
511 [_lastField removeLastObject];
512 return YES;
Jens Geyerdc799ca2015-04-27 22:56:54 +0200513}
514
Jens Geyer56e5b9b2015-10-09 22:01:55 +0200515-(BOOL) readFieldBeginReturningName:(NSString **)pname
516 type:(SInt32 *)pfieldType
517 fieldID:(SInt32 *)pfieldID
518 error:(NSError *__autoreleasing *)error
Jens Geyerdc799ca2015-04-27 22:56:54 +0200519{
Jens Geyer56e5b9b2015-10-09 22:01:55 +0200520 UInt8 byte;
521 if (![self readByte:&byte error:error]) {
522 return NO;
523 }
524
525 UInt8 type = byte & 0x0f;
526
Jens Geyerdc799ca2015-04-27 22:56:54 +0200527 // if it's a stop, then we can return immediately, as the struct is over.
528 if (type == TCType_STOP) {
529 if (pname != NULL) {
530 *pname = @"";
531 }
532 if (pfieldType != NULL) {
Jens Geyer56e5b9b2015-10-09 22:01:55 +0200533 *pfieldType = TTypeSTOP;
Jens Geyerdc799ca2015-04-27 22:56:54 +0200534 }
535 if (pfieldID != NULL) {
536 *pfieldID = 0;
537 }
Jens Geyer56e5b9b2015-10-09 22:01:55 +0200538 return YES;
Jens Geyerdc799ca2015-04-27 22:56:54 +0200539 }
Jens Geyer56e5b9b2015-10-09 22:01:55 +0200540
Jens Geyerdc799ca2015-04-27 22:56:54 +0200541 short fieldId = 0;
Jens Geyer56e5b9b2015-10-09 22:01:55 +0200542
Jens Geyerdc799ca2015-04-27 22:56:54 +0200543 // mask off the 4 MSB of the type header. it could contain a field id delta.
544 short modifier = (byte & 0xf0) >> 4;
545 if (modifier == 0) {
546 // not a delta. look ahead for the zigzag varint field id.
Jens Geyer56e5b9b2015-10-09 22:01:55 +0200547 if (![self readI16:&fieldId error:error]) {
548 return NO;
549 }
Jens Geyerdc799ca2015-04-27 22:56:54 +0200550 }
Jens Geyer56e5b9b2015-10-09 22:01:55 +0200551 else {
552 // has a delta. add the delta to the last Read field id.
553 fieldId = _lastFieldId + modifier;
554 }
555
556 UInt8 fieldType;
557 if (![self ttype:&fieldType forCompactType:type error:error]) {
558 return NO;
559 }
560
Jens Geyerdc799ca2015-04-27 22:56:54 +0200561 if (pname != NULL) {
562 *pname = @"";
563 }
564 if (pfieldType != NULL) {
565 *pfieldType = fieldType;
566 }
567 if (pfieldID != NULL) {
568 *pfieldID = fieldId;
569 }
Jens Geyer56e5b9b2015-10-09 22:01:55 +0200570
Jens Geyerdc799ca2015-04-27 22:56:54 +0200571 // if this happens to be a boolean field, the value is encoded in the type
572 if (type == TCType_BOOLEAN_TRUE ||
Jens Geyer56e5b9b2015-10-09 22:01:55 +0200573 type == TCType_BOOLEAN_FALSE)
574 {
Jens Geyerdc799ca2015-04-27 22:56:54 +0200575 // save the boolean value in a special instance variable.
Jens Geyer56e5b9b2015-10-09 22:01:55 +0200576 _booleanValue = [NSNumber numberWithBool:type == TCType_BOOLEAN_TRUE];
Jens Geyerdc799ca2015-04-27 22:56:54 +0200577 }
Jens Geyer56e5b9b2015-10-09 22:01:55 +0200578
Jens Geyerdc799ca2015-04-27 22:56:54 +0200579 // push the new field onto the field stack so we can keep the deltas going.
Jens Geyer56e5b9b2015-10-09 22:01:55 +0200580 _lastFieldId = fieldId;
581
582 return YES;
Jens Geyerdc799ca2015-04-27 22:56:54 +0200583}
584
Jens Geyer56e5b9b2015-10-09 22:01:55 +0200585-(BOOL) readMapBeginReturningKeyType:(SInt32 *)pkeyType
586 valueType:(SInt32 *)pvalueType
587 size:(SInt32 *)psize
588 error:(NSError *__autoreleasing *)error
Jens Geyerdc799ca2015-04-27 22:56:54 +0200589{
Jens Geyer56e5b9b2015-10-09 22:01:55 +0200590 UInt8 keyAndValueType = 0;
591 UInt32 size;
592 if (![self readVarint32:&size error:error]) {
593 return NO;
Jens Geyerdc799ca2015-04-27 22:56:54 +0200594 }
Jens Geyer56e5b9b2015-10-09 22:01:55 +0200595 if (size != 0) {
596 if (![self readByte:&keyAndValueType error:error]) {
597 return NO;
598 }
599 }
600
601 UInt8 keyType;
602 if (![self ttype:&keyType forCompactType:keyAndValueType >> 4 error:error]) {
603 return NO;
604 }
605
606 UInt8 valueType;
607 if (![self ttype:&valueType forCompactType:keyAndValueType & 0xf error:error]) {
608 return NO;
609 }
610
Jens Geyerdc799ca2015-04-27 22:56:54 +0200611 if (pkeyType != NULL) {
612 *pkeyType = keyType;
613 }
614 if (pvalueType != NULL) {
615 *pvalueType = valueType;
616 }
617 if (psize != NULL) {
618 *psize = size;
619 }
Jens Geyer56e5b9b2015-10-09 22:01:55 +0200620
621 return YES;
Jens Geyerdc799ca2015-04-27 22:56:54 +0200622}
623
Jens Geyer56e5b9b2015-10-09 22:01:55 +0200624-(BOOL) readListBeginReturningElementType:(SInt32 *)pelementType
625 size:(SInt32 *)psize
626 error:(NSError *__autoreleasing *)error
Jens Geyerdc799ca2015-04-27 22:56:54 +0200627{
Jens Geyer56e5b9b2015-10-09 22:01:55 +0200628 UInt8 sizeAndType;
629 if (![self readByte:&sizeAndType error:error]) {
630 return NO;
Jens Geyerdc799ca2015-04-27 22:56:54 +0200631 }
Jens Geyer56e5b9b2015-10-09 22:01:55 +0200632
633 UInt32 size = (sizeAndType >> 4) & 0x0f;
634 if (size == 15) {
635 if (![self readVarint32:&size error:error]) {
636 return NO;
637 }
638 }
639
640 UInt8 elementType;
641 if (![self ttype:&elementType forCompactType:sizeAndType & 0x0f error:error]) {
642 return NO;
643 }
644
Jens Geyerdc799ca2015-04-27 22:56:54 +0200645 if (pelementType != NULL) {
646 *pelementType = elementType;
647 }
648 if (psize != NULL) {
649 *psize = size;
650 }
Jens Geyer56e5b9b2015-10-09 22:01:55 +0200651
652 return YES;
Jens Geyerdc799ca2015-04-27 22:56:54 +0200653}
654
Jens Geyer56e5b9b2015-10-09 22:01:55 +0200655-(BOOL) readSetBeginReturningElementType:(SInt32 *)pelementType
656 size:(SInt32 *)psize
657 error:(NSError *__autoreleasing *)error
Jens Geyerdc799ca2015-04-27 22:56:54 +0200658{
Jens Geyer56e5b9b2015-10-09 22:01:55 +0200659 return [self readListBeginReturningElementType:pelementType size:psize error:error];
Jens Geyerdc799ca2015-04-27 22:56:54 +0200660}
661
Jens Geyer56e5b9b2015-10-09 22:01:55 +0200662-(BOOL) readBool:(BOOL *)value error:(NSError *__autoreleasing *)error
Jens Geyerdc799ca2015-04-27 22:56:54 +0200663{
Jens Geyer56e5b9b2015-10-09 22:01:55 +0200664 if (_booleanValue != nil) {
665
666 BOOL result = _booleanValue.boolValue;
667 _booleanValue = nil;
668
669 *value = result;
Jens Geyerdc799ca2015-04-27 22:56:54 +0200670 }
Jens Geyer56e5b9b2015-10-09 22:01:55 +0200671 else {
672
673 UInt8 result;
674 if (![self readByte:&result error:error]) {
675 return NO;
676 }
677
678 *value = result == TCType_BOOLEAN_TRUE;
679 }
680
681 return YES;
Jens Geyerdc799ca2015-04-27 22:56:54 +0200682}
683
Jens Geyer56e5b9b2015-10-09 22:01:55 +0200684-(BOOL) readByte:(UInt8 *)value error:(NSError *__autoreleasing *)error
Jens Geyerdc799ca2015-04-27 22:56:54 +0200685{
Jens Geyer56e5b9b2015-10-09 22:01:55 +0200686 if (![_transport readAll:value offset:0 length:1 error:error]) {
687 PROTOCOL_TRANSPORT_ERROR(NO, error, @"Transport read failed");
688 }
689 return YES;
Jens Geyerdc799ca2015-04-27 22:56:54 +0200690}
691
Jens Geyer56e5b9b2015-10-09 22:01:55 +0200692-(BOOL) readI16:(SInt16 *)value error:(NSError *__autoreleasing *)error
Jens Geyerdc799ca2015-04-27 22:56:54 +0200693{
Jens Geyer56e5b9b2015-10-09 22:01:55 +0200694 UInt32 v;
695 if (![self readVarint32:&v error:error]) {
696 return NO;
697 }
698
699 if (value) {
700 *value = (SInt16)[self zigZagToi32:v];
701 }
702
703 return YES;
Jens Geyerdc799ca2015-04-27 22:56:54 +0200704}
705
Jens Geyer56e5b9b2015-10-09 22:01:55 +0200706-(BOOL) readI32:(SInt32 *)value error:(NSError *__autoreleasing *)error
Jens Geyerdc799ca2015-04-27 22:56:54 +0200707{
Jens Geyer56e5b9b2015-10-09 22:01:55 +0200708 UInt32 v;
709 if (![self readVarint32:&v error:error]) {
710 return NO;
711 }
712
713 if (value) {
714 *value = [self zigZagToi32:v];
715 }
716
717 return YES;
Jens Geyerdc799ca2015-04-27 22:56:54 +0200718}
719
Jens Geyer56e5b9b2015-10-09 22:01:55 +0200720-(BOOL) readI64:(SInt64 *)value error:(NSError *__autoreleasing *)error
Jens Geyerdc799ca2015-04-27 22:56:54 +0200721{
Jens Geyer56e5b9b2015-10-09 22:01:55 +0200722 UInt64 v;
723 if (![self readVarint64:&v error:error]) {
724 return NO;
725 }
726
727 if (value) {
728 *value = [self zigZagToi64:v];
729 }
730
731 return YES;
Jens Geyerdc799ca2015-04-27 22:56:54 +0200732}
733
Jens Geyer56e5b9b2015-10-09 22:01:55 +0200734-(BOOL) readDouble:(double *)value error:(NSError *__autoreleasing *)error
Jens Geyerdc799ca2015-04-27 22:56:54 +0200735{
Jens Geyer56e5b9b2015-10-09 22:01:55 +0200736 UInt64 bits;
737 if (![_transport readAll:(UInt8 *)&bits offset:0 length:8 error:error]) {
738 PROTOCOL_TRANSPORT_ERROR(NO, error, @"Transport read failed");
739 }
740
Jens Geyerdc799ca2015-04-27 22:56:54 +0200741 bits = OSSwapLittleToHostInt64(bits);
Jens Geyerdc799ca2015-04-27 22:56:54 +0200742
Jens Geyer56e5b9b2015-10-09 22:01:55 +0200743 if (value) {
744 memcpy(value, &bits, sizeof(bits));
Jens Geyerdc799ca2015-04-27 22:56:54 +0200745 }
Jens Geyer56e5b9b2015-10-09 22:01:55 +0200746
747 return YES;
Jens Geyerdc799ca2015-04-27 22:56:54 +0200748}
749
Jens Geyer56e5b9b2015-10-09 22:01:55 +0200750-(BOOL) readString:(NSString *__autoreleasing *)value error:(NSError *__autoreleasing *)error
Jens Geyerdc799ca2015-04-27 22:56:54 +0200751{
Jens Geyer56e5b9b2015-10-09 22:01:55 +0200752 UInt32 length;
753 if (![self readVarint32:&length error:error]) {
754 return NO;
Jens Geyerdc799ca2015-04-27 22:56:54 +0200755 }
Jens Geyer56e5b9b2015-10-09 22:01:55 +0200756
757 NSString *result;
758
759 if (length != 0) {
760
761 NSData *data;
762 if (![self readBinaryOfLength:length data:&data error:error]) {
763 return NO;
764 }
765
766 result = [[NSString alloc] initWithData:data
767 encoding:NSUTF8StringEncoding];
768 }
769 else {
770 result = @"";
771 }
772
773 if (value) {
774 *value = result;
775 }
776
777 return YES;
Jens Geyerdc799ca2015-04-27 22:56:54 +0200778}
779
Jens Geyer56e5b9b2015-10-09 22:01:55 +0200780-(BOOL) readBinary:(NSData *__autoreleasing *)value error:(NSError *__autoreleasing *)error
Jens Geyerdc799ca2015-04-27 22:56:54 +0200781{
Jens Geyer56e5b9b2015-10-09 22:01:55 +0200782 UInt32 length;
783 if (![self readVarint32:&length error:error]) {
784 return NO;
785 }
786
787 return [self readBinaryOfLength:length data:value error:error];
788}
789
790-(BOOL) readBinaryOfLength:(UInt32)length data:(NSData *__autoreleasing *)value error:(NSError *__autoreleasing *)error
791{
792 NSData *result;
793
794 if (length != 0) {
795
796 NSMutableData *buf = [NSMutableData dataWithLength:length];
797 if (![_transport readAll:buf.mutableBytes offset:0 length:length error:error]) {
798 PROTOCOL_TRANSPORT_ERROR(NO, error, @"Transport read failed");
799 }
800
801 result = buf;
802 }
803 else {
804
805 result = [NSData data];
806
807 }
808
809 if (value) {
810 *value = result;
811 }
812
813 return YES;
814}
815
816-(BOOL) readMessageEnd:(NSError *__autoreleasing *)error
817{
818 return YES;
819}
820-(BOOL) readFieldEnd:(NSError *__autoreleasing *)error
821{
822 return YES;
823}
824-(BOOL) readMapEnd:(NSError *__autoreleasing *)error
825{
826 return YES;
827}
828-(BOOL) readListEnd:(NSError *__autoreleasing *)error
829{
830 return YES;
831}
832-(BOOL) readSetEnd:(NSError *__autoreleasing *)error
833{
834 return YES;
835}
836
837-(BOOL) readVarint32:(UInt32 *)value error:(NSError *__autoreleasing *)error
838{
839 UInt32 result = 0;
Jens Geyerdc799ca2015-04-27 22:56:54 +0200840 int shift = 0;
Jens Geyer56e5b9b2015-10-09 22:01:55 +0200841
Jens Geyerdc799ca2015-04-27 22:56:54 +0200842 while (true) {
Jens Geyer56e5b9b2015-10-09 22:01:55 +0200843
844 UInt8 byte;
845 if (![self readByte:&byte error:error]) {
846 return NO;
847 }
848
849 result |= (UInt32)(byte & 0x7f) << shift;
Jens Geyerdc799ca2015-04-27 22:56:54 +0200850 if (!(byte & 0x80)) {
851 break;
852 }
Jens Geyer56e5b9b2015-10-09 22:01:55 +0200853
Jens Geyerdc799ca2015-04-27 22:56:54 +0200854 shift += 7;
855 }
Jens Geyer56e5b9b2015-10-09 22:01:55 +0200856
857 if (value) {
858 *value = result;
859 }
860
861 return YES;
Jens Geyerdc799ca2015-04-27 22:56:54 +0200862}
863
Jens Geyer56e5b9b2015-10-09 22:01:55 +0200864-(BOOL) readVarint64:(UInt64 *)value error:(NSError *__autoreleasing *)error
Jens Geyerdc799ca2015-04-27 22:56:54 +0200865{
866 int shift = 0;
Jens Geyer56e5b9b2015-10-09 22:01:55 +0200867 UInt64 result = 0;
868
Jens Geyerdc799ca2015-04-27 22:56:54 +0200869 while (true) {
Jens Geyer56e5b9b2015-10-09 22:01:55 +0200870
871 UInt8 byte;
872 if (![self readByte:&byte error:error]) {
873 return NO;
874 }
875
876 result |= (UInt64)(byte & 0x7f) << shift;
Jens Geyerdc799ca2015-04-27 22:56:54 +0200877 if (!(byte & 0x80)) {
878 break;
879 }
Jens Geyer56e5b9b2015-10-09 22:01:55 +0200880
Jens Geyerdc799ca2015-04-27 22:56:54 +0200881 shift += 7;
882 }
Jens Geyer56e5b9b2015-10-09 22:01:55 +0200883
884 if (value) {
885 *value = result;
886 }
887
888 return YES;
Jens Geyerdc799ca2015-04-27 22:56:54 +0200889}
890
Jens Geyer56e5b9b2015-10-09 22:01:55 +0200891-(SInt32) zigZagToi32:(UInt32)n
Jens Geyerdc799ca2015-04-27 22:56:54 +0200892{
Jens Geyer56e5b9b2015-10-09 22:01:55 +0200893 return (SInt32)(n >> 1) ^ (-(SInt32)(n & 1));
Jens Geyerdc799ca2015-04-27 22:56:54 +0200894}
895
Jens Geyer56e5b9b2015-10-09 22:01:55 +0200896-(SInt64) zigZagToi64:(UInt64)n
Jens Geyerdc799ca2015-04-27 22:56:54 +0200897{
Jens Geyer56e5b9b2015-10-09 22:01:55 +0200898 return (SInt64)(n >> 1) ^ (-(SInt64)(n & 1));
Jens Geyerdc799ca2015-04-27 22:56:54 +0200899}
900
Jens Geyer56e5b9b2015-10-09 22:01:55 +0200901-(BOOL) ttype:(UInt8 *)ttype forCompactType:(UInt8)ctype error:(NSError *__autoreleasing *)error
Jens Geyerdc799ca2015-04-27 22:56:54 +0200902{
Jens Geyer56e5b9b2015-10-09 22:01:55 +0200903 switch (ctype & 0x0f) {
904 case TCType_STOP:
905 *ttype = TTypeSTOP;
906 return YES;
907
908 case TCType_BOOLEAN_FALSE:
909 case TCType_BOOLEAN_TRUE:
910 *ttype = TTypeBOOL;
911 return YES;
912
913 case TCType_BYTE:
914 *ttype = TTypeBYTE;
915 return YES;
916
917 case TCType_I16:
918 *ttype = TTypeI16;
919 return YES;
920
921 case TCType_I32:
922 *ttype = TTypeI32;
923 return YES;
924
925 case TCType_I64:
926 *ttype = TTypeI64;
927 return YES;
928
929 case TCType_DOUBLE:
930 *ttype = TTypeDOUBLE;
931 return YES;
932
933 case TCType_BINARY:
934 *ttype = TTypeSTRING;
935 return YES;
936
937 case TCType_LIST:
938 *ttype = TTypeLIST;
939 return YES;
940
941 case TCType_SET:
942 *ttype = TTypeSET;
943 return YES;
944
945 case TCType_MAP:
946 *ttype = TTypeMAP;
947 return YES;
948
949 case TCType_STRUCT:
950 *ttype = TTypeSTRUCT;
951 return YES;
952
953 default:
954 if (error) {
955 *error = [NSError errorWithDomain:TProtocolErrorDomain
956 code:TProtocolErrorUnknown
957 userInfo:@{TProtocolErrorTypeKey: @((UInt8)(ctype & 0x0F))}];
958 }
959 return NO;
Jens Geyerdc799ca2015-04-27 22:56:54 +0200960 }
961}
962
Jens Geyer56e5b9b2015-10-09 22:01:55 +0200963-(UInt8) compactTypeForTType:(UInt8)ttype
Jens Geyerdc799ca2015-04-27 22:56:54 +0200964{
Jens Geyer56e5b9b2015-10-09 22:01:55 +0200965 static UInt8 ttypeToCompactType[] = {
966 [TTypeSTOP] = TCType_STOP,
967 [TTypeBOOL] = TCType_BOOLEAN_FALSE,
968 [TTypeBYTE] = TCType_BYTE,
969 [TTypeDOUBLE] = TCType_DOUBLE,
970 [TTypeI16] = TCType_I16,
971 [TTypeI32] = TCType_I32,
972 [TTypeI64] = TCType_I64,
973 [TTypeSTRING] = TCType_BINARY,
974 [TTypeSTRUCT] = TCType_STRUCT,
975 [TTypeMAP] = TCType_MAP,
976 [TTypeSET] = TCType_SET,
977 [TTypeLIST] = TCType_LIST
Jens Geyerdc799ca2015-04-27 22:56:54 +0200978 };
Jens Geyer56e5b9b2015-10-09 22:01:55 +0200979
Jens Geyerdc799ca2015-04-27 22:56:54 +0200980 return ttypeToCompactType[ttype];
981}
982
983@end