blob: e79bd5764e6780e33929cda2d9b6f6f5797afc8f [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
Roger Meier6b616012015-03-01 12:32:50 +010024static const uint16_t VERSION_1 = 0x8001;
Mark Slee7e9eea42007-09-10 21:00:23 +000025
Roger Meier6b616012015-03-01 12:32:50 +010026union versioned_size {
27 int32_t i32;
28 struct {
29 uint16_t version;
30 int16_t size;
31 } packed;
32};
33
34NS_INLINE size_t
35CheckedCastInt32ToSizeT(int32_t size)
36{
37 if (size < 0) {
38 NSString *reason = [NSString stringWithFormat:
39 @"%s: refusing to read data with negative size: %"PRId32,
40 __func__, size];
41 @throw [TProtocolException
42 exceptionWithName: @"TProtocolException"
43 reason: reason];
44 }
45 size_t checkedSize = (size_t)size;
46 return checkedSize;
47}
48
49NS_INLINE int32_t
50CheckedCastSizeTToInt32(size_t size)
51{
52 if (size > INT32_MAX) {
53 NSString *reason = [NSString stringWithFormat:
54 @"%s: data size exceeds values representable by a 32-bit signed integer: %zu",
55 __func__, size];
56 @throw [TProtocolException
57 exceptionWithName: @"TProtocolException"
58 reason: reason];
59 }
60 int32_t checkedSize = (int32_t)size;
61 return checkedSize;
62}
63
64NS_INLINE uint8_t
65CheckedCastIntToUInt8(int size)
66{
67 if (size > UINT8_MAX) {
68 NSString *reason = [NSString stringWithFormat:
69 @"%s: data size exceeds values representable by a 8-bit unsigned integer: %d",
70 __func__, size];
71 @throw [TProtocolException
72 exceptionWithName: @"TProtocolException"
73 reason: reason];
74 }
75 uint8_t checkedSize = (uint8_t)size;
76 return checkedSize;
77}
Mark Slee7e9eea42007-09-10 21:00:23 +000078
Mark Slee77575e62007-09-24 19:24:53 +000079static TBinaryProtocolFactory * gSharedFactory = nil;
80
David Reiss0c90f6f2008-02-06 22:18:40 +000081@implementation TBinaryProtocolFactory
Mark Slee77575e62007-09-24 19:24:53 +000082
83+ (TBinaryProtocolFactory *) sharedFactory {
84 if (gSharedFactory == nil) {
85 gSharedFactory = [[TBinaryProtocolFactory alloc] init];
86 }
David Reiss0c90f6f2008-02-06 22:18:40 +000087
Mark Slee77575e62007-09-24 19:24:53 +000088 return gSharedFactory;
89}
90
91- (TBinaryProtocol *) newProtocolOnTransport: (id <TTransport>) transport {
Andrew McGeachieda50d552010-07-21 19:14:44 +000092 return [[TBinaryProtocol alloc] initWithTransport: transport];
Mark Slee77575e62007-09-24 19:24:53 +000093}
94
95@end
96
97
98
Mark Slee7e9eea42007-09-10 21:00:23 +000099@implementation TBinaryProtocol
100
101- (id) initWithTransport: (id <TTransport>) transport
102{
Carl Yeksigianf0293452013-08-13 18:09:59 -0400103 return [self initWithTransport: transport strictRead: NO strictWrite: YES];
Mark Slee7e9eea42007-09-10 21:00:23 +0000104}
105
David Reiss0c90f6f2008-02-06 22:18:40 +0000106- (id) initWithTransport: (id <TTransport>) transport
Mark Slee7e9eea42007-09-10 21:00:23 +0000107 strictRead: (BOOL) strictRead
108 strictWrite: (BOOL) strictWrite
109{
110 self = [super init];
Jake Farrell9689d892011-12-06 01:07:17 +0000111 mTransport = [transport retain_stub];
Mark Slee7e9eea42007-09-10 21:00:23 +0000112 mStrictRead = strictRead;
113 mStrictWrite = strictWrite;
114 return self;
115}
116
117
Mark Slee84406052007-11-20 01:39:25 +0000118- (int32_t) messageSizeLimit
119{
120 return mMessageSizeLimit;
121}
122
123
124- (void) setMessageSizeLimit: (int32_t) sizeLimit
125{
126 mMessageSizeLimit = sizeLimit;
127}
128
129
Mark Sleeaa3c5a82007-09-19 21:12:52 +0000130- (void) dealloc
131{
Jake Farrell9689d892011-12-06 01:07:17 +0000132 [mTransport release_stub];
133 [super dealloc_stub];
Mark Sleeaa3c5a82007-09-19 21:12:52 +0000134}
135
136
Mark Slee7e9eea42007-09-10 21:00:23 +0000137- (id <TTransport>) transport
138{
139 return mTransport;
140}
141
142
Roger Meier6b616012015-03-01 12:32:50 +0100143- (NSString *) readStringBody: (int) rawSize
Mark Slee7e9eea42007-09-10 21:00:23 +0000144{
Roger Meier6b616012015-03-01 12:32:50 +0100145 size_t size = CheckedCastInt32ToSizeT(rawSize);
Andrew McGeachie061722b2009-07-23 18:12:18 +0000146 char * buffer = malloc(size+1);
147 if (!buffer) {
148 @throw [TProtocolException exceptionWithName: @"TProtocolException"
Roger Meier6b616012015-03-01 12:32:50 +0100149 reason: [NSString stringWithFormat: @"Unable to allocate memory in %s, size: %zu",
Andrew McGeachie061722b2009-07-23 18:12:18 +0000150 __PRETTY_FUNCTION__,
151 size]];;
152 }
153 [mTransport readAll: (uint8_t *) buffer offset: 0 length: size];
154 buffer[size] = 0;
155 NSString * result = [NSString stringWithUTF8String: buffer];
156 free(buffer);
157 return result;
Mark Slee7e9eea42007-09-10 21:00:23 +0000158}
159
160
Mark Slee33a7d892007-09-14 19:44:30 +0000161- (void) readMessageBeginReturningName: (NSString **) name
162 type: (int *) type
163 sequenceID: (int *) sequenceID
Mark Slee7e9eea42007-09-10 21:00:23 +0000164{
Mark Slee84406052007-11-20 01:39:25 +0000165 int32_t size = [self readI32];
Mark Slee7e9eea42007-09-10 21:00:23 +0000166 if (size < 0) {
Roger Meier6b616012015-03-01 12:32:50 +0100167 union versioned_size vsize;
168 vsize.i32 = size;
169 uint16_t version = vsize.packed.version;
Mark Slee7e9eea42007-09-10 21:00:23 +0000170 if (version != VERSION_1) {
Roger Meier6b616012015-03-01 12:32:50 +0100171 NSString *reason = [NSString stringWithFormat:
172 @"%s: Expected version %"PRIu16", instead found: %"PRIu16,
173 __func__, VERSION_1, version];
Mark Slee77575e62007-09-24 19:24:53 +0000174 @throw [TProtocolException exceptionWithName: @"TProtocolException"
Roger Meier6b616012015-03-01 12:32:50 +0100175 reason: reason];
Mark Slee7e9eea42007-09-10 21:00:23 +0000176 }
177 if (type != NULL) {
Roger Meierff951bd2013-03-22 22:12:19 +0100178 *type = size & 0x00FF;
Mark Slee7e9eea42007-09-10 21:00:23 +0000179 }
180 NSString * messageName = [self readString];
181 if (name != NULL) {
182 *name = messageName;
183 }
184 int seqID = [self readI32];
185 if (sequenceID != NULL) {
186 *sequenceID = seqID;
187 }
188 } else {
189 if (mStrictRead) {
Mark Slee77575e62007-09-24 19:24:53 +0000190 @throw [TProtocolException exceptionWithName: @"TProtocolException"
191 reason: @"Missing version in readMessageBegin, old client?"];
Mark Slee7e9eea42007-09-10 21:00:23 +0000192 }
Mark Slee84406052007-11-20 01:39:25 +0000193 if ([self messageSizeLimit] > 0 && size > [self messageSizeLimit]) {
194 @throw [TProtocolException exceptionWithName: @"TProtocolException"
195 reason: [NSString stringWithFormat: @"Message too big. Size limit is: %d Message size is: %d",
196 mMessageSizeLimit,
David Reiss0c90f6f2008-02-06 22:18:40 +0000197 size]];
Mark Slee84406052007-11-20 01:39:25 +0000198 }
Mark Slee7e9eea42007-09-10 21:00:23 +0000199 NSString * messageName = [self readStringBody: size];
200 if (name != NULL) {
201 *name = messageName;
202 }
203 int messageType = [self readByte];
204 if (type != NULL) {
205 *type = messageType;
206 }
207 int seqID = [self readI32];
208 if (sequenceID != NULL) {
209 *sequenceID = seqID;
210 }
211 }
212}
213
214
215- (void) readMessageEnd {}
216
217
Mark Slee33a7d892007-09-14 19:44:30 +0000218- (void) readStructBeginReturningName: (NSString **) name
Mark Slee7e9eea42007-09-10 21:00:23 +0000219{
220 if (name != NULL) {
221 *name = nil;
222 }
223}
224
225
226- (void) readStructEnd {}
227
228
Mark Slee33a7d892007-09-14 19:44:30 +0000229- (void) readFieldBeginReturningName: (NSString **) name
230 type: (int *) fieldType
231 fieldID: (int *) fieldID
Mark Slee7e9eea42007-09-10 21:00:23 +0000232{
233 if (name != NULL) {
234 *name = nil;
235 }
236 int ft = [self readByte];
237 if (fieldType != NULL) {
238 *fieldType = ft;
David Reiss0c90f6f2008-02-06 22:18:40 +0000239 }
Mark Slee7e9eea42007-09-10 21:00:23 +0000240 if (ft != TType_STOP) {
241 int fid = [self readI16];
242 if (fieldID != NULL) {
243 *fieldID = fid;
244 }
245 }
246}
247
248
249- (void) readFieldEnd {}
250
251
252- (int32_t) readI32
253{
254 uint8_t i32rd[4];
255 [mTransport readAll: i32rd offset: 0 length: 4];
256 return
257 ((i32rd[0] & 0xff) << 24) |
258 ((i32rd[1] & 0xff) << 16) |
259 ((i32rd[2] & 0xff) << 8) |
260 ((i32rd[3] & 0xff));
261}
262
263
264- (NSString *) readString
265{
Roger Meier6b616012015-03-01 12:32:50 +0100266 int32_t size = [self readI32];
Mark Slee7e9eea42007-09-10 21:00:23 +0000267 return [self readStringBody: size];
268}
269
270
271- (BOOL) readBool
272{
273 return [self readByte] == 1;
274}
275
276- (uint8_t) readByte
277{
278 uint8_t myByte;
279 [mTransport readAll: &myByte offset: 0 length: 1];
280 return myByte;
281}
282
283- (short) readI16
284{
285 uint8_t buff[2];
286 [mTransport readAll: buff offset: 0 length: 2];
287 return (short)
288 (((buff[0] & 0xff) << 8) |
289 ((buff[1] & 0xff)));
Mark Slee7e9eea42007-09-10 21:00:23 +0000290}
291
Roger Meier6b616012015-03-01 12:32:50 +0100292- (int64_t) readI64
Mark Slee7e9eea42007-09-10 21:00:23 +0000293{
294 uint8_t i64rd[8];
295 [mTransport readAll: i64rd offset: 0 length: 8];
296 return
297 ((int64_t)(i64rd[0] & 0xff) << 56) |
298 ((int64_t)(i64rd[1] & 0xff) << 48) |
299 ((int64_t)(i64rd[2] & 0xff) << 40) |
300 ((int64_t)(i64rd[3] & 0xff) << 32) |
301 ((int64_t)(i64rd[4] & 0xff) << 24) |
302 ((int64_t)(i64rd[5] & 0xff) << 16) |
303 ((int64_t)(i64rd[6] & 0xff) << 8) |
304 ((int64_t)(i64rd[7] & 0xff));
305}
306
Roger Meier6b616012015-03-01 12:32:50 +0100307- (double) readDouble
Mark Slee7e9eea42007-09-10 21:00:23 +0000308{
309 // FIXME - will this get us into trouble on PowerPC?
310 int64_t ieee754 = [self readI64];
311 return *((double *) &ieee754);
312}
313
314
315- (NSData *) readBinary
316{
317 int32_t size = [self readI32];
Roger Meier6b616012015-03-01 12:32:50 +0100318 size_t binarySize = CheckedCastInt32ToSizeT(size);
319 uint8_t * buff = malloc(binarySize);
Mark Slee7e9eea42007-09-10 21:00:23 +0000320 if (buff == NULL) {
David Reiss0c90f6f2008-02-06 22:18:40 +0000321 @throw [TProtocolException
Mark Slee77575e62007-09-24 19:24:53 +0000322 exceptionWithName: @"TProtocolException"
323 reason: [NSString stringWithFormat: @"Out of memory. Unable to allocate %d bytes trying to read binary data.",
Mark Slee33a7d892007-09-14 19:44:30 +0000324 size]];
Mark Slee7e9eea42007-09-10 21:00:23 +0000325 }
Roger Meier6b616012015-03-01 12:32:50 +0100326 [mTransport readAll: buff offset: 0 length: binarySize];
327 return [NSData dataWithBytesNoCopy: buff length: binarySize];
Mark Slee7e9eea42007-09-10 21:00:23 +0000328}
329
330
Mark Slee33a7d892007-09-14 19:44:30 +0000331- (void) readMapBeginReturningKeyType: (int *) keyType
332 valueType: (int *) valueType
333 size: (int *) size
Mark Slee7e9eea42007-09-10 21:00:23 +0000334{
335 int kt = [self readByte];
336 int vt = [self readByte];
337 int s = [self readI32];
338 if (keyType != NULL) {
339 *keyType = kt;
340 }
341 if (valueType != NULL) {
342 *valueType = vt;
343 }
344 if (size != NULL) {
345 *size = s;
346 }
347}
348
349- (void) readMapEnd {}
350
351
Mark Slee33a7d892007-09-14 19:44:30 +0000352- (void) readSetBeginReturningElementType: (int *) elementType
353 size: (int *) size
Mark Slee7e9eea42007-09-10 21:00:23 +0000354{
355 int et = [self readByte];
356 int s = [self readI32];
357 if (elementType != NULL) {
358 *elementType = et;
359 }
360 if (size != NULL) {
361 *size = s;
362 }
363}
364
365
366- (void) readSetEnd {}
367
368
Mark Slee33a7d892007-09-14 19:44:30 +0000369- (void) readListBeginReturningElementType: (int *) elementType
370 size: (int *) size
Mark Slee7e9eea42007-09-10 21:00:23 +0000371{
372 int et = [self readByte];
373 int s = [self readI32];
374 if (elementType != NULL) {
375 *elementType = et;
376 }
377 if (size != NULL) {
378 *size = s;
379 }
380}
381
382
383- (void) readListEnd {}
384
385
386- (void) writeByte: (uint8_t) value
387{
388 [mTransport write: &value offset: 0 length: 1];
389}
390
391
392- (void) writeMessageBeginWithName: (NSString *) name
393 type: (int) messageType
394 sequenceID: (int) sequenceID
395{
396 if (mStrictWrite) {
397 int version = VERSION_1 | messageType;
398 [self writeI32: version];
399 [self writeString: name];
400 [self writeI32: sequenceID];
401 } else {
402 [self writeString: name];
Roger Meier6b616012015-03-01 12:32:50 +0100403 [self writeByte: CheckedCastIntToUInt8(messageType)];
Mark Slee7e9eea42007-09-10 21:00:23 +0000404 [self writeI32: sequenceID];
405 }
406}
407
408
409- (void) writeMessageEnd {}
410
411
412- (void) writeStructBeginWithName: (NSString *) name {}
413
414
415- (void) writeStructEnd {}
416
417
418- (void) writeFieldBeginWithName: (NSString *) name
419 type: (int) fieldType
420 fieldID: (int) fieldID
421{
Roger Meier6b616012015-03-01 12:32:50 +0100422 [self writeByte: CheckedCastIntToUInt8(fieldType)];
423 [self writeI16: CheckedCastIntToUInt8(fieldID)];
Mark Slee7e9eea42007-09-10 21:00:23 +0000424}
425
426
427- (void) writeI32: (int32_t) value
428{
429 uint8_t buff[4];
430 buff[0] = 0xFF & (value >> 24);
431 buff[1] = 0xFF & (value >> 16);
432 buff[2] = 0xFF & (value >> 8);
433 buff[3] = 0xFF & value;
434 [mTransport write: buff offset: 0 length: 4];
435}
436
437- (void) writeI16: (short) value
438{
439 uint8_t buff[2];
440 buff[0] = 0xff & (value >> 8);
441 buff[1] = 0xff & value;
442 [mTransport write: buff offset: 0 length: 2];
443}
444
445
446- (void) writeI64: (int64_t) value
447{
448 uint8_t buff[8];
449 buff[0] = 0xFF & (value >> 56);
450 buff[1] = 0xFF & (value >> 48);
451 buff[2] = 0xFF & (value >> 40);
452 buff[3] = 0xFF & (value >> 32);
453 buff[4] = 0xFF & (value >> 24);
454 buff[5] = 0xFF & (value >> 16);
455 buff[6] = 0xFF & (value >> 8);
456 buff[7] = 0xFF & value;
457 [mTransport write: buff offset: 0 length: 8];
458}
459
460- (void) writeDouble: (double) value
461{
462 // spit out IEEE 754 bits - FIXME - will this get us in trouble on
463 // PowerPC?
464 [self writeI64: *((int64_t *) &value)];
465}
466
Mark Sleeaa3c5a82007-09-19 21:12:52 +0000467
Mark Slee7e9eea42007-09-10 21:00:23 +0000468- (void) writeString: (NSString *) value
469{
Mark Sleeaa3c5a82007-09-19 21:12:52 +0000470 if (value != nil) {
471 const char * utf8Bytes = [value UTF8String];
472 size_t length = strlen(utf8Bytes);
Roger Meier6b616012015-03-01 12:32:50 +0100473 int32_t size = CheckedCastSizeTToInt32(length);
474 [self writeI32: size];
Mark Sleeaa3c5a82007-09-19 21:12:52 +0000475 [mTransport write: (uint8_t *) utf8Bytes offset: 0 length: length];
476 } else {
Mark Slee77575e62007-09-24 19:24:53 +0000477 // instead of crashing when we get null, let's write out a zero
478 // length string
Mark Sleeaa3c5a82007-09-19 21:12:52 +0000479 [self writeI32: 0];
480 }
Mark Slee7e9eea42007-09-10 21:00:23 +0000481}
482
483
David Reiss0c90f6f2008-02-06 22:18:40 +0000484- (void) writeBinary: (NSData *) data
Mark Slee7e9eea42007-09-10 21:00:23 +0000485{
Roger Meier6b616012015-03-01 12:32:50 +0100486 int32_t size = CheckedCastSizeTToInt32([data length]);
487 [self writeI32: size];
Mark Slee7e9eea42007-09-10 21:00:23 +0000488 [mTransport write: [data bytes] offset: 0 length: [data length]];
489}
490
491- (void) writeFieldStop
492{
493 [self writeByte: TType_STOP];
494}
495
496
497- (void) writeFieldEnd {}
498
499
500- (void) writeMapBeginWithKeyType: (int) keyType
501 valueType: (int) valueType
502 size: (int) size
503{
Roger Meier6b616012015-03-01 12:32:50 +0100504 [self writeByte: CheckedCastIntToUInt8(keyType)];
505 [self writeByte: CheckedCastIntToUInt8(valueType)];
Mark Slee7e9eea42007-09-10 21:00:23 +0000506 [self writeI32: size];
507}
508
509- (void) writeMapEnd {}
510
511
512- (void) writeSetBeginWithElementType: (int) elementType
513 size: (int) size
514{
Roger Meier6b616012015-03-01 12:32:50 +0100515 [self writeByte: CheckedCastIntToUInt8(elementType)];
Mark Slee7e9eea42007-09-10 21:00:23 +0000516 [self writeI32: size];
517}
518
519- (void) writeSetEnd {}
520
521
522- (void) writeListBeginWithElementType: (int) elementType
523 size: (int) size
524{
Roger Meier6b616012015-03-01 12:32:50 +0100525 [self writeByte: CheckedCastIntToUInt8(elementType)];
Mark Slee7e9eea42007-09-10 21:00:23 +0000526 [self writeI32: size];
527}
528
529- (void) writeListEnd {}
530
531
532- (void) writeBool: (BOOL) value
533{
534 [self writeByte: (value ? 1 : 0)];
535}
536
537@end