// // Copyright (c) 2018 Open Whisper Systems. All rights reserved. // #import "OWSChunkedOutputStream.h" #import #import NS_ASSUME_NONNULL_BEGIN @interface OWSChunkedOutputStream () @property (nonatomic, readonly) NSOutputStream *outputStream; @property (nonatomic) BOOL hasError; @end #pragma mark - @implementation OWSChunkedOutputStream - (instancetype)initWithOutputStream:(NSOutputStream *)outputStream { if (self = [super init]) { OWSAssertDebug(outputStream); _outputStream = outputStream; } return self; } - (BOOL)writeByte:(uint8_t)value { NSInteger written = [self.outputStream write:&value maxLength:sizeof(value)]; if (written != sizeof(value)) { OWSFailDebug(@"could not write to output stream."); self.hasError = YES; return NO; } return YES; } - (BOOL)writeData:(NSData *)data { OWSAssertDebug(data); if (data.length < 1) { return YES; } while (YES) { NSInteger written = [self.outputStream write:data.bytes maxLength:data.length]; if (written < 1) { OWSFailDebug(@"could not write to output stream."); self.hasError = YES; return NO; } if (written < data.length) { data = [data subdataWithRange:NSMakeRange(written, data.length - written)]; } else { return YES; } } return YES; } - (BOOL)writeUInt32:(UInt32)value { NSData *data = [[NSData alloc] initWithBytes:&value length:sizeof(value)]; // Both Android and desktop seem to like this better const char *bytes = data.bytes; char *reversedBytes = malloc(sizeof(char) * data.length); int i = data.length - 1; for (int j = 0; j < data.length; j++) { reversedBytes[i] = bytes[j]; i = i - 1; } NSData *reversedData = [NSData dataWithBytes:reversedBytes length:data.length]; return [self writeData:reversedData]; } - (BOOL)writeVariableLengthUInt32:(UInt32)value { while (YES) { if (value <= 0x7F) { return [self writeByte:value]; } else { if (![self writeByte:((value & 0x7F) | 0x80)]) { return NO; } value >>= 7; } } } @end NS_ASSUME_NONNULL_END