blob: c99e0c2f92f60199d57c48fa8af444e6f535a11b [file] [log] [blame]
//
// MQTTEncoder.m
// MQtt Client
//
// Copyright (c) 2011, 2013, 2lemetry LLC
//
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// and Eclipse Distribution License v. 1.0 which accompanies this distribution.
// The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
// and the Eclipse Distribution License is available at
// http://www.eclipse.org/org/documents/edl-v10.php.
//
// Contributors:
// Kyle Roche - initial API and implementation and/or initial documentation
//
#import "MQTTEncoder.h"
@implementation MQTTEncoder
- (id)initWithStream:(NSOutputStream*)aStream
runLoop:(NSRunLoop*)aRunLoop
runLoopMode:(NSString*)aMode {
status = MQTTEncoderStatusInitializing;
stream = aStream;
[stream setDelegate:self];
runLoop = aRunLoop;
runLoopMode = aMode;
return self;
}
- (void)setDelegate:(id)aDelegate {
delegate = aDelegate;
}
- (MQTTEncoderStatus)status {
return status;
}
- (void)open {
[stream setDelegate:self];
[stream scheduleInRunLoop:runLoop forMode:runLoopMode];
[stream open];
}
- (void)close {
[stream close];
[stream setDelegate:nil];
[stream removeFromRunLoop:runLoop forMode:runLoopMode];
stream = nil;
}
- (void)stream:(NSStream*)sender handleEvent:(NSStreamEvent)eventCode {
if(stream == nil)
return;
assert(sender == stream);
switch (eventCode) {
case NSStreamEventOpenCompleted:
break;
case NSStreamEventHasSpaceAvailable:
if (status == MQTTEncoderStatusInitializing) {
status = MQTTEncoderStatusReady;
[delegate encoder:self handleEvent:MQTTEncoderEventReady];
}
else if (status == MQTTEncoderStatusReady) {
[delegate encoder:self handleEvent:MQTTEncoderEventReady];
}
else if (status == MQTTEncoderStatusSending) {
UInt8* ptr;
NSInteger n, length;
ptr = (UInt8*) [buffer bytes] + byteIndex;
// Number of bytes pending for transfer
length = [buffer length] - byteIndex;
n = [stream write:ptr maxLength:length];
if (n == -1) {
status = MQTTEncoderStatusError;
[delegate encoder:self handleEvent:MQTTEncoderEventErrorOccurred];
}
else if (n < length) {
byteIndex += n;
}
else {
buffer = NULL;
byteIndex = 0;
status = MQTTEncoderStatusReady;
}
}
break;
case NSStreamEventErrorOccurred:
case NSStreamEventEndEncountered:
if (status != MQTTEncoderStatusError) {
status = MQTTEncoderStatusError;
[delegate encoder:self handleEvent:MQTTEncoderEventErrorOccurred];
}
break;
default:
NSLog(@"Oops, event code not handled: 0x%02x", eventCode);
break;
}
}
- (void)encodeMessage:(MQTTMessage*)msg {
UInt8 header;
NSInteger n, length;
if (status != MQTTEncoderStatusReady) {
NSLog(@"Encoder not ready");
return;
}
assert (buffer == NULL);
assert (byteIndex == 0);
buffer = [[NSMutableData alloc] init];
// encode fixed header
header = [msg type] << 4;
if ([msg isDuplicate]) {
header |= 0x08;
}
header |= [msg qos] << 1;
if ([msg retainFlag]) {
header |= 0x01;
}
[buffer appendBytes:&header length:1];
// encode remaining length
length = [[msg data] length];
do {
UInt8 digit = length % 128;
length /= 128;
if (length > 0) {
digit |= 0x80;
}
[buffer appendBytes:&digit length:1];
}
while (length > 0);
// encode message data
if ([msg data] != NULL) {
[buffer appendData:[msg data]];
}
n = [stream write:[buffer bytes] maxLength:[buffer length]];
if (n == -1) {
status = MQTTEncoderStatusError;
[delegate encoder:self handleEvent:MQTTEncoderEventErrorOccurred];
}
else if (n < [buffer length]) {
byteIndex += n;
status = MQTTEncoderStatusSending;
}
else {
buffer = NULL;
// XXX [delegate encoder:self handleEvent:MQTTEncoderEventReady];
}
}
@end