blob: f269aaa0cc72fb90ce57a1784c7088644696b6cc [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
24int32_t VERSION_1 = 0x80010000;
25int32_t VERSION_MASK = 0xffff0000;
26
27
Mark Slee77575e62007-09-24 19:24:53 +000028static TBinaryProtocolFactory * gSharedFactory = nil;
29
David Reiss0c90f6f2008-02-06 22:18:40 +000030@implementation TBinaryProtocolFactory
Mark Slee77575e62007-09-24 19:24:53 +000031
32+ (TBinaryProtocolFactory *) sharedFactory {
33 if (gSharedFactory == nil) {
34 gSharedFactory = [[TBinaryProtocolFactory alloc] init];
35 }
David Reiss0c90f6f2008-02-06 22:18:40 +000036
Mark Slee77575e62007-09-24 19:24:53 +000037 return gSharedFactory;
38}
39
40- (TBinaryProtocol *) newProtocolOnTransport: (id <TTransport>) transport {
Andrew McGeachieda50d552010-07-21 19:14:44 +000041 return [[TBinaryProtocol alloc] initWithTransport: transport];
Mark Slee77575e62007-09-24 19:24:53 +000042}
43
44@end
45
46
47
Mark Slee7e9eea42007-09-10 21:00:23 +000048@implementation TBinaryProtocol
49
50- (id) initWithTransport: (id <TTransport>) transport
51{
52 return [self initWithTransport: transport strictRead: NO strictWrite: NO];
53}
54
David Reiss0c90f6f2008-02-06 22:18:40 +000055- (id) initWithTransport: (id <TTransport>) transport
Mark Slee7e9eea42007-09-10 21:00:23 +000056 strictRead: (BOOL) strictRead
57 strictWrite: (BOOL) strictWrite
58{
59 self = [super init];
Jake Farrell9689d892011-12-06 01:07:17 +000060 mTransport = [transport retain_stub];
Mark Slee7e9eea42007-09-10 21:00:23 +000061 mStrictRead = strictRead;
62 mStrictWrite = strictWrite;
63 return self;
64}
65
66
Mark Slee84406052007-11-20 01:39:25 +000067- (int32_t) messageSizeLimit
68{
69 return mMessageSizeLimit;
70}
71
72
73- (void) setMessageSizeLimit: (int32_t) sizeLimit
74{
75 mMessageSizeLimit = sizeLimit;
76}
77
78
Mark Sleeaa3c5a82007-09-19 21:12:52 +000079- (void) dealloc
80{
Jake Farrell9689d892011-12-06 01:07:17 +000081 [mTransport release_stub];
82 [super dealloc_stub];
Mark Sleeaa3c5a82007-09-19 21:12:52 +000083}
84
85
Mark Slee7e9eea42007-09-10 21:00:23 +000086- (id <TTransport>) transport
87{
88 return mTransport;
89}
90
91
92- (NSString *) readStringBody: (int) size
93{
Andrew McGeachie061722b2009-07-23 18:12:18 +000094 char * buffer = malloc(size+1);
95 if (!buffer) {
96 @throw [TProtocolException exceptionWithName: @"TProtocolException"
97 reason: [NSString stringWithFormat: @"Unable to allocate memory in %s, size: %i",
98 __PRETTY_FUNCTION__,
99 size]];;
100 }
101 [mTransport readAll: (uint8_t *) buffer offset: 0 length: size];
102 buffer[size] = 0;
103 NSString * result = [NSString stringWithUTF8String: buffer];
104 free(buffer);
105 return result;
Mark Slee7e9eea42007-09-10 21:00:23 +0000106}
107
108
Mark Slee33a7d892007-09-14 19:44:30 +0000109- (void) readMessageBeginReturningName: (NSString **) name
110 type: (int *) type
111 sequenceID: (int *) sequenceID
Mark Slee7e9eea42007-09-10 21:00:23 +0000112{
Mark Slee84406052007-11-20 01:39:25 +0000113 int32_t size = [self readI32];
Mark Slee7e9eea42007-09-10 21:00:23 +0000114 if (size < 0) {
115 int version = size & VERSION_MASK;
116 if (version != VERSION_1) {
Mark Slee77575e62007-09-24 19:24:53 +0000117 @throw [TProtocolException exceptionWithName: @"TProtocolException"
118 reason: @"Bad version in readMessageBegin"];
Mark Slee7e9eea42007-09-10 21:00:23 +0000119 }
120 if (type != NULL) {
121 *type = version & 0x00FF;
122 }
123 NSString * messageName = [self readString];
124 if (name != NULL) {
125 *name = messageName;
126 }
127 int seqID = [self readI32];
128 if (sequenceID != NULL) {
129 *sequenceID = seqID;
130 }
131 } else {
132 if (mStrictRead) {
Mark Slee77575e62007-09-24 19:24:53 +0000133 @throw [TProtocolException exceptionWithName: @"TProtocolException"
134 reason: @"Missing version in readMessageBegin, old client?"];
Mark Slee7e9eea42007-09-10 21:00:23 +0000135 }
Mark Slee84406052007-11-20 01:39:25 +0000136 if ([self messageSizeLimit] > 0 && size > [self messageSizeLimit]) {
137 @throw [TProtocolException exceptionWithName: @"TProtocolException"
138 reason: [NSString stringWithFormat: @"Message too big. Size limit is: %d Message size is: %d",
139 mMessageSizeLimit,
David Reiss0c90f6f2008-02-06 22:18:40 +0000140 size]];
Mark Slee84406052007-11-20 01:39:25 +0000141 }
Mark Slee7e9eea42007-09-10 21:00:23 +0000142 NSString * messageName = [self readStringBody: size];
143 if (name != NULL) {
144 *name = messageName;
145 }
146 int messageType = [self readByte];
147 if (type != NULL) {
148 *type = messageType;
149 }
150 int seqID = [self readI32];
151 if (sequenceID != NULL) {
152 *sequenceID = seqID;
153 }
154 }
155}
156
157
158- (void) readMessageEnd {}
159
160
Mark Slee33a7d892007-09-14 19:44:30 +0000161- (void) readStructBeginReturningName: (NSString **) name
Mark Slee7e9eea42007-09-10 21:00:23 +0000162{
163 if (name != NULL) {
164 *name = nil;
165 }
166}
167
168
169- (void) readStructEnd {}
170
171
Mark Slee33a7d892007-09-14 19:44:30 +0000172- (void) readFieldBeginReturningName: (NSString **) name
173 type: (int *) fieldType
174 fieldID: (int *) fieldID
Mark Slee7e9eea42007-09-10 21:00:23 +0000175{
176 if (name != NULL) {
177 *name = nil;
178 }
179 int ft = [self readByte];
180 if (fieldType != NULL) {
181 *fieldType = ft;
David Reiss0c90f6f2008-02-06 22:18:40 +0000182 }
Mark Slee7e9eea42007-09-10 21:00:23 +0000183 if (ft != TType_STOP) {
184 int fid = [self readI16];
185 if (fieldID != NULL) {
186 *fieldID = fid;
187 }
188 }
189}
190
191
192- (void) readFieldEnd {}
193
194
195- (int32_t) readI32
196{
197 uint8_t i32rd[4];
198 [mTransport readAll: i32rd offset: 0 length: 4];
199 return
200 ((i32rd[0] & 0xff) << 24) |
201 ((i32rd[1] & 0xff) << 16) |
202 ((i32rd[2] & 0xff) << 8) |
203 ((i32rd[3] & 0xff));
204}
205
206
207- (NSString *) readString
208{
209 int size = [self readI32];
210 return [self readStringBody: size];
211}
212
213
214- (BOOL) readBool
215{
216 return [self readByte] == 1;
217}
218
219- (uint8_t) readByte
220{
221 uint8_t myByte;
222 [mTransport readAll: &myByte offset: 0 length: 1];
223 return myByte;
224}
225
226- (short) readI16
227{
228 uint8_t buff[2];
229 [mTransport readAll: buff offset: 0 length: 2];
230 return (short)
231 (((buff[0] & 0xff) << 8) |
232 ((buff[1] & 0xff)));
233 return 0;
234}
235
236- (int64_t) readI64;
237{
238 uint8_t i64rd[8];
239 [mTransport readAll: i64rd offset: 0 length: 8];
240 return
241 ((int64_t)(i64rd[0] & 0xff) << 56) |
242 ((int64_t)(i64rd[1] & 0xff) << 48) |
243 ((int64_t)(i64rd[2] & 0xff) << 40) |
244 ((int64_t)(i64rd[3] & 0xff) << 32) |
245 ((int64_t)(i64rd[4] & 0xff) << 24) |
246 ((int64_t)(i64rd[5] & 0xff) << 16) |
247 ((int64_t)(i64rd[6] & 0xff) << 8) |
248 ((int64_t)(i64rd[7] & 0xff));
249}
250
251- (double) readDouble;
252{
253 // FIXME - will this get us into trouble on PowerPC?
254 int64_t ieee754 = [self readI64];
255 return *((double *) &ieee754);
256}
257
258
259- (NSData *) readBinary
260{
261 int32_t size = [self readI32];
262 uint8_t * buff = malloc(size);
263 if (buff == NULL) {
David Reiss0c90f6f2008-02-06 22:18:40 +0000264 @throw [TProtocolException
Mark Slee77575e62007-09-24 19:24:53 +0000265 exceptionWithName: @"TProtocolException"
266 reason: [NSString stringWithFormat: @"Out of memory. Unable to allocate %d bytes trying to read binary data.",
Mark Slee33a7d892007-09-14 19:44:30 +0000267 size]];
Mark Slee7e9eea42007-09-10 21:00:23 +0000268 }
269 [mTransport readAll: buff offset: 0 length: size];
270 return [NSData dataWithBytesNoCopy: buff length: size];
271}
272
273
Mark Slee33a7d892007-09-14 19:44:30 +0000274- (void) readMapBeginReturningKeyType: (int *) keyType
275 valueType: (int *) valueType
276 size: (int *) size
Mark Slee7e9eea42007-09-10 21:00:23 +0000277{
278 int kt = [self readByte];
279 int vt = [self readByte];
280 int s = [self readI32];
281 if (keyType != NULL) {
282 *keyType = kt;
283 }
284 if (valueType != NULL) {
285 *valueType = vt;
286 }
287 if (size != NULL) {
288 *size = s;
289 }
290}
291
292- (void) readMapEnd {}
293
294
Mark Slee33a7d892007-09-14 19:44:30 +0000295- (void) readSetBeginReturningElementType: (int *) elementType
296 size: (int *) size
Mark Slee7e9eea42007-09-10 21:00:23 +0000297{
298 int et = [self readByte];
299 int s = [self readI32];
300 if (elementType != NULL) {
301 *elementType = et;
302 }
303 if (size != NULL) {
304 *size = s;
305 }
306}
307
308
309- (void) readSetEnd {}
310
311
Mark Slee33a7d892007-09-14 19:44:30 +0000312- (void) readListBeginReturningElementType: (int *) elementType
313 size: (int *) size
Mark Slee7e9eea42007-09-10 21:00:23 +0000314{
315 int et = [self readByte];
316 int s = [self readI32];
317 if (elementType != NULL) {
318 *elementType = et;
319 }
320 if (size != NULL) {
321 *size = s;
322 }
323}
324
325
326- (void) readListEnd {}
327
328
329- (void) writeByte: (uint8_t) value
330{
331 [mTransport write: &value offset: 0 length: 1];
332}
333
334
335- (void) writeMessageBeginWithName: (NSString *) name
336 type: (int) messageType
337 sequenceID: (int) sequenceID
338{
339 if (mStrictWrite) {
340 int version = VERSION_1 | messageType;
341 [self writeI32: version];
342 [self writeString: name];
343 [self writeI32: sequenceID];
344 } else {
345 [self writeString: name];
346 [self writeByte: messageType];
347 [self writeI32: sequenceID];
348 }
349}
350
351
352- (void) writeMessageEnd {}
353
354
355- (void) writeStructBeginWithName: (NSString *) name {}
356
357
358- (void) writeStructEnd {}
359
360
361- (void) writeFieldBeginWithName: (NSString *) name
362 type: (int) fieldType
363 fieldID: (int) fieldID
364{
365 [self writeByte: fieldType];
366 [self writeI16: fieldID];
367}
368
369
370- (void) writeI32: (int32_t) value
371{
372 uint8_t buff[4];
373 buff[0] = 0xFF & (value >> 24);
374 buff[1] = 0xFF & (value >> 16);
375 buff[2] = 0xFF & (value >> 8);
376 buff[3] = 0xFF & value;
377 [mTransport write: buff offset: 0 length: 4];
378}
379
380- (void) writeI16: (short) value
381{
382 uint8_t buff[2];
383 buff[0] = 0xff & (value >> 8);
384 buff[1] = 0xff & value;
385 [mTransport write: buff offset: 0 length: 2];
386}
387
388
389- (void) writeI64: (int64_t) value
390{
391 uint8_t buff[8];
392 buff[0] = 0xFF & (value >> 56);
393 buff[1] = 0xFF & (value >> 48);
394 buff[2] = 0xFF & (value >> 40);
395 buff[3] = 0xFF & (value >> 32);
396 buff[4] = 0xFF & (value >> 24);
397 buff[5] = 0xFF & (value >> 16);
398 buff[6] = 0xFF & (value >> 8);
399 buff[7] = 0xFF & value;
400 [mTransport write: buff offset: 0 length: 8];
401}
402
403- (void) writeDouble: (double) value
404{
405 // spit out IEEE 754 bits - FIXME - will this get us in trouble on
406 // PowerPC?
407 [self writeI64: *((int64_t *) &value)];
408}
409
Mark Sleeaa3c5a82007-09-19 21:12:52 +0000410
Mark Slee7e9eea42007-09-10 21:00:23 +0000411- (void) writeString: (NSString *) value
412{
Mark Sleeaa3c5a82007-09-19 21:12:52 +0000413 if (value != nil) {
414 const char * utf8Bytes = [value UTF8String];
415 size_t length = strlen(utf8Bytes);
416 [self writeI32: length];
417 [mTransport write: (uint8_t *) utf8Bytes offset: 0 length: length];
418 } else {
Mark Slee77575e62007-09-24 19:24:53 +0000419 // instead of crashing when we get null, let's write out a zero
420 // length string
Mark Sleeaa3c5a82007-09-19 21:12:52 +0000421 [self writeI32: 0];
422 }
Mark Slee7e9eea42007-09-10 21:00:23 +0000423}
424
425
David Reiss0c90f6f2008-02-06 22:18:40 +0000426- (void) writeBinary: (NSData *) data
Mark Slee7e9eea42007-09-10 21:00:23 +0000427{
428 [self writeI32: [data length]];
429 [mTransport write: [data bytes] offset: 0 length: [data length]];
430}
431
432- (void) writeFieldStop
433{
434 [self writeByte: TType_STOP];
435}
436
437
438- (void) writeFieldEnd {}
439
440
441- (void) writeMapBeginWithKeyType: (int) keyType
442 valueType: (int) valueType
443 size: (int) size
444{
445 [self writeByte: keyType];
446 [self writeByte: valueType];
447 [self writeI32: size];
448}
449
450- (void) writeMapEnd {}
451
452
453- (void) writeSetBeginWithElementType: (int) elementType
454 size: (int) size
455{
456 [self writeByte: elementType];
457 [self writeI32: size];
458}
459
460- (void) writeSetEnd {}
461
462
463- (void) writeListBeginWithElementType: (int) elementType
464 size: (int) size
465{
466 [self writeByte: elementType];
467 [self writeI32: size];
468}
469
470- (void) writeListEnd {}
471
472
473- (void) writeBool: (BOOL) value
474{
475 [self writeByte: (value ? 1 : 0)];
476}
477
478@end