blob: 5999e25087fc9809ada0c539507fb493a7bc151c [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"
Mark Slee7e9eea42007-09-10 21:00:23 +000022
23int32_t VERSION_1 = 0x80010000;
24int32_t VERSION_MASK = 0xffff0000;
25
26
Mark Slee77575e62007-09-24 19:24:53 +000027static TBinaryProtocolFactory * gSharedFactory = nil;
28
David Reiss0c90f6f2008-02-06 22:18:40 +000029@implementation TBinaryProtocolFactory
Mark Slee77575e62007-09-24 19:24:53 +000030
31+ (TBinaryProtocolFactory *) sharedFactory {
32 if (gSharedFactory == nil) {
33 gSharedFactory = [[TBinaryProtocolFactory alloc] init];
34 }
David Reiss0c90f6f2008-02-06 22:18:40 +000035
Mark Slee77575e62007-09-24 19:24:53 +000036 return gSharedFactory;
37}
38
39- (TBinaryProtocol *) newProtocolOnTransport: (id <TTransport>) transport {
40 return [[[TBinaryProtocol alloc] initWithTransport: transport] autorelease];
41}
42
43@end
44
45
46
Mark Slee7e9eea42007-09-10 21:00:23 +000047@implementation TBinaryProtocol
48
49- (id) initWithTransport: (id <TTransport>) transport
50{
51 return [self initWithTransport: transport strictRead: NO strictWrite: NO];
52}
53
David Reiss0c90f6f2008-02-06 22:18:40 +000054- (id) initWithTransport: (id <TTransport>) transport
Mark Slee7e9eea42007-09-10 21:00:23 +000055 strictRead: (BOOL) strictRead
56 strictWrite: (BOOL) strictWrite
57{
58 self = [super init];
59 mTransport = [transport retain];
60 mStrictRead = strictRead;
61 mStrictWrite = strictWrite;
62 return self;
63}
64
65
Mark Slee84406052007-11-20 01:39:25 +000066- (int32_t) messageSizeLimit
67{
68 return mMessageSizeLimit;
69}
70
71
72- (void) setMessageSizeLimit: (int32_t) sizeLimit
73{
74 mMessageSizeLimit = sizeLimit;
75}
76
77
Mark Sleeaa3c5a82007-09-19 21:12:52 +000078- (void) dealloc
79{
80 [mTransport release];
81 [super dealloc];
82}
83
84
Mark Slee7e9eea42007-09-10 21:00:23 +000085- (id <TTransport>) transport
86{
87 return mTransport;
88}
89
90
91- (NSString *) readStringBody: (int) size
92{
Andrew McGeachie061722b2009-07-23 18:12:18 +000093 char * buffer = malloc(size+1);
94 if (!buffer) {
95 @throw [TProtocolException exceptionWithName: @"TProtocolException"
96 reason: [NSString stringWithFormat: @"Unable to allocate memory in %s, size: %i",
97 __PRETTY_FUNCTION__,
98 size]];;
99 }
100 [mTransport readAll: (uint8_t *) buffer offset: 0 length: size];
101 buffer[size] = 0;
102 NSString * result = [NSString stringWithUTF8String: buffer];
103 free(buffer);
104 return result;
Mark Slee7e9eea42007-09-10 21:00:23 +0000105}
106
107
Mark Slee33a7d892007-09-14 19:44:30 +0000108- (void) readMessageBeginReturningName: (NSString **) name
109 type: (int *) type
110 sequenceID: (int *) sequenceID
Mark Slee7e9eea42007-09-10 21:00:23 +0000111{
Mark Slee84406052007-11-20 01:39:25 +0000112 int32_t size = [self readI32];
Mark Slee7e9eea42007-09-10 21:00:23 +0000113 if (size < 0) {
114 int version = size & VERSION_MASK;
115 if (version != VERSION_1) {
Mark Slee77575e62007-09-24 19:24:53 +0000116 @throw [TProtocolException exceptionWithName: @"TProtocolException"
117 reason: @"Bad version in readMessageBegin"];
Mark Slee7e9eea42007-09-10 21:00:23 +0000118 }
119 if (type != NULL) {
120 *type = version & 0x00FF;
121 }
122 NSString * messageName = [self readString];
123 if (name != NULL) {
124 *name = messageName;
125 }
126 int seqID = [self readI32];
127 if (sequenceID != NULL) {
128 *sequenceID = seqID;
129 }
130 } else {
131 if (mStrictRead) {
Mark Slee77575e62007-09-24 19:24:53 +0000132 @throw [TProtocolException exceptionWithName: @"TProtocolException"
133 reason: @"Missing version in readMessageBegin, old client?"];
Mark Slee7e9eea42007-09-10 21:00:23 +0000134 }
Mark Slee84406052007-11-20 01:39:25 +0000135 if ([self messageSizeLimit] > 0 && size > [self messageSizeLimit]) {
136 @throw [TProtocolException exceptionWithName: @"TProtocolException"
137 reason: [NSString stringWithFormat: @"Message too big. Size limit is: %d Message size is: %d",
138 mMessageSizeLimit,
David Reiss0c90f6f2008-02-06 22:18:40 +0000139 size]];
Mark Slee84406052007-11-20 01:39:25 +0000140 }
Mark Slee7e9eea42007-09-10 21:00:23 +0000141 NSString * messageName = [self readStringBody: size];
142 if (name != NULL) {
143 *name = messageName;
144 }
145 int messageType = [self readByte];
146 if (type != NULL) {
147 *type = messageType;
148 }
149 int seqID = [self readI32];
150 if (sequenceID != NULL) {
151 *sequenceID = seqID;
152 }
153 }
154}
155
156
157- (void) readMessageEnd {}
158
159
Mark Slee33a7d892007-09-14 19:44:30 +0000160- (void) readStructBeginReturningName: (NSString **) name
Mark Slee7e9eea42007-09-10 21:00:23 +0000161{
162 if (name != NULL) {
163 *name = nil;
164 }
165}
166
167
168- (void) readStructEnd {}
169
170
Mark Slee33a7d892007-09-14 19:44:30 +0000171- (void) readFieldBeginReturningName: (NSString **) name
172 type: (int *) fieldType
173 fieldID: (int *) fieldID
Mark Slee7e9eea42007-09-10 21:00:23 +0000174{
175 if (name != NULL) {
176 *name = nil;
177 }
178 int ft = [self readByte];
179 if (fieldType != NULL) {
180 *fieldType = ft;
David Reiss0c90f6f2008-02-06 22:18:40 +0000181 }
Mark Slee7e9eea42007-09-10 21:00:23 +0000182 if (ft != TType_STOP) {
183 int fid = [self readI16];
184 if (fieldID != NULL) {
185 *fieldID = fid;
186 }
187 }
188}
189
190
191- (void) readFieldEnd {}
192
193
194- (int32_t) readI32
195{
196 uint8_t i32rd[4];
197 [mTransport readAll: i32rd offset: 0 length: 4];
198 return
199 ((i32rd[0] & 0xff) << 24) |
200 ((i32rd[1] & 0xff) << 16) |
201 ((i32rd[2] & 0xff) << 8) |
202 ((i32rd[3] & 0xff));
203}
204
205
206- (NSString *) readString
207{
208 int size = [self readI32];
209 return [self readStringBody: size];
210}
211
212
213- (BOOL) readBool
214{
215 return [self readByte] == 1;
216}
217
218- (uint8_t) readByte
219{
220 uint8_t myByte;
221 [mTransport readAll: &myByte offset: 0 length: 1];
222 return myByte;
223}
224
225- (short) readI16
226{
227 uint8_t buff[2];
228 [mTransport readAll: buff offset: 0 length: 2];
229 return (short)
230 (((buff[0] & 0xff) << 8) |
231 ((buff[1] & 0xff)));
232 return 0;
233}
234
235- (int64_t) readI64;
236{
237 uint8_t i64rd[8];
238 [mTransport readAll: i64rd offset: 0 length: 8];
239 return
240 ((int64_t)(i64rd[0] & 0xff) << 56) |
241 ((int64_t)(i64rd[1] & 0xff) << 48) |
242 ((int64_t)(i64rd[2] & 0xff) << 40) |
243 ((int64_t)(i64rd[3] & 0xff) << 32) |
244 ((int64_t)(i64rd[4] & 0xff) << 24) |
245 ((int64_t)(i64rd[5] & 0xff) << 16) |
246 ((int64_t)(i64rd[6] & 0xff) << 8) |
247 ((int64_t)(i64rd[7] & 0xff));
248}
249
250- (double) readDouble;
251{
252 // FIXME - will this get us into trouble on PowerPC?
253 int64_t ieee754 = [self readI64];
254 return *((double *) &ieee754);
255}
256
257
258- (NSData *) readBinary
259{
260 int32_t size = [self readI32];
261 uint8_t * buff = malloc(size);
262 if (buff == NULL) {
David Reiss0c90f6f2008-02-06 22:18:40 +0000263 @throw [TProtocolException
Mark Slee77575e62007-09-24 19:24:53 +0000264 exceptionWithName: @"TProtocolException"
265 reason: [NSString stringWithFormat: @"Out of memory. Unable to allocate %d bytes trying to read binary data.",
Mark Slee33a7d892007-09-14 19:44:30 +0000266 size]];
Mark Slee7e9eea42007-09-10 21:00:23 +0000267 }
268 [mTransport readAll: buff offset: 0 length: size];
269 return [NSData dataWithBytesNoCopy: buff length: size];
270}
271
272
Mark Slee33a7d892007-09-14 19:44:30 +0000273- (void) readMapBeginReturningKeyType: (int *) keyType
274 valueType: (int *) valueType
275 size: (int *) size
Mark Slee7e9eea42007-09-10 21:00:23 +0000276{
277 int kt = [self readByte];
278 int vt = [self readByte];
279 int s = [self readI32];
280 if (keyType != NULL) {
281 *keyType = kt;
282 }
283 if (valueType != NULL) {
284 *valueType = vt;
285 }
286 if (size != NULL) {
287 *size = s;
288 }
289}
290
291- (void) readMapEnd {}
292
293
Mark Slee33a7d892007-09-14 19:44:30 +0000294- (void) readSetBeginReturningElementType: (int *) elementType
295 size: (int *) size
Mark Slee7e9eea42007-09-10 21:00:23 +0000296{
297 int et = [self readByte];
298 int s = [self readI32];
299 if (elementType != NULL) {
300 *elementType = et;
301 }
302 if (size != NULL) {
303 *size = s;
304 }
305}
306
307
308- (void) readSetEnd {}
309
310
Mark Slee33a7d892007-09-14 19:44:30 +0000311- (void) readListBeginReturningElementType: (int *) elementType
312 size: (int *) size
Mark Slee7e9eea42007-09-10 21:00:23 +0000313{
314 int et = [self readByte];
315 int s = [self readI32];
316 if (elementType != NULL) {
317 *elementType = et;
318 }
319 if (size != NULL) {
320 *size = s;
321 }
322}
323
324
325- (void) readListEnd {}
326
327
328- (void) writeByte: (uint8_t) value
329{
330 [mTransport write: &value offset: 0 length: 1];
331}
332
333
334- (void) writeMessageBeginWithName: (NSString *) name
335 type: (int) messageType
336 sequenceID: (int) sequenceID
337{
338 if (mStrictWrite) {
339 int version = VERSION_1 | messageType;
340 [self writeI32: version];
341 [self writeString: name];
342 [self writeI32: sequenceID];
343 } else {
344 [self writeString: name];
345 [self writeByte: messageType];
346 [self writeI32: sequenceID];
347 }
348}
349
350
351- (void) writeMessageEnd {}
352
353
354- (void) writeStructBeginWithName: (NSString *) name {}
355
356
357- (void) writeStructEnd {}
358
359
360- (void) writeFieldBeginWithName: (NSString *) name
361 type: (int) fieldType
362 fieldID: (int) fieldID
363{
364 [self writeByte: fieldType];
365 [self writeI16: fieldID];
366}
367
368
369- (void) writeI32: (int32_t) value
370{
371 uint8_t buff[4];
372 buff[0] = 0xFF & (value >> 24);
373 buff[1] = 0xFF & (value >> 16);
374 buff[2] = 0xFF & (value >> 8);
375 buff[3] = 0xFF & value;
376 [mTransport write: buff offset: 0 length: 4];
377}
378
379- (void) writeI16: (short) value
380{
381 uint8_t buff[2];
382 buff[0] = 0xff & (value >> 8);
383 buff[1] = 0xff & value;
384 [mTransport write: buff offset: 0 length: 2];
385}
386
387
388- (void) writeI64: (int64_t) value
389{
390 uint8_t buff[8];
391 buff[0] = 0xFF & (value >> 56);
392 buff[1] = 0xFF & (value >> 48);
393 buff[2] = 0xFF & (value >> 40);
394 buff[3] = 0xFF & (value >> 32);
395 buff[4] = 0xFF & (value >> 24);
396 buff[5] = 0xFF & (value >> 16);
397 buff[6] = 0xFF & (value >> 8);
398 buff[7] = 0xFF & value;
399 [mTransport write: buff offset: 0 length: 8];
400}
401
402- (void) writeDouble: (double) value
403{
404 // spit out IEEE 754 bits - FIXME - will this get us in trouble on
405 // PowerPC?
406 [self writeI64: *((int64_t *) &value)];
407}
408
Mark Sleeaa3c5a82007-09-19 21:12:52 +0000409
Mark Slee7e9eea42007-09-10 21:00:23 +0000410- (void) writeString: (NSString *) value
411{
Mark Sleeaa3c5a82007-09-19 21:12:52 +0000412 if (value != nil) {
413 const char * utf8Bytes = [value UTF8String];
414 size_t length = strlen(utf8Bytes);
415 [self writeI32: length];
416 [mTransport write: (uint8_t *) utf8Bytes offset: 0 length: length];
417 } else {
Mark Slee77575e62007-09-24 19:24:53 +0000418 // instead of crashing when we get null, let's write out a zero
419 // length string
Mark Sleeaa3c5a82007-09-19 21:12:52 +0000420 [self writeI32: 0];
421 }
Mark Slee7e9eea42007-09-10 21:00:23 +0000422}
423
424
David Reiss0c90f6f2008-02-06 22:18:40 +0000425- (void) writeBinary: (NSData *) data
Mark Slee7e9eea42007-09-10 21:00:23 +0000426{
427 [self writeI32: [data length]];
428 [mTransport write: [data bytes] offset: 0 length: [data length]];
429}
430
431- (void) writeFieldStop
432{
433 [self writeByte: TType_STOP];
434}
435
436
437- (void) writeFieldEnd {}
438
439
440- (void) writeMapBeginWithKeyType: (int) keyType
441 valueType: (int) valueType
442 size: (int) size
443{
444 [self writeByte: keyType];
445 [self writeByte: valueType];
446 [self writeI32: size];
447}
448
449- (void) writeMapEnd {}
450
451
452- (void) writeSetBeginWithElementType: (int) elementType
453 size: (int) size
454{
455 [self writeByte: elementType];
456 [self writeI32: size];
457}
458
459- (void) writeSetEnd {}
460
461
462- (void) writeListBeginWithElementType: (int) elementType
463 size: (int) size
464{
465 [self writeByte: elementType];
466 [self writeI32: size];
467}
468
469- (void) writeListEnd {}
470
471
472- (void) writeBool: (BOOL) value
473{
474 [self writeByte: (value ? 1 : 0)];
475}
476
477@end