Index: src/OFTarArchive.h ================================================================== --- src/OFTarArchive.h +++ src/OFTarArchive.h @@ -15,15 +15,15 @@ * file. */ #import "OFObject.h" #import "OFKernelEventObserver.h" +#import "OFString.h" #import "OFTarArchiveEntry.h" OF_ASSUME_NONNULL_BEGIN -@class OFString; @class OFStream; /*! * @class OFTarArchive OFTarArchive.h ObjFW/OFTarArchive.h * @@ -35,13 +35,19 @@ enum { OF_TAR_ARCHIVE_MODE_READ, OF_TAR_ARCHIVE_MODE_WRITE, OF_TAR_ARCHIVE_MODE_APPEND } _mode; + of_string_encoding_t _encoding; OF_KINDOF(OFStream *) _Nullable _lastReturnedStream; } +/*! + * @brief The encoding to use for the archive. + */ +@property (nonatomic) of_string_encoding_t encoding; + /*! * @brief A stream for reading the current entry * * @note This is only available in read mode. * Index: src/OFTarArchive.m ================================================================== --- src/OFTarArchive.m +++ src/OFTarArchive.m @@ -57,10 +57,12 @@ - (instancetype)initWithStream: (OFStream *)stream entry: (OFTarArchiveEntry *)entry; @end @implementation OFTarArchive: OFObject +@synthesize encoding = _encoding; + + (instancetype)archiveWithStream: (OF_KINDOF(OFStream *))stream mode: (OFString *)mode { return [[[self alloc] initWithStream: stream mode: mode] autorelease]; @@ -115,10 +117,12 @@ @throw [OFInvalidFormatException exception]; [stream seekToOffset: -1024 whence: SEEK_END]; } + + _encoding = OF_STRING_ENCODING_UTF_8; } @catch (id e) { [self release]; @throw e; } @@ -193,11 +197,12 @@ return nil; } entry = [[[OFTarArchiveEntry alloc] - of_initWithHeader: buffer.c] autorelease]; + of_initWithHeader: buffer.c + encoding: _encoding] autorelease]; _lastReturnedStream = [[OFTarArchive_FileReadStream alloc] initWithStream: _stream entry: entry]; @@ -228,11 +233,12 @@ [_lastReturnedStream close]; [_lastReturnedStream release]; _lastReturnedStream = nil; - [entry of_writeToStream: _stream]; + [entry of_writeToStream: _stream + encoding: _encoding]; _lastReturnedStream = [[OFTarArchive_FileWriteStream alloc] initWithStream: _stream entry: entry]; Index: src/OFTarArchiveEntry+Private.h ================================================================== --- src/OFTarArchiveEntry+Private.h +++ src/OFTarArchiveEntry+Private.h @@ -14,17 +14,20 @@ * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this * file. */ #import "OFTarArchiveEntry.h" +#import "OFString.h" OF_ASSUME_NONNULL_BEGIN @class OFStream; @interface OFTarArchiveEntry () - (instancetype)of_initWithHeader: (unsigned char [_Nonnull 512])header + encoding: (of_string_encoding_t)encoding OF_METHOD_FAMILY(init); -- (void)of_writeToStream: (OFStream *)stream; +- (void)of_writeToStream: (OFStream *)stream + encoding: (of_string_encoding_t)encoding; @end OF_ASSUME_NONNULL_END Index: src/OFTarArchiveEntry.m ================================================================== --- src/OFTarArchiveEntry.m +++ src/OFTarArchiveEntry.m @@ -24,31 +24,34 @@ #import "OFString.h" #import "OFOutOfRangeException.h" static OFString * -stringFromBuffer(const unsigned char *buffer, size_t length) +stringFromBuffer(const unsigned char *buffer, size_t length, + of_string_encoding_t encoding) { for (size_t i = 0; i < length; i++) if (buffer[i] == '\0') length = i; - return [OFString stringWithUTF8String: (const char *)buffer - length: length]; + return [OFString stringWithCString: (const char *)buffer + encoding: encoding + length: length]; } static void -stringToBuffer(unsigned char *buffer, OFString *string, size_t length) +stringToBuffer(unsigned char *buffer, OFString *string, size_t length, + of_string_encoding_t encoding) { - size_t UTF8StringLength = [string UTF8StringLength]; + size_t cStringLength = [string cStringLengthWithEncoding: encoding]; - if (UTF8StringLength > length) + if (cStringLength > length) @throw [OFOutOfRangeException exception]; - memcpy(buffer, [string UTF8String], UTF8StringLength); + memcpy(buffer, [string cStringWithEncoding: encoding], cStringLength); - for (size_t i = UTF8StringLength; i < length; i++) + for (size_t i = cStringLength; i < length; i++) buffer[i] = '\0'; } static uintmax_t octalValueFromBuffer(const unsigned char *buffer, size_t length, uintmax_t max) @@ -60,11 +63,12 @@ if (buffer[0] == 0x80) { for (size_t i = 1; i < length; i++) value = (value << 8) | buffer[i]; } else - value = [stringFromBuffer(buffer, length) octalValue]; + value = [stringFromBuffer(buffer, length, + OF_STRING_ENCODING_ASCII) octalValue]; if (value > max) @throw [OFOutOfRangeException exception]; return value; @@ -80,18 +84,19 @@ { OF_INVALID_INIT_METHOD } - (instancetype)of_initWithHeader: (unsigned char [512])header + encoding: (of_string_encoding_t)encoding { self = [super init]; @try { void *pool = objc_autoreleasePoolPush(); OFString *targetFileName; - _fileName = [stringFromBuffer(header, 100) copy]; + _fileName = [stringFromBuffer(header, 100, encoding) copy]; _mode = (uint32_t)octalValueFromBuffer( header + 100, 8, UINT32_MAX); _UID = (uint32_t)octalValueFromBuffer( header + 108, 8, UINT32_MAX); _GID = (uint32_t)octalValueFromBuffer( @@ -102,29 +107,31 @@ initWithTimeIntervalSince1970: (of_time_interval_t)octalValueFromBuffer( header + 136, 12, UINTMAX_MAX)]; _type = header[156]; - targetFileName = stringFromBuffer(header + 157, 100); + targetFileName = stringFromBuffer(header + 157, 100, encoding); if ([targetFileName length] > 0) _targetFileName = [targetFileName copy]; if (_type == '\0') _type = OF_TAR_ARCHIVE_ENTRY_TYPE_FILE; if (memcmp(header + 257, "ustar\0" "00", 8) == 0) { OFString *prefix; - _owner = [stringFromBuffer(header + 265, 32) copy]; - _group = [stringFromBuffer(header + 297, 32) copy]; + _owner = [stringFromBuffer(header + 265, 32, encoding) + copy]; + _group = [stringFromBuffer(header + 297, 32, encoding) + copy]; _deviceMajor = (uint32_t)octalValueFromBuffer( header + 329, 8, UINT32_MAX); _deviceMinor = (uint32_t)octalValueFromBuffer( header + 337, 8, UINT32_MAX); - prefix = stringFromBuffer(header + 345, 155); + prefix = stringFromBuffer(header + 345, 155, encoding); if ([prefix length] > 0) { OFString *fileName = [OFString stringWithFormat: @"%@/%@", prefix, _fileName]; [_fileName release]; @@ -283,53 +290,61 @@ return [ret autorelease]; } - (void)of_writeToStream: (OFStream *)stream + encoding: (of_string_encoding_t)encoding { unsigned char buffer[512]; uint64_t modificationDate; uint16_t checksum = 0; - stringToBuffer(buffer, _fileName, 100); + stringToBuffer(buffer, _fileName, 100, encoding); stringToBuffer(buffer + 100, - [OFString stringWithFormat: @"%06" PRIo16 " ", _mode], 8); + [OFString stringWithFormat: @"%06" PRIo16 " ", _mode], 8, + OF_STRING_ENCODING_ASCII); stringToBuffer(buffer + 108, - [OFString stringWithFormat: @"%06" PRIo16 " ", _UID], 8); + [OFString stringWithFormat: @"%06" PRIo16 " ", _UID], 8, + OF_STRING_ENCODING_ASCII); stringToBuffer(buffer + 116, - [OFString stringWithFormat: @"%06" PRIo16 " ", _GID], 8); + [OFString stringWithFormat: @"%06" PRIo16 " ", _GID], 8, + OF_STRING_ENCODING_ASCII); stringToBuffer(buffer + 124, - [OFString stringWithFormat: @"%011" PRIo64 " ", _size], 12); + [OFString stringWithFormat: @"%011" PRIo64 " ", _size], 12, + OF_STRING_ENCODING_ASCII); modificationDate = [_modificationDate timeIntervalSince1970]; stringToBuffer(buffer + 136, [OFString stringWithFormat: @"%011" PRIo64 " ", modificationDate], - 12); + 12, OF_STRING_ENCODING_ASCII); /* * During checksumming, the checksum field is expected to be set to 8 * spaces. */ memset(buffer + 148, ' ', 8); buffer[156] = _type; - stringToBuffer(buffer + 157, _targetFileName, 100); + stringToBuffer(buffer + 157, _targetFileName, 100, encoding); /* ustar */ memcpy(buffer + 257, "ustar\0" "00", 8); - stringToBuffer(buffer + 265, _owner, 32); - stringToBuffer(buffer + 297, _group, 32); + stringToBuffer(buffer + 265, _owner, 32, encoding); + stringToBuffer(buffer + 297, _group, 32, encoding); stringToBuffer(buffer + 329, - [OFString stringWithFormat: @"%06" PRIo32 " ", _deviceMajor], 8); + [OFString stringWithFormat: @"%06" PRIo32 " ", _deviceMajor], 8, + OF_STRING_ENCODING_ASCII); stringToBuffer(buffer + 337, - [OFString stringWithFormat: @"%06" PRIo32 " ", _deviceMinor], 8); + [OFString stringWithFormat: @"%06" PRIo32 " ", _deviceMinor], 8, + OF_STRING_ENCODING_ASCII); memset(buffer + 345, '\0', 155 + 12); /* Fill in the checksum */ for (size_t i = 0; i < 500; i++) checksum += buffer[i]; stringToBuffer(buffer + 148, - [OFString stringWithFormat: @"%06" PRIo16, checksum], 7); + [OFString stringWithFormat: @"%06" PRIo16, checksum], 7, + OF_STRING_ENCODING_ASCII); [stream writeBuffer: buffer length: sizeof(buffer)]; } @end