Index: src/Makefile ================================================================== --- src/Makefile +++ src/Makefile @@ -106,10 +106,11 @@ OFXMLParser.m \ OFXMLProcessingInstructions.m \ OFZIPArchive.m \ OFZIPArchiveEntry.m \ base64.m \ + crc16.m \ crc32.m \ huffman_tree.m \ of_asprintf.m \ of_strptime.m \ pbkdf2.m \ Index: src/OFLHAArchive.m ================================================================== --- src/OFLHAArchive.m +++ src/OFLHAArchive.m @@ -27,12 +27,14 @@ #endif #import "OFStream.h" #import "OFSeekableStream.h" #import "OFString.h" +#import "crc16.h" #import "huffman_tree.h" +#import "OFChecksumFailedException.h" #import "OFInvalidArgumentException.h" #import "OFInvalidFormatException.h" #import "OFNotImplementedException.h" #import "OFNotOpenException.h" #import "OFTruncatedDataException.h" @@ -69,10 +71,11 @@ @interface OFLHAArchive_FileReadStream: OFStream { OF_KINDOF(OFStream *) _stream; uint32_t _toRead; + uint16_t _expectedCRC16, _CRC16; bool _atEndOfStream; } - (instancetype)of_initWithStream: (OFStream *)stream entry: (OFLHAArchiveEntry *)entry; @@ -726,10 +729,12 @@ [method isEqual: @"-lz4-"] || [method isEqual: @"-lh5-"] || [method isEqual: @"-lh6-"] || [method isEqual: @"-lh6-"]) _toRead = [entry uncompressedSize]; else _toRead = [entry compressedSize]; + + _expectedCRC16 = [entry CRC16]; } @catch (id e) { [self release]; @throw e; } @@ -759,13 +764,18 @@ ret = [_stream readIntoBuffer: buffer length: length]; _toRead -= ret; + _CRC16 = of_crc16(_CRC16, buffer, ret); - if (_toRead == 0) + if (_toRead == 0) { _atEndOfStream = true; + + if (_CRC16 != _expectedCRC16) + @throw [OFChecksumFailedException exception]; + } return ret; } - (bool)lowlevelIsAtEndOfStream Index: src/ObjFW.h ================================================================== --- src/ObjFW.h +++ src/ObjFW.h @@ -220,15 +220,17 @@ # import "OFRecursiveMutex.h" # import "OFCondition.h" #endif #import "base64.h" +#import "crc16.h" #import "crc32.h" +#import "huffman_tree.h" #import "instance.h" #import "of_asprintf.h" #import "of_strptime.h" #ifdef OF_HAVE_SOCKETS # import "resolver.h" #endif #import "pbkdf2.h" #import "scrypt.h" #import "unicode.h" ADDED src/crc16.h Index: src/crc16.h ================================================================== --- src/crc16.h +++ src/crc16.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, + * 2018 + * Jonathan Schleifer + * + * All rights reserved. + * + * This file is part of ObjFW. It may be distributed under the terms of the + * Q Public License 1.0, which can be found in the file LICENSE.QPL included in + * the packaging of this file. + * + * Alternatively, it may be distributed under the terms of the GNU General + * Public License, either version 2 or 3, which can be found in the file + * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this + * file. + */ + +#ifndef __STDC_LIMIT_MACROS +# define __STDC_LIMIT_MACROS +#endif +#ifndef __STDC_CONSTANT_MACROS +# define __STDC_CONSTANT_MACROS +#endif + +#import "macros.h" + +#ifdef __cplusplus +extern "C" { +#endif +extern uint16_t of_crc16(uint16_t crc, const unsigned char *_Nonnull bytes, + size_t length); +#ifdef __cplusplus +} +#endif ADDED src/crc16.m Index: src/crc16.m ================================================================== --- src/crc16.m +++ src/crc16.m @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, + * 2018 + * Jonathan Schleifer + * + * All rights reserved. + * + * This file is part of ObjFW. It may be distributed under the terms of the + * Q Public License 1.0, which can be found in the file LICENSE.QPL included in + * the packaging of this file. + * + * Alternatively, it may be distributed under the terms of the GNU General + * Public License, either version 2 or 3, which can be found in the file + * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this + * file. + */ + +#include "config.h" + +#import "crc32.h" + +#define CRC16_MAGIC 0xA001 + +uint16_t +of_crc16(uint16_t crc, const unsigned char *bytes, size_t length) +{ + for (size_t i = 0; i < length; i++) { + crc ^= bytes[i]; + + for (uint8_t j = 0; j < 8; j++) + crc = (crc >> 1) ^ (CRC16_MAGIC & (~(crc & 1) + 1)); + } + + return crc; +}