//
|
// MQTTProperties.m
|
// MQTTClient
|
//
|
// Created by Christoph Krey on 04.04.17.
|
// Copyright © 2017 Christoph Krey. All rights reserved.
|
//
|
|
#import "MQTTProperties.h"
|
|
@implementation MQTTProperties
|
|
- (instancetype)init {
|
return [self initFromData:[[NSData alloc] init]];
|
}
|
- (instancetype)initFromData:(NSData *)data {
|
self = [super init];
|
|
int propertyLength = [MQTTProperties getVariableLength:data];
|
int offset = [MQTTProperties variableIntLength:propertyLength];
|
NSData *remainingData = [data subdataWithRange:NSMakeRange(offset, data.length - offset)];
|
offset = 0;
|
if (remainingData.length >= propertyLength) {
|
while (propertyLength - offset > 0) {
|
const UInt8 *bytes = remainingData.bytes;
|
UInt8 propertyType = bytes[offset];
|
switch (propertyType) {
|
case MQTTPayloadFormatIndicator:
|
if (propertyLength - offset > 1) {
|
self.payloadFormatIndicator = [NSNumber numberWithInt:bytes[offset + 1]];
|
offset += 2;
|
}
|
break;
|
case MQTTPublicationExpiryInterval:
|
if (propertyLength - offset > 4) {
|
self.publicationExpiryInterval = @([MQTTProperties getFourByteInt:[remainingData subdataWithRange:NSMakeRange(offset + 1, remainingData.length - (offset + 1))]]);
|
offset += 5;
|
}
|
break;
|
case MQTTContentType:
|
if (propertyLength - offset > 2) {
|
int l = [MQTTProperties getTwoByteInt:[remainingData subdataWithRange:NSMakeRange(offset + 1, remainingData.length - (offset + 1))]];
|
|
self.contentType = [MQTTProperties getUtf8String:[remainingData subdataWithRange:NSMakeRange(offset + 1, remainingData.length - (offset + 1))]];
|
offset += 1 + 2 + l;
|
}
|
break;
|
|
case MQTTResponseTopic:
|
if (propertyLength - offset > 2) {
|
int l = [MQTTProperties getTwoByteInt:[remainingData subdataWithRange:NSMakeRange(offset + 1, remainingData.length - (offset + 1))]];
|
|
self.responseTopic = [MQTTProperties getUtf8String:[remainingData subdataWithRange:NSMakeRange(offset + 1, remainingData.length - (offset + 1))]];
|
offset += 1 + 2 + l;
|
}
|
break;
|
|
case MQTTCorrelationData:
|
if (propertyLength - offset > 2) {
|
int l = [MQTTProperties getTwoByteInt:[remainingData subdataWithRange:NSMakeRange(offset + 1, remainingData.length - (offset + 1))]];
|
|
self.correlationData = [MQTTProperties getBinaryData:[remainingData subdataWithRange:NSMakeRange(offset + 1, remainingData.length - (offset + 1))]];
|
offset += 1 + 2 + l;
|
}
|
break;
|
|
case MQTTSubscriptionIdentifier:
|
if (propertyLength - offset > 1) {
|
int subscriptionIdentifier = [MQTTProperties getVariableLength:[remainingData subdataWithRange:NSMakeRange(offset + 1, remainingData.length - (offset + 1))]];
|
int l = [MQTTProperties variableIntLength:subscriptionIdentifier];
|
self.subscriptionIdentifier = @(subscriptionIdentifier);
|
offset += 1 + l;
|
|
}
|
break;
|
|
case MQTTSessionExpiryInterval:
|
if (propertyLength - offset > 4) {
|
self.sessionExpiryInterval = @([MQTTProperties getFourByteInt:[remainingData subdataWithRange:NSMakeRange(offset + 1, remainingData.length - (offset + 1))]]);
|
offset += 5;
|
}
|
break;
|
case MQTTAssignedClientIdentifier:
|
if (propertyLength - offset > 2) {
|
int l = [MQTTProperties getTwoByteInt:[remainingData subdataWithRange:NSMakeRange(offset + 1, remainingData.length - (offset + 1))]];
|
|
self.assignedClientIdentifier = [MQTTProperties getUtf8String:[remainingData subdataWithRange:NSMakeRange(offset + 1, remainingData.length - (offset + 1))]];
|
offset += 1 + 2 + l;
|
}
|
break;
|
|
|
case MQTTServerKeepAlive:
|
if (propertyLength - offset > 2) {
|
self.serverKeepAlive = @([MQTTProperties getTwoByteInt:[remainingData subdataWithRange:NSMakeRange(offset + 1, remainingData.length - (offset + 1))]]);
|
offset += 3;
|
}
|
break;
|
|
case MQTTAuthMethod:
|
if (propertyLength - offset > 2) {
|
int l = [MQTTProperties getTwoByteInt:[remainingData subdataWithRange:NSMakeRange(offset + 1, remainingData.length - (offset + 1))]];
|
|
self.authMethod = [MQTTProperties getUtf8String:[remainingData subdataWithRange:NSMakeRange(offset + 1, remainingData.length - (offset + 1))]];
|
offset += 1 + 2 + l;
|
}
|
break;
|
|
|
case MQTTAuthData:
|
if (propertyLength - offset > 2) {
|
int l = [MQTTProperties getTwoByteInt:[remainingData subdataWithRange:NSMakeRange(offset + 1, remainingData.length - (offset + 1))]];
|
|
self.authData = [MQTTProperties getBinaryData:[remainingData subdataWithRange:NSMakeRange(offset + 1, remainingData.length - (offset + 1))]];
|
offset += 1 + 2 + l;
|
}
|
break;
|
|
|
case MQTTRequestProblemInformation:
|
if (propertyLength - offset > 1) {
|
self.requestProblemInformation = [NSNumber numberWithInt:bytes[offset + 1]];
|
offset += 2;
|
}
|
break;
|
|
case MQTTWillDelayInterval:
|
if (propertyLength - offset > 4) {
|
self.willDelayInterval = @([MQTTProperties getFourByteInt:[remainingData subdataWithRange:NSMakeRange(offset + 1, remainingData.length - (offset + 1))]]);
|
offset += 5;
|
}
|
break;
|
|
case MQTTRequestResponseInformation:
|
if (propertyLength - offset > 1) {
|
self.requestResponseInformation = [NSNumber numberWithInt:bytes[offset + 1]];
|
offset += 2;
|
}
|
break;
|
|
case MQTTResponseInformation:
|
if (propertyLength - offset > 2) {
|
int l = [MQTTProperties getTwoByteInt:[remainingData subdataWithRange:NSMakeRange(offset + 1, remainingData.length - (offset + 1))]];
|
|
self.responseInformation = [MQTTProperties getUtf8String:[remainingData subdataWithRange:NSMakeRange(offset + 1, remainingData.length - (offset + 1))]];
|
offset += 1 + 2 + l;
|
}
|
break;
|
|
|
case MQTTServerReference:
|
if (propertyLength - offset > 2) {
|
int l = [MQTTProperties getTwoByteInt:[remainingData subdataWithRange:NSMakeRange(offset + 1, remainingData.length - (offset + 1))]];
|
|
self.serverReference = [MQTTProperties getUtf8String:[remainingData subdataWithRange:NSMakeRange(offset + 1, remainingData.length - (offset + 1))]];
|
offset += 1 + 2 + l;
|
}
|
break;
|
|
|
case MQTTReasonString:
|
if (propertyLength - offset > 2) {
|
int l = [MQTTProperties getTwoByteInt:[remainingData subdataWithRange:NSMakeRange(offset + 1, remainingData.length - (offset + 1))]];
|
|
self.reasonString = [MQTTProperties getUtf8String:[remainingData subdataWithRange:NSMakeRange(offset + 1, remainingData.length - (offset + 1))]];
|
offset += 1 + 2 + l;
|
}
|
break;
|
|
|
case MQTTReceiveMaximum:
|
if (propertyLength - offset > 2) {
|
self.receiveMaximum = @([MQTTProperties getTwoByteInt:[remainingData subdataWithRange:NSMakeRange(offset + 1, remainingData.length - (offset + 1))]]);
|
offset += 3;
|
}
|
break;
|
|
case MQTTTopicAliasMaximum:
|
if (propertyLength - offset > 2) {
|
self.topicAliasMaximum = @([MQTTProperties getTwoByteInt:[remainingData subdataWithRange:NSMakeRange(offset + 1, remainingData.length - (offset + 1))]]);
|
offset += 3;
|
}
|
break;
|
|
case MQTTTopicAlias:
|
if (propertyLength - offset > 2) {
|
self.topicAlias = @([MQTTProperties getTwoByteInt:[remainingData subdataWithRange:NSMakeRange(offset + 1, remainingData.length - (offset + 1))]]);
|
offset += 3;
|
}
|
break;
|
|
case MQTTMaximumQoS:
|
if (propertyLength - offset > 1) {
|
self.maximumQoS = [NSNumber numberWithInt:bytes[offset + 1]];
|
offset += 2;
|
}
|
break;
|
|
case MQTTRetainAvailable:
|
if (propertyLength - offset > 1) {
|
self.retainAvailable = [NSNumber numberWithInt:bytes[offset + 1]];
|
offset += 2;
|
}
|
break;
|
|
case MQTTUserProperty:
|
if (propertyLength - offset > 4) {
|
int keyL = [MQTTProperties getTwoByteInt:[remainingData subdataWithRange:NSMakeRange(offset + 1, remainingData.length - (offset + 1))]];
|
|
NSString *key = [MQTTProperties getUtf8String:[remainingData subdataWithRange:NSMakeRange(offset + 1, remainingData.length - (offset + 1))]];
|
|
int valueL = [MQTTProperties getTwoByteInt:[remainingData subdataWithRange:NSMakeRange(offset + 1 + 2 + keyL, remainingData.length - (offset + 1))]];
|
|
NSString *value = [MQTTProperties getUtf8String:[remainingData subdataWithRange:NSMakeRange(offset + 1 + 2 + keyL, remainingData.length - (offset + 1))]];
|
|
if (!self.userProperty) {
|
self.userProperty = [[NSMutableDictionary alloc] init];
|
}
|
self.userProperty[key] = value;
|
offset += 1 + 2 + keyL + 2 + valueL;
|
}
|
break;
|
|
case MQTTMaximumPacketSize:
|
if (propertyLength - offset > 4) {
|
self.maximumPacketSize = @([MQTTProperties getFourByteInt:[remainingData subdataWithRange:NSMakeRange(offset + 1, remainingData.length - (offset + 1))]]);
|
offset += 5;
|
}
|
break;
|
|
case MQTTWildcardSubscriptionAvailable:
|
if (propertyLength - offset > 1) {
|
self.wildcardSubscriptionAvailable = [NSNumber numberWithInt:bytes[offset + 1]];
|
offset += 2;
|
}
|
break;
|
|
case MQTTSubscriptionIdentifiersAvailable:
|
if (propertyLength - offset > 1) {
|
self.subscriptionIdentifiersAvailable = [NSNumber numberWithInt:bytes[offset + 1]];
|
offset += 2;
|
}
|
break;
|
|
case MQTTSharedSubscriptionAvailable:
|
if (propertyLength - offset > 1) {
|
self.sharedSubscriptionAvailable = [NSNumber numberWithInt:bytes[offset + 1]];
|
offset += 2;
|
}
|
break;
|
|
default:
|
return self;
|
}
|
}
|
}
|
return self;
|
}
|
|
+ (int)getVariableLength:(NSData *)data {
|
int length = 0;
|
int offset = 0;
|
int multiplier = 1;
|
UInt8 digit;
|
|
do {
|
if (data.length < offset) {
|
return -1;
|
}
|
[data getBytes:&digit range:NSMakeRange(offset, 1)];
|
offset++;
|
length += (digit & 0x7f) * multiplier;
|
multiplier *= 128;
|
if (multiplier > 128 * 128 * 128) {
|
return -2;
|
}
|
} while ((digit & 0x80) != 0);
|
return length;
|
}
|
|
+ (int)getTwoByteInt:(NSData *)data {
|
int i = 0;
|
if (data.length >= 2) {
|
const UInt8 *bytes = data.bytes;
|
i = bytes[0] * 256 +
|
bytes[1];
|
}
|
return i;
|
}
|
|
+ (int)getFourByteInt:(NSData *)data {
|
int i = 0;
|
if (data.length >= 4) {
|
const UInt8 *bytes = data.bytes;
|
i = bytes[0] * 256 * 256 * 256 +
|
bytes[1] * 256 * 256 +
|
bytes[2] * 256 +
|
bytes[3];
|
}
|
return i;
|
}
|
|
+ (NSString *)getUtf8String:(NSData *)data {
|
NSString *s;
|
int l = [MQTTProperties getTwoByteInt:data];
|
if (data.length >= l + 2) {
|
s = [[NSString alloc] initWithData:[data subdataWithRange:NSMakeRange(2, l)] encoding:NSUTF8StringEncoding];
|
}
|
return s;
|
}
|
|
+ (NSData *)getBinaryData:(NSData *)data {
|
NSData *d;
|
int l = [MQTTProperties getTwoByteInt:data];
|
if (data.length >= l + 2) {
|
d = [data subdataWithRange:NSMakeRange(2, l)];
|
}
|
return d;
|
}
|
|
+ (int)variableIntLength:(int)length {
|
int l = 0;
|
if (length <= 127) {
|
l = 1;
|
} else if (length <= 16383) {
|
l = 2;
|
} else if (length <= 2097151) {
|
l = 3;
|
} else if (length <= 268435455) {
|
l = 4;
|
}
|
return l;
|
}
|
@end
|