blob: 847c723f8b69f5317780cb250c2ee42680cf5bae [file] [log] [blame]
David Reissea2cba82009-03-30 21:35:00 +00001/*
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
Mark Slee7e9eea42007-09-10 21:00:23 +000020#import "TBinaryProtocol.h"
Mark Slee33a7d892007-09-14 19:44:30 +000021#import "TProtocolException.h"
Jake Farrell9689d892011-12-06 01:07:17 +000022#import "TObjective-C.h"
Mark Slee7e9eea42007-09-10 21:00:23 +000023
Jens Geyer2aa04bf2015-04-17 18:44:37 +020024/* In the modern protocol, version is stored in the high half of an int32.
25 * The low half contains type info. */
Roger Meier6b616012015-03-01 12:32:50 +010026static const uint16_t VERSION_1 = 0x8001;
Mark Slee7e9eea42007-09-10 21:00:23 +000027
Roger Meier6b616012015-03-01 12:32:50 +010028NS_INLINE size_t
29CheckedCastInt32ToSizeT(int32_t size)
30{
31 if (size < 0) {
32 NSString *reason = [NSString stringWithFormat:
33 @"%s: refusing to read data with negative size: %"PRId32,
34 __func__, size];
35 @throw [TProtocolException
36 exceptionWithName: @"TProtocolException"
37 reason: reason];
38 }
39 size_t checkedSize = (size_t)size;
40 return checkedSize;
41}
42
43NS_INLINE int32_t
44CheckedCastSizeTToInt32(size_t size)
45{
46 if (size > INT32_MAX) {
47 NSString *reason = [NSString stringWithFormat:
48 @"%s: data size exceeds values representable by a 32-bit signed integer: %zu",
49 __func__, size];
50 @throw [TProtocolException
51 exceptionWithName: @"TProtocolException"
52 reason: reason];
53 }
54 int32_t checkedSize = (int32_t)size;
55 return checkedSize;
56}
57
58NS_INLINE uint8_t
59CheckedCastIntToUInt8(int size)
60{
61 if (size > UINT8_MAX) {
62 NSString *reason = [NSString stringWithFormat:
63 @"%s: data size exceeds values representable by a 8-bit unsigned integer: %d",
64 __func__, size];
65 @throw [TProtocolException
66 exceptionWithName: @"TProtocolException"
67 reason: reason];
68 }
69 uint8_t checkedSize = (uint8_t)size;
70 return checkedSize;
71}
Mark Slee7e9eea42007-09-10 21:00:23 +000072
Mark Slee77575e62007-09-24 19:24:53 +000073static TBinaryProtocolFactory * gSharedFactory = nil;
74
David Reiss0c90f6f2008-02-06 22:18:40 +000075@implementation TBinaryProtocolFactory
Mark Slee77575e62007-09-24 19:24:53 +000076
77+ (TBinaryProtocolFactory *) sharedFactory {
78 if (gSharedFactory == nil) {
79 gSharedFactory = [[TBinaryProtocolFactory alloc] init];
80 }
David Reiss0c90f6f2008-02-06 22:18:40 +000081
Mark Slee77575e62007-09-24 19:24:53 +000082 return gSharedFactory;
83}
84
85- (TBinaryProtocol *) newProtocolOnTransport: (id <TTransport>) transport {
Andrew McGeachieda50d552010-07-21 19:14:44 +000086 return [[TBinaryProtocol alloc] initWithTransport: transport];
Mark Slee77575e62007-09-24 19:24:53 +000087}
88
89@end
90
91
92
Mark Slee7e9eea42007-09-10 21:00:23 +000093@implementation TBinaryProtocol
94
95- (id) initWithTransport: (id <TTransport>) transport
96{
Carl Yeksigianf0293452013-08-13 18:09:59 -040097 return [self initWithTransport: transport strictRead: NO strictWrite: YES];
Mark Slee7e9eea42007-09-10 21:00:23 +000098}
99
David Reiss0c90f6f2008-02-06 22:18:40 +0000100- (id) initWithTransport: (id <TTransport>) transport
Mark Slee7e9eea42007-09-10 21:00:23 +0000101 strictRead: (BOOL) strictRead
102 strictWrite: (BOOL) strictWrite
103{
104 self = [super init];
Jake Farrell9689d892011-12-06 01:07:17 +0000105 mTransport = [transport retain_stub];
Mark Slee7e9eea42007-09-10 21:00:23 +0000106 mStrictRead = strictRead;
107 mStrictWrite = strictWrite;
108 return self;
109}
110
111
Mark Slee84406052007-11-20 01:39:25 +0000112- (int32_t) messageSizeLimit
113{
114 return mMessageSizeLimit;
115}
116
117
118- (void) setMessageSizeLimit: (int32_t) sizeLimit
119{
120 mMessageSizeLimit = sizeLimit;
121}
122
123
Mark Sleeaa3c5a82007-09-19 21:12:52 +0000124- (void) dealloc
125{
Jake Farrell9689d892011-12-06 01:07:17 +0000126 [mTransport release_stub];
127 [super dealloc_stub];
Mark Sleeaa3c5a82007-09-19 21:12:52 +0000128}
129
130
Mark Slee7e9eea42007-09-10 21:00:23 +0000131- (id <TTransport>) transport
132{
133 return mTransport;
134}
135
136
Roger Meier6b616012015-03-01 12:32:50 +0100137- (NSString *) readStringBody: (int) rawSize
Mark Slee7e9eea42007-09-10 21:00:23 +0000138{
Roger Meier6b616012015-03-01 12:32:50 +0100139 size_t size = CheckedCastInt32ToSizeT(rawSize);
Andrew McGeachie061722b2009-07-23 18:12:18 +0000140 char * buffer = malloc(size+1);
141 if (!buffer) {
142 @throw [TProtocolException exceptionWithName: @"TProtocolException"
Roger Meier6b616012015-03-01 12:32:50 +0100143 reason: [NSString stringWithFormat: @"Unable to allocate memory in %s, size: %zu",
Andrew McGeachie061722b2009-07-23 18:12:18 +0000144 __PRETTY_FUNCTION__,
145 size]];;
146 }
147 [mTransport readAll: (uint8_t *) buffer offset: 0 length: size];
148 buffer[size] = 0;
149 NSString * result = [NSString stringWithUTF8String: buffer];
150 free(buffer);
151 return result;
Mark Slee7e9eea42007-09-10 21:00:23 +0000152}
153
154
Mark Slee33a7d892007-09-14 19:44:30 +0000155- (void) readMessageBeginReturningName: (NSString **) name
156 type: (int *) type
157 sequenceID: (int *) sequenceID
Mark Slee7e9eea42007-09-10 21:00:23 +0000158{
Mark Slee84406052007-11-20 01:39:25 +0000159 int32_t size = [self readI32];
Mark Slee7e9eea42007-09-10 21:00:23 +0000160 if (size < 0) {
Jens Geyer2aa04bf2015-04-17 18:44:37 +0200161 /* Version (unsigned) is stored in the high halfword. */
162 uint16_t version = (size >> 16) & 0xFFFF;
Mark Slee7e9eea42007-09-10 21:00:23 +0000163 if (version != VERSION_1) {
Roger Meier6b616012015-03-01 12:32:50 +0100164 NSString *reason = [NSString stringWithFormat:
165 @"%s: Expected version %"PRIu16", instead found: %"PRIu16,
166 __func__, VERSION_1, version];
Mark Slee77575e62007-09-24 19:24:53 +0000167 @throw [TProtocolException exceptionWithName: @"TProtocolException"
Roger Meier6b616012015-03-01 12:32:50 +0100168 reason: reason];
Mark Slee7e9eea42007-09-10 21:00:23 +0000169 }
170 if (type != NULL) {
Roger Meierff951bd2013-03-22 22:12:19 +0100171 *type = size & 0x00FF;
Mark Slee7e9eea42007-09-10 21:00:23 +0000172 }
173 NSString * messageName = [self readString];
174 if (name != NULL) {
175 *name = messageName;
176 }
177 int seqID = [self readI32];
178 if (sequenceID != NULL) {
179 *sequenceID = seqID;
180 }
181 } else {
182 if (mStrictRead) {
Mark Slee77575e62007-09-24 19:24:53 +0000183 @throw [TProtocolException exceptionWithName: @"TProtocolException"
184 reason: @"Missing version in readMessageBegin, old client?"];
Mark Slee7e9eea42007-09-10 21:00:23 +0000185 }
Mark Slee84406052007-11-20 01:39:25 +0000186 if ([self messageSizeLimit] > 0 && size > [self messageSizeLimit]) {
187 @throw [TProtocolException exceptionWithName: @"TProtocolException"
188 reason: [NSString stringWithFormat: @"Message too big. Size limit is: %d Message size is: %d",
189 mMessageSizeLimit,
David Reiss0c90f6f2008-02-06 22:18:40 +0000190 size]];
Mark Slee84406052007-11-20 01:39:25 +0000191 }
Mark Slee7e9eea42007-09-10 21:00:23 +0000192 NSString * messageName = [self readStringBody: size];
193 if (name != NULL) {
194 *name = messageName;
195 }
196 int messageType = [self readByte];
197 if (type != NULL) {
198 *type = messageType;
199 }
200 int seqID = [self readI32];
201 if (sequenceID != NULL) {
202 *sequenceID = seqID;
203 }
204 }
205}
206
207
208- (void) readMessageEnd {}
209
210
Mark Slee33a7d892007-09-14 19:44:30 +0000211- (void) readStructBeginReturningName: (NSString **) name
Mark Slee7e9eea42007-09-10 21:00:23 +0000212{
213 if (name != NULL) {
214 *name = nil;
215 }
216}
217
218
219- (void) readStructEnd {}
220
221
Mark Slee33a7d892007-09-14 19:44:30 +0000222- (void) readFieldBeginReturningName: (NSString **) name
223 type: (int *) fieldType
224 fieldID: (int *) fieldID
Mark Slee7e9eea42007-09-10 21:00:23 +0000225{
226 if (name != NULL) {
227 *name = nil;
228 }
229 int ft = [self readByte];
230 if (fieldType != NULL) {
231 *fieldType = ft;
David Reiss0c90f6f2008-02-06 22:18:40 +0000232 }
Mark Slee7e9eea42007-09-10 21:00:23 +0000233 if (ft != TType_STOP) {
234 int fid = [self readI16];
235 if (fieldID != NULL) {
236 *fieldID = fid;
237 }
238 }
239}
240
241
242- (void) readFieldEnd {}
243
244
245- (int32_t) readI32
246{
247 uint8_t i32rd[4];
248 [mTransport readAll: i32rd offset: 0 length: 4];
249 return
250 ((i32rd[0] & 0xff) << 24) |
251 ((i32rd[1] & 0xff) << 16) |
252 ((i32rd[2] & 0xff) << 8) |
253 ((i32rd[3] & 0xff));
254}
255
256
257- (NSString *) readString
258{
Roger Meier6b616012015-03-01 12:32:50 +0100259 int32_t size = [self readI32];
Mark Slee7e9eea42007-09-10 21:00:23 +0000260 return [self readStringBody: size];
261}
262
263
264- (BOOL) readBool
265{
266 return [self readByte] == 1;
267}
268
269- (uint8_t) readByte
270{
271 uint8_t myByte;
272 [mTransport readAll: &myByte offset: 0 length: 1];
273 return myByte;
274}
275
276- (short) readI16
277{
278 uint8_t buff[2];
279 [mTransport readAll: buff offset: 0 length: 2];
280 return (short)
281 (((buff[0] & 0xff) << 8) |
282 ((buff[1] & 0xff)));
Mark Slee7e9eea42007-09-10 21:00:23 +0000283}
284
Roger Meier6b616012015-03-01 12:32:50 +0100285- (int64_t) readI64
Mark Slee7e9eea42007-09-10 21:00:23 +0000286{
287 uint8_t i64rd[8];
288 [mTransport readAll: i64rd offset: 0 length: 8];
289 return
290 ((int64_t)(i64rd[0] & 0xff) << 56) |
291 ((int64_t)(i64rd[1] & 0xff) << 48) |
292 ((int64_t)(i64rd[2] & 0xff) << 40) |
293 ((int64_t)(i64rd[3] & 0xff) << 32) |
294 ((int64_t)(i64rd[4] & 0xff) << 24) |
295 ((int64_t)(i64rd[5] & 0xff) << 16) |
296 ((int64_t)(i64rd[6] & 0xff) << 8) |
297 ((int64_t)(i64rd[7] & 0xff));
298}
299
Roger Meier6b616012015-03-01 12:32:50 +0100300- (double) readDouble
Mark Slee7e9eea42007-09-10 21:00:23 +0000301{
302 // FIXME - will this get us into trouble on PowerPC?
303 int64_t ieee754 = [self readI64];
304 return *((double *) &ieee754);
305}
306
307
308- (NSData *) readBinary
309{
310 int32_t size = [self readI32];
Roger Meier6b616012015-03-01 12:32:50 +0100311 size_t binarySize = CheckedCastInt32ToSizeT(size);
312 uint8_t * buff = malloc(binarySize);
Mark Slee7e9eea42007-09-10 21:00:23 +0000313 if (buff == NULL) {
David Reiss0c90f6f2008-02-06 22:18:40 +0000314 @throw [TProtocolException
Mark Slee77575e62007-09-24 19:24:53 +0000315 exceptionWithName: @"TProtocolException"
316 reason: [NSString stringWithFormat: @"Out of memory. Unable to allocate %d bytes trying to read binary data.",
Mark Slee33a7d892007-09-14 19:44:30 +0000317 size]];
Mark Slee7e9eea42007-09-10 21:00:23 +0000318 }
Roger Meier6b616012015-03-01 12:32:50 +0100319 [mTransport readAll: buff offset: 0 length: binarySize];
320 return [NSData dataWithBytesNoCopy: buff length: binarySize];
Mark Slee7e9eea42007-09-10 21:00:23 +0000321}
322
323
Mark Slee33a7d892007-09-14 19:44:30 +0000324- (void) readMapBeginReturningKeyType: (int *) keyType
325 valueType: (int *) valueType
326 size: (int *) size
Mark Slee7e9eea42007-09-10 21:00:23 +0000327{
328 int kt = [self readByte];
329 int vt = [self readByte];
330 int s = [self readI32];
331 if (keyType != NULL) {
332 *keyType = kt;
333 }
334 if (valueType != NULL) {
335 *valueType = vt;
336 }
337 if (size != NULL) {
338 *size = s;
339 }
340}
341
342- (void) readMapEnd {}
343
344
Mark Slee33a7d892007-09-14 19:44:30 +0000345- (void) readSetBeginReturningElementType: (int *) elementType
346 size: (int *) size
Mark Slee7e9eea42007-09-10 21:00:23 +0000347{
348 int et = [self readByte];
349 int s = [self readI32];
350 if (elementType != NULL) {
351 *elementType = et;
352 }
353 if (size != NULL) {
354 *size = s;
355 }
356}
357
358
359- (void) readSetEnd {}
360
361
Mark Slee33a7d892007-09-14 19:44:30 +0000362- (void) readListBeginReturningElementType: (int *) elementType
363 size: (int *) size
Mark Slee7e9eea42007-09-10 21:00:23 +0000364{
365 int et = [self readByte];
366 int s = [self readI32];
367 if (elementType != NULL) {
368 *elementType = et;
369 }
370 if (size != NULL) {
371 *size = s;
372 }
373}
374
375
376- (void) readListEnd {}
377
378
379- (void) writeByte: (uint8_t) value
380{
381 [mTransport write: &value offset: 0 length: 1];
382}
383
384
385- (void) writeMessageBeginWithName: (NSString *) name
386 type: (int) messageType
387 sequenceID: (int) sequenceID
388{
389 if (mStrictWrite) {
Jens Geyer2aa04bf2015-04-17 18:44:37 +0200390 int version = (VERSION_1 << 16) | messageType;
Mark Slee7e9eea42007-09-10 21:00:23 +0000391 [self writeI32: version];
392 [self writeString: name];
393 [self writeI32: sequenceID];
394 } else {
395 [self writeString: name];
Roger Meier6b616012015-03-01 12:32:50 +0100396 [self writeByte: CheckedCastIntToUInt8(messageType)];
Mark Slee7e9eea42007-09-10 21:00:23 +0000397 [self writeI32: sequenceID];
398 }
399}
400
401
402- (void) writeMessageEnd {}
403
404
405- (void) writeStructBeginWithName: (NSString *) name {}
406
407
408- (void) writeStructEnd {}
409
410
411- (void) writeFieldBeginWithName: (NSString *) name
412 type: (int) fieldType
413 fieldID: (int) fieldID
414{
Roger Meier6b616012015-03-01 12:32:50 +0100415 [self writeByte: CheckedCastIntToUInt8(fieldType)];
416 [self writeI16: CheckedCastIntToUInt8(fieldID)];
Mark Slee7e9eea42007-09-10 21:00:23 +0000417}
418
419
420- (void) writeI32: (int32_t) value
421{
422 uint8_t buff[4];
423 buff[0] = 0xFF & (value >> 24);
424 buff[1] = 0xFF & (value >> 16);
425 buff[2] = 0xFF & (value >> 8);
426 buff[3] = 0xFF & value;
427 [mTransport write: buff offset: 0 length: 4];
428}
429
430- (void) writeI16: (short) value
431{
432 uint8_t buff[2];
433 buff[0] = 0xff & (value >> 8);
434 buff[1] = 0xff & value;
435 [mTransport write: buff offset: 0 length: 2];
436}
437
438
439- (void) writeI64: (int64_t) value
440{
441 uint8_t buff[8];
442 buff[0] = 0xFF & (value >> 56);
443 buff[1] = 0xFF & (value >> 48);
444 buff[2] = 0xFF & (value >> 40);
445 buff[3] = 0xFF & (value >> 32);
446 buff[4] = 0xFF & (value >> 24);
447 buff[5] = 0xFF & (value >> 16);
448 buff[6] = 0xFF & (value >> 8);
449 buff[7] = 0xFF & value;
450 [mTransport write: buff offset: 0 length: 8];
451}
452
453- (void) writeDouble: (double) value
454{
455 // spit out IEEE 754 bits - FIXME - will this get us in trouble on
456 // PowerPC?
457 [self writeI64: *((int64_t *) &value)];
458}
459
Mark Sleeaa3c5a82007-09-19 21:12:52 +0000460
Mark Slee7e9eea42007-09-10 21:00:23 +0000461- (void) writeString: (NSString *) value
462{
Mark Sleeaa3c5a82007-09-19 21:12:52 +0000463 if (value != nil) {
464 const char * utf8Bytes = [value UTF8String];
465 size_t length = strlen(utf8Bytes);
Roger Meier6b616012015-03-01 12:32:50 +0100466 int32_t size = CheckedCastSizeTToInt32(length);
467 [self writeI32: size];
Mark Sleeaa3c5a82007-09-19 21:12:52 +0000468 [mTransport write: (uint8_t *) utf8Bytes offset: 0 length: length];
469 } else {
Mark Slee77575e62007-09-24 19:24:53 +0000470 // instead of crashing when we get null, let's write out a zero
471 // length string
Mark Sleeaa3c5a82007-09-19 21:12:52 +0000472 [self writeI32: 0];
473 }
Mark Slee7e9eea42007-09-10 21:00:23 +0000474}
475
476
David Reiss0c90f6f2008-02-06 22:18:40 +0000477- (void) writeBinary: (NSData *) data
Mark Slee7e9eea42007-09-10 21:00:23 +0000478{
Roger Meier6b616012015-03-01 12:32:50 +0100479 int32_t size = CheckedCastSizeTToInt32([data length]);
480 [self writeI32: size];
Mark Slee7e9eea42007-09-10 21:00:23 +0000481 [mTransport write: [data bytes] offset: 0 length: [data length]];
482}
483
484- (void) writeFieldStop
485{
486 [self writeByte: TType_STOP];
487}
488
489
490- (void) writeFieldEnd {}
491
492
493- (void) writeMapBeginWithKeyType: (int) keyType
494 valueType: (int) valueType
495 size: (int) size
496{
Roger Meier6b616012015-03-01 12:32:50 +0100497 [self writeByte: CheckedCastIntToUInt8(keyType)];
498 [self writeByte: CheckedCastIntToUInt8(valueType)];
Mark Slee7e9eea42007-09-10 21:00:23 +0000499 [self writeI32: size];
500}
501
502- (void) writeMapEnd {}
503
504
505- (void) writeSetBeginWithElementType: (int) elementType
506 size: (int) size
507{
Roger Meier6b616012015-03-01 12:32:50 +0100508 [self writeByte: CheckedCastIntToUInt8(elementType)];
Mark Slee7e9eea42007-09-10 21:00:23 +0000509 [self writeI32: size];
510}
511
512- (void) writeSetEnd {}
513
514
515- (void) writeListBeginWithElementType: (int) elementType
516 size: (int) size
517{
Roger Meier6b616012015-03-01 12:32:50 +0100518 [self writeByte: CheckedCastIntToUInt8(elementType)];
Mark Slee7e9eea42007-09-10 21:00:23 +0000519 [self writeI32: size];
520}
521
522- (void) writeListEnd {}
523
524
525- (void) writeBool: (BOOL) value
526{
527 [self writeByte: (value ? 1 : 0)];
528}
529
530@end