// This source code is dual-licensed under the Mozilla Public License ("MPL"), // version 1.1 and the Apache License ("ASL"), version 2.0. // // The ASL v2.0: // // --------------------------------------------------------------------------- // Copyright 2016 Pivotal Software, Inc. // // Licensed 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. // --------------------------------------------------------------------------- // // The MPL v1.1: // // --------------------------------------------------------------------------- // The contents of this file are subject to the Mozilla Public License // Version 1.1 (the "License"); you may not use this file except in // compliance with the License. You may obtain a copy of the License at // https://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" // basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the // License for the specific language governing rights and limitations // under the License. // // The Original Code is RabbitMQ // // The Initial Developer of the Original Code is Pivotal Software, Inc. // All Rights Reserved. // // Alternatively, the contents of this file may be used under the terms // of the Apache Standard license (the "ASL License"), in which case the // provisions of the ASL License are applicable instead of those // above. If you wish to allow use of your version of this file only // under the terms of the ASL License and not to allow others to use // your version of this file under the MPL, indicate your decision by // deleting the provisions above and replace them with the notice and // other provisions required by the ASL License. If you do not delete // the provisions above, a recipient may use your version of this file // under either the MPL or the ASL License. // --------------------------------------------------------------------------- #import "RMQValues.h" #import "RMQBasicProperties.h" @implementation RMQValue @end @interface RMQOctet () @property (nonatomic, readwrite) char octet; @property (nonatomic, readwrite) NSUInteger integerValue; @end @implementation RMQOctet - (instancetype)init:(char)octet { self = [super init]; if (self) { self.octet = octet; self.integerValue = (NSUInteger)octet; } return self; } - (instancetype)initWithParser:(RMQParser *)parser { return [self init:[parser parseOctet]]; } - (NSData *)amqEncoded { char buffer = self.octet; return [NSData dataWithBytes:&buffer length:1]; } @end @interface RMQSignedByte () @property (nonatomic, readwrite) signed char byte; @property (nonatomic, readwrite) NSInteger integerValue; @end @implementation RMQSignedByte - (instancetype)init:(signed char)byte { self = [super init]; if (self) { self.byte = byte; self.integerValue = (NSInteger)byte; } return self; } - (NSData *)amqEncoded { signed char buffer = self.byte; return [NSData dataWithBytes:&buffer length:1]; } - (NSData *)amqFieldValueType { return [@"b" dataUsingEncoding:NSUTF8StringEncoding]; } @end @interface RMQBoolean () @property (nonatomic, readwrite) BOOL boolValue; @end @implementation RMQBoolean - (instancetype)init:(BOOL)boolean { self = [super init]; if (self) { self.boolValue = boolean; } return self; } - (instancetype)initWithParser:(RMQParser *)parser { return [self init:[parser parseBoolean]]; } - (NSData *)amqEncoded { BOOL val = self.boolValue; return [NSData dataWithBytes:&val length:1]; } - (NSData *)amqFieldValueType { return [@"t" dataUsingEncoding:NSUTF8StringEncoding]; } @end @interface RMQSignedShort () @property (nonatomic, readwrite) NSInteger integerValue; @end @implementation RMQSignedShort - (instancetype)init:(NSInteger)val { self = [super init]; if (self) { self.integerValue = val; } return self; } - (NSData *)amqEncoded { int16_t shortVal = CFSwapInt16HostToBig((int16_t)self.integerValue); return [NSData dataWithBytes:&shortVal length:sizeof(int16_t)]; } - (NSData *)amqFieldValueType { return [@"s" dataUsingEncoding:NSUTF8StringEncoding]; } @end @interface RMQShort () @property (nonatomic, readwrite) NSUInteger integerValue; @end @implementation RMQShort - (instancetype)init:(NSUInteger)val { self = [super init]; if (self) { self.integerValue = val; } return self; } - (instancetype)initWithParser:(RMQParser *)parser { return [self init:[parser parseShortUInt]]; } - (NSData *)amqEncoded { uint16_t shortVal = CFSwapInt16HostToBig((uint16_t)self.integerValue); return [NSData dataWithBytes:&shortVal length:sizeof(uint16_t)]; } - (NSData *)amqFieldValueType { return [@"u" dataUsingEncoding:NSUTF8StringEncoding]; } @end @implementation RMQShortShort - (NSData *)amqFieldValueType { return [@"b" dataUsingEncoding:NSUTF8StringEncoding]; } @end @interface RMQSignedLong () @property (nonatomic, readwrite) NSInteger integerValue; @end @implementation RMQSignedLong - (instancetype)init:(NSInteger)val { self = [super init]; if (self) { self.integerValue = val; } return self; } - (NSData *)amqEncoded { int32_t longVal = CFSwapInt32HostToBig((int32_t)self.integerValue); return [NSData dataWithBytes:&longVal length:sizeof(int32_t)]; } - (NSData *)amqFieldValueType { return [@"I" dataUsingEncoding:NSUTF8StringEncoding]; } @end @interface RMQLong () @property (nonatomic, readwrite) NSUInteger integerValue; @end @implementation RMQLong - (instancetype)init:(NSUInteger)val { self = [super init]; if (self) { self.integerValue = val; } return self; } - (instancetype)initWithParser:(RMQParser *)parser { return [self init:[parser parseLongUInt]]; } - (NSData *)amqEncoded { uint32_t longVal = CFSwapInt32HostToBig((uint32_t)self.integerValue); return [NSData dataWithBytes:&longVal length:sizeof(uint32_t)]; } - (NSData *)amqFieldValueType { return [@"i" dataUsingEncoding:NSUTF8StringEncoding]; } @end @interface RMQSignedLonglong () @property (nonatomic, readwrite) int64_t integerValue; @end @implementation RMQSignedLonglong - (instancetype)init:(int64_t)val { self = [super init]; if (self) { self.integerValue = val; } return self; } - (NSData *)amqEncoded { int64_t longVal = CFSwapInt64HostToBig(self.integerValue); return [NSData dataWithBytes:&longVal length:sizeof(int64_t)]; } - (NSData *)amqFieldValueType { return [@"l" dataUsingEncoding:NSUTF8StringEncoding]; } @end @interface RMQLonglong () @property (nonatomic, readwrite) uint64_t integerValue; @end @implementation RMQLonglong - (instancetype)init:(uint64_t)val { self = [super init]; if (self) { self.integerValue = val; } return self; } - (instancetype)initWithParser:(RMQParser *)parser { return [self init:[parser parseLongLongUInt]]; } - (NSData *)amqEncoded { uint64_t longVal = CFSwapInt64HostToBig(self.integerValue); return [NSData dataWithBytes:&longVal length:sizeof(uint64_t)]; } - (NSData *)amqFieldValueType { return [@"l" dataUsingEncoding:NSUTF8StringEncoding]; } @end @interface RMQFloat () @property (nonatomic, readwrite) float floatValue; @end @implementation RMQFloat - (instancetype)init:(float)val { self = [super init]; if (self) { self.floatValue = val; } return self; } - (NSData *)amqEncoded { CFSwappedFloat32 floatVal = CFConvertFloatHostToSwapped(self.floatValue); return [NSData dataWithBytes:&floatVal length:sizeof(CFSwappedFloat32)]; } - (NSData *)amqFieldValueType { return [@"f" dataUsingEncoding:NSUTF8StringEncoding]; } @end @interface RMQDouble () @property (nonatomic, readwrite) double doubleValue; @end @implementation RMQDouble - (instancetype)init:(double)val { self = [super init]; if (self) { self.doubleValue = val; } return self; } - (NSData *)amqEncoded { CFSwappedFloat64 doubleVal = CFConvertDoubleHostToSwapped(self.doubleValue); return [NSData dataWithBytes:&doubleVal length:sizeof(CFSwappedFloat64)]; } - (NSData *)amqFieldValueType { return [@"d" dataUsingEncoding:NSUTF8StringEncoding]; } @end @implementation RMQDecimal - (NSData *)amqEncoded { NSMutableData *encoded = [NSMutableData new]; [encoded appendData:[[RMQOctet alloc] init:0].amqEncoded]; [encoded appendData:[[RMQLong alloc] init:0].amqEncoded]; return encoded; } - (NSData *)amqFieldValueType { return [@"D" dataUsingEncoding:NSUTF8StringEncoding]; } @end @interface RMQShortstr () @property (nonnull, nonatomic, copy, readwrite) NSString *stringValue; @end @implementation RMQShortstr - (instancetype)init:(NSString *)string { self = [super init]; if (self) { self.stringValue = string; } return self; } - (instancetype)initWithParser:(RMQParser *)parser { return [self init:[parser parseShortString]]; } - (NSData *)amqEncoded { NSMutableData *encoded = [NSMutableData new]; NSData *value = [self.stringValue dataUsingEncoding:NSUTF8StringEncoding]; char len = (char)value.length; [encoded appendBytes:&len length:1]; [encoded appendData:value]; return encoded; } @end @interface RMQLongstr () @property (nonnull, nonatomic, copy, readwrite) NSString *stringValue; @end @implementation RMQLongstr - (instancetype)init:(NSString *)string { self = [super init]; if (self) { self.stringValue = string; } return self; } - (instancetype)initWithParser:(RMQParser *)parser { return [self init:[parser parseLongString]]; } - (NSData *)amqEncoded { NSMutableData *encoded = [NSMutableData new]; NSData *value = [self.stringValue dataUsingEncoding:NSUTF8StringEncoding]; [encoded appendData:[[RMQLong alloc] init:value.length].amqEncoded]; [encoded appendData:value]; return encoded; } - (NSData *)amqFieldValueType { return [@"S" dataUsingEncoding:NSUTF8StringEncoding]; } @end @interface RMQArray () @property (nonatomic, readwrite) NSArray *vals; @end @implementation RMQArray - (instancetype)init:(NSArray *> *)vals { self = [super init]; if (self) { self.vals = vals; } return self; } - (NSData *)amqEncoded { NSMutableData *fieldValues = [NSMutableData new]; for (RMQValue *val in self.vals) { [fieldValues appendData:val.amqFieldValueType]; [fieldValues appendData:val.amqEncoded]; } NSMutableData *encoded = [NSMutableData new]; [encoded appendData:[[RMQLong alloc] init:fieldValues.length].amqEncoded]; [encoded appendData:fieldValues]; return encoded; } - (NSData *)amqFieldValueType { return [@"A" dataUsingEncoding:NSUTF8StringEncoding]; } @end @interface RMQTimestamp () @property (nonatomic, strong) NSDate *dateValue; @end @implementation RMQTimestamp - (instancetype)init:(NSDate *)date { self = [super init]; if (self) { self.dateValue = date; } return self; } - (instancetype)initWithParser:(RMQParser *)parser { return [self init:[parser parseTimestamp]]; } - (NSData *)amqEncoded { NSTimeInterval interval = self.dateValue.timeIntervalSince1970; RMQLonglong *numeric = [[RMQLonglong alloc] init:interval]; return numeric.amqEncoded; } - (NSData *)amqFieldValueType { return [@"T" dataUsingEncoding:NSUTF8StringEncoding]; } @end @implementation RMQVoid - (NSData *)amqEncoded { return [NSData data]; } - (NSData *)amqFieldValueType { return [@"V" dataUsingEncoding:NSUTF8StringEncoding]; } @end @interface RMQByteArray () @property (nonatomic, readwrite) NSData *data; @end @implementation RMQByteArray - (instancetype)init:(NSData *)data { self = [super init]; if (self) { self.data = data; } return self; } - (NSData *)amqEncoded { NSMutableData *encoded = [NSMutableData new]; [encoded appendData:[[RMQLong alloc] init:self.data.length].amqEncoded]; [encoded appendData:self.data]; return encoded; } - (NSData *)amqFieldValueType { return [@"x" dataUsingEncoding:NSUTF8StringEncoding]; } @end @interface RMQFieldValuePair () @property (nonnull, nonatomic, copy) NSString *fieldName; @property (nonnull, nonatomic, copy) id fieldValue; @end @implementation RMQFieldValuePair - (instancetype)initWithFieldName:(NSString *)fieldName fieldValue:(id)fieldValue { self = [super init]; if (self) { self.fieldName = fieldName; self.fieldValue = fieldValue; } return self; } - (NSData *)amqEncoded { NSMutableData *encoded = [NSMutableData new]; [encoded appendData:[[RMQShortstr alloc] init:self.fieldName].amqEncoded]; [encoded appendData:self.fieldValue.amqFieldValueType]; [encoded appendData:self.fieldValue.amqEncoded]; return encoded; } @end @interface RMQCredentials () @property (nonatomic, readwrite) NSString *username; @property (nonatomic, readwrite) NSString *password; @end @implementation RMQCredentials - (instancetype)initWithUsername:(NSString *)username password:(NSString *)password { self = [super init]; if (self) { self.username = username; self.password = password; } return self; } - (NSData *)amqEncoded { NSMutableData *encodedContent = [NSMutableData new]; NSData *username = [self.username dataUsingEncoding:NSUTF8StringEncoding]; NSData *password = [self.password dataUsingEncoding:NSUTF8StringEncoding]; char zero = 0; [encodedContent appendBytes:&zero length:1]; [encodedContent appendData:username]; [encodedContent appendBytes:&zero length:1]; [encodedContent appendData:password]; NSString *s = [[NSString alloc] initWithData:encodedContent encoding:NSUTF8StringEncoding]; return [[RMQLongstr alloc] init:s].amqEncoded; } @end @interface RMQContentHeader () @property (nonatomic, strong) NSNumber *classID; @property (nonatomic, strong) NSNumber *weight; @property (nonatomic, strong) NSNumber *bodySize; @property (nonatomic, strong) NSArray *properties; @end @implementation RMQContentHeader - (instancetype)initWithClassID:(NSNumber *)classID bodySize:(NSNumber *)bodySize properties:(NSArray *)properties { self = [super init]; if (self) { self.classID = classID; self.weight = @0; self.bodySize = bodySize; self.properties = properties; } return self; } - (instancetype)initWithParser:(RMQParser *)parser { NSNumber *classID = @([parser parseShortUInt]); [parser parseShortUInt]; // weight UInt64 bodySize = [parser parseLongLongUInt]; UInt16 flags = [parser parseShortUInt]; NSMutableArray *properties = [NSMutableArray new]; int i = 0; for (Class propertyClass in [self propertyClassesWithFlags:flags]) { properties[i] = [[propertyClass alloc] initWithParser:parser]; i++; } return [self initWithClassID:classID bodySize:@(bodySize) properties:properties]; } - (NSNumber *)frameTypeID { return @2; } - (NSData *)amqEncoded { NSMutableData *encoded = [NSMutableData new]; [encoded appendData:[[RMQShort alloc] init:self.classID.integerValue].amqEncoded]; [encoded appendData:[[RMQShort alloc] init:self.weight.integerValue].amqEncoded]; [encoded appendData:[[RMQLonglong alloc] init:self.bodySize.integerValue].amqEncoded]; NSSortDescriptor *byFlagBit = [[NSSortDescriptor alloc] initWithKey:@"flagBit" ascending:NO]; NSArray *sortedProperties = [self.properties sortedArrayUsingDescriptors:@[byFlagBit]]; NSUInteger flags = 0; for (id property in sortedProperties) { flags |= property.flagBit; } [encoded appendData:[[RMQShort alloc] init:flags].amqEncoded]; for (id property in sortedProperties) { [encoded appendData:property.amqEncoded]; } return encoded; } - (NSArray *)propertyClassesWithFlags:(UInt16)flags { NSPredicate *pred = [NSPredicate predicateWithBlock:^BOOL(id _Nonnull propertyClass, NSDictionary * _Nullable bindings) { return (flags & [propertyClass flagBit]) != 0; }]; return [[[RMQBasicProperties class] properties] filteredArrayUsingPredicate:pred]; } @end @implementation RMQContentHeaderNone - (instancetype)initWithClassID:(NSNumber *)classID bodySize:(NSNumber *)bodySize properties:(NSArray *)properties { [self doesNotRecognizeSelector:_cmd]; return nil; } - (instancetype)initWithParser:(RMQParser *)parser { [self doesNotRecognizeSelector:_cmd]; return nil; } - (NSNumber *)frameTypeID { return nil; } - (NSData *)amqEncoded { return [NSData data]; } @end @interface RMQContentBody () @property (nonatomic, readwrite) NSData *data; @property (nonatomic, readwrite) NSUInteger length; @end @implementation RMQContentBody - (instancetype)initWithData:(NSData *)data { self = [super init]; if (self) { self.data = data; self.length = data.length; } return self; } - (instancetype)initWithParser:(RMQParser *)parser payloadSize:(UInt32)payloadSize { return [self initWithData:[parser parseLength:payloadSize]]; } - (NSNumber *)frameTypeID { return @3; } - (NSData *)amqEncoded { return self.data; } - (NSString *)description { return [NSString stringWithFormat:@"Body: %@", [[NSString alloc] initWithData:self.data encoding:NSUTF8StringEncoding]]; } @end