diff options
Diffstat (limited to 'lib/cocoa/src/protocol/TBinaryProtocol.m')
-rw-r--r-- | lib/cocoa/src/protocol/TBinaryProtocol.m | 469 |
1 files changed, 469 insertions, 0 deletions
diff --git a/lib/cocoa/src/protocol/TBinaryProtocol.m b/lib/cocoa/src/protocol/TBinaryProtocol.m new file mode 100644 index 000000000..ba7f4629d --- /dev/null +++ b/lib/cocoa/src/protocol/TBinaryProtocol.m @@ -0,0 +1,469 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#import "TBinaryProtocol.h" +#import "TProtocolException.h" + +int32_t VERSION_1 = 0x80010000; +int32_t VERSION_MASK = 0xffff0000; + + +static TBinaryProtocolFactory * gSharedFactory = nil; + +@implementation TBinaryProtocolFactory + ++ (TBinaryProtocolFactory *) sharedFactory { + if (gSharedFactory == nil) { + gSharedFactory = [[TBinaryProtocolFactory alloc] init]; + } + + return gSharedFactory; +} + +- (TBinaryProtocol *) newProtocolOnTransport: (id <TTransport>) transport { + return [[[TBinaryProtocol alloc] initWithTransport: transport] autorelease]; +} + +@end + + + +@implementation TBinaryProtocol + +- (id) initWithTransport: (id <TTransport>) transport +{ + return [self initWithTransport: transport strictRead: NO strictWrite: NO]; +} + +- (id) initWithTransport: (id <TTransport>) transport + strictRead: (BOOL) strictRead + strictWrite: (BOOL) strictWrite +{ + self = [super init]; + mTransport = [transport retain]; + mStrictRead = strictRead; + mStrictWrite = strictWrite; + return self; +} + + +- (int32_t) messageSizeLimit +{ + return mMessageSizeLimit; +} + + +- (void) setMessageSizeLimit: (int32_t) sizeLimit +{ + mMessageSizeLimit = sizeLimit; +} + + +- (void) dealloc +{ + [mTransport release]; + [super dealloc]; +} + + +- (id <TTransport>) transport +{ + return mTransport; +} + + +- (NSString *) readStringBody: (int) size +{ + char buff[size+1]; + [mTransport readAll: (uint8_t *) buff offset: 0 length: size]; + buff[size] = 0; + return [NSString stringWithUTF8String: buff]; +} + + +- (void) readMessageBeginReturningName: (NSString **) name + type: (int *) type + sequenceID: (int *) sequenceID +{ + int32_t size = [self readI32]; + if (size < 0) { + int version = size & VERSION_MASK; + if (version != VERSION_1) { + @throw [TProtocolException exceptionWithName: @"TProtocolException" + reason: @"Bad version in readMessageBegin"]; + } + if (type != NULL) { + *type = version & 0x00FF; + } + NSString * messageName = [self readString]; + if (name != NULL) { + *name = messageName; + } + int seqID = [self readI32]; + if (sequenceID != NULL) { + *sequenceID = seqID; + } + } else { + if (mStrictRead) { + @throw [TProtocolException exceptionWithName: @"TProtocolException" + reason: @"Missing version in readMessageBegin, old client?"]; + } + if ([self messageSizeLimit] > 0 && size > [self messageSizeLimit]) { + @throw [TProtocolException exceptionWithName: @"TProtocolException" + reason: [NSString stringWithFormat: @"Message too big. Size limit is: %d Message size is: %d", + mMessageSizeLimit, + size]]; + } + NSString * messageName = [self readStringBody: size]; + if (name != NULL) { + *name = messageName; + } + int messageType = [self readByte]; + if (type != NULL) { + *type = messageType; + } + int seqID = [self readI32]; + if (sequenceID != NULL) { + *sequenceID = seqID; + } + } +} + + +- (void) readMessageEnd {} + + +- (void) readStructBeginReturningName: (NSString **) name +{ + if (name != NULL) { + *name = nil; + } +} + + +- (void) readStructEnd {} + + +- (void) readFieldBeginReturningName: (NSString **) name + type: (int *) fieldType + fieldID: (int *) fieldID +{ + if (name != NULL) { + *name = nil; + } + int ft = [self readByte]; + if (fieldType != NULL) { + *fieldType = ft; + } + if (ft != TType_STOP) { + int fid = [self readI16]; + if (fieldID != NULL) { + *fieldID = fid; + } + } +} + + +- (void) readFieldEnd {} + + +- (int32_t) readI32 +{ + uint8_t i32rd[4]; + [mTransport readAll: i32rd offset: 0 length: 4]; + return + ((i32rd[0] & 0xff) << 24) | + ((i32rd[1] & 0xff) << 16) | + ((i32rd[2] & 0xff) << 8) | + ((i32rd[3] & 0xff)); +} + + +- (NSString *) readString +{ + int size = [self readI32]; + return [self readStringBody: size]; +} + + +- (BOOL) readBool +{ + return [self readByte] == 1; +} + +- (uint8_t) readByte +{ + uint8_t myByte; + [mTransport readAll: &myByte offset: 0 length: 1]; + return myByte; +} + +- (short) readI16 +{ + uint8_t buff[2]; + [mTransport readAll: buff offset: 0 length: 2]; + return (short) + (((buff[0] & 0xff) << 8) | + ((buff[1] & 0xff))); + return 0; +} + +- (int64_t) readI64; +{ + uint8_t i64rd[8]; + [mTransport readAll: i64rd offset: 0 length: 8]; + return + ((int64_t)(i64rd[0] & 0xff) << 56) | + ((int64_t)(i64rd[1] & 0xff) << 48) | + ((int64_t)(i64rd[2] & 0xff) << 40) | + ((int64_t)(i64rd[3] & 0xff) << 32) | + ((int64_t)(i64rd[4] & 0xff) << 24) | + ((int64_t)(i64rd[5] & 0xff) << 16) | + ((int64_t)(i64rd[6] & 0xff) << 8) | + ((int64_t)(i64rd[7] & 0xff)); +} + +- (double) readDouble; +{ + // FIXME - will this get us into trouble on PowerPC? + int64_t ieee754 = [self readI64]; + return *((double *) &ieee754); +} + + +- (NSData *) readBinary +{ + int32_t size = [self readI32]; + uint8_t * buff = malloc(size); + if (buff == NULL) { + @throw [TProtocolException + exceptionWithName: @"TProtocolException" + reason: [NSString stringWithFormat: @"Out of memory. Unable to allocate %d bytes trying to read binary data.", + size]]; + } + [mTransport readAll: buff offset: 0 length: size]; + return [NSData dataWithBytesNoCopy: buff length: size]; +} + + +- (void) readMapBeginReturningKeyType: (int *) keyType + valueType: (int *) valueType + size: (int *) size +{ + int kt = [self readByte]; + int vt = [self readByte]; + int s = [self readI32]; + if (keyType != NULL) { + *keyType = kt; + } + if (valueType != NULL) { + *valueType = vt; + } + if (size != NULL) { + *size = s; + } +} + +- (void) readMapEnd {} + + +- (void) readSetBeginReturningElementType: (int *) elementType + size: (int *) size +{ + int et = [self readByte]; + int s = [self readI32]; + if (elementType != NULL) { + *elementType = et; + } + if (size != NULL) { + *size = s; + } +} + + +- (void) readSetEnd {} + + +- (void) readListBeginReturningElementType: (int *) elementType + size: (int *) size +{ + int et = [self readByte]; + int s = [self readI32]; + if (elementType != NULL) { + *elementType = et; + } + if (size != NULL) { + *size = s; + } +} + + +- (void) readListEnd {} + + +- (void) writeByte: (uint8_t) value +{ + [mTransport write: &value offset: 0 length: 1]; +} + + +- (void) writeMessageBeginWithName: (NSString *) name + type: (int) messageType + sequenceID: (int) sequenceID +{ + if (mStrictWrite) { + int version = VERSION_1 | messageType; + [self writeI32: version]; + [self writeString: name]; + [self writeI32: sequenceID]; + } else { + [self writeString: name]; + [self writeByte: messageType]; + [self writeI32: sequenceID]; + } +} + + +- (void) writeMessageEnd {} + + +- (void) writeStructBeginWithName: (NSString *) name {} + + +- (void) writeStructEnd {} + + +- (void) writeFieldBeginWithName: (NSString *) name + type: (int) fieldType + fieldID: (int) fieldID +{ + [self writeByte: fieldType]; + [self writeI16: fieldID]; +} + + +- (void) writeI32: (int32_t) value +{ + uint8_t buff[4]; + buff[0] = 0xFF & (value >> 24); + buff[1] = 0xFF & (value >> 16); + buff[2] = 0xFF & (value >> 8); + buff[3] = 0xFF & value; + [mTransport write: buff offset: 0 length: 4]; +} + +- (void) writeI16: (short) value +{ + uint8_t buff[2]; + buff[0] = 0xff & (value >> 8); + buff[1] = 0xff & value; + [mTransport write: buff offset: 0 length: 2]; +} + + +- (void) writeI64: (int64_t) value +{ + uint8_t buff[8]; + buff[0] = 0xFF & (value >> 56); + buff[1] = 0xFF & (value >> 48); + buff[2] = 0xFF & (value >> 40); + buff[3] = 0xFF & (value >> 32); + buff[4] = 0xFF & (value >> 24); + buff[5] = 0xFF & (value >> 16); + buff[6] = 0xFF & (value >> 8); + buff[7] = 0xFF & value; + [mTransport write: buff offset: 0 length: 8]; +} + +- (void) writeDouble: (double) value +{ + // spit out IEEE 754 bits - FIXME - will this get us in trouble on + // PowerPC? + [self writeI64: *((int64_t *) &value)]; +} + + +- (void) writeString: (NSString *) value +{ + if (value != nil) { + const char * utf8Bytes = [value UTF8String]; + size_t length = strlen(utf8Bytes); + [self writeI32: length]; + [mTransport write: (uint8_t *) utf8Bytes offset: 0 length: length]; + } else { + // instead of crashing when we get null, let's write out a zero + // length string + [self writeI32: 0]; + } +} + + +- (void) writeBinary: (NSData *) data +{ + [self writeI32: [data length]]; + [mTransport write: [data bytes] offset: 0 length: [data length]]; +} + +- (void) writeFieldStop +{ + [self writeByte: TType_STOP]; +} + + +- (void) writeFieldEnd {} + + +- (void) writeMapBeginWithKeyType: (int) keyType + valueType: (int) valueType + size: (int) size +{ + [self writeByte: keyType]; + [self writeByte: valueType]; + [self writeI32: size]; +} + +- (void) writeMapEnd {} + + +- (void) writeSetBeginWithElementType: (int) elementType + size: (int) size +{ + [self writeByte: elementType]; + [self writeI32: size]; +} + +- (void) writeSetEnd {} + + +- (void) writeListBeginWithElementType: (int) elementType + size: (int) size +{ + [self writeByte: elementType]; + [self writeI32: size]; +} + +- (void) writeListEnd {} + + +- (void) writeBool: (BOOL) value +{ + [self writeByte: (value ? 1 : 0)]; +} + +@end |