blob: 7564f5de66f034c2795bcd990a7a3dc113c9b1ac [file] [log] [blame]
Mark Slee7e9eea42007-09-10 21:00:23 +00001#import "TBinaryProtocol.h"
Mark Slee33a7d892007-09-14 19:44:30 +00002#import "TProtocolException.h"
Mark Slee7e9eea42007-09-10 21:00:23 +00003
4int32_t VERSION_1 = 0x80010000;
5int32_t VERSION_MASK = 0xffff0000;
6
7
Mark Slee77575e62007-09-24 19:24:53 +00008static TBinaryProtocolFactory * gSharedFactory = nil;
9
10@implementation TBinaryProtocolFactory
11
12+ (TBinaryProtocolFactory *) sharedFactory {
13 if (gSharedFactory == nil) {
14 gSharedFactory = [[TBinaryProtocolFactory alloc] init];
15 }
16
17 return gSharedFactory;
18}
19
20- (TBinaryProtocol *) newProtocolOnTransport: (id <TTransport>) transport {
21 return [[[TBinaryProtocol alloc] initWithTransport: transport] autorelease];
22}
23
24@end
25
26
27
Mark Slee7e9eea42007-09-10 21:00:23 +000028@implementation TBinaryProtocol
29
30- (id) initWithTransport: (id <TTransport>) transport
31{
32 return [self initWithTransport: transport strictRead: NO strictWrite: NO];
33}
34
35- (id) initWithTransport: (id <TTransport>) transport
36 strictRead: (BOOL) strictRead
37 strictWrite: (BOOL) strictWrite
38{
39 self = [super init];
40 mTransport = [transport retain];
41 mStrictRead = strictRead;
42 mStrictWrite = strictWrite;
43 return self;
44}
45
46
Mark Slee84406052007-11-20 01:39:25 +000047- (int32_t) messageSizeLimit
48{
49 return mMessageSizeLimit;
50}
51
52
53- (void) setMessageSizeLimit: (int32_t) sizeLimit
54{
55 mMessageSizeLimit = sizeLimit;
56}
57
58
Mark Sleeaa3c5a82007-09-19 21:12:52 +000059- (void) dealloc
60{
61 [mTransport release];
62 [super dealloc];
63}
64
65
Mark Slee7e9eea42007-09-10 21:00:23 +000066- (id <TTransport>) transport
67{
68 return mTransport;
69}
70
71
72- (NSString *) readStringBody: (int) size
73{
74 char buff[size+1];
75 [mTransport readAll: (uint8_t *) buff offset: 0 length: size];
76 buff[size] = 0;
77 return [NSString stringWithUTF8String: buff];
78}
79
80
Mark Slee33a7d892007-09-14 19:44:30 +000081- (void) readMessageBeginReturningName: (NSString **) name
82 type: (int *) type
83 sequenceID: (int *) sequenceID
Mark Slee7e9eea42007-09-10 21:00:23 +000084{
Mark Slee84406052007-11-20 01:39:25 +000085 int32_t size = [self readI32];
Mark Slee7e9eea42007-09-10 21:00:23 +000086 if (size < 0) {
87 int version = size & VERSION_MASK;
88 if (version != VERSION_1) {
Mark Slee77575e62007-09-24 19:24:53 +000089 @throw [TProtocolException exceptionWithName: @"TProtocolException"
90 reason: @"Bad version in readMessageBegin"];
Mark Slee7e9eea42007-09-10 21:00:23 +000091 }
92 if (type != NULL) {
93 *type = version & 0x00FF;
94 }
95 NSString * messageName = [self readString];
96 if (name != NULL) {
97 *name = messageName;
98 }
99 int seqID = [self readI32];
100 if (sequenceID != NULL) {
101 *sequenceID = seqID;
102 }
103 } else {
104 if (mStrictRead) {
Mark Slee77575e62007-09-24 19:24:53 +0000105 @throw [TProtocolException exceptionWithName: @"TProtocolException"
106 reason: @"Missing version in readMessageBegin, old client?"];
Mark Slee7e9eea42007-09-10 21:00:23 +0000107 }
Mark Slee84406052007-11-20 01:39:25 +0000108 if ([self messageSizeLimit] > 0 && size > [self messageSizeLimit]) {
109 @throw [TProtocolException exceptionWithName: @"TProtocolException"
110 reason: [NSString stringWithFormat: @"Message too big. Size limit is: %d Message size is: %d",
111 mMessageSizeLimit,
112 size]];
113 }
Mark Slee7e9eea42007-09-10 21:00:23 +0000114 NSString * messageName = [self readStringBody: size];
115 if (name != NULL) {
116 *name = messageName;
117 }
118 int messageType = [self readByte];
119 if (type != NULL) {
120 *type = messageType;
121 }
122 int seqID = [self readI32];
123 if (sequenceID != NULL) {
124 *sequenceID = seqID;
125 }
126 }
127}
128
129
130- (void) readMessageEnd {}
131
132
Mark Slee33a7d892007-09-14 19:44:30 +0000133- (void) readStructBeginReturningName: (NSString **) name
Mark Slee7e9eea42007-09-10 21:00:23 +0000134{
135 if (name != NULL) {
136 *name = nil;
137 }
138}
139
140
141- (void) readStructEnd {}
142
143
Mark Slee33a7d892007-09-14 19:44:30 +0000144- (void) readFieldBeginReturningName: (NSString **) name
145 type: (int *) fieldType
146 fieldID: (int *) fieldID
Mark Slee7e9eea42007-09-10 21:00:23 +0000147{
148 if (name != NULL) {
149 *name = nil;
150 }
151 int ft = [self readByte];
152 if (fieldType != NULL) {
153 *fieldType = ft;
154 }
155 if (ft != TType_STOP) {
156 int fid = [self readI16];
157 if (fieldID != NULL) {
158 *fieldID = fid;
159 }
160 }
161}
162
163
164- (void) readFieldEnd {}
165
166
167- (int32_t) readI32
168{
169 uint8_t i32rd[4];
170 [mTransport readAll: i32rd offset: 0 length: 4];
171 return
172 ((i32rd[0] & 0xff) << 24) |
173 ((i32rd[1] & 0xff) << 16) |
174 ((i32rd[2] & 0xff) << 8) |
175 ((i32rd[3] & 0xff));
176}
177
178
179- (NSString *) readString
180{
181 int size = [self readI32];
182 return [self readStringBody: size];
183}
184
185
186- (BOOL) readBool
187{
188 return [self readByte] == 1;
189}
190
191- (uint8_t) readByte
192{
193 uint8_t myByte;
194 [mTransport readAll: &myByte offset: 0 length: 1];
195 return myByte;
196}
197
198- (short) readI16
199{
200 uint8_t buff[2];
201 [mTransport readAll: buff offset: 0 length: 2];
202 return (short)
203 (((buff[0] & 0xff) << 8) |
204 ((buff[1] & 0xff)));
205 return 0;
206}
207
208- (int64_t) readI64;
209{
210 uint8_t i64rd[8];
211 [mTransport readAll: i64rd offset: 0 length: 8];
212 return
213 ((int64_t)(i64rd[0] & 0xff) << 56) |
214 ((int64_t)(i64rd[1] & 0xff) << 48) |
215 ((int64_t)(i64rd[2] & 0xff) << 40) |
216 ((int64_t)(i64rd[3] & 0xff) << 32) |
217 ((int64_t)(i64rd[4] & 0xff) << 24) |
218 ((int64_t)(i64rd[5] & 0xff) << 16) |
219 ((int64_t)(i64rd[6] & 0xff) << 8) |
220 ((int64_t)(i64rd[7] & 0xff));
221}
222
223- (double) readDouble;
224{
225 // FIXME - will this get us into trouble on PowerPC?
226 int64_t ieee754 = [self readI64];
227 return *((double *) &ieee754);
228}
229
230
231- (NSData *) readBinary
232{
233 int32_t size = [self readI32];
234 uint8_t * buff = malloc(size);
235 if (buff == NULL) {
Mark Slee33a7d892007-09-14 19:44:30 +0000236 @throw [TProtocolException
Mark Slee77575e62007-09-24 19:24:53 +0000237 exceptionWithName: @"TProtocolException"
238 reason: [NSString stringWithFormat: @"Out of memory. Unable to allocate %d bytes trying to read binary data.",
Mark Slee33a7d892007-09-14 19:44:30 +0000239 size]];
Mark Slee7e9eea42007-09-10 21:00:23 +0000240 }
241 [mTransport readAll: buff offset: 0 length: size];
242 return [NSData dataWithBytesNoCopy: buff length: size];
243}
244
245
Mark Slee33a7d892007-09-14 19:44:30 +0000246- (void) readMapBeginReturningKeyType: (int *) keyType
247 valueType: (int *) valueType
248 size: (int *) size
Mark Slee7e9eea42007-09-10 21:00:23 +0000249{
250 int kt = [self readByte];
251 int vt = [self readByte];
252 int s = [self readI32];
253 if (keyType != NULL) {
254 *keyType = kt;
255 }
256 if (valueType != NULL) {
257 *valueType = vt;
258 }
259 if (size != NULL) {
260 *size = s;
261 }
262}
263
264- (void) readMapEnd {}
265
266
Mark Slee33a7d892007-09-14 19:44:30 +0000267- (void) readSetBeginReturningElementType: (int *) elementType
268 size: (int *) size
Mark Slee7e9eea42007-09-10 21:00:23 +0000269{
270 int et = [self readByte];
271 int s = [self readI32];
272 if (elementType != NULL) {
273 *elementType = et;
274 }
275 if (size != NULL) {
276 *size = s;
277 }
278}
279
280
281- (void) readSetEnd {}
282
283
Mark Slee33a7d892007-09-14 19:44:30 +0000284- (void) readListBeginReturningElementType: (int *) elementType
285 size: (int *) size
Mark Slee7e9eea42007-09-10 21:00:23 +0000286{
287 int et = [self readByte];
288 int s = [self readI32];
289 if (elementType != NULL) {
290 *elementType = et;
291 }
292 if (size != NULL) {
293 *size = s;
294 }
295}
296
297
298- (void) readListEnd {}
299
300
301- (void) writeByte: (uint8_t) value
302{
303 [mTransport write: &value offset: 0 length: 1];
304}
305
306
307- (void) writeMessageBeginWithName: (NSString *) name
308 type: (int) messageType
309 sequenceID: (int) sequenceID
310{
311 if (mStrictWrite) {
312 int version = VERSION_1 | messageType;
313 [self writeI32: version];
314 [self writeString: name];
315 [self writeI32: sequenceID];
316 } else {
317 [self writeString: name];
318 [self writeByte: messageType];
319 [self writeI32: sequenceID];
320 }
321}
322
323
324- (void) writeMessageEnd {}
325
326
327- (void) writeStructBeginWithName: (NSString *) name {}
328
329
330- (void) writeStructEnd {}
331
332
333- (void) writeFieldBeginWithName: (NSString *) name
334 type: (int) fieldType
335 fieldID: (int) fieldID
336{
337 [self writeByte: fieldType];
338 [self writeI16: fieldID];
339}
340
341
342- (void) writeI32: (int32_t) value
343{
344 uint8_t buff[4];
345 buff[0] = 0xFF & (value >> 24);
346 buff[1] = 0xFF & (value >> 16);
347 buff[2] = 0xFF & (value >> 8);
348 buff[3] = 0xFF & value;
349 [mTransport write: buff offset: 0 length: 4];
350}
351
352- (void) writeI16: (short) value
353{
354 uint8_t buff[2];
355 buff[0] = 0xff & (value >> 8);
356 buff[1] = 0xff & value;
357 [mTransport write: buff offset: 0 length: 2];
358}
359
360
361- (void) writeI64: (int64_t) value
362{
363 uint8_t buff[8];
364 buff[0] = 0xFF & (value >> 56);
365 buff[1] = 0xFF & (value >> 48);
366 buff[2] = 0xFF & (value >> 40);
367 buff[3] = 0xFF & (value >> 32);
368 buff[4] = 0xFF & (value >> 24);
369 buff[5] = 0xFF & (value >> 16);
370 buff[6] = 0xFF & (value >> 8);
371 buff[7] = 0xFF & value;
372 [mTransport write: buff offset: 0 length: 8];
373}
374
375- (void) writeDouble: (double) value
376{
377 // spit out IEEE 754 bits - FIXME - will this get us in trouble on
378 // PowerPC?
379 [self writeI64: *((int64_t *) &value)];
380}
381
Mark Sleeaa3c5a82007-09-19 21:12:52 +0000382
Mark Slee7e9eea42007-09-10 21:00:23 +0000383- (void) writeString: (NSString *) value
384{
Mark Sleeaa3c5a82007-09-19 21:12:52 +0000385 if (value != nil) {
386 const char * utf8Bytes = [value UTF8String];
387 size_t length = strlen(utf8Bytes);
388 [self writeI32: length];
389 [mTransport write: (uint8_t *) utf8Bytes offset: 0 length: length];
390 } else {
Mark Slee77575e62007-09-24 19:24:53 +0000391 // instead of crashing when we get null, let's write out a zero
392 // length string
Mark Sleeaa3c5a82007-09-19 21:12:52 +0000393 [self writeI32: 0];
394 }
Mark Slee7e9eea42007-09-10 21:00:23 +0000395}
396
397
398- (void) writeBinary: (NSData *) data
399{
400 [self writeI32: [data length]];
401 [mTransport write: [data bytes] offset: 0 length: [data length]];
402}
403
404- (void) writeFieldStop
405{
406 [self writeByte: TType_STOP];
407}
408
409
410- (void) writeFieldEnd {}
411
412
413- (void) writeMapBeginWithKeyType: (int) keyType
414 valueType: (int) valueType
415 size: (int) size
416{
417 [self writeByte: keyType];
418 [self writeByte: valueType];
419 [self writeI32: size];
420}
421
422- (void) writeMapEnd {}
423
424
425- (void) writeSetBeginWithElementType: (int) elementType
426 size: (int) size
427{
428 [self writeByte: elementType];
429 [self writeI32: size];
430}
431
432- (void) writeSetEnd {}
433
434
435- (void) writeListBeginWithElementType: (int) elementType
436 size: (int) size
437{
438 [self writeByte: elementType];
439 [self writeI32: size];
440}
441
442- (void) writeListEnd {}
443
444
445- (void) writeBool: (BOOL) value
446{
447 [self writeByte: (value ? 1 : 0)];
448}
449
450@end