Skip to content

Instantly share code, notes, and snippets.

@khanlou
Last active November 10, 2022 11:41
Show Gist options
  • Star 8 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save khanlou/8cc2e3cb23ec8d03b1fc187f5922e244 to your computer and use it in GitHub Desktop.
Save khanlou/8cc2e3cb23ec8d03b1fc187f5922e244 to your computer and use it in GitHub Desktop.
Partially adapted from AFMultipartBodyStream
//
// SKSerialInputStream.h
// inputstream
//
// Created by Soroush Khanlou on 11/4/18.
// Copyright © 2018 Soroush Khanlou. All rights reserved.
//
#import <Foundation/Foundation.h>
@interface SKSerialInputStream : NSInputStream
- (instancetype)initWithInputStreams:(NSArray<NSInputStream *> *)inputStreams;
@property (nonatomic, readonly) NSArray<NSInputStream *> *inputStreams;
@end
//
// SKSerialInputStream.m
// inputstream
//
// Created by Soroush Khanlou on 11/4/18.
// Copyright © 2018 Soroush Khanlou. All rights reserved.
//
#import "SKSerialInputStream.h"
@interface SKSerialInputStream ()
@property NSInteger currentIndex;
@property (readwrite) NSStreamStatus streamStatus;
@property (readwrite, copy) NSError *streamError;
@end
@implementation SKSerialInputStream
@synthesize streamError;
@synthesize streamStatus;
@synthesize delegate;
- (instancetype)initWithInputStreams:(NSArray<NSInputStream *> *)inputStreams {
self = [super init];
if (!self) return nil;
_inputStreams = inputStreams;
_currentIndex = 0;
return self;
}
#pragma mark - NSInputStream
- (NSInteger)read:(uint8_t *)buffer maxLength:(NSUInteger)maxLength {
if ([self streamStatus] == NSStreamStatusClosed) {
return 0;
}
NSInteger totalNumberOfBytesRead = 0;
while (totalNumberOfBytesRead < maxLength) {
if (self.currentIndex == self.inputStreams.count) {
[self close];
break;
}
NSInputStream *currentInputStream = self.inputStreams[self.currentIndex];
if (currentInputStream.streamStatus != NSStreamStatusOpen) {
[currentInputStream open];
}
if (!currentInputStream.hasBytesAvailable) {
self.currentIndex += 1;
continue;
}
NSUInteger remainingLength = maxLength - totalNumberOfBytesRead;
NSInteger numberOfBytesRead = [currentInputStream read:&buffer[totalNumberOfBytesRead] maxLength:remainingLength];
if (numberOfBytesRead == 0) {
self.currentIndex += 1;
continue;
}
if (numberOfBytesRead == -1) {
self.streamError = currentInputStream.streamError;
return -1;
}
totalNumberOfBytesRead += numberOfBytesRead;
}
return totalNumberOfBytesRead;
}
- (BOOL)getBuffer:(uint8_t * _Nullable *)buffer length:(NSUInteger *)length {
if (self.currentIndex == self.inputStreams.count) {
return NO;
}
return [self.inputStreams[self.currentIndex] getBuffer:buffer length:length];
}
- (BOOL)hasBytesAvailable {
return YES; // ideally would be self.currentIndex != self.inputStreams.count;
}
#pragma mark - NSStream
- (void)open {
if (self.streamStatus == NSStreamStatusOpen) {
return;
}
self.streamStatus = NSStreamStatusOpen;
}
- (void)close {
self.streamStatus = NSStreamStatusClosed;
}
- (id)propertyForKey:(__unused NSString *)key {
return nil;
}
- (BOOL)setProperty:(__unused id)property forKey:(__unused NSString *)key {
return NO;
}
- (void)scheduleInRunLoop:(__unused NSRunLoop *)runLoop forMode:(__unused NSString *)mode {
}
- (void)removeFromRunLoop:(__unused NSRunLoop *)runLoop forMode:(__unused NSString *)mode {
}
@end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment