blob: ba7f4629d9ae5fdf1d7c44fdc650df4b6422c4ea [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{
93 char buff[size+1];
94 [mTransport readAll: (uint8_t *) buff offset: 0 length: size];
95 buff[size] = 0;
96 return [NSString stringWithUTF8String: buff];
97}
98
99
Mark Slee33a7d892007-09-14 19:44:30 +0000100- (void) readMessageBeginReturningName: (NSString **) name
101 type: (int *) type
102 sequenceID: (int *) sequenceID
Mark Slee7e9eea42007-09-10 21:00:23 +0000103{
Mark Slee84406052007-11-20 01:39:25 +0000104 int32_t size = [self readI32];
Mark Slee7e9eea42007-09-10 21:00:23 +0000105 if (size < 0) {
106 int version = size & VERSION_MASK;
107 if (version != VERSION_1) {
Mark Slee77575e62007-09-24 19:24:53 +0000108 @throw [TProtocolException exceptionWithName: @"TProtocolException"
109 reason: @"Bad version in readMessageBegin"];
Mark Slee7e9eea42007-09-10 21:00:23 +0000110 }
111 if (type != NULL) {
112 *type = version & 0x00FF;
113 }
114 NSString * messageName = [self readString];
115 if (name != NULL) {
116 *name = messageName;
117 }
118 int seqID = [self readI32];
119 if (sequenceID != NULL) {
120 *sequenceID = seqID;
121 }
122 } else {
123 if (mStrictRead) {
Mark Slee77575e62007-09-24 19:24:53 +0000124 @throw [TProtocolException exceptionWithName: @"TProtocolException"
125 reason: @"Missing version in readMessageBegin, old client?"];
Mark Slee7e9eea42007-09-10 21:00:23 +0000126 }
Mark Slee84406052007-11-20 01:39:25 +0000127 if ([self messageSizeLimit] > 0 && size > [self messageSizeLimit]) {
128 @throw [TProtocolException exceptionWithName: @"TProtocolException"
129 reason: [NSString stringWithFormat: @"Message too big. Size limit is: %d Message size is: %d",
130 mMessageSizeLimit,
David Reiss0c90f6f2008-02-06 22:18:40 +0000131 size]];
Mark Slee84406052007-11-20 01:39:25 +0000132 }
Mark Slee7e9eea42007-09-10 21:00:23 +0000133 NSString * messageName = [self readStringBody: size];
134 if (name != NULL) {
135 *name = messageName;
136 }
137 int messageType = [self readByte];
138 if (type != NULL) {
139 *type = messageType;
140 }
141 int seqID = [self readI32];
142 if (sequenceID != NULL) {
143 *sequenceID = seqID;
144 }
145 }
146}
147
148
149- (void) readMessageEnd {}
150
151
Mark Slee33a7d892007-09-14 19:44:30 +0000152- (void) readStructBeginReturningName: (NSString **) name
Mark Slee7e9eea42007-09-10 21:00:23 +0000153{
154 if (name != NULL) {
155 *name = nil;
156 }
157}
158
159
160- (void) readStructEnd {}
161
162
Mark Slee33a7d892007-09-14 19:44:30 +0000163- (void) readFieldBeginReturningName: (NSString **) name
164 type: (int *) fieldType
165 fieldID: (int *) fieldID
Mark Slee7e9eea42007-09-10 21:00:23 +0000166{
167 if (name != NULL) {
168 *name = nil;
169 }
170 int ft = [self readByte];
171 if (fieldType != NULL) {
172 *fieldType = ft;
David Reiss0c90f6f2008-02-06 22:18:40 +0000173 }
Mark Slee7e9eea42007-09-10 21:00:23 +0000174 if (ft != TType_STOP) {
175 int fid = [self readI16];
176 if (fieldID != NULL) {
177 *fieldID = fid;
178 }
179 }
180}
181
182
183- (void) readFieldEnd {}
184
185
186- (int32_t) readI32
187{
188 uint8_t i32rd[4];
189 [mTransport readAll: i32rd offset: 0 length: 4];
190 return
191 ((i32rd[0] & 0xff) << 24) |
192 ((i32rd[1] & 0xff) << 16) |
193 ((i32rd[2] & 0xff) << 8) |
194 ((i32rd[3] & 0xff));
195}
196
197
198- (NSString *) readString
199{
200 int size = [self readI32];
201 return [self readStringBody: size];
202}
203
204
205- (BOOL) readBool
206{
207 return [self readByte] == 1;
208}
209
210- (uint8_t) readByte
211{
212 uint8_t myByte;
213 [mTransport readAll: &myByte offset: 0 length: 1];
214 return myByte;
215}
216
217- (short) readI16
218{
219 uint8_t buff[2];
220 [mTransport readAll: buff offset: 0 length: 2];
221 return (short)
222 (((buff[0] & 0xff) << 8) |
223 ((buff[1] & 0xff)));
224 return 0;
225}
226
227- (int64_t) readI64;
228{
229 uint8_t i64rd[8];
230 [mTransport readAll: i64rd offset: 0 length: 8];
231 return
232 ((int64_t)(i64rd[0] & 0xff) << 56) |
233 ((int64_t)(i64rd[1] & 0xff) << 48) |
234 ((int64_t)(i64rd[2] & 0xff) << 40) |
235 ((int64_t)(i64rd[3] & 0xff) << 32) |
236 ((int64_t)(i64rd[4] & 0xff) << 24) |
237 ((int64_t)(i64rd[5] & 0xff) << 16) |
238 ((int64_t)(i64rd[6] & 0xff) << 8) |
239 ((int64_t)(i64rd[7] & 0xff));
240}
241
242- (double) readDouble;
243{
244 // FIXME - will this get us into trouble on PowerPC?
245 int64_t ieee754 = [self readI64];
246 return *((double *) &ieee754);
247}
248
249
250- (NSData *) readBinary
251{
252 int32_t size = [self readI32];
253 uint8_t * buff = malloc(size);
254 if (buff == NULL) {
David Reiss0c90f6f2008-02-06 22:18:40 +0000255 @throw [TProtocolException
Mark Slee77575e62007-09-24 19:24:53 +0000256 exceptionWithName: @"TProtocolException"
257 reason: [NSString stringWithFormat: @"Out of memory. Unable to allocate %d bytes trying to read binary data.",
Mark Slee33a7d892007-09-14 19:44:30 +0000258 size]];
Mark Slee7e9eea42007-09-10 21:00:23 +0000259 }
260 [mTransport readAll: buff offset: 0 length: size];
261 return [NSData dataWithBytesNoCopy: buff length: size];
262}
263
264
Mark Slee33a7d892007-09-14 19:44:30 +0000265- (void) readMapBeginReturningKeyType: (int *) keyType
266 valueType: (int *) valueType
267 size: (int *) size
Mark Slee7e9eea42007-09-10 21:00:23 +0000268{
269 int kt = [self readByte];
270 int vt = [self readByte];
271 int s = [self readI32];
272 if (keyType != NULL) {
273 *keyType = kt;
274 }
275 if (valueType != NULL) {
276 *valueType = vt;
277 }
278 if (size != NULL) {
279 *size = s;
280 }
281}
282
283- (void) readMapEnd {}
284
285
Mark Slee33a7d892007-09-14 19:44:30 +0000286- (void) readSetBeginReturningElementType: (int *) elementType
287 size: (int *) size
Mark Slee7e9eea42007-09-10 21:00:23 +0000288{
289 int et = [self readByte];
290 int s = [self readI32];
291 if (elementType != NULL) {
292 *elementType = et;
293 }
294 if (size != NULL) {
295 *size = s;
296 }
297}
298
299
300- (void) readSetEnd {}
301
302
Mark Slee33a7d892007-09-14 19:44:30 +0000303- (void) readListBeginReturningElementType: (int *) elementType
304 size: (int *) size
Mark Slee7e9eea42007-09-10 21:00:23 +0000305{
306 int et = [self readByte];
307 int s = [self readI32];
308 if (elementType != NULL) {
309 *elementType = et;
310 }
311 if (size != NULL) {
312 *size = s;
313 }
314}
315
316
317- (void) readListEnd {}
318
319
320- (void) writeByte: (uint8_t) value
321{
322 [mTransport write: &value offset: 0 length: 1];
323}
324
325
326- (void) writeMessageBeginWithName: (NSString *) name
327 type: (int) messageType
328 sequenceID: (int) sequenceID
329{
330 if (mStrictWrite) {
331 int version = VERSION_1 | messageType;
332 [self writeI32: version];
333 [self writeString: name];
334 [self writeI32: sequenceID];
335 } else {
336 [self writeString: name];
337 [self writeByte: messageType];
338 [self writeI32: sequenceID];
339 }
340}
341
342
343- (void) writeMessageEnd {}
344
345
346- (void) writeStructBeginWithName: (NSString *) name {}
347
348
349- (void) writeStructEnd {}
350
351
352- (void) writeFieldBeginWithName: (NSString *) name
353 type: (int) fieldType
354 fieldID: (int) fieldID
355{
356 [self writeByte: fieldType];
357 [self writeI16: fieldID];
358}
359
360
361- (void) writeI32: (int32_t) value
362{
363 uint8_t buff[4];
364 buff[0] = 0xFF & (value >> 24);
365 buff[1] = 0xFF & (value >> 16);
366 buff[2] = 0xFF & (value >> 8);
367 buff[3] = 0xFF & value;
368 [mTransport write: buff offset: 0 length: 4];
369}
370
371- (void) writeI16: (short) value
372{
373 uint8_t buff[2];
374 buff[0] = 0xff & (value >> 8);
375 buff[1] = 0xff & value;
376 [mTransport write: buff offset: 0 length: 2];
377}
378
379
380- (void) writeI64: (int64_t) value
381{
382 uint8_t buff[8];
383 buff[0] = 0xFF & (value >> 56);
384 buff[1] = 0xFF & (value >> 48);
385 buff[2] = 0xFF & (value >> 40);
386 buff[3] = 0xFF & (value >> 32);
387 buff[4] = 0xFF & (value >> 24);
388 buff[5] = 0xFF & (value >> 16);
389 buff[6] = 0xFF & (value >> 8);
390 buff[7] = 0xFF & value;
391 [mTransport write: buff offset: 0 length: 8];
392}
393
394- (void) writeDouble: (double) value
395{
396 // spit out IEEE 754 bits - FIXME - will this get us in trouble on
397 // PowerPC?
398 [self writeI64: *((int64_t *) &value)];
399}
400
Mark Sleeaa3c5a82007-09-19 21:12:52 +0000401
Mark Slee7e9eea42007-09-10 21:00:23 +0000402- (void) writeString: (NSString *) value
403{
Mark Sleeaa3c5a82007-09-19 21:12:52 +0000404 if (value != nil) {
405 const char * utf8Bytes = [value UTF8String];
406 size_t length = strlen(utf8Bytes);
407 [self writeI32: length];
408 [mTransport write: (uint8_t *) utf8Bytes offset: 0 length: length];
409 } else {
Mark Slee77575e62007-09-24 19:24:53 +0000410 // instead of crashing when we get null, let's write out a zero
411 // length string
Mark Sleeaa3c5a82007-09-19 21:12:52 +0000412 [self writeI32: 0];
413 }
Mark Slee7e9eea42007-09-10 21:00:23 +0000414}
415
416
David Reiss0c90f6f2008-02-06 22:18:40 +0000417- (void) writeBinary: (NSData *) data
Mark Slee7e9eea42007-09-10 21:00:23 +0000418{
419 [self writeI32: [data length]];
420 [mTransport write: [data bytes] offset: 0 length: [data length]];
421}
422
423- (void) writeFieldStop
424{
425 [self writeByte: TType_STOP];
426}
427
428
429- (void) writeFieldEnd {}
430
431
432- (void) writeMapBeginWithKeyType: (int) keyType
433 valueType: (int) valueType
434 size: (int) size
435{
436 [self writeByte: keyType];
437 [self writeByte: valueType];
438 [self writeI32: size];
439}
440
441- (void) writeMapEnd {}
442
443
444- (void) writeSetBeginWithElementType: (int) elementType
445 size: (int) size
446{
447 [self writeByte: elementType];
448 [self writeI32: size];
449}
450
451- (void) writeSetEnd {}
452
453
454- (void) writeListBeginWithElementType: (int) elementType
455 size: (int) size
456{
457 [self writeByte: elementType];
458 [self writeI32: size];
459}
460
461- (void) writeListEnd {}
462
463
464- (void) writeBool: (BOOL) value
465{
466 [self writeByte: (value ? 1 : 0)];
467}
468
469@end