Index: .fossil-settings/clean-glob ================================================================== --- .fossil-settings/clean-glob +++ .fossil-settings/clean-glob @@ -25,10 +25,11 @@ extra.mk generators/gen_tables src/Info.plist src/bridge/Info.plist src/objfw-defs.h +src/runtime/Info.plist src/runtime/amiga-library-functable.inc src/runtime/inline.h tests/DerivedData tests/EBOOT.PBP tests/Info.plist Index: .fossil-settings/ignore-glob ================================================================== --- .fossil-settings/ignore-glob +++ .fossil-settings/ignore-glob @@ -27,10 +27,11 @@ extra.mk generators/gen_tables src/Info.plist src/bridge/Info.plist src/objfw-defs.h +src/runtime/Info.plist src/runtime/amiga-library-functable.inc src/runtime/inline.h tests/DerivedData tests/EBOOT.PBP tests/Info.plist Index: .gitignore ================================================================== --- .gitignore +++ .gitignore @@ -27,10 +27,11 @@ extra.mk generators/gen_tables src/Info.plist src/bridge/Info.plist src/objfw-defs.h +src/runtime/Info.plist src/runtime/amiga-library-functable.inc src/runtime/inline.h tests/DerivedData tests/EBOOT.PBP tests/Info.plist Index: README.md ================================================================== --- README.md +++ README.md @@ -119,16 +119,23 @@ It's also possible to open the same local repository multiple times, so that you have multiple working directories all backed by the same local repository. + In order to verify the signature of the currently checked out checkin, you + can use: + + $ fossil artifact current | gpg --verify +

Git

To clone the Git repository, use the following: $ git clone https://github.com/ObjFW/ObjFW + Git commits are not signed, so if you want to check the signature of an + individual commit, branch head or tag, please use Fossil.

Installation

To install ObjFW, just run the following commands: Index: configure.ac ================================================================== --- configure.ac +++ configure.ac @@ -412,10 +412,11 @@ AC_DEFINE_UNQUOTED(PLUGIN_SUFFIX, "$PLUGIN_SUFFIX", [Suffix for plugins]) AS_IF([test x"$enable_files" != x"no" -a x"$PLUGIN_SUFFIX" != x""], [ AC_SUBST(USE_SRCS_PLUGINS, '${SRCS_PLUGINS}') AC_SUBST(TESTPLUGIN, "plugin") AC_DEFINE(OF_HAVE_PLUGINS, 1, [Whether we have plugin support]) + AC_CONFIG_FILES(tests/plugin/Info.plist) AS_IF([test x"$build_framework" = x"yes"], [ TESTPLUGIN_LIBS="-F../../src -F../../src/runtime" TESTPLUGIN_LIBS="$TESTPLUGIN_LIBS -framework ObjFW" TESTPLUGIN_LIBS="$TESTPLUGIN_LIBS \${RUNTIME_FRAMEWORK_LIBS}" @@ -522,10 +523,11 @@ AC_MSG_RESULT(no) old_compiler="yes" ]) AC_SUBST(RUNTIME, "runtime") + AC_CONFIG_FILES(src/runtime/Info.plist) AS_IF([test x"$enable_shared" != x"no"], [ AC_SUBST(OBJFWRT_SHARED_LIB, "${LIB_PREFIX}objfwrt${LIB_SUFFIX}") ]) @@ -1572,10 +1574,11 @@ ]) AS_IF([test x"$objc_runtime" = x"Apple runtime"], [ AC_CHECK_HEADER(Foundation/NSObject.h, [ AC_SUBST(BRIDGE, "bridge") + AC_CONFIG_FILES(src/bridge/Info.plist) AS_IF([test x"$enable_shared" != x"no"], [ AC_SUBST(OBJFWBRIDGE_SHARED_LIB, "${LIB_PREFIX}objfwbridge${LIB_SUFFIX}") ]) @@ -1907,13 +1910,11 @@ AC_CONFIG_FILES([ buildsys.mk extra.mk src/Info.plist - src/bridge/Info.plist tests/Info.plist - tests/plugin/Info.plist utils/objfw-config ]) AC_CONFIG_HEADERS([config.h src/objfw-defs.h]) AC_OUTPUT Index: generators/TableGenerator.m ================================================================== --- generators/TableGenerator.m +++ generators/TableGenerator.m @@ -119,22 +119,22 @@ if (components.count != 15) { of_log(@"Invalid line: %@\n", line); [OFApplication terminateWithStatus: 1]; } - codePoint = (of_unichar_t) - [[components objectAtIndex: 0] hexadecimalValue]; + codePoint = (of_unichar_t)[[components objectAtIndex: 0] + unsignedLongLongValueWithBase: 16]; if (codePoint > 0x10FFFF) @throw [OFOutOfRangeException exception]; - _uppercaseTable[codePoint] = (of_unichar_t) - [[components objectAtIndex: 12] hexadecimalValue]; - _lowercaseTable[codePoint] = (of_unichar_t) - [[components objectAtIndex: 13] hexadecimalValue]; - _titlecaseTable[codePoint] = (of_unichar_t) - [[components objectAtIndex: 14] hexadecimalValue]; + _uppercaseTable[codePoint] = (of_unichar_t)[[components + objectAtIndex: 12] unsignedLongLongValueWithBase: 16]; + _lowercaseTable[codePoint] = (of_unichar_t)[[components + objectAtIndex: 13] unsignedLongLongValueWithBase: 16]; + _titlecaseTable[codePoint] = (of_unichar_t)[[components + objectAtIndex: 14] unsignedLongLongValueWithBase: 16]; if ([[components objectAtIndex: 5] length] > 0) { OFArray *decomposed = [[components objectAtIndex: 5] componentsSeparatedByString: @" "]; bool compat = false; @@ -147,12 +147,12 @@ } string = [OFMutableString string]; for (OFString *character in decomposed) { - of_unichar_t unichar = - (of_unichar_t)character.hexadecimalValue; + of_unichar_t unichar = (of_unichar_t)[character + unsignedLongLongValueWithBase: 16]; [string appendCharacters: &unichar length: 1]; } @@ -202,18 +202,18 @@ if (![[components objectAtIndex: 1] isEqual: @"S"] && ![[components objectAtIndex: 1] isEqual: @"C"]) continue; - codePoint = (of_unichar_t) - [[components objectAtIndex: 0] hexadecimalValue]; + codePoint = (of_unichar_t)[[components objectAtIndex: 0] + unsignedLongLongValueWithBase: 16]; if (codePoint > 0x10FFFF) @throw [OFOutOfRangeException exception]; - _casefoldingTable[codePoint] = (of_unichar_t) - [[components objectAtIndex: 2] hexadecimalValue]; + _casefoldingTable[codePoint] = (of_unichar_t)[[components + objectAtIndex: 2] unsignedLongLongValueWithBase: 16]; objc_autoreleasePoolPop(pool2); } [of_stdout writeLine: @" done"]; @@ -265,10 +265,12 @@ [table[i] release]; table[i] = [replacement copy]; done = false; } + + objc_autoreleasePoolPop(pool); } } while (!done); } - (void)writeFiles Index: src/Info.plist.in ================================================================== --- src/Info.plist.in +++ src/Info.plist.in @@ -5,11 +5,11 @@ CFBundleExecutable ObjFW CFBundleName ObjFW CFBundleIdentifier - zone.heap.objfw + im.nil.objfw CFBundleInfoDictionaryVersion 6.0 CFBundlePackageType FMWK CFBundleVersion Index: src/Makefile ================================================================== --- src/Makefile +++ src/Makefile @@ -27,13 +27,13 @@ OFCharacterSet.m \ OFColor.m \ OFConstantString.m \ OFCountedSet.m \ OFData.m \ - OFData+ASN1DERValue.m \ + OFData+ASN1DERParsing.m \ OFData+CryptoHashing.m \ - OFData+MessagePackValue.m \ + OFData+MessagePackParsing.m \ OFDate.m \ OFDictionary.m \ OFEnumerator.m \ OFFileManager.m \ OFGZIPStream.m \ @@ -84,12 +84,12 @@ OFSortedList.m \ OFStdIOStream.m \ OFStream.m \ OFString.m \ OFString+CryptoHashing.m \ - OFString+JSONValue.m \ - OFString+PropertyListValue.m \ + OFString+JSONParsing.m \ + OFString+PropertyListParsing.m \ OFString+Serialization.m \ OFString+URLEncoding.m \ OFString+XMLEscaping.m \ OFString+XMLUnescaping.m \ OFSystemInfo.m \ Index: src/OFASN1Enumerated.h ================================================================== --- src/OFASN1Enumerated.h +++ src/OFASN1Enumerated.h @@ -24,37 +24,36 @@ * @brief An ASN.1 Enumerated. */ OF_SUBCLASSING_RESTRICTED @interface OFASN1Enumerated: OFObject { - intmax_t _integerValue; + long long _longLongValue; } /*! * @brief The integer value. */ -@property (readonly, nonatomic) intmax_t integerValue; +@property (readonly, nonatomic) long long longLongValue; /*! * @brief Creates an ASN.1 Enumerated with the specified integer value. * - * @param integerValue The integer value of the Enumerated + * @param value The `long long` value of the Enumerated * @return A new, autoreleased OFASN1Enumerated */ -+ (instancetype)enumeratedWithIntegerValue: (intmax_t)integerValue; ++ (instancetype)enumeratedWithLongLong: (long long)value; - (instancetype)init OF_UNAVAILABLE; /*! * @brief Initializes an already allocated ASN.1 Enumerated with the specified * integer value. * - * @param integerValue The integer value of the Enumerated + * @param value The `long long` value of the Enumerated * @return An initialized OFASN1Enumerated */ -- (instancetype)initWithIntegerValue: (intmax_t)integerValue - OF_DESIGNATED_INITIALIZER; +- (instancetype)initWithLongLong: (long long)value OF_DESIGNATED_INITIALIZER; /*! * @brief Initializes an already allocated ASN.1 Enumerated with the specified * arguments. * Index: src/OFASN1Enumerated.m ================================================================== --- src/OFASN1Enumerated.m +++ src/OFASN1Enumerated.m @@ -21,53 +21,53 @@ #import "OFData.h" #import "OFString.h" #import "OFInvalidArgumentException.h" -extern intmax_t of_asn1_der_integer_parse(const unsigned char *buffer, +extern long long of_asn1_der_integer_parse(const unsigned char *buffer, size_t length); @implementation OFASN1Enumerated -@synthesize integerValue = _integerValue; +@synthesize longLongValue = _longLongValue; -+ (instancetype)enumeratedWithIntegerValue: (intmax_t)integerValue ++ (instancetype)enumeratedWithLongLong: (long long)value { - return [[[self alloc] initWithIntegerValue: integerValue] autorelease]; + return [[[self alloc] initWithLongLong: value] autorelease]; } -- (instancetype)initWithIntegerValue: (intmax_t)integerValue +- (instancetype)initWithLongLong: (long long)value { self = [super init]; - _integerValue = integerValue; + _longLongValue = value; return self; } - (instancetype)initWithTagClass: (of_asn1_tag_class_t)tagClass tagNumber: (of_asn1_tag_number_t)tagNumber constructed: (bool)constructed DEREncodedContents: (OFData *)DEREncodedContents { - intmax_t integerValue; + long long value; @try { if (tagClass != OF_ASN1_TAG_CLASS_UNIVERSAL || tagNumber != OF_ASN1_TAG_NUMBER_ENUMERATED || constructed) @throw [OFInvalidArgumentException exception]; if (DEREncodedContents.itemSize != 1) @throw [OFInvalidArgumentException exception]; - integerValue = of_asn1_der_integer_parse( + value = of_asn1_der_integer_parse( DEREncodedContents.items, DEREncodedContents.count); } @catch (id e) { [self release]; @throw e; } - return [self initWithIntegerValue: integerValue]; + return [self initWithLongLong: value]; } - (instancetype)init { OF_INVALID_INIT_METHOD @@ -83,22 +83,22 @@ if (![object isKindOfClass: [OFASN1Enumerated class]]) return false; enumerated = object; - if (enumerated->_integerValue != _integerValue) + if (enumerated->_longLongValue != _longLongValue) return false; return true; } - (uint32_t)hash { - return (uint32_t)_integerValue; + return (uint32_t)_longLongValue; } - (OFString *)description { - return [OFString stringWithFormat: @"", - _integerValue]; + return [OFString stringWithFormat: @"", + _longLongValue]; } @end Index: src/OFASN1Integer.h ================================================================== --- src/OFASN1Integer.h +++ src/OFASN1Integer.h @@ -24,37 +24,36 @@ * @brief An ASN.1 Integer. */ OF_SUBCLASSING_RESTRICTED @interface OFASN1Integer: OFObject { - intmax_t _integerValue; + long long _longLongValue; } /*! * @brief The Integer value. */ -@property (readonly, nonatomic) intmax_t integerValue; +@property (readonly, nonatomic) long long longLongValue; /*! * @brief Creates an ASN.1 Integer with the specified integer value. * - * @param integerValue The integer value of the Integer + * @param value The `long long` value of the Integer * @return A new, autoreleased OFASN1Integer */ -+ (instancetype)integerWithIntegerValue: (intmax_t)integerValue; ++ (instancetype)integerWithLongLong: (long long)value; - (instancetype)init OF_UNAVAILABLE; /*! * @brief Initializes an already allocated ASN.1 Integer with the specified * integer value. * - * @param integerValue The integer value of the Integer + * @param value The `long long` value of the Integer * @return An initialized OFASN1Integer */ -- (instancetype)initWithIntegerValue: (intmax_t)integerValue - OF_DESIGNATED_INITIALIZER; +- (instancetype)initWithLongLong: (long long)value OF_DESIGNATED_INITIALIZER; /*! * @brief Initializes an already allocated ASN.1 Integer with the specified * arguments. * Index: src/OFASN1Integer.m ================================================================== --- src/OFASN1Integer.m +++ src/OFASN1Integer.m @@ -23,73 +23,73 @@ #import "OFInvalidArgumentException.h" #import "OFInvalidFormatException.h" #import "OFOutOfRangeException.h" -intmax_t +long long of_asn1_der_integer_parse(const unsigned char *buffer, size_t length) { - uintmax_t value = 0; + unsigned long long value = 0; /* TODO: Support for big numbers */ - if (length > sizeof(uintmax_t) && - (length != sizeof(uintmax_t) + 1 || buffer[0] != 0)) + if (length > sizeof(unsigned long long) && + (length != sizeof(unsigned long long) + 1 || buffer[0] != 0)) @throw [OFOutOfRangeException exception]; if (length >= 2 && ((buffer[0] == 0 && !(buffer[1] & 0x80)) || (buffer[0] == 0xFF && buffer[1] & 0x80))) @throw [OFInvalidFormatException exception]; if (length >= 1 && buffer[0] & 0x80) - value = ~(uintmax_t)0; + value = ~0ull; while (length--) value = (value << 8) | *buffer++; return value; } @implementation OFASN1Integer -@synthesize integerValue = _integerValue; +@synthesize longLongValue = _longLongValue; -+ (instancetype)integerWithIntegerValue: (intmax_t)integerValue ++ (instancetype)integerWithLongLong: (long long)value { - return [[[self alloc] initWithIntegerValue: integerValue] autorelease]; + return [[[self alloc] initWithLongLong: value] autorelease]; } -- (instancetype)initWithIntegerValue: (intmax_t)integerValue +- (instancetype)initWithLongLong: (long long)value { self = [super init]; - _integerValue = integerValue; + _longLongValue = value; return self; } - (instancetype)initWithTagClass: (of_asn1_tag_class_t)tagClass tagNumber: (of_asn1_tag_number_t)tagNumber constructed: (bool)constructed DEREncodedContents: (OFData *)DEREncodedContents { - intmax_t integerValue; + long long value; @try { if (tagClass != OF_ASN1_TAG_CLASS_UNIVERSAL || tagNumber != OF_ASN1_TAG_NUMBER_INTEGER || constructed) @throw [OFInvalidArgumentException exception]; if (DEREncodedContents.itemSize != 1) @throw [OFInvalidArgumentException exception]; - integerValue = of_asn1_der_integer_parse( + value = of_asn1_der_integer_parse( DEREncodedContents.items, DEREncodedContents.count); } @catch (id e) { [self release]; @throw e; } - return [self initWithIntegerValue: integerValue]; + return [self initWithLongLong: value]; } - (instancetype)init { OF_INVALID_INIT_METHOD @@ -105,22 +105,22 @@ if (![object isKindOfClass: [OFASN1Integer class]]) return false; integer = object; - if (integer->_integerValue != _integerValue) + if (integer->_longLongValue != _longLongValue) return false; return true; } - (uint32_t)hash { - return (uint32_t)_integerValue; + return (uint32_t)_longLongValue; } - (OFString *)description { - return [OFString stringWithFormat: @"", - _integerValue]; + return [OFString stringWithFormat: @"", + _longLongValue]; } @end Index: src/OFASN1ObjectIdentifier.m ================================================================== --- src/OFASN1ObjectIdentifier.m +++ src/OFASN1ObjectIdentifier.m @@ -44,11 +44,11 @@ @try { if (subidentifiers.count < 1) @throw [OFInvalidFormatException exception]; - switch ([[subidentifiers objectAtIndex: 0] intMaxValue]) { + switch ([[subidentifiers objectAtIndex: 0] longLongValue]) { case 0: case 1: case 2: break; default: @@ -73,11 +73,11 @@ OFMutableArray OF_GENERIC(OFNumber *) *subidentifiers; @try { const unsigned char *items = DEREncodedContents.items; size_t count = DEREncodedContents.count; - uintmax_t value = 0; + unsigned long long value = 0; uint_fast8_t bits = 0; if (tagClass != OF_ASN1_TAG_CLASS_UNIVERSAL || tagNumber != OF_ASN1_TAG_NUMBER_OBJECT_IDENTIFIER || constructed) @@ -93,33 +93,33 @@ @throw [OFInvalidFormatException exception]; value = (value << 7) | (items[i] & 0x7F); bits += 7; - if (bits > sizeof(uintmax_t) * 8) + if (bits > sizeof(unsigned long long) * 8) @throw [OFOutOfRangeException exception]; if (items[i] & 0x80) continue; if (subidentifiers.count == 0) { if (value < 40) [subidentifiers addObject: - [OFNumber numberWithUIntMax: 0]]; + [OFNumber numberWithInt: 0]]; else if (value < 80) { [subidentifiers addObject: - [OFNumber numberWithUIntMax: 1]]; + [OFNumber numberWithInt: 1]]; value -= 40; } else { [subidentifiers addObject: - [OFNumber numberWithUIntMax: 2]]; + [OFNumber numberWithInt: 2]]; value -= 80; } } [subidentifiers addObject: - [OFNumber numberWithUIntMax: value]]; + [OFNumber numberWithUnsignedLongLong: value]]; value = 0; bits = 0; } Index: src/OFConstantString.m ================================================================== --- src/OFConstantString.m +++ src/OFConstantString.m @@ -573,29 +573,36 @@ [self finishInitialization]; return self.stringByDeletingLastPathComponent; } -- (intmax_t)decimalValue +- (long long)longLongValue +{ + [self finishInitialization]; + + return self.longLongValue; +} + +- (long long)longLongValueWithBase: (int)base +{ + [self finishInitialization]; + + return [self longLongValueWithBase: base]; +} + +- (unsigned long long)unsignedLongLongValue { [self finishInitialization]; - return self.decimalValue; + return self.unsignedLongLongValue; } -- (uintmax_t)hexadecimalValue +- (unsigned long long)unsignedLongLongValueWithBase: (int)base { [self finishInitialization]; - return self.hexadecimalValue; -} - -- (uintmax_t)octalValue -{ - [self finishInitialization]; - - return self.octalValue; + return [self unsignedLongLongValueWithBase: base]; } - (float)floatValue { [self finishInitialization]; Index: src/OFCountedMapTableSet.m ================================================================== --- src/OFCountedMapTableSet.m +++ src/OFCountedMapTableSet.m @@ -136,26 +136,21 @@ [element elementsForName: @"object" namespace: OF_SERIALIZATION_NS]) { void *pool2 = objc_autoreleasePoolPush(); OFXMLElement *object; OFXMLAttribute *countAttribute; - intmax_t signedCount; - uintmax_t count; + unsigned long long count; object = [objectElement elementsForNamespace: OF_SERIALIZATION_NS].firstObject; countAttribute = [objectElement attributeForName: @"count"]; if (object == nil || countAttribute == nil) @throw [OFInvalidFormatException exception]; - signedCount = countAttribute.decimalValue; - if (signedCount < 0) - @throw [OFOutOfRangeException exception]; - - count = signedCount; + count = countAttribute.unsignedLongLongValue; if (count > SIZE_MAX || count > UINTPTR_MAX) @throw [OFOutOfRangeException exception]; [_mapTable setObject: (void *)(uintptr_t)count forKey: object.objectByDeserializing]; Index: src/OFDNSResolver.m ================================================================== --- src/OFDNSResolver.m +++ src/OFDNSResolver.m @@ -491,11 +491,11 @@ queryData = [OFMutableData dataWithCapacity: 512]; /* Header */ - tmp = OF_BSWAP16_IF_LE(_ID.uInt16Value); + tmp = OF_BSWAP16_IF_LE(_ID.unsignedShortValue); [queryData addItems: &tmp count: 2]; /* RD */ tmp = OF_BSWAP16_IF_LE(1u << 8); @@ -812,11 +812,11 @@ OFNumber *ID; OFDNSResolverContext *context; /* Random, unused ID */ do { - ID = [OFNumber numberWithUInt16: of_random16()]; + ID = [OFNumber numberWithUnsignedShort: of_random16()]; } while ([_queries objectForKey: ID] != nil); if (query.domainName.UTF8StringLength > 253) @throw [OFOutOfRangeException exception]; @@ -911,11 +911,11 @@ if (length < 2) /* We can't get the ID to get the context. Ignore packet. */ return true; - ID = [OFNumber numberWithUInt16: (buffer[0] << 8) | buffer[1]]; + ID = [OFNumber numberWithUnsignedShort: (buffer[0] << 8) | buffer[1]]; context = [[[_queries objectForKey: ID] retain] autorelease]; if (context == nil) return true; Index: src/OFDNSResolverSettings.m ================================================================== --- src/OFDNSResolverSettings.m +++ src/OFDNSResolverSettings.m @@ -32,10 +32,11 @@ #endif #import "OFInvalidFormatException.h" #import "OFOpenItemFailedException.h" #import "OFOutOfMemoryException.h" +#import "OFOutOfRangeException.h" #ifdef OF_WINDOWS # define interface struct # include # undef interface @@ -236,30 +237,41 @@ # if !defined(OF_WINDOWS) && !defined(OF_AMIGAOS4) - (void)parseResolvConfOption: (OFString *)option { @try { if ([option hasPrefix: @"ndots:"]) { + unsigned long long number; + option = [option substringWithRange: of_range(6, option.length - 6)]; + number = option.unsignedLongLongValue; + + if (number > UINT_MAX) + @throw [OFOutOfRangeException exception]; - _minNumberOfDotsInAbsoluteName = - (unsigned int)option.decimalValue; + _minNumberOfDotsInAbsoluteName = (unsigned int)number; } else if ([option hasPrefix: @"timeout:"]) { option = [option substringWithRange: of_range(8, option.length - 8)]; - _timeout = option.decimalValue; + _timeout = option.unsignedLongLongValue; } else if ([option hasPrefix: @"attempts:"]) { + unsigned long long number; + option = [option substringWithRange: of_range(9, option.length - 9)]; + number = option.unsignedLongLongValue; + + if (number > UINT_MAX) + @throw [OFOutOfRangeException exception]; - _maxAttempts = (unsigned int)option.decimalValue; + _maxAttempts = (unsigned int)number; } else if ([option hasPrefix: @"reload-period:"]) { option = [option substringWithRange: of_range(14, option.length - 14)]; - _configReloadInterval = option.decimalValue; + _configReloadInterval = option.unsignedLongLongValue; } else if ([option isEqual: @"tcp"]) _usesTCP = true; } @catch (OFInvalidFormatException *e) { } } Index: src/OFDNSResourceRecord.m ================================================================== --- src/OFDNSResourceRecord.m +++ src/OFDNSResourceRecord.m @@ -79,11 +79,12 @@ if ([string isEqual: @"IN"]) DNSClass = OF_DNS_CLASS_IN; else { @try { - DNSClass = (of_dns_class_t)string.decimalValue; + DNSClass = (of_dns_class_t) + [string unsignedLongLongValueWithBase: 0]; } @catch (OFInvalidFormatException *e) { @throw [OFInvalidArgumentException exception]; } } @@ -123,12 +124,12 @@ recordType = OF_DNS_RECORD_TYPE_SRV; else if ([string isEqual: @"ALL"]) recordType = OF_DNS_RECORD_TYPE_ALL; else { @try { - recordType = - (of_dns_record_type_t)string.decimalValue; + recordType = (of_dns_record_type_t) + [string unsignedLongLongValueWithBase: 0]; } @catch (OFInvalidFormatException *e) { @throw [OFInvalidArgumentException exception]; } } ADDED src/OFData+ASN1DERParsing.h Index: src/OFData+ASN1DERParsing.h ================================================================== --- src/OFData+ASN1DERParsing.h +++ src/OFData+ASN1DERParsing.h @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, + * 2018, 2019, 2020 + * 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. + */ + +#import "OFData.h" +#import "OFASN1Value.h" + +OF_ASSUME_NONNULL_BEGIN + +#ifdef __cplusplus +extern "C" { +#endif +extern int _OFData_ASN1DERParsing_reference; +#ifdef __cplusplus +} +#endif + +@interface OFData (ASN1DERParsing) +/*! + * @brief The data interpreted as ASN.1 in DER representation and parsed as an + * object. + * + * This is either an OFArray (for a sequence), an OFSet (for a set) or an + * OFASN1Value. + */ +@property (readonly, nonatomic) id objectByParsingASN1DER; + +/*! + * @brief Parses the ASN.1 DER representation and returns it as an object. + * + * This is either an OFArray (for a sequence), an OFSet (for a set) or an + * OFASN1Value. + * + * @param depthLimit The maximum depth the parser should accept (defaults to 32 + * if not specified, 0 means no limit (insecure!)) + * @return The ASN.1 DER representation as an object + */ +- (id)objectByParsingASN1DERWithDepthLimit: (size_t)depthLimit; +@end + +OF_ASSUME_NONNULL_END ADDED src/OFData+ASN1DERParsing.m Index: src/OFData+ASN1DERParsing.m ================================================================== --- src/OFData+ASN1DERParsing.m +++ src/OFData+ASN1DERParsing.m @@ -0,0 +1,251 @@ +/* + * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, + * 2018, 2019, 2020 + * 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 "OFData+ASN1DERParsing.h" +#import "OFASN1BitString.h" +#import "OFASN1Boolean.h" +#import "OFASN1Enumerated.h" +#import "OFASN1IA5String.h" +#import "OFASN1Integer.h" +#import "OFASN1NumericString.h" +#import "OFASN1ObjectIdentifier.h" +#import "OFASN1OctetString.h" +#import "OFASN1PrintableString.h" +#import "OFASN1UTF8String.h" +#import "OFASN1Value.h" +#import "OFArray.h" +#import "OFNull.h" +#import "OFSet.h" + +#import "OFInvalidArgumentException.h" +#import "OFInvalidFormatException.h" +#import "OFOutOfRangeException.h" +#import "OFTruncatedDataException.h" + +enum { + ASN1_TAG_CONSTRUCTED_MASK = 0x20 +}; + +int _OFData_ASN1DERParsing_reference; + +static size_t parseObject(OFData *self, id *object, size_t depthLimit); + +static OFArray * +parseSequence(OFData *contents, size_t depthLimit) +{ + OFMutableArray *ret = [OFMutableArray array]; + size_t count = contents.count; + + if (depthLimit == 0) + @throw [OFOutOfRangeException exception]; + + while (count > 0) { + id object; + size_t objectLength; + + objectLength = parseObject(contents, &object, depthLimit); + + count -= objectLength; + contents = [contents subdataWithRange: + of_range(objectLength, count)]; + + [ret addObject: object]; + } + + [ret makeImmutable]; + + return ret; +} + +static OFSet * +parseSet(OFData *contents, size_t depthLimit) +{ + OFMutableSet *ret = [OFMutableSet set]; + size_t count = contents.count; + OFData *previousObjectData = nil; + + if (depthLimit == 0) + @throw [OFOutOfRangeException exception]; + + while (count > 0) { + id object; + size_t objectLength; + OFData *objectData; + + objectLength = parseObject(contents, &object, depthLimit); + objectData = [contents subdataWithRange: + of_range(0, objectLength)]; + + if (previousObjectData != nil && + [objectData compare: previousObjectData] != + OF_ORDERED_DESCENDING) + @throw [OFInvalidFormatException exception]; + + count -= objectLength; + contents = [contents subdataWithRange: + of_range(objectLength, count)]; + + [ret addObject: object]; + + previousObjectData = objectData; + } + + [ret makeImmutable]; + + return ret; +} + +static size_t +parseObject(OFData *self, id *object, size_t depthLimit) +{ + const unsigned char *items = self.items; + size_t count = self.count; + unsigned char tag; + size_t contentsLength, bytesConsumed = 0; + Class valueClass; + OFData *contents; + + if (count < 2) + @throw [OFTruncatedDataException exception]; + + tag = *items++; + contentsLength = *items++; + bytesConsumed += 2; + + if (contentsLength > 127) { + uint_fast8_t lengthLength = contentsLength & 0x7F; + + if (lengthLength > sizeof(size_t)) + @throw [OFOutOfRangeException exception]; + + if (count - bytesConsumed < lengthLength) + @throw [OFTruncatedDataException exception]; + + if (lengthLength == 0 || + (lengthLength == 1 && items[0] < 0x80) || + (lengthLength >= 2 && items[0] == 0)) + @throw [OFInvalidFormatException exception]; + + contentsLength = 0; + + for (uint_fast8_t i = 0; i < lengthLength; i++) + contentsLength = (contentsLength << 8) | *items++; + + bytesConsumed += lengthLength; + + if (contentsLength <= 127) + @throw [OFInvalidFormatException exception]; + } + + if (count - bytesConsumed < contentsLength) + @throw [OFTruncatedDataException exception]; + + contents = [self subdataWithRange: + of_range(bytesConsumed, contentsLength)]; + bytesConsumed += contentsLength; + + switch (tag & ~ASN1_TAG_CONSTRUCTED_MASK) { + case OF_ASN1_TAG_NUMBER_BOOLEAN: + valueClass = [OFASN1Boolean class]; + break; + case OF_ASN1_TAG_NUMBER_INTEGER: + valueClass = [OFASN1Integer class]; + break; + case OF_ASN1_TAG_NUMBER_BIT_STRING: + valueClass = [OFASN1BitString class]; + break; + case OF_ASN1_TAG_NUMBER_OCTET_STRING: + valueClass = [OFASN1OctetString class]; + break; + case OF_ASN1_TAG_NUMBER_NULL: + if (tag & ASN1_TAG_CONSTRUCTED_MASK) + @throw [OFInvalidFormatException exception]; + + if (contents.count != 0) + @throw [OFInvalidFormatException exception]; + + *object = [OFNull null]; + return bytesConsumed; + case OF_ASN1_TAG_NUMBER_OBJECT_IDENTIFIER: + valueClass = [OFASN1ObjectIdentifier class]; + break; + case OF_ASN1_TAG_NUMBER_ENUMERATED: + valueClass = [OFASN1Enumerated class]; + break; + case OF_ASN1_TAG_NUMBER_UTF8_STRING: + valueClass = [OFASN1UTF8String class]; + break; + case OF_ASN1_TAG_NUMBER_SEQUENCE: + if (!(tag & ASN1_TAG_CONSTRUCTED_MASK)) + @throw [OFInvalidFormatException exception]; + + *object = parseSequence(contents, depthLimit - 1); + return bytesConsumed; + case OF_ASN1_TAG_NUMBER_SET: + if (!(tag & ASN1_TAG_CONSTRUCTED_MASK)) + @throw [OFInvalidFormatException exception]; + + *object = parseSet(contents, depthLimit - 1); + return bytesConsumed; + case OF_ASN1_TAG_NUMBER_NUMERIC_STRING: + valueClass = [OFASN1NumericString class]; + break; + case OF_ASN1_TAG_NUMBER_PRINTABLE_STRING: + valueClass = [OFASN1PrintableString class]; + break; + case OF_ASN1_TAG_NUMBER_IA5_STRING: + valueClass = [OFASN1IA5String class]; + break; + default: + valueClass = [OFASN1Value class]; + break; + } + + *object = [[[valueClass alloc] + initWithTagClass: tag >> 6 + tagNumber: tag & 0x1F + constructed: tag & ASN1_TAG_CONSTRUCTED_MASK + DEREncodedContents: contents] autorelease]; + return bytesConsumed; +} + +@implementation OFData (ASN1DERParsing) +- (id)objectByParsingASN1DER +{ + return [self objectByParsingASN1DERWithDepthLimit: 32]; +} + +- (id)objectByParsingASN1DERWithDepthLimit: (size_t)depthLimit +{ + void *pool = objc_autoreleasePoolPush(); + id object; + + if (self.itemSize != 1) + @throw [OFInvalidArgumentException exception]; + + if (parseObject(self, &object, depthLimit) != self.count) + @throw [OFInvalidFormatException exception]; + + [object retain]; + + objc_autoreleasePoolPop(pool); + + return [object autorelease]; +} +@end DELETED src/OFData+ASN1DERValue.h Index: src/OFData+ASN1DERValue.h ================================================================== --- src/OFData+ASN1DERValue.h +++ src/OFData+ASN1DERValue.h @@ -1,54 +0,0 @@ -/* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * 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. - */ - -#import "OFData.h" -#import "OFASN1Value.h" - -OF_ASSUME_NONNULL_BEGIN - -#ifdef __cplusplus -extern "C" { -#endif -extern int _OFData_ASN1DERValue_reference; -#ifdef __cplusplus -} -#endif - -@interface OFData (ASN1DERValue) -/*! - * @brief The data interpreted as ASN.1 in DER representation and parsed as an - * object. - * - * This is either an OFArray (for a sequence), an OFSet (for a set) or an - * OFASN1Value. - */ -@property (readonly, nonatomic) id ASN1DERValue; - -/*! - * @brief Parses the ASN.1 DER representation and returns it as an object. - * - * This is either an OFArray (for a sequence), an OFSet (for a set) or an - * OFASN1Value. - * - * @param depthLimit The maximum depth the parser should accept (defaults to 32 - * if not specified, 0 means no limit (insecure!)) - * @return The ASN.1 DER representation as an object - */ -- (id)ASN1DERValueWithDepthLimit: (size_t)depthLimit; -@end - -OF_ASSUME_NONNULL_END DELETED src/OFData+ASN1DERValue.m Index: src/OFData+ASN1DERValue.m ================================================================== --- src/OFData+ASN1DERValue.m +++ src/OFData+ASN1DERValue.m @@ -1,251 +0,0 @@ -/* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * 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 "OFData+ASN1DERValue.h" -#import "OFASN1BitString.h" -#import "OFASN1Boolean.h" -#import "OFASN1Enumerated.h" -#import "OFASN1IA5String.h" -#import "OFASN1Integer.h" -#import "OFASN1NumericString.h" -#import "OFASN1ObjectIdentifier.h" -#import "OFASN1OctetString.h" -#import "OFASN1PrintableString.h" -#import "OFASN1UTF8String.h" -#import "OFASN1Value.h" -#import "OFArray.h" -#import "OFNull.h" -#import "OFSet.h" - -#import "OFInvalidArgumentException.h" -#import "OFInvalidFormatException.h" -#import "OFOutOfRangeException.h" -#import "OFTruncatedDataException.h" - -enum { - ASN1_TAG_CONSTRUCTED_MASK = 0x20 -}; - -int _OFData_ASN1DERValue_reference; - -static size_t parseObject(OFData *self, id *object, size_t depthLimit); - -static OFArray * -parseSequence(OFData *contents, size_t depthLimit) -{ - OFMutableArray *ret = [OFMutableArray array]; - size_t count = contents.count; - - if (depthLimit == 0) - @throw [OFOutOfRangeException exception]; - - while (count > 0) { - id object; - size_t objectLength; - - objectLength = parseObject(contents, &object, depthLimit); - - count -= objectLength; - contents = [contents subdataWithRange: - of_range(objectLength, count)]; - - [ret addObject: object]; - } - - [ret makeImmutable]; - - return ret; -} - -static OFSet * -parseSet(OFData *contents, size_t depthLimit) -{ - OFMutableSet *ret = [OFMutableSet set]; - size_t count = contents.count; - OFData *previousObjectData = nil; - - if (depthLimit == 0) - @throw [OFOutOfRangeException exception]; - - while (count > 0) { - id object; - size_t objectLength; - OFData *objectData; - - objectLength = parseObject(contents, &object, depthLimit); - objectData = [contents subdataWithRange: - of_range(0, objectLength)]; - - if (previousObjectData != nil && - [objectData compare: previousObjectData] != - OF_ORDERED_DESCENDING) - @throw [OFInvalidFormatException exception]; - - count -= objectLength; - contents = [contents subdataWithRange: - of_range(objectLength, count)]; - - [ret addObject: object]; - - previousObjectData = objectData; - } - - [ret makeImmutable]; - - return ret; -} - -static size_t -parseObject(OFData *self, id *object, size_t depthLimit) -{ - const unsigned char *items = self.items; - size_t count = self.count; - unsigned char tag; - size_t contentsLength, bytesConsumed = 0; - Class valueClass; - OFData *contents; - - if (count < 2) - @throw [OFTruncatedDataException exception]; - - tag = *items++; - contentsLength = *items++; - bytesConsumed += 2; - - if (contentsLength > 127) { - uint_fast8_t lengthLength = contentsLength & 0x7F; - - if (lengthLength > sizeof(size_t)) - @throw [OFOutOfRangeException exception]; - - if (count - bytesConsumed < lengthLength) - @throw [OFTruncatedDataException exception]; - - if (lengthLength == 0 || - (lengthLength == 1 && items[0] < 0x80) || - (lengthLength >= 2 && items[0] == 0)) - @throw [OFInvalidFormatException exception]; - - contentsLength = 0; - - for (uint_fast8_t i = 0; i < lengthLength; i++) - contentsLength = (contentsLength << 8) | *items++; - - bytesConsumed += lengthLength; - - if (contentsLength <= 127) - @throw [OFInvalidFormatException exception]; - } - - if (count - bytesConsumed < contentsLength) - @throw [OFTruncatedDataException exception]; - - contents = [self subdataWithRange: - of_range(bytesConsumed, contentsLength)]; - bytesConsumed += contentsLength; - - switch (tag & ~ASN1_TAG_CONSTRUCTED_MASK) { - case OF_ASN1_TAG_NUMBER_BOOLEAN: - valueClass = [OFASN1Boolean class]; - break; - case OF_ASN1_TAG_NUMBER_INTEGER: - valueClass = [OFASN1Integer class]; - break; - case OF_ASN1_TAG_NUMBER_BIT_STRING: - valueClass = [OFASN1BitString class]; - break; - case OF_ASN1_TAG_NUMBER_OCTET_STRING: - valueClass = [OFASN1OctetString class]; - break; - case OF_ASN1_TAG_NUMBER_NULL: - if (tag & ASN1_TAG_CONSTRUCTED_MASK) - @throw [OFInvalidFormatException exception]; - - if (contents.count != 0) - @throw [OFInvalidFormatException exception]; - - *object = [OFNull null]; - return bytesConsumed; - case OF_ASN1_TAG_NUMBER_OBJECT_IDENTIFIER: - valueClass = [OFASN1ObjectIdentifier class]; - break; - case OF_ASN1_TAG_NUMBER_ENUMERATED: - valueClass = [OFASN1Enumerated class]; - break; - case OF_ASN1_TAG_NUMBER_UTF8_STRING: - valueClass = [OFASN1UTF8String class]; - break; - case OF_ASN1_TAG_NUMBER_SEQUENCE: - if (!(tag & ASN1_TAG_CONSTRUCTED_MASK)) - @throw [OFInvalidFormatException exception]; - - *object = parseSequence(contents, depthLimit - 1); - return bytesConsumed; - case OF_ASN1_TAG_NUMBER_SET: - if (!(tag & ASN1_TAG_CONSTRUCTED_MASK)) - @throw [OFInvalidFormatException exception]; - - *object = parseSet(contents, depthLimit - 1); - return bytesConsumed; - case OF_ASN1_TAG_NUMBER_NUMERIC_STRING: - valueClass = [OFASN1NumericString class]; - break; - case OF_ASN1_TAG_NUMBER_PRINTABLE_STRING: - valueClass = [OFASN1PrintableString class]; - break; - case OF_ASN1_TAG_NUMBER_IA5_STRING: - valueClass = [OFASN1IA5String class]; - break; - default: - valueClass = [OFASN1Value class]; - break; - } - - *object = [[[valueClass alloc] - initWithTagClass: tag >> 6 - tagNumber: tag & 0x1F - constructed: tag & ASN1_TAG_CONSTRUCTED_MASK - DEREncodedContents: contents] autorelease]; - return bytesConsumed; -} - -@implementation OFData (ASN1DERValue) -- (id)ASN1DERValue -{ - return [self ASN1DERValueWithDepthLimit: 32]; -} - -- (id)ASN1DERValueWithDepthLimit: (size_t)depthLimit -{ - void *pool = objc_autoreleasePoolPush(); - id object; - - if (self.itemSize != 1) - @throw [OFInvalidArgumentException exception]; - - if (parseObject(self, &object, depthLimit) != self.count) - @throw [OFInvalidFormatException exception]; - - [object retain]; - - objc_autoreleasePoolPop(pool); - - return [object autorelease]; -} -@end ADDED src/OFData+MessagePackParsing.h Index: src/OFData+MessagePackParsing.h ================================================================== --- src/OFData+MessagePackParsing.h +++ src/OFData+MessagePackParsing.h @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, + * 2018, 2019, 2020 + * 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. + */ + +#import "OFData.h" + +OF_ASSUME_NONNULL_BEGIN + +#ifdef __cplusplus +extern "C" { +#endif +extern int _OFData_MessagePackParsing_reference; +#ifdef __cplusplus +} +#endif + +@interface OFData (MessagePackParsing) +/*! + * @brief The data interpreted as MessagePack representation and parsed as an + * object. + */ +@property (readonly, nonatomic) id objectByParsingMessagePack; + +/*! + * @brief Parses the MessagePack representation and returns it as an object. + * + * @param depthLimit The maximum depth the parser should accept (defaults to 32 + * if not specified, 0 means no limit (insecure!)) + * @return The MessagePack representation as an object + */ +- (id)objectByParsingMessagePackWithDepthLimit: (size_t)depthLimit; +@end + +OF_ASSUME_NONNULL_END ADDED src/OFData+MessagePackParsing.m Index: src/OFData+MessagePackParsing.m ================================================================== --- src/OFData+MessagePackParsing.m +++ src/OFData+MessagePackParsing.m @@ -0,0 +1,572 @@ +/* + * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, + * 2018, 2019, 2020 + * 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" + +#include + +#import "OFData+MessagePackParsing.h" +#import "OFArray.h" +#import "OFDate.h" +#import "OFDictionary.h" +#import "OFMessagePackExtension.h" +#import "OFNull.h" +#import "OFNumber.h" +#import "OFString.h" + +#import "OFInvalidArgumentException.h" +#import "OFInvalidFormatException.h" +#import "OFOutOfRangeException.h" +#import "OFTruncatedDataException.h" + +int _OFData_MessagePackParsing_reference; + +static size_t parseObject(const unsigned char *buffer, size_t length, + id *object, size_t depthLimit); + +static uint16_t +readUInt16(const unsigned char *buffer) +{ + return ((uint16_t)buffer[0] << 8) | buffer[1]; +} + +static uint32_t +readUInt32(const unsigned char *buffer) +{ + return ((uint32_t)buffer[0] << 24) | ((uint32_t)buffer[1] << 16) | + ((uint32_t)buffer[2] << 8) | buffer[3]; +} + +static uint64_t +readUInt64(const unsigned char *buffer) +{ + return ((uint64_t)buffer[0] << 56) | ((uint64_t)buffer[1] << 48) | + ((uint64_t)buffer[2] << 40) | ((uint64_t)buffer[3] << 32) | + ((uint64_t)buffer[4] << 24) | ((uint64_t)buffer[5] << 16) | + ((uint64_t)buffer[6] << 8) | buffer[7]; +} + +static size_t +parseArray(const unsigned char *buffer, size_t length, id *object, size_t count, + size_t depthLimit) +{ + void *pool; + size_t pos = 0; + + if (--depthLimit == 0) + @throw [OFOutOfRangeException exception]; + + /* + * Don't use capacity! For data and strings, this is safe, as we can + * check if we still have enough bytes left. For an array however, we + * can't know this, as every child can be more than one byte. + */ + *object = [OFMutableArray array]; + + for (size_t i = 0; i < count; i++) { + id child; + + pool = objc_autoreleasePoolPush(); + + pos += parseObject(buffer + pos, length - pos, &child, + depthLimit); + + [*object addObject: child]; + + objc_autoreleasePoolPop(pool); + } + + return pos; +} + +static size_t +parseTable(const unsigned char *buffer, size_t length, id *object, size_t count, + size_t depthLimit) +{ + void *pool; + size_t pos = 0; + + if (--depthLimit == 0) + @throw [OFOutOfRangeException exception]; + + /* + * Don't use capacity! For data and strings, this is safe, as we can + * check if we still have enough bytes left. For a dictionary however, + * we can't know this, as every key / value can be more than one byte. + */ + *object = [OFMutableDictionary dictionary]; + + for (size_t i = 0; i < count; i++) { + id key, value; + + pool = objc_autoreleasePoolPush(); + + pos += parseObject(buffer + pos, length - pos, &key, + depthLimit); + pos += parseObject(buffer + pos, length - pos, &value, + depthLimit); + + [*object setObject: value + forKey: key]; + + objc_autoreleasePoolPop(pool); + } + + return pos; +} + +static OFDate * +createDate(OFData *data) +{ + switch (data.count) { + case 4: { + uint32_t timestamp; + + memcpy(×tamp, data.items, 4); + timestamp = OF_BSWAP32_IF_LE(timestamp); + + return [OFDate dateWithTimeIntervalSince1970: timestamp]; + } + case 8: { + uint64_t combined; + + memcpy(&combined, data.items, 8); + combined = OF_BSWAP64_IF_LE(combined); + + return [OFDate dateWithTimeIntervalSince1970: + (double)(combined & 0x3FFFFFFFF) + + (double)(combined >> 34) / 1000000000]; + } + case 12: { + uint32_t nanoseconds; + int64_t seconds; + + memcpy(&nanoseconds, data.items, 4); + memcpy(&seconds, (char *)data.items + 4, 8); + + nanoseconds = OF_BSWAP32_IF_LE(nanoseconds); + seconds = OF_BSWAP64_IF_LE(seconds); + + return [OFDate dateWithTimeIntervalSince1970: + (double)seconds + (double)nanoseconds / 1000000000]; + } + default: + @throw [OFInvalidFormatException exception]; + } +} + +static id +createExtension(int8_t type, OFData *data) +{ + switch (type) { + case -1: + return createDate(data); + default: + return [OFMessagePackExtension extensionWithType: type + data: data]; + } +} + +static size_t +parseObject(const unsigned char *buffer, size_t length, id *object, + size_t depthLimit) +{ + size_t count; + OFData *data; + + if (length < 1) + @throw [OFTruncatedDataException exception]; + + /* positive fixint */ + if ((buffer[0] & 0x80) == 0) { + *object = [OFNumber numberWithUnsignedChar: buffer[0] & 0x7F]; + return 1; + } + /* negative fixint */ + if ((buffer[0] & 0xE0) == 0xE0) { + *object = [OFNumber numberWithChar: + ((int8_t)(buffer[0] & 0x1F)) - 32]; + return 1; + } + + /* fixstr */ + if ((buffer[0] & 0xE0) == 0xA0) { + count = buffer[0] & 0x1F; + + if (length < count + 1) + @throw [OFTruncatedDataException exception]; + + *object = [OFString + stringWithUTF8String: (const char *)buffer + 1 + length: count]; + return count + 1; + } + + /* fixarray */ + if ((buffer[0] & 0xF0) == 0x90) + return parseArray(buffer + 1, length - 1, object, + buffer[0] & 0xF, depthLimit) + 1; + + /* fixmap */ + if ((buffer[0] & 0xF0) == 0x80) + return parseTable(buffer + 1, length - 1, object, + buffer[0] & 0xF, depthLimit) + 1; + + /* Prefix byte */ + switch (buffer[0]) { + /* Unsigned integers */ + case 0xCC: /* uint8 */ + if (length < 2) + @throw [OFTruncatedDataException exception]; + + *object = [OFNumber numberWithUnsignedChar: buffer[1]]; + return 2; + case 0xCD: /* uint 16 */ + if (length < 3) + @throw [OFTruncatedDataException exception]; + + *object = [OFNumber numberWithUnsignedShort: + readUInt16(buffer + 1)]; + return 3; + case 0xCE: /* uint 32 */ + if (length < 5) + @throw [OFTruncatedDataException exception]; + + *object = [OFNumber numberWithUnsignedLong: + readUInt32(buffer + 1)]; + return 5; + case 0xCF: /* uint 64 */ + if (length < 9) + @throw [OFTruncatedDataException exception]; + + *object = [OFNumber numberWithUnsignedLongLong: + readUInt64(buffer + 1)]; + return 9; + /* Signed integers */ + case 0xD0: /* int 8 */ + if (length < 2) + @throw [OFTruncatedDataException exception]; + + *object = [OFNumber numberWithChar: buffer[1]]; + return 2; + case 0xD1: /* int 16 */ + if (length < 3) + @throw [OFTruncatedDataException exception]; + + *object = [OFNumber numberWithShort: readUInt16(buffer + 1)]; + return 3; + case 0xD2: /* int 32 */ + if (length < 5) + @throw [OFTruncatedDataException exception]; + + *object = [OFNumber numberWithLong: readUInt32(buffer + 1)]; + return 5; + case 0xD3: /* int 64 */ + if (length < 9) + @throw [OFTruncatedDataException exception]; + + *object = [OFNumber numberWithLongLong: readUInt64(buffer + 1)]; + return 9; + /* Floating point */ + case 0xCA:; /* float 32 */ + float f; + + if (length < 5) + @throw [OFTruncatedDataException exception]; + + memcpy(&f, buffer + 1, 4); + + *object = [OFNumber numberWithFloat: OF_BSWAP_FLOAT_IF_LE(f)]; + return 5; + case 0xCB:; /* float 64 */ + double d; + + if (length < 9) + @throw [OFTruncatedDataException exception]; + + memcpy(&d, buffer + 1, 8); + + *object = [OFNumber numberWithDouble: OF_BSWAP_DOUBLE_IF_LE(d)]; + return 9; + /* nil */ + case 0xC0: + *object = [OFNull null]; + return 1; + /* false */ + case 0xC2: + *object = [OFNumber numberWithBool: false]; + return 1; + /* true */ + case 0xC3: + *object = [OFNumber numberWithBool: true]; + return 1; + /* Data */ + case 0xC4: /* bin 8 */ + if (length < 2) + @throw [OFTruncatedDataException exception]; + + count = buffer[1]; + + if (length < count + 2) + @throw [OFTruncatedDataException exception]; + + *object = [OFData dataWithItems: buffer + 2 + count: count]; + + return count + 2; + case 0xC5: /* bin 16 */ + if (length < 3) + @throw [OFTruncatedDataException exception]; + + count = readUInt16(buffer + 1); + + if (length < count + 3) + @throw [OFTruncatedDataException exception]; + + *object = [OFData dataWithItems: buffer + 3 + count: count]; + + return count + 3; + case 0xC6: /* bin 32 */ + if (length < 5) + @throw [OFTruncatedDataException exception]; + + count = readUInt32(buffer + 1); + + if (length < count + 5) + @throw [OFTruncatedDataException exception]; + + *object = [OFData dataWithItems: buffer + 5 + count: count]; + + return count + 5; + /* Extensions */ + case 0xC7: /* ext 8 */ + if (length < 3) + @throw [OFTruncatedDataException exception]; + + count = buffer[1]; + + if (length < count + 3) + @throw [OFTruncatedDataException exception]; + + data = [[OFData alloc] initWithItems: buffer + 3 + count: count]; + @try { + *object = createExtension(buffer[2], data); + } @finally { + [data release]; + } + + return count + 3; + case 0xC8: /* ext 16 */ + if (length < 4) + @throw [OFTruncatedDataException exception]; + + count = readUInt16(buffer + 1); + + if (length < count + 4) + @throw [OFTruncatedDataException exception]; + + data = [[OFData alloc] initWithItems: buffer + 4 + count: count]; + @try { + *object = createExtension(buffer[3], data); + } @finally { + [data release]; + } + + return count + 4; + case 0xC9: /* ext 32 */ + if (length < 6) + @throw [OFTruncatedDataException exception]; + + count = readUInt32(buffer + 1); + + if (length < count + 6) + @throw [OFTruncatedDataException exception]; + + data = [[OFData alloc] initWithItems: buffer + 6 + count: count]; + @try { + *object = createExtension(buffer[5], data); + } @finally { + [data release]; + } + + return count + 6; + case 0xD4: /* fixext 1 */ + if (length < 3) + @throw [OFTruncatedDataException exception]; + + data = [[OFData alloc] initWithItems: buffer + 2 + count: 1]; + @try { + *object = createExtension(buffer[1], data); + } @finally { + [data release]; + } + + return 3; + case 0xD5: /* fixext 2 */ + if (length < 4) + @throw [OFTruncatedDataException exception]; + + data = [[OFData alloc] initWithItems: buffer + 2 + count: 2]; + @try { + *object = createExtension(buffer[1], data); + } @finally { + [data release]; + } + + return 4; + case 0xD6: /* fixext 4 */ + if (length < 6) + @throw [OFTruncatedDataException exception]; + + data = [[OFData alloc] initWithItems: buffer + 2 + count: 4]; + @try { + *object = createExtension(buffer[1], data); + } @finally { + [data release]; + } + + return 6; + case 0xD7: /* fixext 8 */ + if (length < 10) + @throw [OFTruncatedDataException exception]; + + data = [[OFData alloc] initWithItems: buffer + 2 + count: 8]; + @try { + *object = createExtension(buffer[1], data); + } @finally { + [data release]; + } + + return 10; + case 0xD8: /* fixext 16 */ + if (length < 18) + @throw [OFTruncatedDataException exception]; + + data = [[OFData alloc] initWithItems: buffer + 2 + count: 16]; + @try { + *object = createExtension(buffer[1], data); + } @finally { + [data release]; + } + + return 18; + /* Strings */ + case 0xD9: /* str 8 */ + if (length < 2) + @throw [OFTruncatedDataException exception]; + + count = buffer[1]; + + if (length < count + 2) + @throw [OFTruncatedDataException exception]; + + *object = [OFString + stringWithUTF8String: (const char *)buffer + 2 + length: count]; + return count + 2; + case 0xDA: /* str 16 */ + if (length < 3) + @throw [OFTruncatedDataException exception]; + + count = readUInt16(buffer + 1); + + if (length < count + 3) + @throw [OFTruncatedDataException exception]; + + *object = [OFString + stringWithUTF8String: (const char *)buffer + 3 + length: count]; + return count + 3; + case 0xDB: /* str 32 */ + if (length < 5) + @throw [OFTruncatedDataException exception]; + + count = readUInt32(buffer + 1); + + if (length < count + 5) + @throw [OFTruncatedDataException exception]; + + *object = [OFString + stringWithUTF8String: (const char *)buffer + 5 + length: count]; + return count + 5; + /* Arrays */ + case 0xDC: /* array 16 */ + if (length < 3) + @throw [OFTruncatedDataException exception]; + + return parseArray(buffer + 3, length - 3, object, + readUInt16(buffer + 1), depthLimit) + 3; + case 0xDD: /* array 32 */ + if (length < 5) + @throw [OFTruncatedDataException exception]; + + return parseArray(buffer + 5, length - 5, object, + readUInt32(buffer + 1), depthLimit) + 5; + /* Maps */ + case 0xDE: /* map 16 */ + if (length < 3) + @throw [OFTruncatedDataException exception]; + + return parseTable(buffer + 3, length - 3, object, + readUInt16(buffer + 1), depthLimit) + 3; + case 0xDF: /* map 32 */ + if (length < 5) + @throw [OFTruncatedDataException exception]; + + return parseTable(buffer + 5, length - 5, object, + readUInt32(buffer + 1), depthLimit) + 5; + default: + @throw [OFInvalidFormatException exception]; + } +} + +@implementation OFData (MessagePackParsing) +- (id)objectByParsingMessagePack +{ + return [self objectByParsingMessagePackWithDepthLimit: 32]; +} + +- (id)objectByParsingMessagePackWithDepthLimit: (size_t)depthLimit +{ + void *pool = objc_autoreleasePoolPush(); + size_t count = self.count; + id object; + + if (self.itemSize != 1) + @throw [OFInvalidArgumentException exception]; + + if (parseObject(self.items, count, &object, depthLimit) != count) + @throw [OFInvalidFormatException exception]; + + [object retain]; + + objc_autoreleasePoolPop(pool); + + return [object autorelease]; +} +@end DELETED src/OFData+MessagePackValue.h Index: src/OFData+MessagePackValue.h ================================================================== --- src/OFData+MessagePackValue.h +++ src/OFData+MessagePackValue.h @@ -1,47 +0,0 @@ -/* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * 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. - */ - -#import "OFData.h" - -OF_ASSUME_NONNULL_BEGIN - -#ifdef __cplusplus -extern "C" { -#endif -extern int _OFData_MessagePackValue_reference; -#ifdef __cplusplus -} -#endif - -@interface OFData (MessagePackValue) -/*! - * @brief The data interpreted as MessagePack representation and parsed as an - * object. - */ -@property (readonly, nonatomic) id messagePackValue; - -/*! - * @brief Parses the MessagePack representation and returns it as an object. - * - * @param depthLimit The maximum depth the parser should accept (defaults to 32 - * if not specified, 0 means no limit (insecure!)) - * @return The MessagePack representation as an object - */ -- (id)messagePackValueWithDepthLimit: (size_t)depthLimit; -@end - -OF_ASSUME_NONNULL_END DELETED src/OFData+MessagePackValue.m Index: src/OFData+MessagePackValue.m ================================================================== --- src/OFData+MessagePackValue.m +++ src/OFData+MessagePackValue.m @@ -1,569 +0,0 @@ -/* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * 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" - -#include - -#import "OFData+MessagePackValue.h" -#import "OFArray.h" -#import "OFDate.h" -#import "OFDictionary.h" -#import "OFMessagePackExtension.h" -#import "OFNull.h" -#import "OFNumber.h" -#import "OFString.h" - -#import "OFInvalidArgumentException.h" -#import "OFInvalidFormatException.h" -#import "OFOutOfRangeException.h" -#import "OFTruncatedDataException.h" - -int _OFData_MessagePackValue_reference; - -static size_t parseObject(const unsigned char *buffer, size_t length, - id *object, size_t depthLimit); - -static uint16_t -readUInt16(const unsigned char *buffer) -{ - return ((uint16_t)buffer[0] << 8) | buffer[1]; -} - -static uint32_t -readUInt32(const unsigned char *buffer) -{ - return ((uint32_t)buffer[0] << 24) | ((uint32_t)buffer[1] << 16) | - ((uint32_t)buffer[2] << 8) | buffer[3]; -} - -static uint64_t -readUInt64(const unsigned char *buffer) -{ - return ((uint64_t)buffer[0] << 56) | ((uint64_t)buffer[1] << 48) | - ((uint64_t)buffer[2] << 40) | ((uint64_t)buffer[3] << 32) | - ((uint64_t)buffer[4] << 24) | ((uint64_t)buffer[5] << 16) | - ((uint64_t)buffer[6] << 8) | buffer[7]; -} - -static size_t -parseArray(const unsigned char *buffer, size_t length, id *object, size_t count, - size_t depthLimit) -{ - void *pool; - size_t pos = 0; - - if (--depthLimit == 0) - @throw [OFOutOfRangeException exception]; - - /* - * Don't use capacity! For data and strings, this is safe, as we can - * check if we still have enough bytes left. For an array however, we - * can't know this, as every child can be more than one byte. - */ - *object = [OFMutableArray array]; - - for (size_t i = 0; i < count; i++) { - id child; - - pool = objc_autoreleasePoolPush(); - - pos += parseObject(buffer + pos, length - pos, &child, - depthLimit); - - [*object addObject: child]; - - objc_autoreleasePoolPop(pool); - } - - return pos; -} - -static size_t -parseTable(const unsigned char *buffer, size_t length, id *object, size_t count, - size_t depthLimit) -{ - void *pool; - size_t pos = 0; - - if (--depthLimit == 0) - @throw [OFOutOfRangeException exception]; - - /* - * Don't use capacity! For data and strings, this is safe, as we can - * check if we still have enough bytes left. For a dictionary however, - * we can't know this, as every key / value can be more than one byte. - */ - *object = [OFMutableDictionary dictionary]; - - for (size_t i = 0; i < count; i++) { - id key, value; - - pool = objc_autoreleasePoolPush(); - - pos += parseObject(buffer + pos, length - pos, &key, - depthLimit); - pos += parseObject(buffer + pos, length - pos, &value, - depthLimit); - - [*object setObject: value - forKey: key]; - - objc_autoreleasePoolPop(pool); - } - - return pos; -} - -static OFDate * -createDate(OFData *data) -{ - switch (data.count) { - case 4: { - uint32_t timestamp; - - memcpy(×tamp, data.items, 4); - timestamp = OF_BSWAP32_IF_LE(timestamp); - - return [OFDate dateWithTimeIntervalSince1970: timestamp]; - } - case 8: { - uint64_t combined; - - memcpy(&combined, data.items, 8); - combined = OF_BSWAP64_IF_LE(combined); - - return [OFDate dateWithTimeIntervalSince1970: - (double)(combined & 0x3FFFFFFFF) + - (double)(combined >> 34) / 1000000000]; - } - case 12: { - uint32_t nanoseconds; - int64_t seconds; - - memcpy(&nanoseconds, data.items, 4); - memcpy(&seconds, (char *)data.items + 4, 8); - - nanoseconds = OF_BSWAP32_IF_LE(nanoseconds); - seconds = OF_BSWAP64_IF_LE(seconds); - - return [OFDate dateWithTimeIntervalSince1970: - (double)seconds + (double)nanoseconds / 1000000000]; - } - default: - @throw [OFInvalidFormatException exception]; - } -} - -static id -createExtension(int8_t type, OFData *data) -{ - switch (type) { - case -1: - return createDate(data); - default: - return [OFMessagePackExtension extensionWithType: type - data: data]; - } -} - -static size_t -parseObject(const unsigned char *buffer, size_t length, id *object, - size_t depthLimit) -{ - size_t count; - OFData *data; - - if (length < 1) - @throw [OFTruncatedDataException exception]; - - /* positive fixint */ - if ((buffer[0] & 0x80) == 0) { - *object = [OFNumber numberWithUInt8: buffer[0] & 0x7F]; - return 1; - } - /* negative fixint */ - if ((buffer[0] & 0xE0) == 0xE0) { - *object = [OFNumber numberWithInt8: - ((int8_t)(buffer[0] & 0x1F)) - 32]; - return 1; - } - - /* fixstr */ - if ((buffer[0] & 0xE0) == 0xA0) { - count = buffer[0] & 0x1F; - - if (length < count + 1) - @throw [OFTruncatedDataException exception]; - - *object = [OFString - stringWithUTF8String: (const char *)buffer + 1 - length: count]; - return count + 1; - } - - /* fixarray */ - if ((buffer[0] & 0xF0) == 0x90) - return parseArray(buffer + 1, length - 1, object, - buffer[0] & 0xF, depthLimit) + 1; - - /* fixmap */ - if ((buffer[0] & 0xF0) == 0x80) - return parseTable(buffer + 1, length - 1, object, - buffer[0] & 0xF, depthLimit) + 1; - - /* Prefix byte */ - switch (buffer[0]) { - /* Unsigned integers */ - case 0xCC: /* uint8 */ - if (length < 2) - @throw [OFTruncatedDataException exception]; - - *object = [OFNumber numberWithUInt8: buffer[1]]; - return 2; - case 0xCD: /* uint 16 */ - if (length < 3) - @throw [OFTruncatedDataException exception]; - - *object = [OFNumber numberWithUInt16: readUInt16(buffer + 1)]; - return 3; - case 0xCE: /* uint 32 */ - if (length < 5) - @throw [OFTruncatedDataException exception]; - - *object = [OFNumber numberWithUInt32: readUInt32(buffer + 1)]; - return 5; - case 0xCF: /* uint 64 */ - if (length < 9) - @throw [OFTruncatedDataException exception]; - - *object = [OFNumber numberWithUInt64: readUInt64(buffer + 1)]; - return 9; - /* Signed integers */ - case 0xD0: /* int 8 */ - if (length < 2) - @throw [OFTruncatedDataException exception]; - - *object = [OFNumber numberWithInt8: buffer[1]]; - return 2; - case 0xD1: /* int 16 */ - if (length < 3) - @throw [OFTruncatedDataException exception]; - - *object = [OFNumber numberWithInt16: readUInt16(buffer + 1)]; - return 3; - case 0xD2: /* int 32 */ - if (length < 5) - @throw [OFTruncatedDataException exception]; - - *object = [OFNumber numberWithInt32: readUInt32(buffer + 1)]; - return 5; - case 0xD3: /* int 64 */ - if (length < 9) - @throw [OFTruncatedDataException exception]; - - *object = [OFNumber numberWithInt64: readUInt64(buffer + 1)]; - return 9; - /* Floating point */ - case 0xCA:; /* float 32 */ - float f; - - if (length < 5) - @throw [OFTruncatedDataException exception]; - - memcpy(&f, buffer + 1, 4); - - *object = [OFNumber numberWithFloat: OF_BSWAP_FLOAT_IF_LE(f)]; - return 5; - case 0xCB:; /* float 64 */ - double d; - - if (length < 9) - @throw [OFTruncatedDataException exception]; - - memcpy(&d, buffer + 1, 8); - - *object = [OFNumber numberWithDouble: OF_BSWAP_DOUBLE_IF_LE(d)]; - return 9; - /* nil */ - case 0xC0: - *object = [OFNull null]; - return 1; - /* false */ - case 0xC2: - *object = [OFNumber numberWithBool: false]; - return 1; - /* true */ - case 0xC3: - *object = [OFNumber numberWithBool: true]; - return 1; - /* Data */ - case 0xC4: /* bin 8 */ - if (length < 2) - @throw [OFTruncatedDataException exception]; - - count = buffer[1]; - - if (length < count + 2) - @throw [OFTruncatedDataException exception]; - - *object = [OFData dataWithItems: buffer + 2 - count: count]; - - return count + 2; - case 0xC5: /* bin 16 */ - if (length < 3) - @throw [OFTruncatedDataException exception]; - - count = readUInt16(buffer + 1); - - if (length < count + 3) - @throw [OFTruncatedDataException exception]; - - *object = [OFData dataWithItems: buffer + 3 - count: count]; - - return count + 3; - case 0xC6: /* bin 32 */ - if (length < 5) - @throw [OFTruncatedDataException exception]; - - count = readUInt32(buffer + 1); - - if (length < count + 5) - @throw [OFTruncatedDataException exception]; - - *object = [OFData dataWithItems: buffer + 5 - count: count]; - - return count + 5; - /* Extensions */ - case 0xC7: /* ext 8 */ - if (length < 3) - @throw [OFTruncatedDataException exception]; - - count = buffer[1]; - - if (length < count + 3) - @throw [OFTruncatedDataException exception]; - - data = [[OFData alloc] initWithItems: buffer + 3 - count: count]; - @try { - *object = createExtension(buffer[2], data); - } @finally { - [data release]; - } - - return count + 3; - case 0xC8: /* ext 16 */ - if (length < 4) - @throw [OFTruncatedDataException exception]; - - count = readUInt16(buffer + 1); - - if (length < count + 4) - @throw [OFTruncatedDataException exception]; - - data = [[OFData alloc] initWithItems: buffer + 4 - count: count]; - @try { - *object = createExtension(buffer[3], data); - } @finally { - [data release]; - } - - return count + 4; - case 0xC9: /* ext 32 */ - if (length < 6) - @throw [OFTruncatedDataException exception]; - - count = readUInt32(buffer + 1); - - if (length < count + 6) - @throw [OFTruncatedDataException exception]; - - data = [[OFData alloc] initWithItems: buffer + 6 - count: count]; - @try { - *object = createExtension(buffer[5], data); - } @finally { - [data release]; - } - - return count + 6; - case 0xD4: /* fixext 1 */ - if (length < 3) - @throw [OFTruncatedDataException exception]; - - data = [[OFData alloc] initWithItems: buffer + 2 - count: 1]; - @try { - *object = createExtension(buffer[1], data); - } @finally { - [data release]; - } - - return 3; - case 0xD5: /* fixext 2 */ - if (length < 4) - @throw [OFTruncatedDataException exception]; - - data = [[OFData alloc] initWithItems: buffer + 2 - count: 2]; - @try { - *object = createExtension(buffer[1], data); - } @finally { - [data release]; - } - - return 4; - case 0xD6: /* fixext 4 */ - if (length < 6) - @throw [OFTruncatedDataException exception]; - - data = [[OFData alloc] initWithItems: buffer + 2 - count: 4]; - @try { - *object = createExtension(buffer[1], data); - } @finally { - [data release]; - } - - return 6; - case 0xD7: /* fixext 8 */ - if (length < 10) - @throw [OFTruncatedDataException exception]; - - data = [[OFData alloc] initWithItems: buffer + 2 - count: 8]; - @try { - *object = createExtension(buffer[1], data); - } @finally { - [data release]; - } - - return 10; - case 0xD8: /* fixext 16 */ - if (length < 18) - @throw [OFTruncatedDataException exception]; - - data = [[OFData alloc] initWithItems: buffer + 2 - count: 16]; - @try { - *object = createExtension(buffer[1], data); - } @finally { - [data release]; - } - - return 18; - /* Strings */ - case 0xD9: /* str 8 */ - if (length < 2) - @throw [OFTruncatedDataException exception]; - - count = buffer[1]; - - if (length < count + 2) - @throw [OFTruncatedDataException exception]; - - *object = [OFString - stringWithUTF8String: (const char *)buffer + 2 - length: count]; - return count + 2; - case 0xDA: /* str 16 */ - if (length < 3) - @throw [OFTruncatedDataException exception]; - - count = readUInt16(buffer + 1); - - if (length < count + 3) - @throw [OFTruncatedDataException exception]; - - *object = [OFString - stringWithUTF8String: (const char *)buffer + 3 - length: count]; - return count + 3; - case 0xDB: /* str 32 */ - if (length < 5) - @throw [OFTruncatedDataException exception]; - - count = readUInt32(buffer + 1); - - if (length < count + 5) - @throw [OFTruncatedDataException exception]; - - *object = [OFString - stringWithUTF8String: (const char *)buffer + 5 - length: count]; - return count + 5; - /* Arrays */ - case 0xDC: /* array 16 */ - if (length < 3) - @throw [OFTruncatedDataException exception]; - - return parseArray(buffer + 3, length - 3, object, - readUInt16(buffer + 1), depthLimit) + 3; - case 0xDD: /* array 32 */ - if (length < 5) - @throw [OFTruncatedDataException exception]; - - return parseArray(buffer + 5, length - 5, object, - readUInt32(buffer + 1), depthLimit) + 5; - /* Maps */ - case 0xDE: /* map 16 */ - if (length < 3) - @throw [OFTruncatedDataException exception]; - - return parseTable(buffer + 3, length - 3, object, - readUInt16(buffer + 1), depthLimit) + 3; - case 0xDF: /* map 32 */ - if (length < 5) - @throw [OFTruncatedDataException exception]; - - return parseTable(buffer + 5, length - 5, object, - readUInt32(buffer + 1), depthLimit) + 5; - default: - @throw [OFInvalidFormatException exception]; - } -} - -@implementation OFData (MessagePackValue) -- (id)messagePackValue -{ - return [self messagePackValueWithDepthLimit: 32]; -} - -- (id)messagePackValueWithDepthLimit: (size_t)depthLimit -{ - void *pool = objc_autoreleasePoolPush(); - size_t count = self.count; - id object; - - if (self.itemSize != 1) - @throw [OFInvalidArgumentException exception]; - - if (parseObject(self.items, count, &object, depthLimit) != count) - @throw [OFInvalidFormatException exception]; - - [object retain]; - - objc_autoreleasePoolPop(pool); - - return [object autorelease]; -} -@end Index: src/OFData.h ================================================================== --- src/OFData.h +++ src/OFData.h @@ -325,8 +325,8 @@ @end OF_ASSUME_NONNULL_END #import "OFMutableData.h" -#import "OFData+ASN1DERValue.h" +#import "OFData+ASN1DERParsing.h" #import "OFData+CryptoHashing.h" -#import "OFData+MessagePackValue.h" +#import "OFData+MessagePackParsing.h" Index: src/OFData.m ================================================================== --- src/OFData.m +++ src/OFData.m @@ -46,13 +46,13 @@ /* References for static linking */ void _references_to_categories_of_OFData(void) { - _OFData_ASN1DERValue_reference = 1; + _OFData_ASN1DERParsing_reference = 1; _OFData_CryptoHashing_reference = 1; - _OFData_MessagePackValue_reference = 1; + _OFData_MessagePackParsing_reference = 1; } @implementation OFData @synthesize itemSize = _itemSize; @@ -182,19 +182,19 @@ #ifdef OF_HAVE_FILES - (instancetype)initWithContentsOfFile: (OFString *)path { char *buffer = NULL; - uintmax_t size; + unsigned long long size; @try { OFFile *file; size = [[OFFileManager defaultManager] attributesOfItemAtPath: path].fileSize; -# if UINTMAX_MAX > SIZE_MAX +# if ULLONG_MAX > SIZE_MAX if (size > SIZE_MAX) @throw [OFOutOfRangeException exception]; # endif if ((buffer = malloc((size_t)size)) == NULL) Index: src/OFDate.m ================================================================== --- src/OFDate.m +++ src/OFDate.m @@ -485,21 +485,33 @@ return [self initWithTimeIntervalSince1970: seconds]; } - (instancetype)initWithSerialization: (OFXMLElement *)element { - void *pool = objc_autoreleasePoolPush(); of_time_interval_t seconds; - if (![element.name isEqual: @"OFDate"] || - ![element.namespace isEqual: OF_SERIALIZATION_NS]) - @throw [OFInvalidArgumentException exception]; - - seconds = OF_BSWAP_DOUBLE_IF_LE(OF_INT_TO_DOUBLE_RAW(OF_BSWAP64_IF_LE( - element.hexadecimalValue))); - - objc_autoreleasePoolPop(pool); + @try { + void *pool = objc_autoreleasePoolPush(); + unsigned long long value; + + if (![element.name isEqual: @"OFDate"] || + ![element.namespace isEqual: OF_SERIALIZATION_NS]) + @throw [OFInvalidArgumentException exception]; + + value = [element unsignedLongLongValueWithBase: 16]; + + if (value > UINT64_MAX) + @throw [OFOutOfRangeException exception]; + + seconds = OF_BSWAP_DOUBLE_IF_LE(OF_INT_TO_DOUBLE_RAW( + OF_BSWAP64_IF_LE(value))); + + objc_autoreleasePoolPop(pool); + } @catch (id e) { + [self release]; + @throw e; + } return [self initWithTimeIntervalSince1970: seconds]; } - (bool)isEqual: (id)object Index: src/OFFileManager.h ================================================================== --- src/OFFileManager.h +++ src/OFFileManager.h @@ -576,11 +576,11 @@ /*! * @brief The @ref of_file_attribute_key_size key from the dictionary. * * Raises an @ref OFUndefinedKeyException if the key is missing. */ -@property (readonly, nonatomic) uintmax_t fileSize; +@property (readonly, nonatomic) unsigned long long fileSize; /*! * @brief The @ref of_file_attribute_key_type key from the dictionary. * * Raises an @ref OFUndefinedKeyException if the key is missing. @@ -591,25 +591,25 @@ * @brief The @ref of_file_attribute_key_posix_permissions key from the * dictionary. * * Raises an @ref OFUndefinedKeyException if the key is missing. */ -@property (readonly, nonatomic) uint16_t filePOSIXPermissions; +@property (readonly, nonatomic) unsigned long filePOSIXPermissions; /*! * @brief The @ref of_file_attribute_key_posix_uid key from the dictionary. * * Raises an @ref OFUndefinedKeyException if the key is missing. */ -@property (readonly, nonatomic) uint32_t filePOSIXUID; +@property (readonly, nonatomic) unsigned long filePOSIXUID; /*! * @brief The @ref of_file_attribute_key_posix_gid key from the dictionary. * * Raises an @ref OFUndefinedKeyException if the key is missing. */ -@property (readonly, nonatomic) uint32_t filePOSIXGID; +@property (readonly, nonatomic) unsigned long filePOSIXGID; /*! * @brief The @ref of_file_attribute_key_owner key from the dictionary. * * Raises an @ref OFUndefinedKeyException if the key is missing. Index: src/OFFileManager.m ================================================================== --- src/OFFileManager.m +++ src/OFFileManager.m @@ -936,37 +936,37 @@ return OF_RETAIN_COUNT_MAX; } @end @implementation OFDictionary (FileAttributes) -- (uintmax_t)fileSize +- (unsigned long long)fileSize { return [attributeForKeyOrException(self, of_file_attribute_key_size) - uIntMaxValue]; + unsignedLongLongValue]; } - (of_file_type_t)fileType { return attributeForKeyOrException(self, of_file_attribute_key_type); } -- (uint16_t)filePOSIXPermissions -{ - return [attributeForKeyOrException(self, - of_file_attribute_key_posix_permissions) uInt16Value]; -} - -- (uint32_t)filePOSIXUID -{ - return [attributeForKeyOrException(self, - of_file_attribute_key_posix_uid) uInt32Value]; -} - -- (uint32_t)filePOSIXGID -{ - return [attributeForKeyOrException(self, - of_file_attribute_key_posix_gid) uInt32Value]; +- (unsigned long)filePOSIXPermissions +{ + return [attributeForKeyOrException(self, + of_file_attribute_key_posix_permissions) unsignedLongValue]; +} + +- (unsigned long)filePOSIXUID +{ + return [attributeForKeyOrException(self, + of_file_attribute_key_posix_uid) unsignedLongValue]; +} + +- (unsigned long)filePOSIXGID +{ + return [attributeForKeyOrException(self, + of_file_attribute_key_posix_gid) unsignedLongValue]; } - (OFString *)fileOwner { return attributeForKeyOrException(self, of_file_attribute_key_owner); Index: src/OFFileURLHandler.m ================================================================== --- src/OFFileURLHandler.m +++ src/OFFileURLHandler.m @@ -409,13 +409,13 @@ static void setOwnerAndGroupAttributes(of_mutable_file_attributes_t attributes, of_stat_t *s) { #ifdef OF_FILE_MANAGER_SUPPORTS_OWNER - [attributes setObject: [NSNumber numberWithUInt16: s->st_uid] + [attributes setObject: [NSNumber numberWithUnsignedLong: s->st_uid] forKey: of_file_attribute_key_posix_uid]; - [attributes setObject: [NSNumber numberWithUInt16: s->st_gid] + [attributes setObject: [NSNumber numberWithUnsignedLong: s->st_gid] forKey: of_file_attribute_key_posix_gid]; # ifdef OF_HAVE_THREADS [passwdMutex lock]; @try { @@ -618,16 +618,16 @@ errNo: errno]; if (s.st_size < 0) @throw [OFOutOfRangeException exception]; - [ret setObject: [NSNumber numberWithUIntMax: s.st_size] + [ret setObject: [NSNumber numberWithUnsignedLongLong: s.st_size] forKey: of_file_attribute_key_size]; setTypeAttribute(ret, &s); - [ret setObject: [NSNumber numberWithUInt16: s.st_mode & 07777] + [ret setObject: [NSNumber numberWithUnsignedLong: s.st_mode] forKey: of_file_attribute_key_posix_permissions]; setOwnerAndGroupAttributes(ret, &s); setDateAttributes(ret, &s); @@ -758,11 +758,11 @@ - (void)of_setPOSIXPermissions: (OFNumber *)permissions ofItemAtURL: (OFURL *)URL attributes: (of_file_attributes_t)attributes OF_DIRECT { #ifdef OF_FILE_MANAGER_SUPPORTS_PERMISSIONS - uint16_t mode = permissions.uInt16Value & 0777; + mode_t mode = (mode_t)permissions.unsignedLongValue; OFString *path = URL.fileSystemRepresentation; int status; # ifdef OF_WINDOWS if ([OFSystemInfo isWindowsNT]) Index: src/OFHTTPClient.m ================================================================== --- src/OFHTTPClient.m +++ src/OFHTTPClient.m @@ -77,11 +77,11 @@ @interface OFHTTPClientRequestBodyStream: OFStream { OFHTTPClientRequestHandler *_handler; OFTCPSocket *_socket; bool _chunked; - uintmax_t _toWrite; + unsigned long long _toWrite; bool _atEndOfStream; } - (instancetype)initWithHandler: (OFHTTPClientRequestHandler *)handler socket: (OFTCPSocket *)sock; @@ -91,11 +91,11 @@ @interface OFHTTPClientResponse: OFHTTPResponse { OFTCPSocket *_socket; bool _hasContentLength, _chunked, _keepAlive; bool _atEndOfStream, _setAtEndOfStream; - intmax_t _toRead; + long long _toRead; } @property (nonatomic, setter=of_setKeepAlive:) bool of_keepAlive; - (instancetype)initWithSocket: (OFTCPSocket *)sock; @@ -443,10 +443,12 @@ } } - (bool)handleFirstLine: (OFString *)line { + long long status; + /* * It's possible that the write succeeds on a connection that is * keep-alive, but the connection has already been closed by the remote * end due to a timeout. In this case, we need to reconnect. */ @@ -462,11 +464,16 @@ _version = [[line substringWithRange: of_range(5, 3)] copy]; if (![_version isEqual: @"1.0"] && ![_version isEqual: @"1.1"]) @throw [OFUnsupportedVersionException exceptionWithVersion: _version]; - _status = (int)[line substringWithRange: of_range(9, 3)].decimalValue; + status = [line substringWithRange: of_range(9, 3)].longLongValue; + + if (status < 0 || status > 599) + @throw [OFInvalidServerReplyException exception]; + + _status = (int)status; return true; } - (bool)handleServerHeader: (OFString *)line @@ -711,11 +718,11 @@ port = 80; } URLPort = URL.port; if (URLPort != nil) - port = URLPort.uInt16Value; + port = URLPort.unsignedShortValue; sock.delegate = self; [sock asyncConnectToHost: URL.host port: port]; } @catch (id e) { @@ -730,11 +737,10 @@ { self = [super init]; @try { OFDictionary OF_GENERIC(OFString *, OFString *) *headers; - intmax_t contentLength; OFString *transferEncoding, *contentLengthString; _handler = [handler retain]; _socket = [sock retain]; @@ -747,15 +753,11 @@ if (contentLengthString != nil) { if (_chunked || contentLengthString.length == 0) @throw [OFInvalidArgumentException exception]; - contentLength = contentLengthString.decimalValue; - if (contentLength < 0) - @throw [OFOutOfRangeException exception]; - - _toWrite = contentLength; + _toWrite = contentLengthString.unsignedLongLongValue; } else if (!_chunked) @throw [OFInvalidArgumentException exception]; } @catch (id e) { [self release]; @throw e; @@ -893,15 +895,17 @@ @throw [OFInvalidServerReplyException exception]; _hasContentLength = true; @try { - _toRead = contentLength.decimalValue; + unsigned long long toRead = + contentLength.unsignedLongLongValue; - if (_toRead < 0) - @throw [OFInvalidServerReplyException - exception]; + if (toRead > LLONG_MAX) + @throw [OFOutOfRangeException exception]; + + _toRead = (long long)toRead; } @catch (OFInvalidFormatException *e) { @throw [OFInvalidServerReplyException exception]; } } } @@ -924,11 +928,11 @@ /* Content-Length */ if (!_chunked) { size_t ret; - if (length > (uintmax_t)_toRead) + if (length > (unsigned long long)_toRead) length = (size_t)_toRead; ret = [_socket readIntoBuffer: buffer length: length]; @@ -979,11 +983,11 @@ if (_setAtEndOfStream && _toRead == 0) _atEndOfStream = true; return 0; } else if (_toRead > 0) { - if (length > (uintmax_t)_toRead) + if (length > (unsigned long long)_toRead) length = (size_t)_toRead; length = [_socket readIntoBuffer: buffer length: length]; @@ -1024,12 +1028,17 @@ @throw [OFInvalidServerReplyException exception]; } @try { - if ((_toRead = line.hexadecimalValue) < 0) + unsigned long long toRead = + [line unsignedLongLongValueWithBase: 16]; + + if (toRead > LLONG_MAX) @throw [OFOutOfRangeException exception]; + + _toRead = (long long)toRead; } @catch (OFInvalidFormatException *e) { @throw [OFInvalidServerReplyException exception]; } if (_toRead == 0) { Index: src/OFHTTPCookie.m ================================================================== --- src/OFHTTPCookie.m +++ src/OFHTTPCookie.m @@ -36,11 +36,11 @@ dateWithDateString: value format: @"%a, %d %b %Y %H:%M:%S %z"]; cookie.expires = date; } else if ([lowercaseName isEqual: @"max-age"]) { OFDate *date = [OFDate dateWithTimeIntervalSinceNow: - value.decimalValue]; + value.unsignedLongLongValue]; cookie.expires = date; } else if ([lowercaseName isEqual: @"domain"]) cookie.domain = value; else if ([lowercaseName isEqual: @"path"]) cookie.path = value; Index: src/OFHTTPRequest.m ================================================================== --- src/OFHTTPRequest.m +++ src/OFHTTPRequest.m @@ -212,20 +212,20 @@ - (void)setProtocolVersionString: (OFString *)string { void *pool = objc_autoreleasePoolPush(); OFArray *components = [string componentsSeparatedByString: @"."]; - intmax_t major, minor; + unsigned long long major, minor; of_http_request_protocol_version_t protocolVersion; if (components.count != 2) @throw [OFInvalidFormatException exception]; - major = [components.firstObject decimalValue]; - minor = [components.lastObject decimalValue]; + major = [components.firstObject unsignedLongLongValue]; + minor = [components.lastObject unsignedLongLongValue]; - if (major < 0 || major > UINT8_MAX || minor < 0 || minor > UINT8_MAX) + if (major > UINT8_MAX || minor > UINT8_MAX) @throw [OFOutOfRangeException exception]; protocolVersion.major = (uint8_t)major; protocolVersion.minor = (uint8_t)minor; Index: src/OFHTTPResponse.m ================================================================== --- src/OFHTTPResponse.m +++ src/OFHTTPResponse.m @@ -269,20 +269,20 @@ - (void)setProtocolVersionString: (OFString *)string { void *pool = objc_autoreleasePoolPush(); OFArray *components = [string componentsSeparatedByString: @"."]; - intmax_t major, minor; + unsigned long long major, minor; of_http_request_protocol_version_t protocolVersion; if (components.count != 2) @throw [OFInvalidFormatException exception]; - major = [components.firstObject decimalValue]; - minor = [components.lastObject decimalValue]; + major = [components.firstObject unsignedLongLongValue]; + minor = [components.lastObject unsignedLongLongValue]; - if (major < 0 || major > UINT8_MAX || minor < 0 || minor > UINT8_MAX) + if (major > UINT8_MAX || minor > UINT8_MAX) @throw [OFOutOfRangeException exception]; protocolVersion.major = (uint8_t)major; protocolVersion.minor = (uint8_t)minor; @@ -304,11 +304,11 @@ } - (OFString *)stringWithEncoding: (of_string_encoding_t)encoding { void *pool = objc_autoreleasePoolPush(); - OFString *contentType, *contentLength, *ret; + OFString *contentType, *contentLengthString, *ret; OFData *data; if (encoding == OF_STRING_ENCODING_AUTODETECT && (contentType = [_headers objectForKey: @"Content-Type"]) != nil) encoding = encodingForContentType(contentType); @@ -316,13 +316,21 @@ if (encoding == OF_STRING_ENCODING_AUTODETECT) encoding = OF_STRING_ENCODING_UTF_8; data = [self readDataUntilEndOfStream]; - if ((contentLength = [_headers objectForKey: @"Content-Length"]) != nil) - if (data.count != (size_t)contentLength.decimalValue) + contentLengthString = [_headers objectForKey: @"Content-Length"]; + if (contentLengthString != nil) { + unsigned long long contentLength = + contentLengthString.unsignedLongLongValue; + + if (contentLength > SIZE_MAX) + @throw [OFOutOfRangeException exception]; + + if (data.count != (size_t)contentLength) @throw [OFTruncatedDataException exception]; + } ret = [[OFString alloc] initWithCString: (char *)data.items encoding: encoding length: data.count]; Index: src/OFHTTPServer.m ================================================================== --- src/OFHTTPServer.m +++ src/OFHTTPServer.m @@ -103,17 +103,17 @@ OF_DIRECT_MEMBERS @interface OFHTTPServerRequestBodyStream: OFStream { OFStreamSocket *_socket; bool _chunked; - intmax_t _toRead; + long long _toRead; bool _atEndOfStream, _setAtEndOfStream; } - (instancetype)initWithSocket: (OFStreamSocket *)sock chunked: (bool)chunked - contentLength: (uintmax_t)contentLength; + contentLength: (unsigned long long)contentLength; @end #ifdef OF_HAVE_THREADS OF_DIRECT_MEMBERS @interface OFHTTPServerThread: OFThread @@ -413,25 +413,22 @@ if (line.length == 0) { bool chunked = [[_headers objectForKey: @"Transfer-Encoding"] isEqual: @"chunked"]; OFString *contentLengthString = [_headers objectForKey: @"Content-Length"]; - intmax_t contentLength = 0; + unsigned long long contentLength = 0; if (contentLengthString != nil) { if (chunked || contentLengthString.length == 0) return [self sendErrorAndClose: 400]; @try { contentLength = - contentLengthString.decimalValue; + contentLengthString.unsignedLongLongValue; } @catch (OFInvalidFormatException *e) { return [self sendErrorAndClose: 400]; } - - if (contentLength < 0) - return [self sendErrorAndClose: 400]; } if (chunked || contentLengthString != nil) { [_requestBody release]; _requestBody = nil; @@ -480,12 +477,13 @@ of_range(0, pos)] retain]; @try { of_range_t range = of_range(pos + 1, value.length - pos - 1); - intmax_t portTmp = [value - substringWithRange: range].decimalValue; + unsigned long long portTmp = + [value substringWithRange: range] + .unsignedLongLongValue; if (portTmp < 1 || portTmp > UINT16_MAX) return [self sendErrorAndClose: 400]; _port = (uint16_t)portTmp; @@ -543,11 +541,11 @@ URL = [OFMutableURL URL]; URL.scheme = @"http"; URL.host = _host; if (_port != 80) - URL.port = [OFNumber numberWithUInt16: _port]; + URL.port = [OFNumber numberWithUnsignedShort: _port]; if ((pos = [_path rangeOfString: @"?"].location) != OF_NOT_FOUND) { OFString *path, *query; path = [_path substringWithRange: of_range(0, pos)]; @@ -583,18 +581,21 @@ @end @implementation OFHTTPServerRequestBodyStream - (instancetype)initWithSocket: (OFStreamSocket *)sock chunked: (bool)chunked - contentLength: (uintmax_t)contentLength + contentLength: (unsigned long long)contentLength { self = [super init]; @try { + if (contentLength > LLONG_MAX) + @throw [OFOutOfRangeException exception]; + _socket = [sock retain]; _chunked = chunked; - _toRead = contentLength; + _toRead = (long long)contentLength; if (_chunked && _toRead > 0) @throw [OFInvalidArgumentException exception]; } @catch (id e) { [self release]; @@ -631,11 +632,11 @@ /* Content-Length */ if (!_chunked) { size_t ret; - if (length > (uintmax_t)_toRead) + if (length > (unsigned long long)_toRead) length = (size_t)_toRead; ret = [_socket readIntoBuffer: buffer length: length]; @@ -680,11 +681,11 @@ if (_setAtEndOfStream && _toRead == 0) _atEndOfStream = true; return 0; } else if (_toRead > 0) { - if (length > (uintmax_t)_toRead) + if (length > (unsigned long long)_toRead) length = (size_t)_toRead; length = [_socket readIntoBuffer: buffer length: length]; @@ -696,10 +697,11 @@ return length; } else { void *pool = objc_autoreleasePoolPush(); OFString *line; of_range_t range; + unsigned long long toRead; @try { line = [_socket tryReadLine]; } @catch (OFInvalidEncodingException *e) { @throw [OFInvalidFormatException exception]; @@ -723,12 +725,14 @@ @throw [OFTruncatedDataException exception]; else @throw [OFInvalidFormatException exception]; } - if ((_toRead = line.hexadecimalValue) < 0) + toRead = [line unsignedLongLongValueWithBase: 16]; + if (toRead > LLONG_MAX) @throw [OFOutOfRangeException exception]; + _toRead = (long long)toRead; if (_toRead == 0) { _setAtEndOfStream = true; _toRead = -2; } Index: src/OFINICategory.h ================================================================== --- src/OFINICategory.h +++ src/OFINICategory.h @@ -79,12 +79,12 @@ * @param key The key for which the integer value should be returned * @param defaultValue The value to return if the key does not exist * @return The integer value for the specified key or the specified default * value if it does not exist */ -- (intmax_t)integerForKey: (OFString *)key - defaultValue: (intmax_t)defaultValue; +- (long long)integerForKey: (OFString *)key + defaultValue: (long long)defaultValue; /*! * @brief Returns the bool value for the specified key or the specified default * value if it does not exist. * @@ -161,11 +161,11 @@ * the first key/value pair found is changed. * * @param integer The integer to which the value of the key should be set * @param key The key for which the new value should be set */ -- (void)setInteger: (intmax_t)integer +- (void)setInteger: (long long)integer forKey: (OFString *)key; /*! * @brief Sets the value of the specified key to the specified bool. * Index: src/OFINICategory.m ================================================================== --- src/OFINICategory.m +++ src/OFINICategory.m @@ -207,24 +207,21 @@ } return defaultValue; } -- (intmax_t)integerForKey: (OFString *)key - defaultValue: (intmax_t)defaultValue +- (long long)integerForKey: (OFString *)key + defaultValue: (long long)defaultValue { void *pool = objc_autoreleasePoolPush(); OFString *value = [self stringForKey: key defaultValue: nil]; - intmax_t ret; - - if (value != nil) { - if ([value hasPrefix: @"0x"] || [value hasPrefix: @"$"]) - ret = value.hexadecimalValue; - else - ret = value.decimalValue; - } else + long long ret; + + if (value != nil) + ret = [value longLongValueWithBase: 0]; + else ret = defaultValue; objc_autoreleasePoolPop(pool); return ret; @@ -352,16 +349,16 @@ } objc_autoreleasePoolPop(pool); } -- (void)setInteger: (intmax_t)integer +- (void)setInteger: (long long)integer forKey: (OFString *)key { void *pool = objc_autoreleasePoolPush(); - [self setString: [OFString stringWithFormat: @"%jd", integer] + [self setString: [OFString stringWithFormat: @"%lld", integer] forKey: key]; objc_autoreleasePoolPop(pool); } Index: src/OFINIFileSettings.m ================================================================== --- src/OFINIFileSettings.m +++ src/OFINIFileSettings.m @@ -86,11 +86,11 @@ forKey: key]; objc_autoreleasePoolPop(pool); } -- (void)setInteger: (intmax_t)integer +- (void)setInteger: (long long)integer forPath: (OFString *)path { void *pool = objc_autoreleasePoolPush(); OFString *category, *key; @@ -184,16 +184,16 @@ [ret retain]; objc_autoreleasePoolPop(pool); return [ret autorelease]; } -- (intmax_t)integerForPath: (OFString *)path - defaultValue: (intmax_t)defaultValue +- (long long)integerForPath: (OFString *)path + defaultValue: (long long)defaultValue { void *pool = objc_autoreleasePoolPush(); OFString *category, *key; - intmax_t ret; + long long ret; [self of_getCategory: &category andKey: &key forPath: path]; Index: src/OFLHAArchiveEntry.m ================================================================== --- src/OFLHAArchiveEntry.m +++ src/OFLHAArchiveEntry.m @@ -125,11 +125,11 @@ mode = OF_BSWAP16_IF_BE(mode); [entry->_mode release]; entry->_mode = nil; - entry->_mode = [[OFNumber alloc] initWithUInt16: mode]; + entry->_mode = [[OFNumber alloc] initWithUnsignedShort: mode]; } static void parseGIDUIDExtension(OFLHAArchiveEntry *entry, OFData *extension, of_string_encoding_t encoding) @@ -149,12 +149,12 @@ entry->_GID = nil; [entry->_UID release]; entry->_UID = nil; - entry->_GID = [[OFNumber alloc] initWithUInt16: GID]; - entry->_UID = [[OFNumber alloc] initWithUInt16: UID]; + entry->_GID = [[OFNumber alloc] initWithUnsignedShort: GID]; + entry->_UID = [[OFNumber alloc] initWithUnsignedShort: UID]; } static void parseGroupExtension(OFLHAArchiveEntry *entry, OFData *extension, of_string_encoding_t encoding) @@ -653,11 +653,11 @@ tmp16 = OF_BSWAP16_IF_BE(5); [data addItems: &tmp16 count: sizeof(tmp16)]; [data addItem: "\x50"]; - tmp16 = OF_BSWAP16_IF_BE(_mode.uInt16Value); + tmp16 = OF_BSWAP16_IF_BE(_mode.unsignedShortValue); [data addItems: &tmp16 count: sizeof(tmp16)]; } if (_UID != nil || _GID != nil) { @@ -667,15 +667,15 @@ tmp16 = OF_BSWAP16_IF_BE(7); [data addItems: &tmp16 count: sizeof(tmp16)]; [data addItem: "\x51"]; - tmp16 = OF_BSWAP16_IF_BE(_GID.uInt16Value); + tmp16 = OF_BSWAP16_IF_BE(_GID.unsignedShortValue); [data addItems: &tmp16 count: sizeof(tmp16)]; - tmp16 = OF_BSWAP16_IF_BE(_UID.uInt16Value); + tmp16 = OF_BSWAP16_IF_BE(_UID.unsignedShortValue); [data addItems: &tmp16 count: sizeof(tmp16)]; } if (_group != nil) { @@ -759,11 +759,11 @@ - (OFString *)description { void *pool = objc_autoreleasePoolPush(); OFString *mode = (_mode == nil ? nil - : [OFString stringWithFormat: @"%" PRIo16, _mode.uInt16Value]); + : [OFString stringWithFormat: @"%ho", _mode.unsignedShortValue]); OFString *extensions = [_extensions.description stringByReplacingOccurrencesOfString: @"\n" withString: @"\n\t"]; OFString *ret = [OFString stringWithFormat: @"<%@:\n" Index: src/OFLocale.m ================================================================== --- src/OFLocale.m +++ src/OFLocale.m @@ -213,12 +213,13 @@ compare: second] != OF_ORDERED_ASCENDING]; else if ([token isEqual: @"+"]) var = [OFNumber numberWithDouble: [first doubleValue] + [second doubleValue]]; else if ([token isEqual: @"%"]) - var = [OFNumber numberWithIntMax: - [first intMaxValue] % [second intMaxValue]]; + var = [OFNumber numberWithLongLong: + [first longLongValue] % + [second longLongValue]]; else if ([token isEqual: @"&&"]) var = [OFNumber numberWithBool: [first boolValue] && [second boolValue]]; else if ([token isEqual: @"||"]) var = [OFNumber numberWithBool: @@ -236,11 +237,12 @@ if ([token isEqual: @"!"]) var = [OFNumber numberWithBool: ![first boolValue]]; else if ([token isEqual: @"is_real"]) var = [OFNumber numberWithBool: - [first doubleValue] != [first intMaxValue]]; + ([first doubleValue] != + [first longLongValue])]; else OF_ENSURE(0); [stack replaceObjectAtIndex: stackSize - 1 withObject: var]; @@ -508,11 +510,12 @@ pool = objc_autoreleasePoolPush(); mapPath = [path stringByAppendingPathComponent: @"languages.json"]; @try { - map = [[OFString stringWithContentsOfFile: mapPath] JSONValue]; + map = [[OFString stringWithContentsOfFile: mapPath] + objectByParsingJSON]; } @catch (OFOpenItemFailedException *e) { objc_autoreleasePoolPop(pool); return; } @@ -532,12 +535,12 @@ } languageFile = [path stringByAppendingPathComponent: [languageFile stringByAppendingString: @".json"]]; - [_localizedStrings addObject: - [[OFString stringWithContentsOfFile: languageFile] JSONValue]]; + [_localizedStrings addObject: [[OFString stringWithContentsOfFile: + languageFile] objectByParsingJSON]]; objc_autoreleasePoolPop(pool); } #endif Index: src/OFMutableTarArchiveEntry.h ================================================================== --- src/OFMutableTarArchiveEntry.h +++ src/OFMutableTarArchiveEntry.h @@ -36,26 +36,26 @@ @property (readwrite, copy, nonatomic) OFString *fileName; /*! * @brief The mode of the entry. */ -@property (readwrite, nonatomic) uint32_t mode; +@property (readwrite, nonatomic) unsigned long mode; /*! * @brief The UID of the owner. */ -@property (readwrite, nonatomic) uint32_t UID; +@property (readwrite, nonatomic) unsigned long UID; /*! * @brief The GID of the group. */ -@property (readwrite, nonatomic) uint32_t GID; +@property (readwrite, nonatomic) unsigned long GID; /*! * @brief The size of the file. */ -@property (readwrite, nonatomic) uint64_t size; +@property (readwrite, nonatomic) unsigned long long size; /*! * @brief The date of the last modification of the file. */ @property (readwrite, retain, nonatomic) OFDate *modificationDate; @@ -84,20 +84,20 @@ @property OF_NULLABLE_PROPERTY (readwrite, copy, nonatomic) OFString *group; /*! * @brief The device major (if the file is a device). */ -@property (readwrite, nonatomic) uint32_t deviceMajor; +@property (readwrite, nonatomic) unsigned long deviceMajor; /*! * @brief The device major (if the file is a device). */ -@property (readwrite, nonatomic) uint32_t deviceMinor; +@property (readwrite, nonatomic) unsigned long deviceMinor; /*! * @brief Converts the OFMutableTarArchiveEntry to an immutable * OFTarArchiveEntry. */ - (void)makeImmutable; @end OF_ASSUME_NONNULL_END Index: src/OFMutableTarArchiveEntry.m ================================================================== --- src/OFMutableTarArchiveEntry.m +++ src/OFMutableTarArchiveEntry.m @@ -39,26 +39,26 @@ OFString *old = _fileName; _fileName = [fileName copy]; [old release]; } -- (void)setMode: (uint32_t)mode +- (void)setMode: (unsigned long)mode { _mode = mode; } -- (void)setUID: (uint32_t)UID +- (void)setUID: (unsigned long)UID { _UID = UID; } -- (void)setGID: (uint32_t)GID +- (void)setGID: (unsigned long)GID { _GID = GID; } -- (void)setSize: (uint64_t)size +- (void)setSize: (unsigned long long)size { _size = size; } - (void)setModificationDate: (OFDate *)modificationDate @@ -92,20 +92,20 @@ OFString *old = _group; _group = [group copy]; [old release]; } -- (void)setDeviceMajor: (uint32_t)deviceMajor +- (void)setDeviceMajor: (unsigned long)deviceMajor { _deviceMajor = deviceMajor; } -- (void)setDeviceMinor: (uint32_t)deviceMinor +- (void)setDeviceMinor: (unsigned long)deviceMinor { _deviceMinor = deviceMinor; } - (void)makeImmutable { object_setClass(self, [OFTarArchiveEntry class]); } @end Index: src/OFNumber.h ================================================================== --- src/OFNumber.h +++ src/OFNumber.h @@ -47,13 +47,13 @@ #endif @interface OFNumber: OFValue { union of_number_value { - double float_; - intmax_t signed_; - uintmax_t unsigned_; + double float_; + long long signed_; + unsigned long long unsigned_; } _value; enum of_number_type { OF_NUMBER_TYPE_FLOAT = 1, OF_NUMBER_TYPE_SIGNED, OF_NUMBER_TYPE_UNSIGNED @@ -114,85 +114,10 @@ /*! * @brief The OFNumber as an `unsigned long long`. */ @property (readonly, nonatomic) unsigned long long unsignedLongLongValue; -/*! - * @brief The OFNumber as an `int8_t`. - */ -@property (readonly, nonatomic) int8_t int8Value; - -/*! - * @brief The OFNumber as an `int16_t`. - */ -@property (readonly, nonatomic) int16_t int16Value; - -/*! - * @brief The OFNumber as an `int32_t`. - */ -@property (readonly, nonatomic) int32_t int32Value; - -/*! - * @brief The OFNumber as an `int64_t`. - */ -@property (readonly, nonatomic) int64_t int64Value; - -/*! - * @brief The OFNumber as a `uint8_t`. - */ -@property (readonly, nonatomic) uint8_t uInt8Value; - -/*! - * @brief The OFNumber as a `uint16_t`. - */ -@property (readonly, nonatomic) uint16_t uInt16Value; - -/*! - * @brief The OFNumber as a `uint32_t`. - */ -@property (readonly, nonatomic) uint32_t uInt32Value; - -/*! - * @brief The OFNumber as a `uint64_t`. - */ -@property (readonly, nonatomic) uint64_t uInt64Value; - -/*! - * @brief The OFNumber as a `size_t`. - */ -@property (readonly, nonatomic) size_t sizeValue; - -/*! - * @brief The OFNumber as an `ssize_t`. - */ -@property (readonly, nonatomic) ssize_t sSizeValue; - -/*! - * @brief The OFNumber as an `intmax_t`. - */ -@property (readonly, nonatomic) intmax_t intMaxValue; - -/*! - * @brief The OFNumber as a `uintmax_t`. - */ -@property (readonly, nonatomic) uintmax_t uIntMaxValue; - -/*! - * @brief The OFNumber as a `ptrdiff_t`. - */ -@property (readonly, nonatomic) ptrdiff_t ptrDiffValue; - -/*! - * @brief The OFNumber as an `intptr_t`. - */ -@property (readonly, nonatomic) intptr_t intPtrValue; - -/*! - * @brief The OFNumber as a `uintptr_t`. - */ -@property (readonly, nonatomic) uintptr_t uIntPtrValue; - /*! * @brief The OFNumber as a `float`. */ @property (readonly, nonatomic) float floatValue; @@ -218,230 +143,110 @@ #endif /*! * @brief Creates a new OFNumber with the specified `bool`. * - * @param bool_ A `bool` which the OFNumber should contain + * @param value The `bool` value which the OFNumber should contain * @return A new autoreleased OFNumber */ -+ (instancetype)numberWithBool: (bool)bool_; ++ (instancetype)numberWithBool: (bool)value; /*! * @brief Creates a new OFNumber with the specified `signed char`. * - * @param sChar A `signed char` which the OFNumber should contain + * @param value The `signed char` value which the OFNumber should contain * @return A new autoreleased OFNumber */ -+ (instancetype)numberWithChar: (signed char)sChar; ++ (instancetype)numberWithChar: (signed char)value; /*! * @brief Creates a new OFNumber with the specified `short`. * - * @param sShort A `short` which the OFNumber should contain + * @param value The `short` value which the OFNumber should contain * @return A new autoreleased OFNumber */ -+ (instancetype)numberWithShort: (short)sShort; ++ (instancetype)numberWithShort: (short)value; /*! * @brief Creates a new OFNumber with the specified `int`. * - * @param sInt An `int` which the OFNumber should contain + * @param value The `int` value which the OFNumber should contain * @return A new autoreleased OFNumber */ -+ (instancetype)numberWithInt: (int)sInt; ++ (instancetype)numberWithInt: (int)value; /*! * @brief Creates a new OFNumber with the specified `long`. * - * @param sLong A `long` which the OFNumber should contain + * @param value The `long` value which the OFNumber should contain * @return A new autoreleased OFNumber */ -+ (instancetype)numberWithLong: (long)sLong; ++ (instancetype)numberWithLong: (long)value; /*! * @brief Creates a new OFNumber with the specified `long long`. * - * @param sLongLong A `long long` which the OFNumber should contain + * @param value The `long long` value which the OFNumber should contain * @return A new autoreleased OFNumber */ -+ (instancetype)numberWithLongLong: (long long)sLongLong; ++ (instancetype)numberWithLongLong: (long long)value; /*! * @brief Creates a new OFNumber with the specified `unsigned char`. * - * @param uChar An `unsigned char` which the OFNumber should contain + * @param value The `unsigned char` value which the OFNumber should contain * @return A new autoreleased OFNumber */ -+ (instancetype)numberWithUnsignedChar: (unsigned char)uChar; ++ (instancetype)numberWithUnsignedChar: (unsigned char)value; /*! * @brief Creates a new OFNumber with the specified `unsigned short`. * - * @param uShort An `unsigned short` which the OFNumber should contain + * @param value The `unsigned short` value which the OFNumber should contain * @return A new autoreleased OFNumber */ -+ (instancetype)numberWithUnsignedShort: (unsigned short)uShort; ++ (instancetype)numberWithUnsignedShort: (unsigned short)value; /*! * @brief Creates a new OFNumber with the specified `unsigned int`. * - * @param uInt An `unsigned int` which the OFNumber should contain + * @param value The `unsigned int` value which the OFNumber should contain * @return A new autoreleased OFNumber */ -+ (instancetype)numberWithUnsignedInt: (unsigned int)uInt; ++ (instancetype)numberWithUnsignedInt: (unsigned int)value; /*! * @brief Creates a new OFNumber with the specified `unsigned long`. * - * @param uLong An `unsigned long` which the OFNumber should contain + * @param value The `unsigned long` value which the OFNumber should contain * @return A new autoreleased OFNumber */ -+ (instancetype)numberWithUnsignedLong: (unsigned long)uLong; ++ (instancetype)numberWithUnsignedLong: (unsigned long)value; /*! * @brief Creates a new OFNumber with the specified `unsigned long long`. * - * @param uLongLong An `unsigned long long` which the OFNumber should contain - * @return A new autoreleased OFNumber - */ -+ (instancetype)numberWithUnsignedLongLong: (unsigned long long)uLongLong; - -/*! - * @brief Creates a new OFNumber with the specified `int8_t`. - * - * @param int8 An `int8_t` which the OFNumber should contain - * @return A new autoreleased OFNumber - */ -+ (instancetype)numberWithInt8: (int8_t)int8; - -/*! - * @brief Creates a new OFNumber with the specified `int16_t`. - * - * @param int16 An `int16_t` which the OFNumber should contain - * @return A new autoreleased OFNumber - */ -+ (instancetype)numberWithInt16: (int16_t)int16; - -/*! - * @brief Creates a new OFNumber with the specified `int32_t`. - * - * @param int32 An `int32_t` which the OFNumber should contain - * @return A new autoreleased OFNumber - */ -+ (instancetype)numberWithInt32: (int32_t)int32; - -/*! - * @brief Creates a new OFNumber with the specified `int64_t`. - * - * @param int64 An `int64_t` which the OFNumber should contain - * @return A new autoreleased OFNumber - */ -+ (instancetype)numberWithInt64: (int64_t)int64; - -/*! - * @brief Creates a new OFNumber with the specified `uint8_t`. - * - * @param uInt8 A `uint8_t` which the OFNumber should contain - * @return A new autoreleased OFNumber - */ -+ (instancetype)numberWithUInt8: (uint8_t)uInt8; - -/*! - * @brief Creates a new OFNumber with the specified `uint16_t`. - * - * @param uInt16 A `uint16_t` which the OFNumber should contain - * @return A new autoreleased OFNumber - */ -+ (instancetype)numberWithUInt16: (uint16_t)uInt16; - -/*! - * @brief Creates a new OFNumber with the specified `uint32_t`. - * - * @param uInt32 A `uint32_t` which the OFNumber should contain - * @return A new autoreleased OFNumber - */ -+ (instancetype)numberWithUInt32: (uint32_t)uInt32; - -/*! - * @brief Creates a new OFNumber with the specified `uint64_t`. - * - * @param uInt64 A `uint64_t` which the OFNumber should contain - * @return A new autoreleased OFNumber - */ -+ (instancetype)numberWithUInt64: (uint64_t)uInt64; - -/*! - * @brief Creates a new OFNumber with the specified `size_t`. - * - * @param size A `size_t` which the OFNumber should contain - * @return A new autoreleased OFNumber - */ -+ (instancetype)numberWithSize: (size_t)size; - -/*! - * @brief Creates a new OFNumber with the specified `ssize_t`. - * - * @param sSize An `ssize_t` which the OFNumber should contain - * @return A new autoreleased OFNumber - */ -+ (instancetype)numberWithSSize: (ssize_t)sSize; - -/*! - * @brief Creates a new OFNumber with the specified `intmax_t`. - * - * @param intMax An `intmax_t` which the OFNumber should contain - * @return A new autoreleased OFNumber - */ -+ (instancetype)numberWithIntMax: (intmax_t)intMax; - -/*! - * @brief Creates a new OFNumber with the specified `uintmax_t`. - * - * @param uIntMax A `uintmax_t` which the OFNumber should contain - * @return A new autoreleased OFNumber - */ -+ (instancetype)numberWithUIntMax: (uintmax_t)uIntMax; - -/*! - * @brief Creates a new OFNumber with the specified `ptrdiff_t`. - * - * @param ptrDiff A `ptrdiff_t` which the OFNumber should contain - * @return A new autoreleased OFNumber - */ -+ (instancetype)numberWithPtrDiff: (ptrdiff_t)ptrDiff; - -/*! - * @brief Creates a new OFNumber with the specified `intptr_t`. - * - * @param intPtr An `intptr_t` which the OFNumber should contain - * @return A new autoreleased OFNumber - */ -+ (instancetype)numberWithIntPtr: (intptr_t)intPtr; - -/*! - * @brief Creates a new OFNumber with the specified `uintptr_t`. - * - * @param uIntPtr A `uintptr_t` which the OFNumber should contain - * @return A new autoreleased OFNumber - */ -+ (instancetype)numberWithUIntPtr: (uintptr_t)uIntPtr; + * @param value The `unsigned long long` value which the OFNumber should contain + * @return A new autoreleased OFNumber + */ ++ (instancetype)numberWithUnsignedLongLong: (unsigned long long)value; /*! * @brief Creates a new OFNumber with the specified `float`. * - * @param float_ A `float` which the OFNumber should contain + * @param value The `float` value which the OFNumber should contain * @return A new autoreleased OFNumber */ -+ (instancetype)numberWithFloat: (float)float_; ++ (instancetype)numberWithFloat: (float)value; /*! * @brief Creates a new OFNumber with the specified `double`. * - * @param double_ A `double` which the OFNumber should contain + * @param value The `double` value which the OFNumber should contain * @return A new autoreleased OFNumber */ -+ (instancetype)numberWithDouble: (double)double_; ++ (instancetype)numberWithDouble: (double)value; - (instancetype)init OF_UNAVAILABLE; #ifdef OF_HAVE_UNAVAILABLE - (instancetype)initWithBytes: (const void *)bytes objCType: (const char *)objCType OF_UNAVAILABLE; @@ -454,253 +259,120 @@ #endif /*! * @brief Initializes an already allocated OFNumber with the specified `bool`. * - * @param bool_ A `bool` which the OFNumber should contain + * @param value The `bool` value which the OFNumber should contain * @return An initialized OFNumber */ -- (instancetype)initWithBool: (bool)bool_; +- (instancetype)initWithBool: (bool)value; /*! * @brief Initializes an already allocated OFNumber with the specified * `signed char`. * - * @param sChar A `signed char` which the OFNumber should contain + * @param value The `signed char` value which the OFNumber should contain * @return An initialized OFNumber */ -- (instancetype)initWithChar: (signed char)sChar; +- (instancetype)initWithChar: (signed char)value; /*! * @brief Initializes an already allocated OFNumber with the specified `short`. * - * @param sShort A `short` which the OFNumber should contain + * @param value The `short` value which the OFNumber should contain * @return An initialized OFNumber */ -- (instancetype)initWithShort: (short)sShort; +- (instancetype)initWithShort: (short)value; /*! * @brief Initializes an already allocated OFNumber with the specified `int`. * - * @param sInt An `int` which the OFNumber should contain + * @param value The `int` value which the OFNumber should contain * @return An initialized OFNumber */ -- (instancetype)initWithInt: (int)sInt; +- (instancetype)initWithInt: (int)value; /*! * @brief Initializes an already allocated OFNumber with the specified `long`. * - * @param sLong A `long` which the OFNumber should contain + * @param value The `long` value which the OFNumber should contain * @return An initialized OFNumber */ -- (instancetype)initWithLong: (long)sLong; +- (instancetype)initWithLong: (long)value; /*! * @brief Initializes an already allocated OFNumber with the specified * `long long`. * - * @param sLongLong A `long long` which the OFNumber should contain + * @param value The `long long` value which the OFNumber should contain * @return An initialized OFNumber */ -- (instancetype)initWithLongLong: (long long)sLongLong; +- (instancetype)initWithLongLong: (long long)value; /*! * @brief Initializes an already allocated OFNumber with the specified * `unsigned char`. * - * @param uChar An `unsigned char` which the OFNumber should contain + * @param value The `unsigned char` value which the OFNumber should contain * @return An initialized OFNumber */ -- (instancetype)initWithUnsignedChar: (unsigned char)uChar; +- (instancetype)initWithUnsignedChar: (unsigned char)value; /*! * @brief Initializes an already allocated OFNumber with the specified * `unsigned short`. * - * @param uShort An `unsigned short` which the OFNumber should contain + * @param value The `unsigned short` value which the OFNumber should contain * @return An initialized OFNumber */ -- (instancetype)initWithUnsignedShort: (unsigned short)uShort; +- (instancetype)initWithUnsignedShort: (unsigned short)value; /*! * @brief Initializes an already allocated OFNumber with the specified * `unsigned int`. * - * @param uInt An `unsigned int` which the OFNumber should contain + * @param value The `unsigned int` value which the OFNumber should contain * @return An initialized OFNumber */ -- (instancetype)initWithUnsignedInt: (unsigned int)uInt; +- (instancetype)initWithUnsignedInt: (unsigned int)value; /*! * @brief Initializes an already allocated OFNumber with the specified * `unsigned long`. * - * @param uLong An `unsigned long` which the OFNumber should contain + * @param value The `unsigned long` value which the OFNumber should contain * @return An initialized OFNumber */ -- (instancetype)initWithUnsignedLong: (unsigned long)uLong; +- (instancetype)initWithUnsignedLong: (unsigned long)value; /*! * @brief Initializes an already allocated OFNumber with the specified * `unsigned long long`. * - * @param uLongLong An `unsigned long long` which the OFNumber should contain - * @return An initialized OFNumber - */ -- (instancetype)initWithUnsignedLongLong: (unsigned long long)uLongLong; - -/*! - * @brief Initializes an already allocated OFNumber with the specified `int8_t`. - * - * @param int8 An `int8_t` which the OFNumber should contain - * @return An initialized OFNumber - */ -- (instancetype)initWithInt8: (int8_t)int8; - -/*! - * @brief Initializes an already allocated OFNumber with the specified - * `int16_t`. - * - * @param int16 An `int16_t` which the OFNumber should contain - * @return An initialized OFNumber - */ -- (instancetype)initWithInt16: (int16_t)int16; - -/*! - * @brief Initializes an already allocated OFNumber with the specified - * `int32_t`. - * - * @param int32 An `int32_t` which the OFNumber should contain - * @return An initialized OFNumber - */ -- (instancetype)initWithInt32: (int32_t)int32; - -/*! - * @brief Initializes an already allocated OFNumber with the specified - * `int64_t`. - * - * @param int64 An `int64_t` which the OFNumber should contain - * @return An initialized OFNumber - */ -- (instancetype)initWithInt64: (int64_t)int64; - -/*! - * @brief Initializes an already allocated OFNumber with the specified - * `uint8_t`. - * - * @param uInt8 A `uint8_t` which the OFNumber should contain - * @return An initialized OFNumber - */ -- (instancetype)initWithUInt8: (uint8_t)uInt8; - -/*! - * @brief Initializes an already allocated OFNumber with the specified - * `uint16_t`. - * - * @param uInt16 A `uint16_t` which the OFNumber should contain - * @return An initialized OFNumber - */ -- (instancetype)initWithUInt16: (uint16_t)uInt16; - -/*! - * @brief Initializes an already allocated OFNumber with the specified - * `uint32_t`. - * - * @param uInt32 A `uint32_t` which the OFNumber should contain - * @return An initialized OFNumber - */ -- (instancetype)initWithUInt32: (uint32_t)uInt32; - -/*! - * @brief Initializes an already allocated OFNumber with the specified - * `uint64_t`. - * - * @param uInt64 A `uint64_t` which the OFNumber should contain - * @return An initialized OFNumber - */ -- (instancetype)initWithUInt64: (uint64_t)uInt64; - -/*! - * @brief Initializes an already allocated OFNumber with the specified `size_t`. - * - * @param size A `size_t` which the OFNumber should contain - * @return An initialized OFNumber - */ -- (instancetype)initWithSize: (size_t)size; - -/*! - * @brief Initializes an already allocated OFNumber with the specified - * `ssize_t`. - * - * @param sSize An `ssize_t` which the OFNumber should contain - * @return An initialized OFNumber - */ -- (instancetype)initWithSSize: (ssize_t)sSize; - -/*! - * @brief Initializes an already allocated OFNumber with the specified - * `intmax_t`. - * - * @param intMax An `intmax_t` which the OFNumber should contain - * @return An initialized OFNumber - */ -- (instancetype)initWithIntMax: (intmax_t)intMax; - -/*! - * @brief Initializes an already allocated OFNumber with the specified - * `uintmax_t`. - * - * @param uIntMax A `uintmax_t` which the OFNumber should contain - * @return An initialized OFNumber - */ -- (instancetype)initWithUIntMax: (uintmax_t)uIntMax; - -/*! - * @brief Initializes an already allocated OFNumber with the specified - * `ptrdiff_t`. - * - * @param ptrDiff A `ptrdiff_t` which the OFNumber should contain - * @return An initialized OFNumber - */ -- (instancetype)initWithPtrDiff: (ptrdiff_t)ptrDiff; - -/*! - * @brief Initializes an already allocated OFNumber with the specified - * `intptr_t`. - * - * @param intPtr An `intptr_t` which the OFNumber should contain - * @return An initialized OFNumber - */ -- (instancetype)initWithIntPtr: (intptr_t)intPtr; - -/*! - * @brief Initializes an already allocated OFNumber with the specified - * `uintptr_t`. - * - * @param uIntPtr A `uintptr_t` which the OFNumber should contain - * @return An initialized OFNumber - */ -- (instancetype)initWithUIntPtr: (uintptr_t)uIntPtr; + * @param value The `unsigned long long` value which the OFNumber should contain + * @return An initialized OFNumber + */ +- (instancetype)initWithUnsignedLongLong: (unsigned long long)value; /*! * @brief Initializes an already allocated OFNumber with the specified `float`. * - * @param float_ A `float` which the OFNumber should contain + * @param value The `float` value which the OFNumber should contain * @return An initialized OFNumber */ -- (instancetype)initWithFloat: (float)float_; +- (instancetype)initWithFloat: (float)value; /*! * @brief Initializes an already allocated OFNumber with the specified `double`. * - * @param double_ A `double` which the OFNumber should contain + * @param value The `double` value which the OFNumber should contain * @return An initialized OFNumber */ -- (instancetype)initWithDouble: (double)double_; +- (instancetype)initWithDouble: (double)value; @end OF_ASSUME_NONNULL_END #if !defined(NSINTEGER_DEFINED) && !__has_feature(modules) /* Required for number literals to work */ @compatibility_alias NSNumber OFNumber; #endif Index: src/OFNumber.m ================================================================== --- src/OFNumber.m +++ src/OFNumber.m @@ -45,324 +45,178 @@ static struct { Class isa; } placeholder; -static OFNumberSingleton *zeroNumber, *oneNumber, *twoNumber; -static OFNumberSingleton *trueNumber, *falseNumber; - -static void -initZeroNumber(void) -{ - zeroNumber = [[OFNumberSingleton alloc] initWithUnsignedChar: 0]; -} - -static void -initOneNumber(void) -{ - oneNumber = [[OFNumberSingleton alloc] initWithUnsignedChar: 1]; -} - -static void -initTwoNumber(void) -{ - twoNumber = [[OFNumberSingleton alloc] initWithUnsignedChar: 2]; -} - -static void -initTrueNumber(void) -{ - trueNumber = [[OFNumberSingleton alloc] initWithBool: true]; -} - -static void -initFalseNumber(void) -{ - falseNumber = [[OFNumberSingleton alloc] initWithBool: false]; -} +#define SINGLETON(var, sel, val) \ + static OFNumberSingleton *var; \ + \ + static void \ + var##Init(void) \ + { \ + var = [[OFNumberSingleton alloc] sel val]; \ + } +SINGLETON(falseNumber, initWithBool:, false) +SINGLETON(trueNumber, initWithBool:, true) +SINGLETON(charZeroNumber, initWithChar:, 0) +SINGLETON(shortZeroNumber, initWithShort:, 0) +SINGLETON(intZeroNumber, initWithInt:, 0) +SINGLETON(longZeroNumber, initWithLong:, 0) +SINGLETON(longLongZeroNumber, initWithLongLong:, 0) +SINGLETON(unsignedCharZeroNumber, initWithUnsignedChar:, 0) +SINGLETON(unsignedShortZeroNumber, initWithUnsignedShort:, 0) +SINGLETON(unsignedIntZeroNumber, initWithUnsignedInt:, 0) +SINGLETON(unsignedLongZeroNumber, initWithUnsignedLong:, 0) +SINGLETON(unsignedLongLongZeroNumber, initWithUnsignedLongLong:, 0) +SINGLETON(floatZeroNumber, initWithFloat:, 0) +SINGLETON(doubleZeroNumber, initWithDouble:, 0) +#undef SINGLETON @implementation OFNumberPlaceholder -- (instancetype)initWithBool: (bool)bool_ +- (instancetype)initWithBool: (bool)value { - if (bool_) { - static of_once_t once; - of_once(&once, initTrueNumber); + if (value) { + static of_once_t once = OF_ONCE_INIT; + of_once(&once, trueNumberInit); return (id)trueNumber; } else { - static of_once_t once; - of_once(&once, initFalseNumber); + static of_once_t once = OF_ONCE_INIT; + of_once(&once, falseNumberInit); return (id)falseNumber; } } -- (instancetype)initWithChar: (signed char)sChar -{ - if (sChar >= 0) - return [self initWithUnsignedChar: sChar]; - - return (id)[[OFNumber of_alloc] initWithChar: sChar]; -} - -- (instancetype)initWithShort: (short)sShort -{ - if (sShort >= 0) - return [self initWithUnsignedShort: sShort]; - if (sShort >= SCHAR_MIN) - return [self initWithChar: (signed char)sShort]; - - return (id)[[OFNumber of_alloc] initWithShort: sShort]; -} - -- (instancetype)initWithInt: (int)sInt -{ - if (sInt >= 0) - return [self initWithUnsignedInt: sInt]; - if (sInt >= SHRT_MIN) - return [self initWithShort: (short)sInt]; - - return (id)[[OFNumber of_alloc] initWithInt: sInt]; -} - -- (instancetype)initWithLong: (long)sLong -{ - if (sLong >= 0) - return [self initWithUnsignedLong: sLong]; - if (sLong >= INT_MIN) - return [self initWithShort: (int)sLong]; - - return (id)[[OFNumber of_alloc] initWithLong: sLong]; -} - -- (instancetype)initWithLongLong: (long long)sLongLong -{ - if (sLongLong >= 0) - return [self initWithUnsignedLongLong: sLongLong]; - if (sLongLong >= LONG_MIN) - return [self initWithLong: (long)sLongLong]; - - return (id)[[OFNumber of_alloc] initWithLongLong: sLongLong]; -} - -- (instancetype)initWithUnsignedChar: (unsigned char)uChar -{ - switch (uChar) { - case 0: { - static of_once_t once = OF_ONCE_INIT; - of_once(&once, initZeroNumber); - return (id)zeroNumber; - } - case 1: { - static of_once_t once = OF_ONCE_INIT; - of_once(&once, initOneNumber); - return (id)oneNumber; - } - case 2: { - static of_once_t once = OF_ONCE_INIT; - of_once(&once, initTwoNumber); - return (id)twoNumber; - } - } - - return (id)[[OFNumber of_alloc] initWithUnsignedChar: uChar]; -} - -- (instancetype)initWithUnsignedShort: (unsigned short)uShort -{ - if (uShort <= UCHAR_MAX) - return [self initWithUnsignedChar: (unsigned char)uShort]; - - return (id)[[OFNumber of_alloc] initWithUnsignedShort: uShort]; -} - -- (instancetype)initWithUnsignedInt: (unsigned int)uInt -{ - if (uInt <= USHRT_MAX) - return [self initWithUnsignedShort: (unsigned short)uInt]; - - return (id)[[OFNumber of_alloc] initWithUnsignedInt: uInt]; -} - -- (instancetype)initWithUnsignedLong: (unsigned long)uLong -{ - if (uLong <= UINT_MAX) - return [self initWithUnsignedInt: (unsigned int)uLong]; - - return (id)[[OFNumber of_alloc] initWithUnsignedLong: uLong]; -} - -- (instancetype)initWithUnsignedLongLong: (unsigned long long)uLongLong -{ - if (uLongLong <= ULONG_MAX) - return [self initWithUnsignedLong: (unsigned long)uLongLong]; - - return (id)[[OFNumber of_alloc] initWithUnsignedLongLong: uLongLong]; -} - -- (instancetype)initWithInt8: (int8_t)int8 -{ - if (int8 >= 0) - return [self initWithUInt8: int8]; - - return (id)[[OFNumber of_alloc] initWithInt8: int8]; -} - -- (instancetype)initWithInt16: (int16_t)int16 -{ - if (int16 >= 0) - return [self initWithUInt16: int16]; - if (int16 >= INT8_MIN) - return [self initWithInt8: (int8_t)int16]; - - return (id)[[OFNumber of_alloc] initWithInt16: int16]; -} - -- (instancetype)initWithInt32: (int32_t)int32 -{ - if (int32 >= 0) - return [self initWithUInt32: int32]; - if (int32 >= INT16_MIN) - return [self initWithInt16: (int16_t)int32]; - - return (id)[[OFNumber of_alloc] initWithInt32: int32]; -} - -- (instancetype)initWithInt64: (int64_t)int64 -{ - if (int64 >= 0) - return [self initWithUInt64: int64]; - if (int64 >= INT32_MIN) - return [self initWithInt32: (int32_t)int64]; - - return (id)[[OFNumber of_alloc] initWithInt64: int64]; -} - -- (instancetype)initWithUInt8: (uint8_t)uInt8 -{ - return (id)[[OFNumber of_alloc] initWithUInt8: uInt8]; -} - -- (instancetype)initWithUInt16: (uint16_t)uInt16 -{ - if (uInt16 <= UINT8_MAX) - return [self initWithUInt8: (uint8_t)uInt16]; - - return (id)[[OFNumber of_alloc] initWithUInt16: uInt16]; -} - -- (instancetype)initWithUInt32: (uint32_t)uInt32 -{ - if (uInt32 <= UINT16_MAX) - return [self initWithUInt16: (uint16_t)uInt32]; - - return (id)[[OFNumber of_alloc] initWithUInt32: uInt32]; -} - -- (instancetype)initWithUInt64: (uint64_t)uInt64 -{ - if (uInt64 <= UINT32_MAX) - return [self initWithUInt32: (uint32_t)uInt64]; - - return (id)[[OFNumber of_alloc] initWithUInt64: uInt64]; -} - -- (instancetype)initWithSize: (size_t)size -{ - if (size <= ULONG_MAX) - return [self initWithUnsignedLong: (unsigned long)size]; - - return (id)[[OFNumber of_alloc] initWithSize: size]; -} - -- (instancetype)initWithSSize: (ssize_t)sSize -{ - if (sSize >= 0) - return [self initWithSize: sSize]; - if (sSize <= LONG_MIN) - return [self initWithLong: (long)sSize]; - - return (id)[[OFNumber of_alloc] initWithSSize: sSize]; -} - -- (instancetype)initWithIntMax: (intmax_t)intMax -{ - if (intMax >= 0) - return [self initWithUIntMax: intMax]; - if (intMax <= LLONG_MIN) - return [self initWithLongLong: (long long)intMax]; - - return (id)[[OFNumber of_alloc] initWithIntMax: intMax]; -} - -- (instancetype)initWithUIntMax: (uintmax_t)uIntMax -{ - if (uIntMax <= ULLONG_MAX) - return [self initWithUnsignedLongLong: - (unsigned long long)uIntMax]; - - return (id)[[OFNumber of_alloc] initWithUIntMax: uIntMax]; -} - -#ifdef __clang__ -/* - * This warning should probably not exist at all, as it prevents checking - * whether one type fits into another in a portable way. - */ -# pragma clang diagnostic push -# pragma clang diagnostic ignored "-Wtautological-constant-out-of-range-compare" -#endif - -- (instancetype)initWithPtrDiff: (ptrdiff_t)ptrDiff -{ - if (ptrDiff >= LLONG_MIN && ptrDiff <= LLONG_MAX) - return [self initWithLongLong: (long long)ptrDiff]; - - return (id)[[OFNumber of_alloc] initWithPtrDiff: ptrDiff]; -} - -- (instancetype)initWithIntPtr: (intptr_t)intPtr -{ - if (intPtr >= 0) - return [self initWithUIntPtr: intPtr]; - if (intPtr >= LLONG_MIN) - return [self initWithLongLong: (long long)intPtr]; - - return (id)[[OFNumber of_alloc] initWithIntPtr: intPtr]; -} - -- (instancetype)initWithUIntPtr: (uintptr_t)uIntPtr -{ - if (uIntPtr <= ULLONG_MAX) - return [self initWithUnsignedLongLong: - (unsigned long long)uIntPtr]; - - return (id)[[OFNumber of_alloc] initWithUIntPtr: uIntPtr]; -} - -#ifdef __clang__ -# pragma clang diagnostic pop -#endif - -- (instancetype)initWithFloat: (float)float_ -{ - if (float_ == (uintmax_t)float_) - return [self initWithUIntMax: (uintmax_t)float_]; - if (float_ == (intmax_t)float_) - return [self initWithIntMax: (intmax_t)float_]; - - return (id)[[OFNumber of_alloc] initWithFloat: float_]; -} - -- (instancetype)initWithDouble: (double)double_ -{ - if (double_ == (uintmax_t)double_) - return [self initWithUIntMax: (uintmax_t)double_]; - if (double_ == (intmax_t)double_) - return [self initWithIntMax: (intmax_t)double_]; - if (double_ == (float)double_) - return [self initWithFloat: (float)double_]; - - return (id)[[OFNumber of_alloc] initWithDouble: double_]; +- (instancetype)initWithChar: (signed char)value +{ + if (value == 0) { + static of_once_t once = OF_ONCE_INIT; + of_once(&once, charZeroNumberInit); + return (id)charZeroNumber; + } + + return (id)[[OFNumber of_alloc] initWithChar: value]; +} + +- (instancetype)initWithShort: (short)value +{ + if (value == 0) { + static of_once_t once = OF_ONCE_INIT; + of_once(&once, shortZeroNumberInit); + return (id)shortZeroNumber; + } + + return (id)[[OFNumber of_alloc] initWithShort: value]; +} + +- (instancetype)initWithInt: (int)value +{ + if (value == 0) { + static of_once_t once = OF_ONCE_INIT; + of_once(&once, intZeroNumberInit); + return (id)intZeroNumber; + } + + return (id)[[OFNumber of_alloc] initWithInt: value]; +} + +- (instancetype)initWithLong: (long)value +{ + if (value == 0) { + static of_once_t once = OF_ONCE_INIT; + of_once(&once, longZeroNumberInit); + return (id)longZeroNumber; + } + + return (id)[[OFNumber of_alloc] initWithLong: value]; +} + +- (instancetype)initWithLongLong: (long long)value +{ + if (value == 0) { + static of_once_t once = OF_ONCE_INIT; + of_once(&once, longLongZeroNumberInit); + return (id)longLongZeroNumber; + } + + return (id)[[OFNumber of_alloc] initWithLongLong: value]; +} + +- (instancetype)initWithUnsignedChar: (unsigned char)value +{ + if (value == 0) { + static of_once_t once = OF_ONCE_INIT; + of_once(&once, unsignedCharZeroNumberInit); + return (id)unsignedCharZeroNumber; + } + + return (id)[[OFNumber of_alloc] initWithUnsignedChar: value]; +} + +- (instancetype)initWithUnsignedShort: (unsigned short)value +{ + if (value == 0) { + static of_once_t once = OF_ONCE_INIT; + of_once(&once, unsignedShortZeroNumberInit); + return (id)unsignedShortZeroNumber; + } + + return (id)[[OFNumber of_alloc] initWithUnsignedShort: value]; +} + +- (instancetype)initWithUnsignedInt: (unsigned int)value +{ + if (value == 0) { + static of_once_t once = OF_ONCE_INIT; + of_once(&once, unsignedIntZeroNumberInit); + return (id)unsignedIntZeroNumber; + } + + return (id)[[OFNumber of_alloc] initWithUnsignedInt: value]; +} + +- (instancetype)initWithUnsignedLong: (unsigned long)value +{ + if (value == 0) { + static of_once_t once = OF_ONCE_INIT; + of_once(&once, unsignedLongZeroNumberInit); + return (id)unsignedLongZeroNumber; + } + + return (id)[[OFNumber of_alloc] initWithUnsignedLong: value]; +} + +- (instancetype)initWithUnsignedLongLong: (unsigned long long)value +{ + if (value == 0) { + static of_once_t once = OF_ONCE_INIT; + of_once(&once, unsignedLongLongZeroNumberInit); + return (id)unsignedLongLongZeroNumber; + } + + return (id)[[OFNumber of_alloc] initWithUnsignedLongLong: value]; +} + +- (instancetype)initWithFloat: (float)value +{ + if (value == 0) { + static of_once_t once = OF_ONCE_INIT; + of_once(&once, floatZeroNumberInit); + return (id)floatZeroNumber; + } + + return (id)[[OFNumber of_alloc] initWithFloat: value]; +} + +- (instancetype)initWithDouble: (double)value +{ + if (value == 0) { + static of_once_t once = OF_ONCE_INIT; + of_once(&once, doubleZeroNumberInit); + return (id)doubleZeroNumber; + } + + return (id)[[OFNumber of_alloc] initWithDouble: value]; } - (instancetype)initWithSerialization: (OFXMLElement *)element { return (id)[[OFNumber of_alloc] initWithSerialization: element]; @@ -408,457 +262,250 @@ return (id)&placeholder; return [super alloc]; } -+ (instancetype)numberWithBool: (bool)bool_ -{ - return [[[self alloc] initWithBool: bool_] autorelease]; -} - -+ (instancetype)numberWithChar: (signed char)sChar -{ - return [[[self alloc] initWithChar: sChar] autorelease]; -} - -+ (instancetype)numberWithShort: (short)sShort -{ - return [[[self alloc] initWithShort: sShort] autorelease]; -} - -+ (instancetype)numberWithInt: (int)sInt -{ - return [[[self alloc] initWithInt: sInt] autorelease]; -} - -+ (instancetype)numberWithLong: (long)sLong -{ - return [[[self alloc] initWithLong: sLong] autorelease]; -} - -+ (instancetype)numberWithLongLong: (long long)sLongLong -{ - return [[[self alloc] initWithLongLong: sLongLong] autorelease]; -} - -+ (instancetype)numberWithUnsignedChar: (unsigned char)uChar -{ - return [[[self alloc] initWithUnsignedChar: uChar] autorelease]; -} - -+ (instancetype)numberWithUnsignedShort: (unsigned short)uShort -{ - return [[[self alloc] initWithUnsignedShort: uShort] autorelease]; -} - -+ (instancetype)numberWithUnsignedInt: (unsigned int)uInt -{ - return [[[self alloc] initWithUnsignedInt: uInt] autorelease]; -} - -+ (instancetype)numberWithUnsignedLong: (unsigned long)uLong -{ - return [[[self alloc] initWithUnsignedLong: uLong] autorelease]; -} - -+ (instancetype)numberWithUnsignedLongLong: (unsigned long long)uLongLong -{ - return [[[self alloc] initWithUnsignedLongLong: uLongLong] autorelease]; -} - -+ (instancetype)numberWithInt8: (int8_t)int8 -{ - return [[[self alloc] initWithInt8: int8] autorelease]; -} - -+ (instancetype)numberWithInt16: (int16_t)int16 -{ - return [[[self alloc] initWithInt16: int16] autorelease]; -} - -+ (instancetype)numberWithInt32: (int32_t)int32 -{ - return [[[self alloc] initWithInt32: int32] autorelease]; -} - -+ (instancetype)numberWithInt64: (int64_t)int64 -{ - return [[[self alloc] initWithInt64: int64] autorelease]; -} - -+ (instancetype)numberWithUInt8: (uint8_t)uInt8 -{ - return [[[self alloc] initWithUInt8: uInt8] autorelease]; -} - -+ (instancetype)numberWithUInt16: (uint16_t)uInt16 -{ - return [[[self alloc] initWithUInt16: uInt16] autorelease]; -} - -+ (instancetype)numberWithUInt32: (uint32_t)uInt32 -{ - return [[[self alloc] initWithUInt32: uInt32] autorelease]; -} - -+ (instancetype)numberWithUInt64: (uint64_t)uInt64 -{ - return [[[self alloc] initWithUInt64: uInt64] autorelease]; -} - -+ (instancetype)numberWithSize: (size_t)size -{ - return [[[self alloc] initWithSize: size] autorelease]; -} - -+ (instancetype)numberWithSSize: (ssize_t)sSize -{ - return [[[self alloc] initWithSSize: sSize] autorelease]; -} - -+ (instancetype)numberWithIntMax: (intmax_t)intMax -{ - return [[[self alloc] initWithIntMax: intMax] autorelease]; -} - -+ (instancetype)numberWithUIntMax: (uintmax_t)uIntMax -{ - return [[[self alloc] initWithUIntMax: uIntMax] autorelease]; -} - -+ (instancetype)numberWithPtrDiff: (ptrdiff_t)ptrDiff -{ - return [[[self alloc] initWithPtrDiff: ptrDiff] autorelease]; -} - -+ (instancetype)numberWithIntPtr: (intptr_t)intPtr -{ - return [[[self alloc] initWithIntPtr: intPtr] autorelease]; -} - -+ (instancetype)numberWithUIntPtr: (uintptr_t)uIntPtr -{ - return [[[self alloc] initWithUIntPtr: uIntPtr] autorelease]; -} - -+ (instancetype)numberWithFloat: (float)float_ -{ - return [[[self alloc] initWithFloat: float_] autorelease]; -} - -+ (instancetype)numberWithDouble: (double)double_ -{ - return [[[self alloc] initWithDouble: double_] autorelease]; ++ (instancetype)numberWithBool: (bool)value +{ + return [[[self alloc] initWithBool: value] autorelease]; +} + ++ (instancetype)numberWithChar: (signed char)value +{ + return [[[self alloc] initWithChar: value] autorelease]; +} + ++ (instancetype)numberWithShort: (short)value +{ + return [[[self alloc] initWithShort: value] autorelease]; +} + ++ (instancetype)numberWithInt: (int)value +{ + return [[[self alloc] initWithInt: value] autorelease]; +} + ++ (instancetype)numberWithLong: (long)value +{ + return [[[self alloc] initWithLong: value] autorelease]; +} + ++ (instancetype)numberWithLongLong: (long long)value +{ + return [[[self alloc] initWithLongLong: value] autorelease]; +} + ++ (instancetype)numberWithUnsignedChar: (unsigned char)value +{ + return [[[self alloc] initWithUnsignedChar: value] autorelease]; +} + ++ (instancetype)numberWithUnsignedShort: (unsigned short)value +{ + return [[[self alloc] initWithUnsignedShort: value] autorelease]; +} + ++ (instancetype)numberWithUnsignedInt: (unsigned int)value +{ + return [[[self alloc] initWithUnsignedInt: value] autorelease]; +} + ++ (instancetype)numberWithUnsignedLong: (unsigned long)value +{ + return [[[self alloc] initWithUnsignedLong: value] autorelease]; +} + ++ (instancetype)numberWithUnsignedLongLong: (unsigned long long)value +{ + return [[[self alloc] initWithUnsignedLongLong: value] autorelease]; +} + ++ (instancetype)numberWithFloat: (float)value +{ + return [[[self alloc] initWithFloat: value] autorelease]; +} + ++ (instancetype)numberWithDouble: (double)value +{ + return [[[self alloc] initWithDouble: value] autorelease]; } - (instancetype)init { OF_INVALID_INIT_METHOD } -- (instancetype)initWithBool: (bool)bool_ +- (instancetype)initWithBool: (bool)value { self = [super init]; - _value.unsigned_ = bool_; + _value.unsigned_ = value; _type = OF_NUMBER_TYPE_UNSIGNED; _typeEncoding = @encode(bool); return self; } -- (instancetype)initWithChar: (signed char)sChar +- (instancetype)initWithChar: (signed char)value { self = [super init]; - _value.signed_ = sChar; + _value.signed_ = value; _type = OF_NUMBER_TYPE_SIGNED; _typeEncoding = @encode(signed char); return self; } -- (instancetype)initWithShort: (short)sShort +- (instancetype)initWithShort: (short)value { self = [super init]; - _value.signed_ = sShort; + _value.signed_ = value; _type = OF_NUMBER_TYPE_SIGNED; _typeEncoding = @encode(short); return self; } -- (instancetype)initWithInt: (int)sInt +- (instancetype)initWithInt: (int)value { self = [super init]; - _value.signed_ = sInt; + _value.signed_ = value; _type = OF_NUMBER_TYPE_SIGNED; _typeEncoding = @encode(int); return self; } -- (instancetype)initWithLong: (long)sLong +- (instancetype)initWithLong: (long)value { self = [super init]; - _value.signed_ = sLong; + _value.signed_ = value; _type = OF_NUMBER_TYPE_SIGNED; _typeEncoding = @encode(long); return self; } -- (instancetype)initWithLongLong: (long long)sLongLong +- (instancetype)initWithLongLong: (long long)value { self = [super init]; - _value.signed_ = sLongLong; + _value.signed_ = value; _type = OF_NUMBER_TYPE_SIGNED; _typeEncoding = @encode(long long); return self; } -- (instancetype)initWithUnsignedChar: (unsigned char)uChar +- (instancetype)initWithUnsignedChar: (unsigned char)value { self = [super init]; - _value.unsigned_ = uChar; + _value.unsigned_ = value; _type = OF_NUMBER_TYPE_UNSIGNED; _typeEncoding = @encode(unsigned long); return self; } -- (instancetype)initWithUnsignedShort: (unsigned short)uShort +- (instancetype)initWithUnsignedShort: (unsigned short)value { self = [super init]; - _value.unsigned_ = uShort; + _value.unsigned_ = value; _type = OF_NUMBER_TYPE_UNSIGNED; _typeEncoding = @encode(unsigned short); return self; } -- (instancetype)initWithUnsignedInt: (unsigned int)uInt +- (instancetype)initWithUnsignedInt: (unsigned int)value { self = [super init]; - _value.unsigned_ = uInt; + _value.unsigned_ = value; _type = OF_NUMBER_TYPE_UNSIGNED; _typeEncoding = @encode(unsigned int); return self; } -- (instancetype)initWithUnsignedLong: (unsigned long)uLong +- (instancetype)initWithUnsignedLong: (unsigned long)value { self = [super init]; - _value.unsigned_ = uLong; + _value.unsigned_ = value; _type = OF_NUMBER_TYPE_UNSIGNED; _typeEncoding = @encode(unsigned long); return self; } -- (instancetype)initWithUnsignedLongLong: (unsigned long long)uLongLong +- (instancetype)initWithUnsignedLongLong: (unsigned long long)value { self = [super init]; - _value.unsigned_ = uLongLong; + _value.unsigned_ = value; _type = OF_NUMBER_TYPE_UNSIGNED; _typeEncoding = @encode(unsigned long long); return self; } -- (instancetype)initWithInt8: (int8_t)int8 -{ - self = [super init]; - - _value.signed_ = int8; - _type = OF_NUMBER_TYPE_SIGNED; - _typeEncoding = @encode(int8_t); - - return self; -} - -- (instancetype)initWithInt16: (int16_t)int16 -{ - self = [super init]; - - _value.signed_ = int16; - _type = OF_NUMBER_TYPE_SIGNED; - _typeEncoding = @encode(int16_t); - - return self; -} - -- (instancetype)initWithInt32: (int32_t)int32 -{ - self = [super init]; - - _value.signed_ = int32; - _type = OF_NUMBER_TYPE_SIGNED; - _typeEncoding = @encode(int32_t); - - return self; -} - -- (instancetype)initWithInt64: (int64_t)int64 -{ - self = [super init]; - - _value.signed_ = int64; - _type = OF_NUMBER_TYPE_SIGNED; - _typeEncoding = @encode(int64_t); - - return self; -} - -- (instancetype)initWithUInt8: (uint8_t)uInt8 -{ - self = [super init]; - - _value.unsigned_ = uInt8; - _type = OF_NUMBER_TYPE_UNSIGNED; - _typeEncoding = @encode(uint8_t); - - return self; -} - -- (instancetype)initWithUInt16: (uint16_t)uInt16 -{ - self = [super init]; - - _value.unsigned_ = uInt16; - _type = OF_NUMBER_TYPE_UNSIGNED; - _typeEncoding = @encode(uint16_t); - - return self; -} - -- (instancetype)initWithUInt32: (uint32_t)uInt32 -{ - self = [super init]; - - _value.unsigned_ = uInt32; - _type = OF_NUMBER_TYPE_UNSIGNED; - _typeEncoding = @encode(uint32_t); - - return self; -} - -- (instancetype)initWithUInt64: (uint64_t)uInt64 -{ - self = [super init]; - - _value.unsigned_ = uInt64; - _type = OF_NUMBER_TYPE_UNSIGNED; - _typeEncoding = @encode(uint64_t); - - return self; -} - -- (instancetype)initWithSize: (size_t)size -{ - self = [super init]; - - _value.unsigned_ = size; - _type = OF_NUMBER_TYPE_UNSIGNED; - _typeEncoding = @encode(size_t); - - return self; -} - -- (instancetype)initWithSSize: (ssize_t)sSize -{ - self = [super init]; - - _value.signed_ = sSize; - _type = OF_NUMBER_TYPE_SIGNED; - _typeEncoding = @encode(ssize_t); - - return self; -} - -- (instancetype)initWithIntMax: (intmax_t)intMax -{ - self = [super init]; - - _value.signed_ = intMax; - _type = OF_NUMBER_TYPE_SIGNED; - _typeEncoding = @encode(intmax_t); - - return self; -} - -- (instancetype)initWithUIntMax: (uintmax_t)uIntMax -{ - self = [super init]; - - _value.unsigned_ = uIntMax; - _type = OF_NUMBER_TYPE_UNSIGNED; - _typeEncoding = @encode(uintmax_t); - - return self; -} - -- (instancetype)initWithPtrDiff: (ptrdiff_t)ptrDiff -{ - self = [super init]; - - _value.signed_ = ptrDiff; +- (instancetype)initWithPtrDiff: (ptrdiff_t)value +{ + self = [super init]; + + _value.signed_ = value; _type = OF_NUMBER_TYPE_SIGNED; _typeEncoding = @encode(ptrdiff_t); return self; } -- (instancetype)initWithIntPtr: (intptr_t)intPtr +- (instancetype)initWithIntPtr: (intptr_t)value { self = [super init]; - _value.signed_ = intPtr; + _value.signed_ = value; _type = OF_NUMBER_TYPE_SIGNED; _typeEncoding = @encode(intptr_t); return self; } -- (instancetype)initWithUIntPtr: (uintptr_t)uIntPtr +- (instancetype)initWithUIntPtr: (uintptr_t)value { self = [super init]; - _value.unsigned_ = uIntPtr; + _value.unsigned_ = value; _type = OF_NUMBER_TYPE_UNSIGNED; _typeEncoding = @encode(uintptr_t); return self; } -- (instancetype)initWithFloat: (float)float_ +- (instancetype)initWithFloat: (float)value { self = [super init]; - _value.float_ = float_; + _value.float_ = value; _type = OF_NUMBER_TYPE_FLOAT; _typeEncoding = @encode(float); return self; } -- (instancetype)initWithDouble: (double)double_ +- (instancetype)initWithDouble: (double)value { self = [super init]; - _value.float_ = double_; + _value.float_ = value; _type = OF_NUMBER_TYPE_FLOAT; _typeEncoding = @encode(double); return self; } @@ -883,22 +530,24 @@ self = [self initWithBool: true]; else if ([stringValue isEqual: @"false"]) self = [self initWithBool: false]; else @throw [OFInvalidArgumentException exception]; - } else if ([typeString isEqual: @"float"]) + } else if ([typeString isEqual: @"float"]) { + unsigned long long value = + [element unsignedLongLongValueWithBase: 16]; + + if (value > UINT64_MAX) + @throw [OFOutOfRangeException exception]; + self = [self initWithDouble: OF_BSWAP_DOUBLE_IF_LE( - OF_INT_TO_DOUBLE_RAW(OF_BSWAP64_IF_LE( - (uint64_t)element.hexadecimalValue)))]; - else if ([typeString isEqual: @"signed"]) - self = [self initWithIntMax: element.doubleValue]; + OF_INT_TO_DOUBLE_RAW(OF_BSWAP64_IF_LE(value)))]; + } else if ([typeString isEqual: @"signed"]) + self = [self initWithLongLong: element.longLongValue]; else if ([typeString isEqual: @"unsigned"]) - /* - * FIXME: This will fail if the value is bigger than - * INTMAX_MAX! - */ - self = [self initWithUIntMax: element.decimalValue]; + self = [self initWithUnsignedLongLong: + element.unsignedLongLongValue]; else @throw [OFInvalidArgumentException exception]; objc_autoreleasePoolPop(pool); } @catch (id e) { @@ -1011,85 +660,10 @@ - (unsigned long long)unsignedLongLongValue { RETURN_AS(unsigned long long) } -- (int8_t)int8Value -{ - RETURN_AS(int8_t) -} - -- (int16_t)int16Value -{ - RETURN_AS(int16_t) -} - -- (int32_t)int32Value -{ - RETURN_AS(int32_t) -} - -- (int64_t)int64Value -{ - RETURN_AS(int64_t) -} - -- (uint8_t)uInt8Value -{ - RETURN_AS(uint8_t) -} - -- (uint16_t)uInt16Value -{ - RETURN_AS(uint16_t) -} - -- (uint32_t)uInt32Value -{ - RETURN_AS(uint32_t) -} - -- (uint64_t)uInt64Value -{ - RETURN_AS(uint64_t) -} - -- (size_t)sizeValue -{ - RETURN_AS(size_t) -} - -- (ssize_t)sSizeValue -{ - RETURN_AS(ssize_t) -} - -- (intmax_t)intMaxValue -{ - RETURN_AS(intmax_t) -} - -- (uintmax_t)uIntMaxValue -{ - RETURN_AS(uintmax_t) -} - -- (ptrdiff_t)ptrDiffValue -{ - RETURN_AS(ptrdiff_t) -} - -- (intptr_t)intPtrValue -{ - RETURN_AS(intptr_t) -} - -- (uintptr_t)uIntPtrValue -{ - RETURN_AS(uintptr_t) -} - - (float)floatValue { RETURN_AS(float) } @@ -1124,13 +698,13 @@ return (value1 == value2); } if (_type == OF_NUMBER_TYPE_SIGNED || number->_type == OF_NUMBER_TYPE_SIGNED) - return (number.intMaxValue == self.intMaxValue); + return (number.longLongValue == self.longLongValue); - return (number.uIntMaxValue == self.uIntMaxValue); + return (number.unsignedLongLongValue == self.unsignedLongLongValue); } - (of_comparison_result_t)compare: (id )object { OFNumber *number; @@ -1151,22 +725,22 @@ return OF_ORDERED_ASCENDING; return OF_ORDERED_SAME; } else if (_type == OF_NUMBER_TYPE_SIGNED || number->_type == OF_NUMBER_TYPE_SIGNED) { - intmax_t int1 = self.intMaxValue; - intmax_t int2 = number.intMaxValue; + long long int1 = self.longLongValue; + long long int2 = number.longLongValue; if (int1 > int2) return OF_ORDERED_DESCENDING; if (int1 < int2) return OF_ORDERED_ASCENDING; return OF_ORDERED_SAME; } else { - uintmax_t uint1 = self.uIntMaxValue; - uintmax_t uint2 = number.uIntMaxValue; + unsigned long long uint1 = self.unsignedLongLongValue; + unsigned long long uint2 = number.unsignedLongLongValue; if (uint1 > uint2) return OF_ORDERED_DESCENDING; if (uint1 < uint2) return OF_ORDERED_ASCENDING; @@ -1190,25 +764,17 @@ d = OF_BSWAP_DOUBLE_IF_BE(self.doubleValue); for (uint_fast8_t i = 0; i < sizeof(double); i++) OF_HASH_ADD(hash, ((char *)&d)[i]); - } else if (type == OF_NUMBER_TYPE_SIGNED) { - intmax_t v = self.intMaxValue * -1; - - while (v != 0) { - OF_HASH_ADD(hash, v & 0xFF); - v >>= 8; - } - - OF_HASH_ADD(hash, 1); - } else if (type == OF_NUMBER_TYPE_UNSIGNED) { - uintmax_t v = self.uIntMaxValue; - - while (v != 0) { - OF_HASH_ADD(hash, v & 0xFF); - v >>= 8; + } else if (type == OF_NUMBER_TYPE_SIGNED || + type == OF_NUMBER_TYPE_UNSIGNED) { + unsigned long long value = self.unsignedLongLongValue; + + while (value != 0) { + OF_HASH_ADD(hash, value & 0xFF); + value >>= 8; } } else @throw [OFInvalidFormatException exception]; OF_HASH_FINALIZE(hash); @@ -1231,13 +797,13 @@ if (*_typeEncoding == 'B') return (_value.unsigned_ ? @"true" : @"false"); if (_type == OF_NUMBER_TYPE_FLOAT) return [OFString stringWithFormat: @"%g", _value.float_]; if (_type == OF_NUMBER_TYPE_SIGNED) - return [OFString stringWithFormat: @"%jd", _value.signed_]; + return [OFString stringWithFormat: @"%lld", _value.signed_]; if (_type == OF_NUMBER_TYPE_UNSIGNED) - return [OFString stringWithFormat: @"%ju", _value.unsigned_]; + return [OFString stringWithFormat: @"%llu", _value.unsigned_]; @throw [OFInvalidFormatException exception]; } - (OFXMLElement *)XMLElementBySerializing @@ -1337,11 +903,11 @@ [data addItem: &type]; [data addItems: &tmp count: sizeof(tmp)]; } else if (_type == OF_NUMBER_TYPE_SIGNED) { - intmax_t value = self.intMaxValue; + long long value = self.longLongValue; if (value >= -32 && value < 0) { uint8_t tmp = 0xE0 | ((uint8_t)(value - 32) & 0x1F); data = [OFMutableData dataWithItems: &tmp @@ -1386,11 +952,11 @@ [data addItems: &tmp count: sizeof(tmp)]; } else @throw [OFOutOfRangeException exception]; } else if (_type == OF_NUMBER_TYPE_UNSIGNED) { - uintmax_t value = self.uIntMaxValue; + unsigned long long value = self.unsignedLongLongValue; if (value <= 127) { uint8_t tmp = ((uint8_t)value & 0x7F); data = [OFMutableData dataWithItems: &tmp Index: src/OFSettings.h ================================================================== --- src/OFSettings.h +++ src/OFSettings.h @@ -81,11 +81,11 @@ * @brief Sets the specified path to the specified integer. * * @param integer The integer to set * @param path The path to store the integer at */ -- (void)setInteger: (intmax_t)integer +- (void)setInteger: (long long)integer forPath: (OFString *)path; /*! * @brief Sets the specified path to the specified bool. * @@ -148,12 +148,12 @@ * * @param path The path for which the integer value should be returned * @param defaultValue The default value to return if the path does not exist * @return The integer value of the specified path */ -- (intmax_t)integerForPath: (OFString *)path - defaultValue: (intmax_t)defaultValue; +- (long long)integerForPath: (OFString *)path + defaultValue: (long long)defaultValue; /*! * @brief Returns the bool for the specified path, or the default value if the * path does not exist. * Index: src/OFSettings.m ================================================================== --- src/OFSettings.m +++ src/OFSettings.m @@ -68,11 +68,11 @@ forPath: (OFString *)path { OF_UNRECOGNIZED_SELECTOR } -- (void)setInteger: (intmax_t)integer +- (void)setInteger: (long long)integer forPath: (OFString *)path { OF_UNRECOGNIZED_SELECTOR } @@ -110,12 +110,12 @@ defaultValue: (OFString *)defaultValue { OF_UNRECOGNIZED_SELECTOR } -- (intmax_t)integerForPath: (OFString *)path - defaultValue: (intmax_t)defaultValue +- (long long)integerForPath: (OFString *)path + defaultValue: (long long)defaultValue { OF_UNRECOGNIZED_SELECTOR } - (bool)boolForPath: (OFString *)path ADDED src/OFString+JSONParsing.h Index: src/OFString+JSONParsing.h ================================================================== --- src/OFString+JSONParsing.h +++ src/OFString+JSONParsing.h @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, + * 2018, 2019, 2020 + * 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. + */ + +#import "OFString.h" + +OF_ASSUME_NONNULL_BEGIN + +#ifdef __cplusplus +extern "C" { +#endif +extern int _OFString_JSONParsing_reference; +#ifdef __cplusplus +} +#endif + +@interface OFString (JSONParsing) +/*! + * @brief The string interpreted as JSON and parsed as an object. + * + * @note This also allows parsing JSON5, an extension of JSON. See + * http://json5.org/ for more details. + * + * @warning Although not specified by the JSON specification, this can also + * return primitives like strings and numbers. The rationale behind + * this is that most JSON parsers allow JSON data just consisting of a + * single primitive, leading to real world JSON files sometimes only + * consisting of a single primitive. Therefore, you should not make any + * assumptions about the object returned by this method if you don't + * want your program to terminate due to a message not understood, but + * instead check the returned object using @ref isKindOfClass:. + */ +@property (readonly, nonatomic) id objectByParsingJSON; + +/*! + * @brief Creates an object from the JSON value of the string. + * + * @note This also allows parsing JSON5, an extension of JSON. See + * http://json5.org/ for more details. + * + * @warning Although not specified by the JSON specification, this can also + * return primitives like strings and numbers. The rationale behind + * this is that most JSON parsers allow JSON data just consisting of a + * single primitive, leading to real world JSON files sometimes only + * consisting of a single primitive. Therefore, you should not make any + * assumptions about the object returned by this method if you don't + * want your program to terminate due to a message not understood, but + * instead check the returned object using @ref isKindOfClass:. + * + * @param depthLimit The maximum depth the parser should accept (defaults to 32 + * if not specified, 0 means no limit (insecure!)) + * + * @return An object + */ +- (id)objectByParsingJSONWithDepthLimit: (size_t)depthLimit; +@end + +OF_ASSUME_NONNULL_END ADDED src/OFString+JSONParsing.m Index: src/OFString+JSONParsing.m ================================================================== --- src/OFString+JSONParsing.m +++ src/OFString+JSONParsing.m @@ -0,0 +1,675 @@ +/* + * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, + * 2018, 2019, 2020 + * 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" + +#include +#include + +#include + +#include + +#import "OFString+JSONParsing.h" +#import "OFArray.h" +#import "OFDictionary.h" +#import "OFNumber.h" +#import "OFNull.h" + +#import "OFInvalidJSONException.h" + +int _OFString_JSONParsing_reference; + +static id nextObject(const char **pointer, const char *stop, size_t *line, + size_t depthLimit); + +static void +skipWhitespaces(const char **pointer, const char *stop, size_t *line) +{ + while (*pointer < stop && (**pointer == ' ' || **pointer == '\t' || + **pointer == '\r' || **pointer == '\n')) { + if (**pointer == '\n') + (*line)++; + + (*pointer)++; + } +} + +static void +skipComment(const char **pointer, const char *stop, size_t *line) +{ + if (**pointer != '/') + return; + + if (*pointer + 1 >= stop) + return; + + (*pointer)++; + + if (**pointer == '*') { + bool lastIsAsterisk = false; + + (*pointer)++; + + while (*pointer < stop) { + if (lastIsAsterisk && **pointer == '/') { + (*pointer)++; + return; + } + + lastIsAsterisk = (**pointer == '*'); + + if (**pointer == '\n') + (*line)++; + + (*pointer)++; + } + } else if (**pointer == '/') { + (*pointer)++; + + while (*pointer < stop) { + if (**pointer == '\r' || **pointer == '\n') { + (*pointer)++; + (*line)++; + return; + } + + (*pointer)++; + } + } else + (*pointer)--; +} + +static void +skipWhitespacesAndComments(const char **pointer, const char *stop, size_t *line) +{ + const char *old = NULL; + + while (old != *pointer) { + old = *pointer; + + skipWhitespaces(pointer, stop, line); + skipComment(pointer, stop, line); + } +} + +static inline of_char16_t +parseUnicodeEscape(const char *pointer, const char *stop) +{ + of_char16_t ret = 0; + + if (pointer + 5 >= stop) + return 0xFFFF; + + if (pointer[0] != '\\' || pointer[1] != 'u') + return 0xFFFF; + + for (uint8_t i = 0; i < 4; i++) { + char c = pointer[i + 2]; + ret <<= 4; + + if (c >= '0' && c <= '9') + ret |= c - '0'; + else if (c >= 'a' && c <= 'f') + ret |= c + 10 - 'a'; + else if (c >= 'A' && c <= 'F') + ret |= c + 10 - 'A'; + else + return 0xFFFF; + } + + if (ret == 0) + return 0xFFFF; + + return ret; +} + +static inline OFString * +parseString(const char **pointer, const char *stop, size_t *line) +{ + char *buffer; + size_t i = 0; + char delimiter = **pointer; + + if (++(*pointer) + 1 >= stop) + return nil; + + if ((buffer = malloc(stop - *pointer)) == NULL) + return nil; + + while (*pointer < stop) { + /* Parse escape codes */ + if (**pointer == '\\') { + if (++(*pointer) >= stop) { + free(buffer); + return nil; + } + + switch (**pointer) { + case '"': + case '\\': + case '/': + buffer[i++] = **pointer; + (*pointer)++; + break; + case 'b': + buffer[i++] = '\b'; + (*pointer)++; + break; + case 'f': + buffer[i++] = '\f'; + (*pointer)++; + break; + case 'n': + buffer[i++] = '\n'; + (*pointer)++; + break; + case 'r': + buffer[i++] = '\r'; + (*pointer)++; + break; + case 't': + buffer[i++] = '\t'; + (*pointer)++; + break; + /* Parse Unicode escape sequence */ + case 'u':; + of_char16_t c1, c2; + of_unichar_t c; + size_t l; + + c1 = parseUnicodeEscape(*pointer - 1, stop); + if (c1 == 0xFFFF) { + free(buffer); + return nil; + } + + /* Low surrogate */ + if ((c1 & 0xFC00) == 0xDC00) { + free(buffer); + return nil; + } + + /* Normal character */ + if ((c1 & 0xFC00) != 0xD800) { + l = of_string_utf8_encode(c1, + buffer + i); + if (l == 0) { + free(buffer); + return nil; + } + + i += l; + *pointer += 5; + + break; + } + + /* + * If we are still here, we only got one UTF-16 + * surrogate and now need to get the other one + * in order to produce UTF-8 and not CESU-8. + */ + c2 = parseUnicodeEscape(*pointer + 5, stop); + if (c2 == 0xFFFF) { + free(buffer); + return nil; + } + + c = (((c1 & 0x3FF) << 10) | + (c2 & 0x3FF)) + 0x10000; + + l = of_string_utf8_encode(c, buffer + i); + if (l == 0) { + free(buffer); + return nil; + } + + i += l; + *pointer += 11; + + break; + case '\r': + (*pointer)++; + + if (*pointer < stop && **pointer == '\n') { + (*pointer)++; + (*line)++; + } + + break; + case '\n': + (*pointer)++; + (*line)++; + break; + default: + free(buffer); + return nil; + } + /* End of string found */ + } else if (**pointer == delimiter) { + OFString *ret; + + @try { + ret = [OFString stringWithUTF8String: buffer + length: i]; + } @finally { + free(buffer); + } + + (*pointer)++; + + return ret; + /* Newlines in strings are disallowed */ + } else if (**pointer == '\n' || **pointer == '\r') { + (*line)++; + free(buffer); + return nil; + } else { + buffer[i++] = **pointer; + (*pointer)++; + } + } + + free(buffer); + return nil; +} + +static inline OFString * +parseIdentifier(const char **pointer, const char *stop) +{ + char *buffer; + size_t i = 0; + + if ((buffer = malloc(stop - *pointer)) == NULL) + return nil; + + while (*pointer < stop) { + if ((**pointer >= 'a' && **pointer <= 'z') || + (**pointer >= 'A' && **pointer <= 'Z') || + (**pointer >= '0' && **pointer <= '9') || + **pointer == '_' || **pointer == '$' || + (**pointer & 0x80)) { + buffer[i++] = **pointer; + (*pointer)++; + } else if (**pointer == '\\') { + of_char16_t c1, c2; + of_unichar_t c; + size_t l; + + if (++(*pointer) >= stop || **pointer != 'u') { + free(buffer); + return nil; + } + + c1 = parseUnicodeEscape(*pointer - 1, stop); + if (c1 == 0xFFFF) { + free(buffer); + return nil; + } + + /* Low surrogate */ + if ((c1 & 0xFC00) == 0xDC00) { + free(buffer); + return nil; + } + + /* Normal character */ + if ((c1 & 0xFC00) != 0xD800) { + l = of_string_utf8_encode(c1, buffer + i); + if (l == 0) { + free(buffer); + return nil; + } + + i += l; + *pointer += 5; + + continue; + } + + /* + * If we are still here, we only got one UTF-16 + * surrogate and now need to get the other one in order + * to produce UTF-8 and not CESU-8. + */ + c2 = parseUnicodeEscape(*pointer + 5, stop); + if (c2 == 0xFFFF) { + free(buffer); + return nil; + } + + c = (((c1 & 0x3FF) << 10) | (c2 & 0x3FF)) + 0x10000; + + l = of_string_utf8_encode(c, buffer + i); + if (l == 0) { + free(buffer); + return nil; + } + + i += l; + *pointer += 11; + } else { + OFString *ret; + + if (i == 0 || (buffer[0] >= '0' && buffer[0] <= '9')) { + free(buffer); + return nil; + } + + @try { + ret = [OFString stringWithUTF8String: buffer + length: i]; + } @finally { + free(buffer); + } + + return ret; + } + } + + /* + * It is never possible to end with an identifier, thus we should never + * reach stop. + */ + return nil; +} + +static inline OFMutableArray * +parseArray(const char **pointer, const char *stop, size_t *line, + size_t depthLimit) +{ + OFMutableArray *array = [OFMutableArray array]; + + if (++(*pointer) >= stop) + return nil; + + if (--depthLimit == 0) + return nil; + + while (**pointer != ']') { + id object; + + skipWhitespacesAndComments(pointer, stop, line); + if (*pointer >= stop) + return nil; + + if (**pointer == ']') + break; + + if (**pointer == ',') { + (*pointer)++; + skipWhitespacesAndComments(pointer, stop, line); + + if (*pointer >= stop || **pointer != ']') + return nil; + + break; + } + + object = nextObject(pointer, stop, line, depthLimit); + if (object == nil) + return nil; + + [array addObject: object]; + + skipWhitespacesAndComments(pointer, stop, line); + if (*pointer >= stop) + return nil; + + if (**pointer == ',') { + (*pointer)++; + skipWhitespacesAndComments(pointer, stop, line); + + if (*pointer >= stop) + return nil; + } else if (**pointer != ']') + return nil; + } + + (*pointer)++; + + return array; +} + +static inline OFMutableDictionary * +parseDictionary(const char **pointer, const char *stop, size_t *line, + size_t depthLimit) +{ + OFMutableDictionary *dictionary = [OFMutableDictionary dictionary]; + + if (++(*pointer) >= stop) + return nil; + + if (--depthLimit == 0) + return nil; + + while (**pointer != '}') { + OFString *key; + id object; + + skipWhitespacesAndComments(pointer, stop, line); + if (*pointer >= stop) + return nil; + + if (**pointer == '}') + break; + + if (**pointer == ',') { + (*pointer)++; + skipWhitespacesAndComments(pointer, stop, line); + + if (*pointer >= stop || **pointer != '}') + return nil; + + break; + } + + skipWhitespacesAndComments(pointer, stop, line); + if (*pointer + 1 >= stop) + return nil; + + if ((**pointer >= 'a' && **pointer <= 'z') || + (**pointer >= 'A' && **pointer <= 'Z') || + **pointer == '_' || **pointer == '$' || **pointer == '\\') + key = parseIdentifier(pointer, stop); + else + key = nextObject(pointer, stop, line, depthLimit); + + if (![key isKindOfClass: [OFString class]]) + return nil; + + skipWhitespacesAndComments(pointer, stop, line); + if (*pointer + 1 >= stop || **pointer != ':') + return nil; + + (*pointer)++; + + object = nextObject(pointer, stop, line, depthLimit); + if (object == nil) + return nil; + + [dictionary setObject: object + forKey: key]; + + skipWhitespacesAndComments(pointer, stop, line); + if (*pointer >= stop) + return nil; + + if (**pointer == ',') { + (*pointer)++; + skipWhitespacesAndComments(pointer, stop, line); + + if (*pointer >= stop) + return nil; + } else if (**pointer != '}') + return nil; + } + + (*pointer)++; + + return dictionary; +} + +static inline OFNumber * +parseNumber(const char **pointer, const char *stop, size_t *line) +{ + bool isNegative = (*pointer < stop && (*pointer)[0] == '-'); + bool hasDecimal = false; + size_t i; + OFString *string; + OFNumber *number; + + for (i = 0; *pointer + i < stop; i++) { + if ((*pointer)[i] == '.') + hasDecimal = true; + + if ((*pointer)[i] == ' ' || (*pointer)[i] == '\t' || + (*pointer)[i] == '\r' || (*pointer)[i] == '\n' || + (*pointer)[i] == ',' || (*pointer)[i] == ']' || + (*pointer)[i] == '}') { + if ((*pointer)[i] == '\n') + (*line)++; + + break; + } + } + + string = [[OFString alloc] initWithUTF8String: *pointer + length: i]; + *pointer += i; + + @try { + if (hasDecimal) + number = [OFNumber numberWithDouble: + string.doubleValue]; + else if ([string isEqual: @"Infinity"]) + number = [OFNumber numberWithDouble: INFINITY]; + else if ([string isEqual: @"-Infinity"]) + number = [OFNumber numberWithDouble: -INFINITY]; + else if (isNegative) + number = [OFNumber numberWithLongLong: + [string longLongValueWithBase: 0]]; + else + number = [OFNumber numberWithUnsignedLongLong: + [string unsignedLongLongValueWithBase: 0]]; + } @finally { + [string release]; + } + + return number; +} + +static id +nextObject(const char **pointer, const char *stop, size_t *line, + size_t depthLimit) +{ + skipWhitespacesAndComments(pointer, stop, line); + + if (*pointer >= stop) + return nil; + + switch (**pointer) { + case '"': + case '\'': + return parseString(pointer, stop, line); + case '[': + return parseArray(pointer, stop, line, depthLimit); + case '{': + return parseDictionary(pointer, stop, line, depthLimit); + case 't': + if (*pointer + 3 >= stop) + return nil; + + if (memcmp(*pointer, "true", 4) != 0) + return nil; + + (*pointer) += 4; + + return [OFNumber numberWithBool: true]; + case 'f': + if (*pointer + 4 >= stop) + return nil; + + if (memcmp(*pointer, "false", 5) != 0) + return nil; + + (*pointer) += 5; + + return [OFNumber numberWithBool: false]; + case 'n': + if (*pointer + 3 >= stop) + return nil; + + if (memcmp(*pointer, "null", 4) != 0) + return nil; + + (*pointer) += 4; + + return [OFNull null]; + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + case '+': + case '-': + case '.': + case 'I': + return parseNumber(pointer, stop, line); + default: + return nil; + } +} + +@implementation OFString (JSONParsing) +- (id)objectByParsingJSON +{ + return [self objectByParsingJSONWithDepthLimit: 32]; +} + +- (id)objectByParsingJSONWithDepthLimit: (size_t)depthLimit +{ + void *pool = objc_autoreleasePoolPush(); + const char *pointer = self.UTF8String; + const char *stop = pointer + self.UTF8StringLength; + id object; + size_t line = 1; + +#ifdef __clang_analyzer__ + assert(pointer != NULL); +#endif + + object = nextObject(&pointer, stop, &line, depthLimit); + skipWhitespacesAndComments(&pointer, stop, &line); + + if (pointer < stop || object == nil) + @throw [OFInvalidJSONException exceptionWithString: self + line: line]; + + [object retain]; + + objc_autoreleasePoolPop(pool); + + return [object autorelease]; +} +@end DELETED src/OFString+JSONValue.h Index: src/OFString+JSONValue.h ================================================================== --- src/OFString+JSONValue.h +++ src/OFString+JSONValue.h @@ -1,71 +0,0 @@ -/* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * 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. - */ - -#import "OFString.h" - -OF_ASSUME_NONNULL_BEGIN - -#ifdef __cplusplus -extern "C" { -#endif -extern int _OFString_JSONValue_reference; -#ifdef __cplusplus -} -#endif - -@interface OFString (JSONValue) -/*! - * @brief The string interpreted as JSON and parsed as an object. - * - * @note This also allows parsing JSON5, an extension of JSON. See - * http://json5.org/ for more details. - * - * @warning Although not specified by the JSON specification, this can also - * return primitives like strings and numbers. The rationale behind - * this is that most JSON parsers allow JSON data just consisting of a - * single primitive, leading to real world JSON files sometimes only - * consisting of a single primitive. Therefore, you should not make any - * assumptions about the object returned by this method if you don't - * want your program to terminate due to a message not understood, but - * instead check the returned object using @ref isKindOfClass:. - */ -@property (readonly, nonatomic) id JSONValue; - -/*! - * @brief Creates an object from the JSON value of the string. - * - * @note This also allows parsing JSON5, an extension of JSON. See - * http://json5.org/ for more details. - * - * @warning Although not specified by the JSON specification, this can also - * return primitives like strings and numbers. The rationale behind - * this is that most JSON parsers allow JSON data just consisting of a - * single primitive, leading to real world JSON files sometimes only - * consisting of a single primitive. Therefore, you should not make any - * assumptions about the object returned by this method if you don't - * want your program to terminate due to a message not understood, but - * instead check the returned object using @ref isKindOfClass:. - * - * @param depthLimit The maximum depth the parser should accept (defaults to 32 - * if not specified, 0 means no limit (insecure!)) - * - * @return An object - */ -- (id)JSONValueWithDepthLimit: (size_t)depthLimit; -@end - -OF_ASSUME_NONNULL_END DELETED src/OFString+JSONValue.m Index: src/OFString+JSONValue.m ================================================================== --- src/OFString+JSONValue.m +++ src/OFString+JSONValue.m @@ -1,675 +0,0 @@ -/* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * 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" - -#include -#include - -#include - -#include - -#import "OFString+JSONValue.h" -#import "OFArray.h" -#import "OFDictionary.h" -#import "OFNumber.h" -#import "OFNull.h" - -#import "OFInvalidJSONException.h" - -int _OFString_JSONValue_reference; - -static id nextObject(const char **pointer, const char *stop, size_t *line, - size_t depthLimit); - -static void -skipWhitespaces(const char **pointer, const char *stop, size_t *line) -{ - while (*pointer < stop && (**pointer == ' ' || **pointer == '\t' || - **pointer == '\r' || **pointer == '\n')) { - if (**pointer == '\n') - (*line)++; - - (*pointer)++; - } -} - -static void -skipComment(const char **pointer, const char *stop, size_t *line) -{ - if (**pointer != '/') - return; - - if (*pointer + 1 >= stop) - return; - - (*pointer)++; - - if (**pointer == '*') { - bool lastIsAsterisk = false; - - (*pointer)++; - - while (*pointer < stop) { - if (lastIsAsterisk && **pointer == '/') { - (*pointer)++; - return; - } - - lastIsAsterisk = (**pointer == '*'); - - if (**pointer == '\n') - (*line)++; - - (*pointer)++; - } - } else if (**pointer == '/') { - (*pointer)++; - - while (*pointer < stop) { - if (**pointer == '\r' || **pointer == '\n') { - (*pointer)++; - (*line)++; - return; - } - - (*pointer)++; - } - } else - (*pointer)--; -} - -static void -skipWhitespacesAndComments(const char **pointer, const char *stop, size_t *line) -{ - const char *old = NULL; - - while (old != *pointer) { - old = *pointer; - - skipWhitespaces(pointer, stop, line); - skipComment(pointer, stop, line); - } -} - -static inline of_char16_t -parseUnicodeEscape(const char *pointer, const char *stop) -{ - of_char16_t ret = 0; - - if (pointer + 5 >= stop) - return 0xFFFF; - - if (pointer[0] != '\\' || pointer[1] != 'u') - return 0xFFFF; - - for (uint8_t i = 0; i < 4; i++) { - char c = pointer[i + 2]; - ret <<= 4; - - if (c >= '0' && c <= '9') - ret |= c - '0'; - else if (c >= 'a' && c <= 'f') - ret |= c + 10 - 'a'; - else if (c >= 'A' && c <= 'F') - ret |= c + 10 - 'A'; - else - return 0xFFFF; - } - - if (ret == 0) - return 0xFFFF; - - return ret; -} - -static inline OFString * -parseString(const char **pointer, const char *stop, size_t *line) -{ - char *buffer; - size_t i = 0; - char delimiter = **pointer; - - if (++(*pointer) + 1 >= stop) - return nil; - - if ((buffer = malloc(stop - *pointer)) == NULL) - return nil; - - while (*pointer < stop) { - /* Parse escape codes */ - if (**pointer == '\\') { - if (++(*pointer) >= stop) { - free(buffer); - return nil; - } - - switch (**pointer) { - case '"': - case '\\': - case '/': - buffer[i++] = **pointer; - (*pointer)++; - break; - case 'b': - buffer[i++] = '\b'; - (*pointer)++; - break; - case 'f': - buffer[i++] = '\f'; - (*pointer)++; - break; - case 'n': - buffer[i++] = '\n'; - (*pointer)++; - break; - case 'r': - buffer[i++] = '\r'; - (*pointer)++; - break; - case 't': - buffer[i++] = '\t'; - (*pointer)++; - break; - /* Parse Unicode escape sequence */ - case 'u':; - of_char16_t c1, c2; - of_unichar_t c; - size_t l; - - c1 = parseUnicodeEscape(*pointer - 1, stop); - if (c1 == 0xFFFF) { - free(buffer); - return nil; - } - - /* Low surrogate */ - if ((c1 & 0xFC00) == 0xDC00) { - free(buffer); - return nil; - } - - /* Normal character */ - if ((c1 & 0xFC00) != 0xD800) { - l = of_string_utf8_encode(c1, - buffer + i); - if (l == 0) { - free(buffer); - return nil; - } - - i += l; - *pointer += 5; - - break; - } - - /* - * If we are still here, we only got one UTF-16 - * surrogate and now need to get the other one - * in order to produce UTF-8 and not CESU-8. - */ - c2 = parseUnicodeEscape(*pointer + 5, stop); - if (c2 == 0xFFFF) { - free(buffer); - return nil; - } - - c = (((c1 & 0x3FF) << 10) | - (c2 & 0x3FF)) + 0x10000; - - l = of_string_utf8_encode(c, buffer + i); - if (l == 0) { - free(buffer); - return nil; - } - - i += l; - *pointer += 11; - - break; - case '\r': - (*pointer)++; - - if (*pointer < stop && **pointer == '\n') { - (*pointer)++; - (*line)++; - } - - break; - case '\n': - (*pointer)++; - (*line)++; - break; - default: - free(buffer); - return nil; - } - /* End of string found */ - } else if (**pointer == delimiter) { - OFString *ret; - - @try { - ret = [OFString stringWithUTF8String: buffer - length: i]; - } @finally { - free(buffer); - } - - (*pointer)++; - - return ret; - /* Newlines in strings are disallowed */ - } else if (**pointer == '\n' || **pointer == '\r') { - (*line)++; - free(buffer); - return nil; - } else { - buffer[i++] = **pointer; - (*pointer)++; - } - } - - free(buffer); - return nil; -} - -static inline OFString * -parseIdentifier(const char **pointer, const char *stop) -{ - char *buffer; - size_t i = 0; - - if ((buffer = malloc(stop - *pointer)) == NULL) - return nil; - - while (*pointer < stop) { - if ((**pointer >= 'a' && **pointer <= 'z') || - (**pointer >= 'A' && **pointer <= 'Z') || - (**pointer >= '0' && **pointer <= '9') || - **pointer == '_' || **pointer == '$' || - (**pointer & 0x80)) { - buffer[i++] = **pointer; - (*pointer)++; - } else if (**pointer == '\\') { - of_char16_t c1, c2; - of_unichar_t c; - size_t l; - - if (++(*pointer) >= stop || **pointer != 'u') { - free(buffer); - return nil; - } - - c1 = parseUnicodeEscape(*pointer - 1, stop); - if (c1 == 0xFFFF) { - free(buffer); - return nil; - } - - /* Low surrogate */ - if ((c1 & 0xFC00) == 0xDC00) { - free(buffer); - return nil; - } - - /* Normal character */ - if ((c1 & 0xFC00) != 0xD800) { - l = of_string_utf8_encode(c1, buffer + i); - if (l == 0) { - free(buffer); - return nil; - } - - i += l; - *pointer += 5; - - continue; - } - - /* - * If we are still here, we only got one UTF-16 - * surrogate and now need to get the other one in order - * to produce UTF-8 and not CESU-8. - */ - c2 = parseUnicodeEscape(*pointer + 5, stop); - if (c2 == 0xFFFF) { - free(buffer); - return nil; - } - - c = (((c1 & 0x3FF) << 10) | (c2 & 0x3FF)) + 0x10000; - - l = of_string_utf8_encode(c, buffer + i); - if (l == 0) { - free(buffer); - return nil; - } - - i += l; - *pointer += 11; - } else { - OFString *ret; - - if (i == 0 || (buffer[0] >= '0' && buffer[0] <= '9')) { - free(buffer); - return nil; - } - - @try { - ret = [OFString stringWithUTF8String: buffer - length: i]; - } @finally { - free(buffer); - } - - return ret; - } - } - - /* - * It is never possible to end with an identifier, thus we should never - * reach stop. - */ - return nil; -} - -static inline OFMutableArray * -parseArray(const char **pointer, const char *stop, size_t *line, - size_t depthLimit) -{ - OFMutableArray *array = [OFMutableArray array]; - - if (++(*pointer) >= stop) - return nil; - - if (--depthLimit == 0) - return nil; - - while (**pointer != ']') { - id object; - - skipWhitespacesAndComments(pointer, stop, line); - if (*pointer >= stop) - return nil; - - if (**pointer == ']') - break; - - if (**pointer == ',') { - (*pointer)++; - skipWhitespacesAndComments(pointer, stop, line); - - if (*pointer >= stop || **pointer != ']') - return nil; - - break; - } - - object = nextObject(pointer, stop, line, depthLimit); - if (object == nil) - return nil; - - [array addObject: object]; - - skipWhitespacesAndComments(pointer, stop, line); - if (*pointer >= stop) - return nil; - - if (**pointer == ',') { - (*pointer)++; - skipWhitespacesAndComments(pointer, stop, line); - - if (*pointer >= stop) - return nil; - } else if (**pointer != ']') - return nil; - } - - (*pointer)++; - - return array; -} - -static inline OFMutableDictionary * -parseDictionary(const char **pointer, const char *stop, size_t *line, - size_t depthLimit) -{ - OFMutableDictionary *dictionary = [OFMutableDictionary dictionary]; - - if (++(*pointer) >= stop) - return nil; - - if (--depthLimit == 0) - return nil; - - while (**pointer != '}') { - OFString *key; - id object; - - skipWhitespacesAndComments(pointer, stop, line); - if (*pointer >= stop) - return nil; - - if (**pointer == '}') - break; - - if (**pointer == ',') { - (*pointer)++; - skipWhitespacesAndComments(pointer, stop, line); - - if (*pointer >= stop || **pointer != '}') - return nil; - - break; - } - - skipWhitespacesAndComments(pointer, stop, line); - if (*pointer + 1 >= stop) - return nil; - - if ((**pointer >= 'a' && **pointer <= 'z') || - (**pointer >= 'A' && **pointer <= 'Z') || - **pointer == '_' || **pointer == '$' || **pointer == '\\') - key = parseIdentifier(pointer, stop); - else - key = nextObject(pointer, stop, line, depthLimit); - - if (![key isKindOfClass: [OFString class]]) - return nil; - - skipWhitespacesAndComments(pointer, stop, line); - if (*pointer + 1 >= stop || **pointer != ':') - return nil; - - (*pointer)++; - - object = nextObject(pointer, stop, line, depthLimit); - if (object == nil) - return nil; - - [dictionary setObject: object - forKey: key]; - - skipWhitespacesAndComments(pointer, stop, line); - if (*pointer >= stop) - return nil; - - if (**pointer == ',') { - (*pointer)++; - skipWhitespacesAndComments(pointer, stop, line); - - if (*pointer >= stop) - return nil; - } else if (**pointer != '}') - return nil; - } - - (*pointer)++; - - return dictionary; -} - -static inline OFNumber * -parseNumber(const char **pointer, const char *stop, size_t *line) -{ - bool isHex = (*pointer + 1 < stop && (*pointer)[1] == 'x'); - bool hasDecimal = false; - size_t i; - OFString *string; - OFNumber *number; - - for (i = 0; *pointer + i < stop; i++) { - if ((*pointer)[i] == '.') - hasDecimal = true; - - if ((*pointer)[i] == ' ' || (*pointer)[i] == '\t' || - (*pointer)[i] == '\r' || (*pointer)[i] == '\n' || - (*pointer)[i] == ',' || (*pointer)[i] == ']' || - (*pointer)[i] == '}') { - if ((*pointer)[i] == '\n') - (*line)++; - - break; - } - } - - string = [[OFString alloc] initWithUTF8String: *pointer - length: i]; - *pointer += i; - - @try { - if (hasDecimal) - number = [OFNumber numberWithDouble: - string.doubleValue]; - else if (isHex) - number = [OFNumber numberWithIntMax: - string.hexadecimalValue]; - else if ([string isEqual: @"Infinity"]) - number = [OFNumber numberWithDouble: INFINITY]; - else if ([string isEqual: @"-Infinity"]) - number = [OFNumber numberWithDouble: -INFINITY]; - else - number = [OFNumber numberWithIntMax: - string.decimalValue]; - } @finally { - [string release]; - } - - return number; -} - -static id -nextObject(const char **pointer, const char *stop, size_t *line, - size_t depthLimit) -{ - skipWhitespacesAndComments(pointer, stop, line); - - if (*pointer >= stop) - return nil; - - switch (**pointer) { - case '"': - case '\'': - return parseString(pointer, stop, line); - case '[': - return parseArray(pointer, stop, line, depthLimit); - case '{': - return parseDictionary(pointer, stop, line, depthLimit); - case 't': - if (*pointer + 3 >= stop) - return nil; - - if (memcmp(*pointer, "true", 4) != 0) - return nil; - - (*pointer) += 4; - - return [OFNumber numberWithBool: true]; - case 'f': - if (*pointer + 4 >= stop) - return nil; - - if (memcmp(*pointer, "false", 5) != 0) - return nil; - - (*pointer) += 5; - - return [OFNumber numberWithBool: false]; - case 'n': - if (*pointer + 3 >= stop) - return nil; - - if (memcmp(*pointer, "null", 4) != 0) - return nil; - - (*pointer) += 4; - - return [OFNull null]; - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - case '+': - case '-': - case '.': - case 'I': - return parseNumber(pointer, stop, line); - default: - return nil; - } -} - -@implementation OFString (JSONValue) -- (id)JSONValue -{ - return [self JSONValueWithDepthLimit: 32]; -} - -- (id)JSONValueWithDepthLimit: (size_t)depthLimit -{ - void *pool = objc_autoreleasePoolPush(); - const char *pointer = self.UTF8String; - const char *stop = pointer + self.UTF8StringLength; - id object; - size_t line = 1; - -#ifdef __clang_analyzer__ - assert(pointer != NULL); -#endif - - object = nextObject(&pointer, stop, &line, depthLimit); - skipWhitespacesAndComments(&pointer, stop, &line); - - if (pointer < stop || object == nil) - @throw [OFInvalidJSONException exceptionWithString: self - line: line]; - - [object retain]; - - objc_autoreleasePoolPop(pool); - - return [object autorelease]; -} -@end ADDED src/OFString+PropertyListParsing.h Index: src/OFString+PropertyListParsing.h ================================================================== --- src/OFString+PropertyListParsing.h +++ src/OFString+PropertyListParsing.h @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, + * 2018, 2019, 2020 + * 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. + */ + +#import "OFString.h" + +OF_ASSUME_NONNULL_BEGIN + +#ifdef __cplusplus +extern "C" { +#endif +extern int _OFString_PropertyListParsing_reference; +#ifdef __cplusplus +} +#endif + +@interface OFString (PropertyListParsing) +/*! + * @brief The string interpreted as a property list and parsed as an object. + * + * @note This only supports XML property lists! + */ +@property (readonly, nonatomic) id objectByParsingPropertyList; +@end + +OF_ASSUME_NONNULL_END ADDED src/OFString+PropertyListParsing.m Index: src/OFString+PropertyListParsing.m ================================================================== --- src/OFString+PropertyListParsing.m +++ src/OFString+PropertyListParsing.m @@ -0,0 +1,212 @@ +/* + * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, + * 2018, 2019, 2020 + * 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 "OFString+PropertyListParsing.h" +#import "OFArray.h" +#import "OFData.h" +#import "OFDate.h" +#import "OFDictionary.h" +#import "OFNumber.h" +#import "OFXMLAttribute.h" +#import "OFXMLElement.h" + +#import "OFInvalidFormatException.h" +#import "OFUnsupportedVersionException.h" + +int _OFString_PropertyListParsing_reference; + +static id parseElement(OFXMLElement *element); + +static OFArray * +parseArrayElement(OFXMLElement *element) +{ + OFMutableArray *ret = [OFMutableArray array]; + void *pool = objc_autoreleasePoolPush(); + + for (OFXMLElement *child in element.elements) + [ret addObject: parseElement(child)]; + + [ret makeImmutable]; + + objc_autoreleasePoolPop(pool); + + return ret; +} + +static OFDictionary * +parseDictElement(OFXMLElement *element) +{ + OFMutableDictionary *ret = [OFMutableDictionary dictionary]; + void *pool = objc_autoreleasePoolPush(); + OFArray OF_GENERIC(OFXMLElement *) *children = element.elements; + OFEnumerator OF_GENERIC(OFXMLElement *) *enumerator; + OFXMLElement *key, *object; + + if (children.count % 2 != 0) + @throw [OFInvalidFormatException exception]; + + enumerator = [children objectEnumerator]; + while ((key = [enumerator nextObject]) && + (object = [enumerator nextObject])) { + if (key.namespace != nil || key.attributes.count != 0 || + ![key.name isEqual: @"key"]) + @throw [OFInvalidFormatException exception]; + + [ret setObject: parseElement(object) + forKey: key.stringValue]; + } + + [ret makeImmutable]; + + objc_autoreleasePoolPop(pool); + + return ret; +} + +static OFString * +parseStringElement(OFXMLElement *element) +{ + return element.stringValue; +} + +static OFData * +parseDataElement(OFXMLElement *element) +{ + return [OFData dataWithBase64EncodedString: element.stringValue]; +} + +static OFDate * +parseDateElement(OFXMLElement *element) +{ + return [OFDate dateWithDateString: element.stringValue + format: @"%Y-%m-%dT%H:%M:%SZ"]; +} + +static OFNumber * +parseTrueElement(OFXMLElement *element) +{ + if (element.children.count != 0) + @throw [OFInvalidFormatException exception]; + + return [OFNumber numberWithBool: true]; +} + +static OFNumber * +parseFalseElement(OFXMLElement *element) +{ + if (element.children.count != 0) + @throw [OFInvalidFormatException exception]; + + return [OFNumber numberWithBool: false]; +} + +static OFNumber * +parseRealElement(OFXMLElement *element) +{ + return [OFNumber numberWithDouble: element.doubleValue]; +} + +static OFNumber * +parseIntegerElement(OFXMLElement *element) +{ + void *pool = objc_autoreleasePoolPush(); + OFString *stringValue; + OFNumber *ret; + + stringValue = element.stringValue.stringByDeletingEnclosingWhitespaces; + + if ([stringValue hasPrefix: @"-"]) + ret = [OFNumber numberWithLongLong: stringValue.longLongValue]; + else + ret = [OFNumber numberWithUnsignedLongLong: + stringValue.unsignedLongLongValue]; + + [ret retain]; + + objc_autoreleasePoolPop(pool); + + return [ret autorelease]; +} + +static id +parseElement(OFXMLElement *element) +{ + OFString *elementName; + + if (element.namespace != nil || element.attributes.count != 0) + @throw [OFInvalidFormatException exception]; + + elementName = element.name; + + if ([elementName isEqual: @"array"]) + return parseArrayElement(element); + else if ([elementName isEqual: @"dict"]) + return parseDictElement(element); + else if ([elementName isEqual: @"string"]) + return parseStringElement(element); + else if ([elementName isEqual: @"data"]) + return parseDataElement(element); + else if ([elementName isEqual: @"date"]) + return parseDateElement(element); + else if ([elementName isEqual: @"true"]) + return parseTrueElement(element); + else if ([elementName isEqual: @"false"]) + return parseFalseElement(element); + else if ([elementName isEqual: @"real"]) + return parseRealElement(element); + else if ([elementName isEqual: @"integer"]) + return parseIntegerElement(element); + else + @throw [OFInvalidFormatException exception]; +} + +@implementation OFString (PropertyListParsing) +- (id)objectByParsingPropertyList +{ + void *pool = objc_autoreleasePoolPush(); + OFXMLElement *rootElement = [OFXMLElement elementWithXMLString: self]; + OFXMLAttribute *versionAttribute; + OFArray OF_GENERIC(OFXMLElement *) *elements; + id ret; + + if (![rootElement.name isEqual: @"plist"] || + rootElement.namespace != nil) + @throw [OFInvalidFormatException exception]; + + versionAttribute = [rootElement attributeForName: @"version"]; + + if (versionAttribute == nil) + @throw [OFInvalidFormatException exception]; + + if (![versionAttribute.stringValue isEqual: @"1.0"]) + @throw [OFUnsupportedVersionException + exceptionWithVersion: [versionAttribute stringValue]]; + + elements = rootElement.elements; + + if (elements.count != 1) + @throw [OFInvalidFormatException exception]; + + ret = parseElement(elements.firstObject); + + [ret retain]; + objc_autoreleasePoolPop(pool); + return [ret autorelease]; +} +@end DELETED src/OFString+PropertyListValue.h Index: src/OFString+PropertyListValue.h ================================================================== --- src/OFString+PropertyListValue.h +++ src/OFString+PropertyListValue.h @@ -1,39 +0,0 @@ -/* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * 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. - */ - -#import "OFString.h" - -OF_ASSUME_NONNULL_BEGIN - -#ifdef __cplusplus -extern "C" { -#endif -extern int _OFString_PropertyListValue_reference; -#ifdef __cplusplus -} -#endif - -@interface OFString (PropertyListValue) -/*! - * @brief The string interpreted as a property list and parsed as an object. - * - * @note This only supports XML property lists! - */ -@property (readonly, nonatomic) id propertyListValue; -@end - -OF_ASSUME_NONNULL_END DELETED src/OFString+PropertyListValue.m Index: src/OFString+PropertyListValue.m ================================================================== --- src/OFString+PropertyListValue.m +++ src/OFString+PropertyListValue.m @@ -1,196 +0,0 @@ -/* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * 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 "OFString+PropertyListValue.h" -#import "OFArray.h" -#import "OFData.h" -#import "OFDate.h" -#import "OFDictionary.h" -#import "OFNumber.h" -#import "OFXMLAttribute.h" -#import "OFXMLElement.h" - -#import "OFInvalidFormatException.h" -#import "OFUnsupportedVersionException.h" - -int _OFString_PropertyListValue_reference; - -static id parseElement(OFXMLElement *element); - -static OFArray * -parseArrayElement(OFXMLElement *element) -{ - OFMutableArray *ret = [OFMutableArray array]; - void *pool = objc_autoreleasePoolPush(); - - for (OFXMLElement *child in element.elements) - [ret addObject: parseElement(child)]; - - [ret makeImmutable]; - - objc_autoreleasePoolPop(pool); - - return ret; -} - -static OFDictionary * -parseDictElement(OFXMLElement *element) -{ - OFMutableDictionary *ret = [OFMutableDictionary dictionary]; - void *pool = objc_autoreleasePoolPush(); - OFArray OF_GENERIC(OFXMLElement *) *children = element.elements; - OFEnumerator OF_GENERIC(OFXMLElement *) *enumerator; - OFXMLElement *key, *object; - - if (children.count % 2 != 0) - @throw [OFInvalidFormatException exception]; - - enumerator = [children objectEnumerator]; - while ((key = [enumerator nextObject]) && - (object = [enumerator nextObject])) { - if (key.namespace != nil || key.attributes.count != 0 || - ![key.name isEqual: @"key"]) - @throw [OFInvalidFormatException exception]; - - [ret setObject: parseElement(object) - forKey: key.stringValue]; - } - - [ret makeImmutable]; - - objc_autoreleasePoolPop(pool); - - return ret; -} - -static OFString * -parseStringElement(OFXMLElement *element) -{ - return element.stringValue; -} - -static OFData * -parseDataElement(OFXMLElement *element) -{ - return [OFData dataWithBase64EncodedString: element.stringValue]; -} - -static OFDate * -parseDateElement(OFXMLElement *element) -{ - return [OFDate dateWithDateString: element.stringValue - format: @"%Y-%m-%dT%H:%M:%SZ"]; -} - -static OFNumber * -parseTrueElement(OFXMLElement *element) -{ - if (element.children.count != 0) - @throw [OFInvalidFormatException exception]; - - return [OFNumber numberWithBool: true]; -} - -static OFNumber * -parseFalseElement(OFXMLElement *element) -{ - if (element.children.count != 0) - @throw [OFInvalidFormatException exception]; - - return [OFNumber numberWithBool: false]; -} - -static OFNumber * -parseRealElement(OFXMLElement *element) -{ - return [OFNumber numberWithDouble: element.doubleValue]; -} - -static OFNumber * -parseIntegerElement(OFXMLElement *element) -{ - return [OFNumber numberWithIntMax: element.decimalValue]; -} - -static id -parseElement(OFXMLElement *element) -{ - OFString *elementName; - - if (element.namespace != nil || element.attributes.count != 0) - @throw [OFInvalidFormatException exception]; - - elementName = element.name; - - if ([elementName isEqual: @"array"]) - return parseArrayElement(element); - else if ([elementName isEqual: @"dict"]) - return parseDictElement(element); - else if ([elementName isEqual: @"string"]) - return parseStringElement(element); - else if ([elementName isEqual: @"data"]) - return parseDataElement(element); - else if ([elementName isEqual: @"date"]) - return parseDateElement(element); - else if ([elementName isEqual: @"true"]) - return parseTrueElement(element); - else if ([elementName isEqual: @"false"]) - return parseFalseElement(element); - else if ([elementName isEqual: @"real"]) - return parseRealElement(element); - else if ([elementName isEqual: @"integer"]) - return parseIntegerElement(element); - else - @throw [OFInvalidFormatException exception]; -} - -@implementation OFString (PropertyListValue) -- (id)propertyListValue -{ - void *pool = objc_autoreleasePoolPush(); - OFXMLElement *rootElement = [OFXMLElement elementWithXMLString: self]; - OFXMLAttribute *versionAttribute; - OFArray OF_GENERIC(OFXMLElement *) *elements; - id ret; - - if (![rootElement.name isEqual: @"plist"] || - rootElement.namespace != nil) - @throw [OFInvalidFormatException exception]; - - versionAttribute = [rootElement attributeForName: @"version"]; - - if (versionAttribute == nil) - @throw [OFInvalidFormatException exception]; - - if (![versionAttribute.stringValue isEqual: @"1.0"]) - @throw [OFUnsupportedVersionException - exceptionWithVersion: [versionAttribute stringValue]]; - - elements = rootElement.elements; - - if (elements.count != 1) - @throw [OFInvalidFormatException exception]; - - ret = parseElement(elements.firstObject); - - [ret retain]; - objc_autoreleasePoolPop(pool); - return [ret autorelease]; -} -@end Index: src/OFString+Serialization.m ================================================================== --- src/OFString+Serialization.m +++ src/OFString+Serialization.m @@ -50,11 +50,11 @@ version = [root attributeForName: @"version"].stringValue; if (version == nil) @throw [OFInvalidArgumentException exception]; - if (version.decimalValue != 1) + if (version.unsignedLongLongValue != 1) @throw [OFUnsupportedVersionException exceptionWithVersion: version]; elements = [root elementsForNamespace: OF_SERIALIZATION_NS]; Index: src/OFString.h ================================================================== --- src/OFString.h +++ src/OFString.h @@ -169,47 +169,34 @@ * specified by Unicode! */ @property (readonly, nonatomic) OFString *capitalizedString; /*! - * @brief The decimal value of the string as an `intmax_t`. + * @brief The decimal value of the string as a `long long`. * * Leading and trailing whitespaces are ignored. * * If the string contains any non-number characters, an * @ref OFInvalidFormatException is thrown. * - * If the number is too big to fit into an `intmax_t`, an + * If the number is too big to fit into a `long long`, an * @ref OFOutOfRangeException is thrown. */ -@property (readonly, nonatomic) intmax_t decimalValue; +@property (readonly, nonatomic) long long longLongValue; /*! - * @brief The hexadecimal value of the string as an `uintmax_t`. + * @brief The decimal value of the string as an `unsigned long long`. * * Leading and trailing whitespaces are ignored. * * If the string contains any non-number characters, an * @ref OFInvalidFormatException is thrown. * - * If the number is too big to fit into an `uintmax_t`, an - * @ref OFOutOfRangeException is thrown. - */ -@property (readonly, nonatomic) uintmax_t hexadecimalValue; - -/*! - * @brief The octal value of the string as an `uintmax_t`. - * - * Leading and trailing whitespaces are ignored. - * - * If the string contains any non-number characters, an - * @ref OFInvalidFormatException is thrown. - * - * If the number is too big to fit into an `uintmax_t`, an - * @ref OFOutOfRangeException is thrown. - */ -@property (readonly, nonatomic) uintmax_t octalValue; + * If the number is too big to fit into an `unsigned long long`, an + * @ref OFOutOfRangeException is thrown. + */ +@property (readonly, nonatomic) unsigned long long unsignedLongLongValue; /*! * @brief The float value of the string as a float. * * If the string contains any non-number characters, an @@ -1023,10 +1010,49 @@ * @param range The range of the substring * @return The substring as a new autoreleased OFString */ - (OFString *)substringWithRange: (of_range_t)range; +/*! + * @brief The value of the string in the specified base as a `long long`. + * + * Leading and trailing whitespaces are ignored. + * + * If the string contains any non-number characters, an + * @ref OFInvalidFormatException is thrown. + * + * If the number is too big to fit into a `long long`, an + * @ref OFOutOfRangeException is thrown. + * + * @param base The base to use. If the base is 0, base 16 is assumed if the + * string starts with 0x (after stripping white spaces). If the + * string starts with 0, base 8 is assumed. Otherwise, base 10 is + * assumed. + * @return The value of the string in the specified base + */ +- (long long)longLongValueWithBase: (int)base; + +/*! + * @brief The value of the string in the specified base as an + * `unsigned long long`. + * + * Leading and trailing whitespaces are ignored. + * + * If the string contains any non-number characters, an + * @ref OFInvalidFormatException is thrown. + * + * If the number is too big to fit into an `unsigned long long`, an + * @ref OFOutOfRangeException is thrown. + * + * @param base The base to use. If the base is 0, base 16 is assumed if the + * string starts with 0x (after stripping white spaces). If the + * string starts with 0, base 8 is assumed. Otherwise, base 10 is + * assumed. + * @return The value of the string in the specified base + */ +- (unsigned long long)unsignedLongLongValueWithBase: (int)base; + /*! * @brief Creates a new string by appending another string. * * @param string The string to append * @return A new, autoreleased OFString with the specified string appended @@ -1252,15 +1278,15 @@ #include "OFConstantString.h" #include "OFMutableString.h" #ifdef __OBJC__ # import "OFString+CryptoHashing.h" -# import "OFString+JSONValue.h" +# import "OFString+JSONParsing.h" # ifdef OF_HAVE_FILES # import "OFString+PathAdditions.h" # endif -# import "OFString+PropertyListValue.h" +# import "OFString+PropertyListParsing.h" # import "OFString+Serialization.h" # import "OFString+URLEncoding.h" # import "OFString+XMLEscaping.h" # import "OFString+XMLUnescaping.h" #endif Index: src/OFString.m ================================================================== --- src/OFString.m +++ src/OFString.m @@ -15,10 +15,11 @@ * file. */ #include "config.h" +#include #include #include #include #include #include @@ -124,15 +125,15 @@ /* References for static linking */ void _references_to_categories_of_OFString(void) { _OFString_CryptoHashing_reference = 1; - _OFString_JSONValue_reference = 1; + _OFString_JSONParsing_reference = 1; #ifdef OF_HAVE_FILES _OFString_PathAdditions_reference = 1; #endif - _OFString_PropertyListValue_reference = 1; + _OFString_PropertyListParsing_reference = 1; _OFString_Serialization_reference = 1; _OFString_URLEncoding_reference = 1; _OFString_XMLEscaping_reference = 1; _OFString_XMLUnescaping_reference = 1; } @@ -988,11 +989,11 @@ - (instancetype)initWithContentsOfFile: (OFString *)path encoding: (of_string_encoding_t)encoding { char *tmp; - uintmax_t fileSize; + unsigned long long fileSize; @try { void *pool = objc_autoreleasePoolPush(); OFFile *file = nil; @@ -1006,11 +1007,11 @@ errNo: e.errNo]; } objc_autoreleasePoolPop(pool); -# if UINTMAX_MAX > SIZE_MAX +# if ULLONG_MAX > SIZE_MAX if (fileSize > SIZE_MAX) @throw [OFOutOfRangeException exception]; #endif /* @@ -2311,183 +2312,88 @@ objc_autoreleasePoolPop(pool); return array; } -- (intmax_t)decimalValue +- (long long)longLongValue +{ + return [self longLongValueWithBase: 10]; +} + +- (long long)longLongValueWithBase: (int)base { void *pool = objc_autoreleasePoolPush(); - const of_unichar_t *characters = self.characters; - size_t i = 0, length = self.length; - intmax_t value = 0; - bool expectWhitespace = false; - - while (length > 0 && of_ascii_isspace(*characters)) { - characters++; - length--; - } - - if (length == 0) { - objc_autoreleasePoolPop(pool); - return 0; - } - - if (characters[0] == '-' || characters[0] == '+') - i++; - - for (; i < length; i++) { - if (expectWhitespace) { - if (of_ascii_isspace(characters[i])) - continue; - - @throw [OFInvalidFormatException exception]; - } - - if (characters[i] >= '0' && characters[i] <= '9') { - if (INTMAX_MAX / 10 < value || - INTMAX_MAX - value * 10 < characters[i] - '0') - @throw [OFOutOfRangeException exception]; - - value = (value * 10) + (characters[i] - '0'); - } else if (of_ascii_isspace(characters[i])) - expectWhitespace = true; - else - @throw [OFInvalidFormatException exception]; - } - - if (characters[0] == '-') - value *= -1; + const char *UTF8String = self.UTF8String; + char *endPointer = NULL; + long long value; + + errno = 0; + value = strtoll(UTF8String, &endPointer, base); + + if ((value == LLONG_MIN || value == LLONG_MAX) && errno == ERANGE) + @throw [OFOutOfRangeException exception]; + + /* Check if there are any invalid chars left */ + if (endPointer != NULL) + for (; *endPointer != '\0'; endPointer++) + /* Use isspace since strtoll uses the same. */ + if (!isspace((unsigned char)*endPointer)) + @throw [OFInvalidFormatException exception]; objc_autoreleasePoolPop(pool); return value; } -- (uintmax_t)hexadecimalValue -{ - void *pool = objc_autoreleasePoolPush(); - const of_unichar_t *characters = self.characters; - size_t i = 0, length = self.length; - uintmax_t value = 0; - bool expectWhitespace = false, foundValue = false; - - while (length > 0 && of_ascii_isspace(*characters)) { - characters++; - length--; - } - - if (length == 0) { - objc_autoreleasePoolPop(pool); - return 0; - } - - if (length >= 2 && characters[0] == '0' && characters[1] == 'x') - i = 2; - else if (length >= 1 && (characters[0] == 'x' || characters[0] == '$')) - i = 1; - - for (; i < length; i++) { - uintmax_t newValue; - - if (expectWhitespace) { - if (of_ascii_isspace(characters[i])) - continue; - - @throw [OFInvalidFormatException exception]; - } - - if (characters[i] >= '0' && characters[i] <= '9') { - newValue = (value << 4) | (characters[i] - '0'); - foundValue = true; - } else if (characters[i] >= 'A' && characters[i] <= 'F') { - newValue = (value << 4) | (characters[i] - 'A' + 10); - foundValue = true; - } else if (characters[i] >= 'a' && characters[i] <= 'f') { - newValue = (value << 4) | (characters[i] - 'a' + 10); - foundValue = true; - } else if (characters[i] == 'h' || - of_ascii_isspace(characters[i])) { - expectWhitespace = true; - continue; - } else - @throw [OFInvalidFormatException exception]; - - if (newValue < value) - @throw [OFOutOfRangeException exception]; - - value = newValue; - } - - if (!foundValue) - @throw [OFInvalidFormatException exception]; - - objc_autoreleasePoolPop(pool); - - return value; -} - -- (uintmax_t)octalValue -{ - void *pool = objc_autoreleasePoolPush(); - const of_unichar_t *characters = self.characters; - size_t i = 0, length = self.length; - uintmax_t value = 0; - bool expectWhitespace = false; - - while (length > 0 && of_ascii_isspace(*characters)) { - characters++; - length--; - } - - if (length == 0) { - objc_autoreleasePoolPop(pool); - return 0; - } - - for (; i < length; i++) { - uintmax_t newValue; - - if (expectWhitespace) { - if (of_ascii_isspace(characters[i])) - continue; - - @throw [OFInvalidFormatException exception]; - } - - if (characters[i] >= '0' && characters[i] <= '7') - newValue = (value << 3) | (characters[i] - '0'); - else if (of_ascii_isspace(characters[i])) { - expectWhitespace = true; - continue; - } else - @throw [OFInvalidFormatException exception]; - - if (newValue < value) - @throw [OFOutOfRangeException exception]; - - value = newValue; - } +- (unsigned long long)unsignedLongLongValue +{ + return [self unsignedLongLongValueWithBase: 10]; +} + +- (unsigned long long)unsignedLongLongValueWithBase: (int)base +{ + void *pool = objc_autoreleasePoolPush(); + const char *UTF8String = self.UTF8String; + char *endPointer = NULL; + unsigned long long value; + + /* Use isspace since strtoull uses the same. */ + while (isspace((unsigned char)*UTF8String)) + UTF8String++; + + if (*UTF8String == '-') + @throw [OFInvalidFormatException exception]; + + errno = 0; + value = strtoull(UTF8String, &endPointer, base); + + if (value == ULLONG_MAX && errno == ERANGE) + @throw [OFOutOfRangeException exception]; + + /* Check if there are any invalid chars left */ + if (endPointer != NULL) + for (; *endPointer != '\0'; endPointer++) + /* Use isspace since strtoull uses the same. */ + if (!isspace((unsigned char)*endPointer)) + @throw [OFInvalidFormatException exception]; objc_autoreleasePoolPop(pool); return value; } - (float)floatValue { void *pool = objc_autoreleasePoolPush(); - -#if defined(OF_AMIGAOS_M68K) || defined(OF_MORPHOS) OFString *stripped = self.stringByDeletingEnclosingWhitespaces; if ([stripped caseInsensitiveCompare: @"INF"] == OF_ORDERED_SAME || [stripped caseInsensitiveCompare: @"INFINITY"] == OF_ORDERED_SAME) return INFINITY; if ([stripped caseInsensitiveCompare: @"-INF"] == OF_ORDERED_SAME || [stripped caseInsensitiveCompare: @"-INFINITY"] == OF_ORDERED_SAME) return -INFINITY; -#endif #ifdef HAVE_STRTOF_L const char *UTF8String = self.UTF8String; #else /* @@ -2500,23 +2406,25 @@ withString: decimalPoint].UTF8String; #endif char *endPointer = NULL; float value; - while (of_ascii_isspace(*UTF8String)) - UTF8String++; - + errno = 0; #ifdef HAVE_STRTOF_L value = strtof_l(UTF8String, &endPointer, cLocale); #else value = strtof(UTF8String, &endPointer); #endif + + if (value == HUGE_VALF && errno == ERANGE) + @throw [OFOutOfRangeException exception]; /* Check if there are any invalid chars left */ if (endPointer != NULL) for (; *endPointer != '\0'; endPointer++) - if (!of_ascii_isspace(*endPointer)) + /* Use isspace since strtof uses the same. */ + if (!isspace((unsigned char)*endPointer)) @throw [OFInvalidFormatException exception]; objc_autoreleasePoolPop(pool); return value; @@ -2523,21 +2431,18 @@ } - (double)doubleValue { void *pool = objc_autoreleasePoolPush(); - -#if defined(OF_AMIGAOS_M68K) || defined(OF_MORPHOS) OFString *stripped = self.stringByDeletingEnclosingWhitespaces; if ([stripped caseInsensitiveCompare: @"INF"] == OF_ORDERED_SAME || [stripped caseInsensitiveCompare: @"INFINITY"] == OF_ORDERED_SAME) return INFINITY; if ([stripped caseInsensitiveCompare: @"-INF"] == OF_ORDERED_SAME || [stripped caseInsensitiveCompare: @"-INFINITY"] == OF_ORDERED_SAME) return -INFINITY; -#endif #ifdef HAVE_STRTOD_L const char *UTF8String = self.UTF8String; #else /* @@ -2550,23 +2455,25 @@ withString: decimalPoint].UTF8String; #endif char *endPointer = NULL; double value; - while (of_ascii_isspace(*UTF8String)) - UTF8String++; - + errno = 0; #ifdef HAVE_STRTOD_L value = strtod_l(UTF8String, &endPointer, cLocale); #else value = strtod(UTF8String, &endPointer); #endif + if (value == HUGE_VAL && errno == ERANGE) + @throw [OFOutOfRangeException exception]; + /* Check if there are any invalid chars left */ if (endPointer != NULL) for (; *endPointer != '\0'; endPointer++) - if (!of_ascii_isspace(*endPointer)) + /* Use isspace since strtod uses the same. */ + if (!isspace((unsigned char)*endPointer)) @throw [OFInvalidFormatException exception]; objc_autoreleasePoolPop(pool); return value; Index: src/OFSystemInfo.m ================================================================== --- src/OFSystemInfo.m +++ src/OFSystemInfo.m @@ -150,11 +150,11 @@ void *pool = objc_autoreleasePoolPush(); @try { OFDictionary *propertyList = [OFString stringWithContentsOfFile: @"/System/Library/CoreServices/SystemVersion.plist"] - .propertyListValue; + .objectByParsingPropertyList; operatingSystemVersion = [[propertyList objectForKey: @"ProductVersion"] copy]; } @finally { objc_autoreleasePoolPop(pool); Index: src/OFTarArchiveEntry.h ================================================================== --- src/OFTarArchiveEntry.h +++ src/OFTarArchiveEntry.h @@ -51,18 +51,18 @@ * @brief A class which represents an entry of a tar archive. */ @interface OFTarArchiveEntry: OFObject { OFString *_fileName; - uint32_t _mode; - uint64_t _size; - uint32_t _UID, _GID; + unsigned long _mode; + unsigned long long _size; + unsigned long _UID, _GID; OFDate *_modificationDate; of_tar_archive_entry_type_t _type; OFString *_Nullable _targetFileName; OFString *_Nullable _owner, *_Nullable _group; - uint32_t _deviceMajor, _deviceMinor; + unsigned long _deviceMajor, _deviceMinor; OF_RESERVE_IVARS(4) } /*! * @brief The file name of the entry. @@ -70,26 +70,26 @@ @property (readonly, copy, nonatomic) OFString *fileName; /*! * @brief The mode of the entry. */ -@property (readonly, nonatomic) uint32_t mode; +@property (readonly, nonatomic) unsigned long mode; /*! * @brief The UID of the owner. */ -@property (readonly, nonatomic) uint32_t UID; +@property (readonly, nonatomic) unsigned long UID; /*! * @brief The GID of the group. */ -@property (readonly, nonatomic) uint32_t GID; +@property (readonly, nonatomic) unsigned long GID; /*! * @brief The size of the file. */ -@property (readonly, nonatomic) uint64_t size; +@property (readonly, nonatomic) unsigned long long size; /*! * @brief The date of the last modification of the file. */ @property (readonly, retain, nonatomic) OFDate *modificationDate; @@ -118,16 +118,16 @@ @property OF_NULLABLE_PROPERTY (readonly, copy, nonatomic) OFString *group; /*! * @brief The device major (if the file is a device). */ -@property (readonly, nonatomic) uint32_t deviceMajor; +@property (readonly, nonatomic) unsigned long deviceMajor; /*! * @brief The device major (if the file is a device). */ -@property (readonly, nonatomic) uint32_t deviceMinor; +@property (readonly, nonatomic) unsigned long deviceMinor; /*! * @brief Creates a new OFTarArchiveEntry with the specified file name. * * @param fileName The file name for the OFTarArchiveEntry Index: src/OFTarArchiveEntry.m ================================================================== --- src/OFTarArchiveEntry.m +++ src/OFTarArchiveEntry.m @@ -51,24 +51,25 @@ 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) +static unsigned long long +octalValueFromBuffer(const unsigned char *buffer, size_t length, + unsigned long long max) { - uintmax_t value = 0; + unsigned long long value = 0; if (length == 0) return 0; if (buffer[0] == 0x80) { for (size_t i = 1; i < length; i++) value = (value << 8) | buffer[i]; } else - value = stringFromBuffer(buffer, length, - OF_STRING_ENCODING_ASCII).octalValue; + value = [stringFromBuffer(buffer, length, + OF_STRING_ENCODING_ASCII) unsignedLongLongValueWithBase: 8]; if (value > max) @throw [OFOutOfRangeException exception]; return value; @@ -93,22 +94,22 @@ @try { void *pool = objc_autoreleasePoolPush(); OFString *targetFileName; _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( - header + 116, 8, UINT32_MAX); - _size = (uint64_t)octalValueFromBuffer( - header + 124, 12, UINT64_MAX); + _mode = (unsigned long)octalValueFromBuffer( + header + 100, 8, ULONG_MAX); + _UID = (unsigned long)octalValueFromBuffer( + header + 108, 8, ULONG_MAX); + _GID = (unsigned long)octalValueFromBuffer( + header + 116, 8, ULONG_MAX); + _size = (unsigned long long)octalValueFromBuffer( + header + 124, 12, ULLONG_MAX); _modificationDate = [[OFDate alloc] initWithTimeIntervalSince1970: (of_time_interval_t)octalValueFromBuffer( - header + 136, 12, UINTMAX_MAX)]; + header + 136, 12, ULLONG_MAX)]; _type = header[156]; targetFileName = stringFromBuffer(header + 157, 100, encoding); if (targetFileName.length > 0) _targetFileName = [targetFileName copy]; @@ -122,14 +123,14 @@ _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); + _deviceMajor = (unsigned long)octalValueFromBuffer( + header + 329, 8, ULONG_MAX); + _deviceMinor = (unsigned long)octalValueFromBuffer( + header + 337, 8, ULONG_MAX); prefix = stringFromBuffer(header + 345, 155, encoding); if (prefix.length > 0) { OFString *fileName = [OFString stringWithFormat: @"%@/%@", @@ -206,26 +207,26 @@ - (OFString *)fileName { return _fileName; } -- (uint32_t)mode +- (unsigned long)mode { return _mode; } -- (uint32_t)UID +- (unsigned long)UID { return _UID; } -- (uint32_t)GID +- (unsigned long)GID { return _GID; } -- (uint64_t)size +- (unsigned long long)size { return _size; } - (OFDate *)modificationDate @@ -251,16 +252,16 @@ - (OFString *)group { return _group; } -- (uint32_t)deviceMajor +- (unsigned long)deviceMajor { return _deviceMajor; } -- (uint32_t)deviceMinor +- (unsigned long)deviceMinor { return _deviceMinor; } - (OFString *)description @@ -292,11 +293,11 @@ - (void)of_writeToStream: (OFStream *)stream encoding: (of_string_encoding_t)encoding { unsigned char buffer[512]; - uint64_t modificationDate; + unsigned long long modificationDate; uint16_t checksum = 0; stringToBuffer(buffer, _fileName, 100, encoding); stringToBuffer(buffer + 100, [OFString stringWithFormat: @"%06" PRIo16 " ", _mode], 8, @@ -310,11 +311,11 @@ stringToBuffer(buffer + 124, [OFString stringWithFormat: @"%011" PRIo64 " ", _size], 12, OF_STRING_ENCODING_ASCII); modificationDate = _modificationDate.timeIntervalSince1970; stringToBuffer(buffer + 136, - [OFString stringWithFormat: @"%011" PRIo64 " ", modificationDate], + [OFString stringWithFormat: @"%011llo", modificationDate], 12, OF_STRING_ENCODING_ASCII); /* * During checksumming, the checksum field is expected to be set to 8 * spaces. Index: src/OFURL.m ================================================================== --- src/OFURL.m +++ src/OFURL.m @@ -486,16 +486,16 @@ portString = [OFString stringWithUTF8String: tmp2 length: UTF8String - tmp2]; if (portString.length == 0 || - portString.decimalValue > 65535) + portString.unsignedLongLongValue > 65535) @throw [OFInvalidFormatException exception]; - _port = [[OFNumber alloc] initWithUInt16: - (uint16_t)portString.decimalValue]; + _port = [[OFNumber alloc] initWithUnsignedShort: + portString.unsignedLongLongValue]; } else if (*UTF8String != '\0') @throw [OFInvalidFormatException exception]; isIPv6Host = true; } else if ((tmp2 = strchr(UTF8String, ':')) != NULL) { @@ -507,15 +507,15 @@ _URLEncodedHost = [[OFString alloc] initWithUTF8String: UTF8String]; portString = [OFString stringWithUTF8String: tmp2]; - if (portString.decimalValue > 65535) + if (portString.unsignedLongLongValue > 65535) @throw [OFInvalidFormatException exception]; - _port = [[OFNumber alloc] initWithUInt16: - (uint16_t)portString.decimalValue]; + _port = [[OFNumber alloc] initWithUnsignedShort: + portString.unsignedLongLongValue]; } else _URLEncodedHost = [[OFString alloc] initWithUTF8String: UTF8String]; if (!isIPv6Host) Index: src/OFXMLNode.h ================================================================== --- src/OFXMLNode.h +++ src/OFXMLNode.h @@ -39,18 +39,18 @@ * single child with the specified string value. */ @property (nonatomic, copy) OFString *stringValue; /*! - * @brief The contents of the receiver as a decimal value. + * @brief The contents of the receiver as a `long long` value. */ -@property (readonly, nonatomic) intmax_t decimalValue; +@property (readonly, nonatomic) long long longLongValue; /*! - * @brief The contents of the receiver as a hexadecimal value. + * @brief The contents of the receiver as an `unsigned long long` value. */ -@property (readonly, nonatomic) uintmax_t hexadecimalValue; +@property (readonly, nonatomic) unsigned long long unsignedLongLongValue; /*! * @brief The contents of the receiver as a float value. */ @property (readonly, nonatomic) float floatValue; @@ -87,8 +87,34 @@ * @return An OFString representing the OFXMLNode as an XML string with * indentation */ - (OFString *)XMLStringWithIndentation: (unsigned int)indentation level: (unsigned int)level; + +/*! + * @brief The contents of the receiver as a `long long` value in the specified + * base. + * + * @param base The base to use. If the base is 0, base 16 is assumed if the + * string starts with 0x (after stripping white spaces). If the + * string starts with 0, base 8 is assumed. Otherwise, base 10 is + * assumed. + * @return The contents of the receiver as a `long long` value in the specified + * base + */ +- (long long)longLongValueWithBase: (int)base; + +/*! + * @brief The contents of the receiver as an `unsigned long long` value in the + * specified base. + * + * @param base The base to use. If the base is 0, base 16 is assumed if the + * string starts with 0x (after stripping white spaces). If the + * string starts with 0, base 8 is assumed. Otherwise, base 10 is + * assumed. + * @return The contents of the receiver as an `unsigned long long` value in the + * specified base + */ +- (unsigned long long)unsignedLongLongValueWithBase: (int)base; @end OF_ASSUME_NONNULL_END Index: src/OFXMLNode.m ================================================================== --- src/OFXMLNode.m +++ src/OFXMLNode.m @@ -44,18 +44,28 @@ - (void)setStringValue: (OFString *)stringValue { OF_UNRECOGNIZED_SELECTOR } -- (intmax_t)decimalValue +- (long long)longLongValue +{ + return self.stringValue.longLongValue; +} + +- (long long)longLongValueWithBase: (int)base +{ + return [self.stringValue longLongValueWithBase: base]; +} + +- (unsigned long long)unsignedLongLongValue { - return self.stringValue.decimalValue; + return self.stringValue.unsignedLongLongValue; } -- (uintmax_t)hexadecimalValue +- (unsigned long long)unsignedLongLongValueWithBase: (int)base { - return self.stringValue.hexadecimalValue; + return [self.stringValue unsignedLongLongValueWithBase: base]; } - (float)floatValue { return self.stringValue.floatValue; Index: src/bridge/Info.plist.in ================================================================== --- src/bridge/Info.plist.in +++ src/bridge/Info.plist.in @@ -5,11 +5,11 @@ CFBundleExecutable ObjFWBridge CFBundleName ObjFWBridge CFBundleIdentifier - zone.heap.objfw.bridge + im.nil.objfw.bridge CFBundleInfoDictionaryVersion 6.0 CFBundlePackageType FMWK CFBundleVersion ADDED src/runtime/Info.plist.in Index: src/runtime/Info.plist.in ================================================================== --- src/runtime/Info.plist.in +++ src/runtime/Info.plist.in @@ -0,0 +1,22 @@ + + + + + CFBundleExecutable + ObjFWRT + CFBundleName + ObjFWRT + CFBundleIdentifier + im.nil.objfw.rt + CFBundleInfoDictionaryVersion + 6.0 + CFBundlePackageType + FMWK + CFBundleVersion + @BUNDLE_VERSION@ + CFBundleShortVersionString + @BUNDLE_SHORT_VERSION@ + MinimumOSVersion + 9.0 + + Index: src/runtime/Makefile ================================================================== --- src/runtime/Makefile +++ src/runtime/Makefile @@ -1,10 +1,11 @@ include ../../extra.mk SUBDIRS = lookup-asm SUBDIRS_AFTER = ${LINKLIB} CLEAN = amiga-library-functable.inc inline.h +DISTCLEAN = Info.plist SHARED_LIB = ${OBJFWRT_SHARED_LIB} STATIC_LIB = ${OBJFWRT_STATIC_LIB} FRAMEWORK = ${OBJFWRT_FRAMEWORK} AMIGA_LIB = ${OBJFWRT_AMIGA_LIB} Index: src/socket.m ================================================================== --- src/socket.m +++ src/socket.m @@ -374,22 +374,22 @@ @throw [OFInvalidFormatException exception]; addr = 0; for (OFString *component in components) { - intmax_t number; + unsigned long long number; if (component.length == 0) @throw [OFInvalidFormatException exception]; if ([component indexOfCharacterFromSet: whitespaceCharacterSet] != OF_NOT_FOUND) @throw [OFInvalidFormatException exception]; - number = component.decimalValue; + number = component.unsignedLongLongValue; - if (number < 0 || number > UINT8_MAX) + if (number > UINT8_MAX) @throw [OFInvalidFormatException exception]; addr = (addr << 8) | (number & 0xFF); } @@ -401,17 +401,17 @@ } static uint16_t parseIPv6Component(OFString *component) { - uintmax_t number; + unsigned long long number; if ([component indexOfCharacterFromSet: [OFCharacterSet whitespaceCharacterSet]] != OF_NOT_FOUND) @throw [OFInvalidFormatException exception]; - number = component.hexadecimalValue; + number = [component unsignedLongLongValueWithBase: 16]; if (number > UINT16_MAX) @throw [OFInvalidFormatException exception]; return (uint16_t)number; Index: tests/Info.plist.in ================================================================== --- tests/Info.plist.in +++ tests/Info.plist.in @@ -11,13 +11,13 @@ CFBundleInfoDictionaryVersion 6.0 CFBundlePackageType APPL CFBundleVersion - @PACKAGE_VERSION@ + @BUNDLE_VERSION@ CFBundleShortVersionString - @PACKAGE_VERSION@ + @BUNDLE_SHORT_VERSION@ LSRequiresIPhoneOS UILaunchStoryboardName LaunchScreen UIMainStoryboardFile Index: tests/Makefile ================================================================== --- tests/Makefile +++ tests/Makefile @@ -9,12 +9,12 @@ DISTCLEAN = Info.plist PROG_NOINST = tests${PROG_SUFFIX} STATIC_LIB_NOINST = ${TESTS_STATIC_LIB} SRCS = ForwardingTests.m \ + OFASN1DERParsingTests.m \ OFASN1DERRepresentationTests.m \ - OFASN1DERValueTests.m \ OFArrayTests.m \ ${OF_BLOCK_TESTS_M} \ OFCharacterSetTests.m \ OFDataTests.m \ OFDateTests.m \ ADDED tests/OFASN1DERParsingTests.m Index: tests/OFASN1DERParsingTests.m ================================================================== --- tests/OFASN1DERParsingTests.m +++ tests/OFASN1DERParsingTests.m @@ -0,0 +1,483 @@ +/* + * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, + * 2018, 2019, 2020 + * 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 "TestsAppDelegate.h" + +static OFString *module = @"OFData+ASN1DERParsing"; + +@implementation TestsAppDelegate (OFASN1DERParsingTests) +- (void)ASN1DERParsingTests +{ + void *pool = objc_autoreleasePoolPush(); + OFASN1BitString *bitString; + OFArray *array; + OFSet *set; + OFEnumerator *enumerator; + + /* Boolean */ + TEST(@"Parsing of boolean", + ![[[OFData dataWithItems: "\x01\x01\x00" + count: 3] objectByParsingASN1DER] + booleanValue] && + [[[OFData dataWithItems: "\x01\x01\xFF" + count: 3] objectByParsingASN1DER] booleanValue]) + + EXPECT_EXCEPTION(@"Detection of invalid boolean #1", + OFInvalidFormatException, + [[OFData dataWithItems: "\x01\x01\x01" + count: 3] objectByParsingASN1DER]) + + EXPECT_EXCEPTION(@"Detection of invalid boolean #2", + OFInvalidFormatException, + [[OFData dataWithItems: "\x01\x02\x00\x00" + count: 4] objectByParsingASN1DER]) + + EXPECT_EXCEPTION(@"Detection of invalid boolean #3", + OFInvalidFormatException, + [[OFData dataWithItems: "\x01\x00" + count: 2] objectByParsingASN1DER]) + + EXPECT_EXCEPTION(@"Detection of truncated boolean", + OFTruncatedDataException, + [[OFData dataWithItems: "\x01\x01" + count: 2] objectByParsingASN1DER]) + + /* Integer */ + TEST(@"Parsing of integer", + [[[OFData dataWithItems: "\x02\x00" + count: 2] objectByParsingASN1DER] + longLongValue] == 0 && + [[[OFData dataWithItems: "\x02\x01\x01" + count: 3] objectByParsingASN1DER] + longLongValue] == 1 && + [[[OFData dataWithItems: "\x02\x02\x01\x04" + count: 4] objectByParsingASN1DER] + longLongValue] == 260 && + [[[OFData dataWithItems: "\x02\x01\xFF" + count: 3] objectByParsingASN1DER] + longLongValue] == -1 && + [[[OFData dataWithItems: "\x02\x03\xFF\x00\x00" + count: 5] objectByParsingASN1DER] + longLongValue] == -65536 && + (unsigned long long)[[[OFData dataWithItems: "\x02\x09\x00\xFF\xFF" + "\xFF\xFF\xFF\xFF\xFF" + "\xFF" + count: 11] + objectByParsingASN1DER] longLongValue] == ULLONG_MAX) + + EXPECT_EXCEPTION(@"Detection of invalid integer #1", + OFInvalidFormatException, + [[OFData dataWithItems: "\x02\x02\x00\x00" + count: 4] objectByParsingASN1DER]) + + EXPECT_EXCEPTION(@"Detection of invalid integer #2", + OFInvalidFormatException, + [[OFData dataWithItems: "\x02\x02\x00\x7F" + count: 4] objectByParsingASN1DER]) + + EXPECT_EXCEPTION(@"Detection of invalid integer #3", + OFInvalidFormatException, + [[OFData dataWithItems: "\x02\x02\xFF\x80" + count: 4] objectByParsingASN1DER]) + + EXPECT_EXCEPTION(@"Detection of out of range integer", + OFOutOfRangeException, + [[OFData dataWithItems: "\x02\x09\x01" + "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF" + count: 11] objectByParsingASN1DER]) + + EXPECT_EXCEPTION(@"Detection of truncated integer", + OFTruncatedDataException, + [[OFData dataWithItems: "\x02\x02\x00" + count: 3] objectByParsingASN1DER]) + + /* Bit string */ + TEST(@"Parsing of bit string", + (bitString = [[OFData dataWithItems: "\x03\x01\x00" + count: 3] objectByParsingASN1DER]) && + [bitString.bitStringValue isEqual: [OFData dataWithItems: "" + count: 0]] && + bitString.bitStringLength == 0 && + (bitString = [[OFData dataWithItems: "\x03\x0D\x01Hello World\x80" + count: 15] objectByParsingASN1DER]) && + [bitString.bitStringValue + isEqual: [OFData dataWithItems: "Hello World\x80" + count: 12]] && + bitString.bitStringLength == 95 && + (bitString = [[OFData dataWithItems: "\x03\x81\x80\x00xxxxxxxxxxxxx" + "xxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + "xxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + "xxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + "xxxxxxxxxxxxxxxxxxxxxxxxxxx" + count: 131] objectByParsingASN1DER]) && + [bitString.bitStringValue + isEqual: [OFData dataWithItems: "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + "xxxxxxxxxxxxxxxxxxxxxxxxx" + count: 127]] && + bitString.bitStringLength == 127 * 8) + + EXPECT_EXCEPTION(@"Detection of invalid bit string #1", + OFInvalidFormatException, + [[OFData dataWithItems: "\x03\x00" + count: 2] objectByParsingASN1DER]) + + EXPECT_EXCEPTION(@"Detection of invalid bit string #2", + OFInvalidFormatException, + [[OFData dataWithItems: "\x03\x01\x01" + count: 3] objectByParsingASN1DER]) + + EXPECT_EXCEPTION(@"Detection of out of range bit string", + OFOutOfRangeException, + [[OFData dataWithItems: "\x03\x89" + "\x01\x01\x01\x01\x01\x01\x01\x01\x01" + count: 11] objectByParsingASN1DER]) + + EXPECT_EXCEPTION(@"Detection of truncated bit string", + OFTruncatedDataException, + [[OFData dataWithItems: "\x03\x01" + count: 2] objectByParsingASN1DER]) + + /* Octet string */ + TEST(@"Parsing of octet string", + [[[[OFData dataWithItems: "\x04\x0CHello World!" + count: 14] objectByParsingASN1DER] + octetStringValue] isEqual: [OFData dataWithItems: "Hello World!" + count: 12]] && + [[[[OFData dataWithItems: "\x04\x81\x80xxxxxxxxxxxxxxxxxxxxxxxxxxxx" + "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + "xxxxxxxxxxxxxxxxxxxx" + count: 131] objectByParsingASN1DER] + octetStringValue] isEqual: + [OFData dataWithItems: "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + count: 128]]) + + EXPECT_EXCEPTION(@"Detection of out of range octet string", + OFOutOfRangeException, + [[OFData dataWithItems: "\x04\x89" + "\x01\x01\x01\x01\x01\x01\x01\x01\x01" + count: 11] objectByParsingASN1DER]) + + EXPECT_EXCEPTION(@"Detection of truncated octet string", + OFTruncatedDataException, + [[OFData dataWithItems: "\x04\x01" + count: 2] objectByParsingASN1DER]) + + /* Null */ + TEST(@"Parsing of null", + [[[OFData dataWithItems: "\x05\x00" + count: 2] objectByParsingASN1DER] + isEqual: [OFNull null]]) + + EXPECT_EXCEPTION(@"Detection of invalid null", + OFInvalidFormatException, + [[OFData dataWithItems: "\x05\x01\x00" + count: 3] objectByParsingASN1DER]) + + /* Object Identifier */ + TEST(@"Parsing of Object Identifier", + (array = [[[OFData dataWithItems: "\x06\x01\x27" + count: 3] objectByParsingASN1DER] + subidentifiers]) && array.count == 2 && + [[array objectAtIndex: 0] unsignedLongLongValue] == 0 && + [[array objectAtIndex: 1] unsignedLongLongValue] == 39 && + (array = [[[OFData dataWithItems: "\x06\x01\x4F" + count: 3] objectByParsingASN1DER] + subidentifiers]) && array.count == 2 && + [[array objectAtIndex: 0] unsignedLongLongValue] == 1 && + [[array objectAtIndex: 1] unsignedLongLongValue] == 39 && + (array = [[[OFData dataWithItems: "\x06\x02\x88\x37" + count: 4] objectByParsingASN1DER] + subidentifiers]) && array.count == 2 && + [[array objectAtIndex: 0] unsignedLongLongValue] == 2 && + [[array objectAtIndex: 1] unsignedLongLongValue] == 999 && + (array = [[[OFData dataWithItems: "\x06\x09\x2A\x86\x48\x86\xF7\x0D" + "\x01\x01\x0B" + count: 11] objectByParsingASN1DER] + subidentifiers]) && array.count == 7 && + [[array objectAtIndex: 0] unsignedLongLongValue] == 1 && + [[array objectAtIndex: 1] unsignedLongLongValue] == 2 && + [[array objectAtIndex: 2] unsignedLongLongValue] == 840 && + [[array objectAtIndex: 3] unsignedLongLongValue] == 113549 && + [[array objectAtIndex: 4] unsignedLongLongValue] == 1 && + [[array objectAtIndex: 5] unsignedLongLongValue] == 1 && + [[array objectAtIndex: 6] unsignedLongLongValue] == 11) + + EXPECT_EXCEPTION(@"Detection of invalid Object Identifier #1", + OFInvalidFormatException, + [[OFData dataWithItems: "\x06\x01\x81" + count: 3] objectByParsingASN1DER]) + + EXPECT_EXCEPTION(@"Detection of invalid Object Identifier #2", + OFInvalidFormatException, + [[OFData dataWithItems: "\x06\x02\x80\x01" + count: 4] objectByParsingASN1DER]) + + EXPECT_EXCEPTION(@"Detection of out of range Object Identifier", + OFOutOfRangeException, + [[OFData dataWithItems: "\x06\x0A\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF" + "\xFF\x7F" + count: 12] objectByParsingASN1DER]) + + EXPECT_EXCEPTION(@"Detection of truncated Object Identifier", + OFTruncatedDataException, + [[OFData dataWithItems: "\x06\x02\x00" + count: 3] objectByParsingASN1DER]) + + /* Enumerated */ + TEST(@"Parsing of enumerated", + [[[OFData dataWithItems: "\x0A\x00" + count: 2] objectByParsingASN1DER] longLongValue] == + 0 && + [[[OFData dataWithItems: "\x0A\x01\x01" + count: 3] objectByParsingASN1DER] longLongValue] == + 1 && + [[[OFData dataWithItems: "\x0A\x02\x01\x04" + count: 4] objectByParsingASN1DER] longLongValue] == + 260 && + [[[OFData dataWithItems: "\x0A\x01\xFF" + count: 3] objectByParsingASN1DER] longLongValue] == + -1 && + [[[OFData dataWithItems: "\x0A\x03\xFF\x00\x00" + count: 5] objectByParsingASN1DER] longLongValue] == + -65536 && + (unsigned long long)[[[OFData dataWithItems: "\x0A\x09\x00\xFF\xFF" + "\xFF\xFF\xFF\xFF\xFF" + "\xFF" + count: 11] + objectByParsingASN1DER] longLongValue] == ULLONG_MAX) + + EXPECT_EXCEPTION(@"Detection of invalid enumerated #1", + OFInvalidFormatException, + [[OFData dataWithItems: "\x0A\x02\x00\x00" + count: 4] objectByParsingASN1DER]) + + EXPECT_EXCEPTION(@"Detection of invalid enumerated #2", + OFInvalidFormatException, + [[OFData dataWithItems: "\x0A\x02\x00\x7F" + count: 4] objectByParsingASN1DER]) + + EXPECT_EXCEPTION(@"Detection of invalid enumerated #3", + OFInvalidFormatException, + [[OFData dataWithItems: "\x0A\x02\xFF\x80" + count: 4] objectByParsingASN1DER]) + + EXPECT_EXCEPTION(@"Detection of out of range enumerated", + OFOutOfRangeException, + [[OFData dataWithItems: "\x0A\x09\x01" + "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF" + count: 11] objectByParsingASN1DER]) + + EXPECT_EXCEPTION(@"Detection of truncated enumerated", + OFTruncatedDataException, + [[OFData dataWithItems: "\x0A\x02\x00" + count: 3] objectByParsingASN1DER]) + + /* UTF-8 string */ + TEST(@"Parsing of UTF-8 string", + [[[[OFData dataWithItems: "\x0C\x0EHällo Wörld!" + count: 16] objectByParsingASN1DER] + UTF8StringValue] isEqual: @"Hällo Wörld!"] && + [[[[OFData dataWithItems: "\x0C\x81\x80xxxxxxxxxxxxxxxxxxxxxxxxxxxx" + "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + "xxxxxxxxxxxxxxxxxxxx" + count: 131] objectByParsingASN1DER] + UTF8StringValue] isEqual: @"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + @"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + @"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + @"xxxxxxxxxxx"]) + + EXPECT_EXCEPTION(@"Detection of out of range UTF-8 string", + OFOutOfRangeException, + [[OFData dataWithItems: "\x0C\x89" + "\x01\x01\x01\x01\x01\x01\x01\x01\x01" + count: 11] objectByParsingASN1DER]) + + EXPECT_EXCEPTION(@"Detection of truncated UTF-8 string", + OFTruncatedDataException, + [[OFData dataWithItems: "\x0C\x01" + count: 2] objectByParsingASN1DER]) + + EXPECT_EXCEPTION(@"Detection of truncated length", + OFTruncatedDataException, + [[OFData dataWithItems: "\x0C\x83\x01\x01" + count: 4] objectByParsingASN1DER]) + + EXPECT_EXCEPTION(@"Detection of invalid / inefficient length #1", + OFInvalidFormatException, + [[OFData dataWithItems: "\x0C\x81\x7F" + count: 3] objectByParsingASN1DER]) + + EXPECT_EXCEPTION(@"Detection of invalid / inefficient length #2", + OFInvalidFormatException, + [[OFData dataWithItems: "\x0C\x82\x00\x80xxxxxxxxxxxxxxxxxxxxxxxxxx" + "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + "xxxxxxxxxxxxxxxxxx" + count: 132] objectByParsingASN1DER]) + + /* Sequence */ + TEST(@"Parsing of sequence", + (array = [[OFData dataWithItems: "\x30\x00" + count: 2] objectByParsingASN1DER]) && + [array isKindOfClass: [OFArray class]] && array.count == 0 && + (array = [[OFData dataWithItems: "\x30\x09\x02\x01\x7B\x0C\x04Test" + count: 11] objectByParsingASN1DER]) && + [array isKindOfClass: [OFArray class]] && array.count == 2 && + [[array objectAtIndex: 0] longLongValue] == 123 && + [[[array objectAtIndex: 1] stringValue] isEqual: @"Test"]) + + EXPECT_EXCEPTION(@"Detection of truncated sequence #1", + OFTruncatedDataException, + [[OFData dataWithItems: "\x30\x01" + count: 2] objectByParsingASN1DER]) + + EXPECT_EXCEPTION(@"Detection of truncated sequence #2", + OFTruncatedDataException, + [[OFData dataWithItems: "\x30\x04\x02\x01\x01\x00\x00" + count: 7] objectByParsingASN1DER]) + + /* Set */ + TEST(@"Parsing of set", + (set = [[OFData dataWithItems: "\x31\x00" + count: 2] objectByParsingASN1DER]) && + [set isKindOfClass: [OFSet class]] && set.count == 0 && + (set = [[OFData dataWithItems: "\x31\x09\x02\x01\x7B\x0C\x04Test" + count: 11] objectByParsingASN1DER]) && + [set isKindOfClass: [OFSet class]] && set.count == 2 && + (enumerator = [set objectEnumerator]) && + [[enumerator nextObject] longLongValue] == 123 && + [[[enumerator nextObject] stringValue] isEqual: @"Test"]) + + EXPECT_EXCEPTION(@"Detection of invalid set", + OFInvalidFormatException, + [[OFData dataWithItems: "\x31\x06\x02\x01\x02\x02\x01\x01" + count: 8] objectByParsingASN1DER]) + + EXPECT_EXCEPTION(@"Detection of truncated set #1", + OFTruncatedDataException, + [[OFData dataWithItems: "\x31\x01" + count: 2] objectByParsingASN1DER]) + + EXPECT_EXCEPTION(@"Detection of truncated set #2", + OFTruncatedDataException, + [[OFData dataWithItems: "\x31\x04\x02\x01\x01\x00\x00" + count: 7] objectByParsingASN1DER]) + + /* NumericString */ + TEST(@"Parsing of NumericString", + [[[[OFData dataWithItems: "\x12\x0B" "12345 67890" + count: 13] objectByParsingASN1DER] + numericStringValue] isEqual: @"12345 67890"] && + [[[[OFData dataWithItems: "\x12\x81\x80" "0000000000000000000000000" + "0000000000000000000000000000000000000000" + "0000000000000000000000000000000000000000" + "00000000000000000000000" + count: 131] objectByParsingASN1DER] + numericStringValue] isEqual: @"000000000000000000000000000000000000" + @"000000000000000000000000000000000000" + @"000000000000000000000000000000000000" + @"00000000000000000000"]) + + EXPECT_EXCEPTION(@"Detection of invalid NumericString", + OFInvalidEncodingException, + [[OFData dataWithItems: "\x12\x02." + count: 4] objectByParsingASN1DER]) + + EXPECT_EXCEPTION(@"Detection of out of range NumericString", + OFOutOfRangeException, + [[OFData dataWithItems: "\x12\x89" + "\x01\x01\x01\x01\x01\x01\x01\x01\x01" + count: 11] objectByParsingASN1DER]) + + EXPECT_EXCEPTION(@"Detection of truncated NumericString", + OFTruncatedDataException, + [[OFData dataWithItems: "\x12\x01" + count: 2] objectByParsingASN1DER]) + + /* PrintableString */ + TEST(@"Parsing of PrintableString", + [[[[OFData dataWithItems: "\x13\x0CHello World." + count: 14] objectByParsingASN1DER] + printableStringValue] isEqual: @"Hello World."] && + [[[[OFData dataWithItems: "\x13\x81\x80 '()+,-./:=?abcdefghijklmnop" + "qrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ '()" + "+,-./:=?abcdefghijklmnopqrstuvwxyzABCDEF" + "GHIJKLMNOPQRSTUVWXYZ" + count: 131] objectByParsingASN1DER] + printableStringValue] isEqual: @" '()+,-./:=?abcdefghijklmnopqrstuv" + @"wxyzABCDEFGHIJKLMNOPQRSTUVWXYZ '()" + @"+,-./:=?abcdefghijklmnopqrstuvwxyz" + @"ABCDEFGHIJKLMNOPQRSTUVWXYZ"]) + + EXPECT_EXCEPTION(@"Detection of invalid PrintableString", + OFInvalidEncodingException, + [[OFData dataWithItems: "\x13\x02;" + count: 4] objectByParsingASN1DER]) + + EXPECT_EXCEPTION(@"Detection of out of range PrintableString", + OFOutOfRangeException, + [[OFData dataWithItems: "\x13\x89" + "\x01\x01\x01\x01\x01\x01\x01\x01\x01" + count: 11] objectByParsingASN1DER]) + + EXPECT_EXCEPTION(@"Detection of truncated PrintableString", + OFTruncatedDataException, + [[OFData dataWithItems: "\x13\x01" + count: 2] objectByParsingASN1DER]) + + /* IA5String */ + TEST(@"Parsing of IA5String", + [[[[OFData dataWithItems: "\x16\x0CHello World!" + count: 14] objectByParsingASN1DER] + IA5StringValue] isEqual: @"Hello World!"] && + [[[[OFData dataWithItems: "\x16\x81\x80xxxxxxxxxxxxxxxxxxxxxxxxxxxx" + "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + "xxxxxxxxxxxxxxxxxxxx" + count: 131] objectByParsingASN1DER] + IA5StringValue] isEqual: @"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + @"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + @"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + @"xxxxxxxx"]) + + EXPECT_EXCEPTION(@"Detection of invalid IA5String", + OFInvalidEncodingException, + [[OFData dataWithItems: "\x16\x02ä" + count: 4] objectByParsingASN1DER]) + + EXPECT_EXCEPTION(@"Detection of out of range IA5String", + OFOutOfRangeException, + [[OFData dataWithItems: "\x16\x89" + "\x01\x01\x01\x01\x01\x01\x01\x01\x01" + count: 11] objectByParsingASN1DER]) + + EXPECT_EXCEPTION(@"Detection of truncated IA5String", + OFTruncatedDataException, + [[OFData dataWithItems: "\x16\x01" + count: 2] objectByParsingASN1DER]) + + objc_autoreleasePoolPop(pool); +} +@end DELETED tests/OFASN1DERValueTests.m Index: tests/OFASN1DERValueTests.m ================================================================== --- tests/OFASN1DERValueTests.m +++ tests/OFASN1DERValueTests.m @@ -1,437 +0,0 @@ -/* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * 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 "TestsAppDelegate.h" - -static OFString *module = @"OFData+ASN1DERValue"; - -@implementation TestsAppDelegate (OFASN1DERValueTests) -- (void)ASN1DERValueTests -{ - void *pool = objc_autoreleasePoolPush(); - OFASN1BitString *bitString; - OFArray *array; - OFSet *set; - OFEnumerator *enumerator; - - /* Boolean */ - TEST(@"Parsing of boolean", - ![[[OFData dataWithItems: "\x01\x01\x00" - count: 3] ASN1DERValue] booleanValue] && - [[[OFData dataWithItems: "\x01\x01\xFF" - count: 3] ASN1DERValue] booleanValue]) - - EXPECT_EXCEPTION(@"Detection of invalid boolean #1", - OFInvalidFormatException, [[OFData dataWithItems: "\x01\x01\x01" - count: 3] ASN1DERValue]) - - EXPECT_EXCEPTION(@"Detection of invalid boolean #2", - OFInvalidFormatException, [[OFData dataWithItems: "\x01\x02\x00\x00" - count: 4] ASN1DERValue]) - - EXPECT_EXCEPTION(@"Detection of invalid boolean #3", - OFInvalidFormatException, [[OFData dataWithItems: "\x01\x00" - count: 2] ASN1DERValue]) - - EXPECT_EXCEPTION(@"Detection of truncated boolean", - OFTruncatedDataException, [[OFData dataWithItems: "\x01\x01" - count: 2] ASN1DERValue]) - - /* Integer */ - TEST(@"Parsing of integer", - [[[OFData dataWithItems: "\x02\x00" - count: 2] ASN1DERValue] integerValue] == 0 && - [[[OFData dataWithItems: "\x02\x01\x01" - count: 3] ASN1DERValue] integerValue] == 1 && - [[[OFData dataWithItems: "\x02\x02\x01\x04" - count: 4] ASN1DERValue] integerValue] == 260 && - [[[OFData dataWithItems: "\x02\x01\xFF" - count: 3] ASN1DERValue] integerValue] == -1 && - [[[OFData dataWithItems: "\x02\x03\xFF\x00\x00" - count: 5] ASN1DERValue] integerValue] == -65536 && - (uintmax_t)[[[OFData dataWithItems: "\x02\x09\x00\xFF\xFF\xFF\xFF" - "\xFF\xFF\xFF\xFF" - count: 11] ASN1DERValue] - integerValue] == UINTMAX_MAX) - - EXPECT_EXCEPTION(@"Detection of invalid integer #1", - OFInvalidFormatException, [[OFData dataWithItems: "\x02\x02\x00\x00" - count: 4] ASN1DERValue]) - - EXPECT_EXCEPTION(@"Detection of invalid integer #2", - OFInvalidFormatException, [[OFData dataWithItems: "\x02\x02\x00\x7F" - count: 4] ASN1DERValue]) - - EXPECT_EXCEPTION(@"Detection of invalid integer #3", - OFInvalidFormatException, [[OFData dataWithItems: "\x02\x02\xFF\x80" - count: 4] ASN1DERValue]) - - EXPECT_EXCEPTION(@"Detection of out of range integer", - OFOutOfRangeException, - [[OFData dataWithItems: "\x02\x09\x01" - "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF" - count: 11] ASN1DERValue]) - - EXPECT_EXCEPTION(@"Detection of truncated integer", - OFTruncatedDataException, [[OFData dataWithItems: "\x02\x02\x00" - count: 3] ASN1DERValue]) - - /* Bit string */ - TEST(@"Parsing of bit string", - (bitString = [[OFData dataWithItems: "\x03\x01\x00" - count: 3] ASN1DERValue]) && - [bitString.bitStringValue isEqual: [OFData dataWithItems: "" - count: 0]] && - bitString.bitStringLength == 0 && - (bitString = [[OFData dataWithItems: "\x03\x0D\x01Hello World\x80" - count: 15] ASN1DERValue]) && - [bitString.bitStringValue - isEqual: [OFData dataWithItems: "Hello World\x80" - count: 12]] && - bitString.bitStringLength == 95 && - (bitString = [[OFData dataWithItems: "\x03\x81\x80\x00xxxxxxxxxxxxx" - "xxxxxxxxxxxxxxxxxxxxxxxxxxxxx" - "xxxxxxxxxxxxxxxxxxxxxxxxxxxxx" - "xxxxxxxxxxxxxxxxxxxxxxxxxxxxx" - "xxxxxxxxxxxxxxxxxxxxxxxxxxx" - count: 131] ASN1DERValue]) && - [bitString.bitStringValue - isEqual: [OFData dataWithItems: "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" - "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" - "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" - "xxxxxxxxxxxxxxxxxxxxxxxxx" - count: 127]] && - bitString.bitStringLength == 127 * 8) - - EXPECT_EXCEPTION(@"Detection of invalid bit string #1", - OFInvalidFormatException, [[OFData dataWithItems: "\x03\x00" - count: 2] ASN1DERValue]) - - EXPECT_EXCEPTION(@"Detection of invalid bit string #2", - OFInvalidFormatException, [[OFData dataWithItems: "\x03\x01\x01" - count: 3] ASN1DERValue]) - - EXPECT_EXCEPTION(@"Detection of out of range bit string", - OFOutOfRangeException, - [[OFData dataWithItems: "\x03\x89" - "\x01\x01\x01\x01\x01\x01\x01\x01\x01" - count: 11] ASN1DERValue]) - - EXPECT_EXCEPTION(@"Detection of truncated bit string", - OFTruncatedDataException, [[OFData dataWithItems: "\x03\x01" - count: 2] ASN1DERValue]) - - /* Octet string */ - TEST(@"Parsing of octet string", - [[[[OFData dataWithItems: "\x04\x0CHello World!" - count: 14] ASN1DERValue] octetStringValue] - isEqual: [OFData dataWithItems: "Hello World!" - count: 12]] && - [[[[OFData dataWithItems: "\x04\x81\x80xxxxxxxxxxxxxxxxxxxxxxxxxxxx" - "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" - "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" - "xxxxxxxxxxxxxxxxxxxx" - count: 131] ASN1DERValue] octetStringValue] - isEqual: [OFData dataWithItems: "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" - "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" - "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" - "xxxxxxxxxxxxxxxxxxxxxxxxxx" - count: 128]]) - - EXPECT_EXCEPTION(@"Detection of out of range octet string", - OFOutOfRangeException, - [[OFData dataWithItems: "\x04\x89" - "\x01\x01\x01\x01\x01\x01\x01\x01\x01" - count: 11] ASN1DERValue]) - - EXPECT_EXCEPTION(@"Detection of truncated octet string", - OFTruncatedDataException, [[OFData dataWithItems: "\x04\x01" - count: 2] ASN1DERValue]) - - /* Null */ - TEST(@"Parsing of null", - [[[OFData dataWithItems: "\x05\x00" - count: 2] ASN1DERValue] isEqual: [OFNull null]]) - - EXPECT_EXCEPTION(@"Detection of invalid null", - OFInvalidFormatException, [[OFData dataWithItems: "\x05\x01\x00" - count: 3] ASN1DERValue]) - - /* Object Identifier */ - TEST(@"Parsing of Object Identifier", - (array = [[[OFData dataWithItems: "\x06\x01\x27" - count: 3] ASN1DERValue] - subidentifiers]) && array.count == 2 && - [[array objectAtIndex: 0] uIntMaxValue] == 0 && - [[array objectAtIndex: 1] uIntMaxValue] == 39 && - (array = [[[OFData dataWithItems: "\x06\x01\x4F" - count: 3] ASN1DERValue] - subidentifiers]) && array.count == 2 && - [[array objectAtIndex: 0] uIntMaxValue] == 1 && - [[array objectAtIndex: 1] uIntMaxValue] == 39 && - (array = [[[OFData dataWithItems: "\x06\x02\x88\x37" - count: 4] ASN1DERValue] - subidentifiers]) && array.count == 2 && - [[array objectAtIndex: 0] uIntMaxValue] == 2 && - [[array objectAtIndex: 1] uIntMaxValue] == 999 && - (array = [[[OFData dataWithItems: "\x06\x09\x2A\x86\x48\x86\xF7\x0D" - "\x01\x01\x0B" - count: 11] ASN1DERValue] - subidentifiers]) && array.count == 7 && - [[array objectAtIndex: 0] uIntMaxValue] == 1 && - [[array objectAtIndex: 1] uIntMaxValue] == 2 && - [[array objectAtIndex: 2] uIntMaxValue] == 840 && - [[array objectAtIndex: 3] uIntMaxValue] == 113549 && - [[array objectAtIndex: 4] uIntMaxValue] == 1 && - [[array objectAtIndex: 5] uIntMaxValue] == 1 && - [[array objectAtIndex: 6] uIntMaxValue] == 11) - - EXPECT_EXCEPTION(@"Detection of invalid Object Identifier #1", - OFInvalidFormatException, [[OFData dataWithItems: "\x06\x01\x81" - count: 3] ASN1DERValue]) - - EXPECT_EXCEPTION(@"Detection of invalid Object Identifier #2", - OFInvalidFormatException, [[OFData dataWithItems: "\x06\x02\x80\x01" - count: 4] ASN1DERValue]) - - EXPECT_EXCEPTION(@"Detection of out of range Object Identifier", - OFOutOfRangeException, - [[OFData dataWithItems: "\x06\x0A\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF" - "\xFF\x7F" - count: 12] ASN1DERValue]) - - EXPECT_EXCEPTION(@"Detection of truncated Object Identifier", - OFTruncatedDataException, [[OFData dataWithItems: "\x06\x02\x00" - count: 3] ASN1DERValue]) - - /* Enumerated */ - TEST(@"Parsing of enumerated", - [[[OFData dataWithItems: "\x0A\x00" - count: 2] ASN1DERValue] integerValue] == 0 && - [[[OFData dataWithItems: "\x0A\x01\x01" - count: 3] ASN1DERValue] integerValue] == 1 && - [[[OFData dataWithItems: "\x0A\x02\x01\x04" - count: 4] ASN1DERValue] integerValue] == 260 && - [[[OFData dataWithItems: "\x0A\x01\xFF" - count: 3] ASN1DERValue] integerValue] == -1 && - [[[OFData dataWithItems: "\x0A\x03\xFF\x00\x00" - count: 5] ASN1DERValue] integerValue] == -65536 && - (uintmax_t)[[[OFData dataWithItems: "\x0A\x09\x00\xFF\xFF\xFF\xFF" - "\xFF\xFF\xFF\xFF" - count: 11] ASN1DERValue] - integerValue] == UINTMAX_MAX) - - EXPECT_EXCEPTION(@"Detection of invalid enumerated #1", - OFInvalidFormatException, [[OFData dataWithItems: "\x0A\x02\x00\x00" - count: 4] ASN1DERValue]) - - EXPECT_EXCEPTION(@"Detection of invalid enumerated #2", - OFInvalidFormatException, [[OFData dataWithItems: "\x0A\x02\x00\x7F" - count: 4] ASN1DERValue]) - - EXPECT_EXCEPTION(@"Detection of invalid enumerated #3", - OFInvalidFormatException, [[OFData dataWithItems: "\x0A\x02\xFF\x80" - count: 4] ASN1DERValue]) - - EXPECT_EXCEPTION(@"Detection of out of range enumerated", - OFOutOfRangeException, - [[OFData dataWithItems: "\x0A\x09\x01" - "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF" - count: 11] ASN1DERValue]) - - EXPECT_EXCEPTION(@"Detection of truncated enumerated", - OFTruncatedDataException, [[OFData dataWithItems: "\x0A\x02\x00" - count: 3] ASN1DERValue]) - - /* UTF-8 string */ - TEST(@"Parsing of UTF-8 string", - [[[[OFData dataWithItems: "\x0C\x0EHällo Wörld!" - count: 16] ASN1DERValue] UTF8StringValue] - isEqual: @"Hällo Wörld!"] && - [[[[OFData dataWithItems: "\x0C\x81\x80xxxxxxxxxxxxxxxxxxxxxxxxxxxx" - "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" - "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" - "xxxxxxxxxxxxxxxxxxxx" - count: 131] ASN1DERValue] UTF8StringValue] - isEqual: @"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" - @"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" - @"xxxxxxxxxxxxxxxx"]) - - EXPECT_EXCEPTION(@"Detection of out of range UTF-8 string", - OFOutOfRangeException, - [[OFData dataWithItems: "\x0C\x89" - "\x01\x01\x01\x01\x01\x01\x01\x01\x01" - count: 11] ASN1DERValue]) - - EXPECT_EXCEPTION(@"Detection of truncated UTF-8 string", - OFTruncatedDataException, [[OFData dataWithItems: "\x0C\x01" - count: 2] ASN1DERValue]) - - EXPECT_EXCEPTION(@"Detection of truncated length", - OFTruncatedDataException, [[OFData dataWithItems: "\x0C\x83\x01\x01" - count: 4] ASN1DERValue]) - - EXPECT_EXCEPTION(@"Detection of invalid / inefficient length #1", - OFInvalidFormatException, [[OFData dataWithItems: "\x0C\x81\x7F" - count: 3] ASN1DERValue]) - - EXPECT_EXCEPTION(@"Detection of invalid / inefficient length #2", - OFInvalidFormatException, - [[OFData dataWithItems: "\x0C\x82\x00\x80xxxxxxxxxxxxxxxxxxxxxxxxxx" - "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" - "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" - "xxxxxxxxxxxxxxxxxx" - count: 132] ASN1DERValue]) - - /* Sequence */ - TEST(@"Parsing of sequence", - (array = [[OFData dataWithItems: "\x30\x00" - count: 2] ASN1DERValue]) && - [array isKindOfClass: [OFArray class]] && array.count == 0 && - (array = [[OFData dataWithItems: "\x30\x09\x02\x01\x7B\x0C\x04Test" - count: 11] ASN1DERValue]) && - [array isKindOfClass: [OFArray class]] && array.count == 2 && - [[array objectAtIndex: 0] integerValue] == 123 && - [[[array objectAtIndex: 1] stringValue] isEqual: @"Test"]) - - EXPECT_EXCEPTION(@"Detection of truncated sequence #1", - OFTruncatedDataException, [[OFData dataWithItems: "\x30\x01" - count: 2] ASN1DERValue]) - - EXPECT_EXCEPTION(@"Detection of truncated sequence #2", - OFTruncatedDataException, - [[OFData dataWithItems: "\x30\x04\x02\x01\x01\x00\x00" - count: 7] ASN1DERValue]) - - /* Set */ - TEST(@"Parsing of set", - (set = [[OFData dataWithItems: "\x31\x00" - count: 2] ASN1DERValue]) && - [set isKindOfClass: [OFSet class]] && set.count == 0 && - (set = [[OFData dataWithItems: "\x31\x09\x02\x01\x7B\x0C\x04Test" - count: 11] ASN1DERValue]) && - [set isKindOfClass: [OFSet class]] && set.count == 2 && - (enumerator = [set objectEnumerator]) && - [[enumerator nextObject] integerValue] == 123 && - [[[enumerator nextObject] stringValue] isEqual: @"Test"]) - - EXPECT_EXCEPTION(@"Detection of invalid set", - OFInvalidFormatException, - [[OFData dataWithItems: "\x31\x06\x02\x01\x02\x02\x01\x01" - count: 8] ASN1DERValue]) - - EXPECT_EXCEPTION(@"Detection of truncated set #1", - OFTruncatedDataException, [[OFData dataWithItems: "\x31\x01" - count: 2] ASN1DERValue]) - - EXPECT_EXCEPTION(@"Detection of truncated set #2", - OFTruncatedDataException, - [[OFData dataWithItems: "\x31\x04\x02\x01\x01\x00\x00" - count: 7] ASN1DERValue]) - - /* NumericString */ - TEST(@"Parsing of NumericString", - [[[[OFData dataWithItems: "\x12\x0B" "12345 67890" - count: 13] ASN1DERValue] numericStringValue] - isEqual: @"12345 67890"] && - [[[[OFData dataWithItems: "\x12\x81\x80" "0000000000000000000000000" - "0000000000000000000000000000000000000000" - "0000000000000000000000000000000000000000" - "00000000000000000000000" - count: 131] ASN1DERValue] numericStringValue] - isEqual: @"00000000000000000000000000000000000000000000000000000000" - @"00000000000000000000000000000000000000000000000000000000" - @"0000000000000000"]) - - EXPECT_EXCEPTION(@"Detection of invalid NumericString", - OFInvalidEncodingException, - [[OFData dataWithItems: "\x12\x02." - count: 4] ASN1DERValue]) - - EXPECT_EXCEPTION(@"Detection of out of range NumericString", - OFOutOfRangeException, - [[OFData dataWithItems: "\x12\x89" - "\x01\x01\x01\x01\x01\x01\x01\x01\x01" - count: 11] ASN1DERValue]) - - EXPECT_EXCEPTION(@"Detection of truncated NumericString", - OFTruncatedDataException, [[OFData dataWithItems: "\x12\x01" - count: 2] ASN1DERValue]) - - /* PrintableString */ - TEST(@"Parsing of PrintableString", - [[[[OFData dataWithItems: "\x13\x0CHello World." - count: 14] ASN1DERValue] printableStringValue] - isEqual: @"Hello World."] && - [[[[OFData dataWithItems: "\x13\x81\x80 '()+,-./:=?abcdefghijklmnop" - "qrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ '()" - "+,-./:=?abcdefghijklmnopqrstuvwxyzABCDEF" - "GHIJKLMNOPQRSTUVWXYZ" - count: 131] ASN1DERValue] printableStringValue] - isEqual: @" '()+,-./:=?abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQR" - @"STUVWXYZ '()+,-./:=?abcdefghijklmnopqrstuvwxyzABCDEFGHIJ" - @"KLMNOPQRSTUVWXYZ"]) - - EXPECT_EXCEPTION(@"Detection of invalid PrintableString", - OFInvalidEncodingException, - [[OFData dataWithItems: "\x13\x02;" - count: 4] ASN1DERValue]) - - EXPECT_EXCEPTION(@"Detection of out of range PrintableString", - OFOutOfRangeException, - [[OFData dataWithItems: "\x13\x89" - "\x01\x01\x01\x01\x01\x01\x01\x01\x01" - count: 11] ASN1DERValue]) - - EXPECT_EXCEPTION(@"Detection of truncated PrintableString", - OFTruncatedDataException, [[OFData dataWithItems: "\x13\x01" - count: 2] ASN1DERValue]) - - /* IA5String */ - TEST(@"Parsing of IA5String", - [[[[OFData dataWithItems: "\x16\x0CHello World!" - count: 14] ASN1DERValue] IA5StringValue] - isEqual: @"Hello World!"] && - [[[[OFData dataWithItems: "\x16\x81\x80xxxxxxxxxxxxxxxxxxxxxxxxxxxx" - "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" - "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" - "xxxxxxxxxxxxxxxxxxxx" - count: 131] ASN1DERValue] IA5StringValue] - isEqual: @"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" - @"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" - @"xxxxxxxxxxxxxxxx"]) - - EXPECT_EXCEPTION(@"Detection of invalid IA5String", - OFInvalidEncodingException, - [[OFData dataWithItems: "\x16\x02ä" - count: 4] ASN1DERValue]) - - EXPECT_EXCEPTION(@"Detection of out of range IA5String", - OFOutOfRangeException, - [[OFData dataWithItems: "\x16\x89" - "\x01\x01\x01\x01\x01\x01\x01\x01\x01" - count: 11] ASN1DERValue]) - - EXPECT_EXCEPTION(@"Detection of truncated IA5String", - OFTruncatedDataException, [[OFData dataWithItems: "\x16\x01" - count: 2] ASN1DERValue]) - - objc_autoreleasePoolPop(pool); -} -@end Index: tests/OFArrayTests.m ================================================================== --- tests/OFArrayTests.m +++ tests/OFArrayTests.m @@ -420,14 +420,14 @@ #endif TEST(@"-[valueForKey:]", [[[arrayClass arrayWithObjects: @"foo", @"bar", @"quxqux", nil] valueForKey: @"length"] isEqual: - [arrayClass arrayWithObjects: [OFNumber numberWithSize: 3], - [OFNumber numberWithSize: 3], [OFNumber numberWithSize: 6], nil]] && + [arrayClass arrayWithObjects: [OFNumber numberWithInt: 3], + [OFNumber numberWithInt: 3], [OFNumber numberWithInt: 6], nil]] && [[[arrayClass arrayWithObjects: @"1", @"2", nil] - valueForKey: @"@count"] isEqual: [OFNumber numberWithSize: 2]]) + valueForKey: @"@count"] isEqual: [OFNumber numberWithInt: 2]]) m[0] = [mutableArrayClass arrayWithObjects: [OFMutableURL URLWithString: @"http://foo.bar/"], [OFMutableURL URLWithString: @"http://bar.qux/"], [OFMutableURL URLWithString: @"http://qux.quxqux/"], nil]; Index: tests/OFDictionaryTests.m ================================================================== --- tests/OFDictionaryTests.m +++ tests/OFDictionaryTests.m @@ -180,11 +180,11 @@ [mutDict objectForKey: @"key3"] == nil) TEST(@"-[valueForKey:]", [[mutDict valueForKey: keys[0]] isEqual: values[0]] && [[mutDict valueForKey: @"@count"] isEqual: - [OFNumber numberWithSize: 2]]) + [OFNumber numberWithInt: 2]]) EXPECT_EXCEPTION(@"Catching -[setValue:forKey:] on immutable " @"dictionary", OFUndefinedKeyException, [[dictionaryClass dictionary] setValue: @"x" forKey: @"x"]) Index: tests/OFJSONTests.m ================================================================== --- tests/OFJSONTests.m +++ tests/OFJSONTests.m @@ -36,11 +36,11 @@ @"foo", [OFNumber numberWithBool: false], nil], nil]; - TEST(@"-[JSONValue] #1", [s.JSONValue isEqual: d]) + TEST(@"-[objectByParsingJSON] #1", [s.objectByParsingJSON isEqual: d]) TEST(@"-[JSONRepresentation]", [[d JSONRepresentation] isEqual: @"{\"x\":[0.5,15,null,\"foo\",false],\"foo\":\"b\\na\\r\"}"]) TEST(@"OF_JSON_REPRESENTATION_PRETTY", @@ -50,22 +50,22 @@ TEST(@"OF_JSON_REPRESENTATION_JSON5", [[d JSONRepresentationWithOptions: OF_JSON_REPRESENTATION_JSON5] isEqual: @"{x:[0.5,15,null,\"foo\",false],foo:\"b\\\na\\r\"}"]) - EXPECT_EXCEPTION(@"-[JSONValue] #2", OFInvalidJSONException, - [@"{" JSONValue]) - EXPECT_EXCEPTION(@"-[JSONValue] #3", OFInvalidJSONException, - [@"]" JSONValue]) - EXPECT_EXCEPTION(@"-[JSONValue] #4", OFInvalidJSONException, - [@"bar" JSONValue]) - EXPECT_EXCEPTION(@"-[JSONValue] #5", OFInvalidJSONException, - [@"[\"a\" \"b\"]" JSONValue]) - - TEST(@"-[JSONValue] #6", - [@"[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[{}]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]" - .JSONValue isEqual: [OFArray arrayWithObject: + EXPECT_EXCEPTION(@"-[objectByParsingJSON] #2", OFInvalidJSONException, + [@"{" objectByParsingJSON]) + EXPECT_EXCEPTION(@"-[objectByParsingJSON] #3", OFInvalidJSONException, + [@"]" objectByParsingJSON]) + EXPECT_EXCEPTION(@"-[objectByParsingJSON] #4", OFInvalidJSONException, + [@"bar" objectByParsingJSON]) + EXPECT_EXCEPTION(@"-[objectByParsingJSON] #5", OFInvalidJSONException, + [@"[\"a\" \"b\"]" objectByParsingJSON]) + + TEST(@"-[objectByParsingJSON] #6", + [@"[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[{}]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]" + .objectByParsingJSON isEqual: [OFArray arrayWithObject: [OFArray arrayWithObject: [OFArray arrayWithObject: [OFArray arrayWithObject: [OFArray arrayWithObject: [OFArray arrayWithObject: [OFArray arrayWithObject: [OFArray arrayWithObject: [OFArray arrayWithObject: [OFArray arrayWithObject: [OFArray arrayWithObject: @@ -79,12 +79,12 @@ [OFArray arrayWithObject: [OFArray arrayWithObject: [OFArray arrayWithObject: [OFArray arrayWithObject: [OFArray arrayWithObject: [OFDictionary dictionary]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]) - EXPECT_EXCEPTION(@"-[JSONValue] #7", OFInvalidJSONException, + EXPECT_EXCEPTION(@"-[objectByParsingJSON] #7", OFInvalidJSONException, [@"[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[{}]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]" - JSONValue]) + objectByParsingJSON]) objc_autoreleasePoolPop(pool); } @end Index: tests/OFNumberTests.m ================================================================== --- tests/OFNumberTests.m +++ tests/OFNumberTests.m @@ -25,15 +25,15 @@ - (void)numberTests { void *pool = objc_autoreleasePoolPush(); OFNumber *num; - TEST(@"+[numberWithIntMax:]", - (num = [OFNumber numberWithIntMax: 123456789])) + TEST(@"+[numberWithLongLong:]", + (num = [OFNumber numberWithLongLong: 123456789])) TEST(@"-[isEqual:]", - [num isEqual: [OFNumber numberWithUInt32: 123456789]]) + [num isEqual: [OFNumber numberWithLong: 123456789]]) TEST(@"-[hash]", num.hash == 0x82D8BC42) TEST(@"-[charValue]", num.charValue == 21) Index: tests/OFPropertyListTests.m ================================================================== --- tests/OFPropertyListTests.m +++ tests/OFPropertyListTests.m @@ -68,52 +68,54 @@ [OFNumber numberWithBool: false], [OFNumber numberWithFloat: 12.25], [OFNumber numberWithInt: -10], nil]; - TEST(@"-[propertyListValue:] #1", - [PLIST1.propertyListValue isEqual: @"Hello"]) - - TEST(@"-[propertyListValue:] #2", - [PLIST2.propertyListValue isEqual: array]) - - TEST(@"-[propertyListValue:] #3", - [PLIST3.propertyListValue isEqual: + TEST(@"-[objectByParsingPropertyList:] #1", + [PLIST1.objectByParsingPropertyList isEqual: @"Hello"]) + + TEST(@"-[objectByParsingPropertyList:] #2", + [PLIST2.objectByParsingPropertyList isEqual: array]) + + TEST(@"-[objectByParsingPropertyList:] #3", + [PLIST3.objectByParsingPropertyList isEqual: [OFDictionary dictionaryWithKeysAndObjects: @"array", array, @"foo", @"bar", nil]]) - EXPECT_EXCEPTION(@"-[propertyListValue] detecting unsupported version", + EXPECT_EXCEPTION(@"Detecting unsupported version", OFUnsupportedVersionException, [[PLIST(@"") stringByReplacingOccurrencesOfString: @"1.0" withString: @"1.1"] - propertyListValue]) - - EXPECT_EXCEPTION( - @"-[propertyListValue] detecting invalid format #1", - OFInvalidFormatException, - [PLIST(@"") propertyListValue]) - - EXPECT_EXCEPTION( - @"-[propertyListValue] detecting invalid format #2", - OFInvalidFormatException, - [PLIST(@"") propertyListValue]) - - EXPECT_EXCEPTION( - @"-[propertyListValue] detecting invalid format #3", - OFInvalidFormatException, - [PLIST(@"") propertyListValue]) - - EXPECT_EXCEPTION( - @"-[propertyListValue] detecting invalid format #4", - OFInvalidFormatException, - [PLIST(@"") propertyListValue]) - - EXPECT_EXCEPTION( - @"-[propertyListValue] detecting invalid format #5", - OFInvalidFormatException, - [PLIST(@"") propertyListValue]) + objectByParsingPropertyList]) + + EXPECT_EXCEPTION( + @"-[objectByParsingPropertyList] detecting invalid format #1", + OFInvalidFormatException, + [PLIST(@"") objectByParsingPropertyList]) + + EXPECT_EXCEPTION( + @"-[objectByParsingPropertyList] detecting invalid format #2", + OFInvalidFormatException, + [PLIST(@"") objectByParsingPropertyList]) + + EXPECT_EXCEPTION( + @"-[objectByParsingPropertyList] detecting invalid format #3", + OFInvalidFormatException, + [PLIST(@"") objectByParsingPropertyList]) + + EXPECT_EXCEPTION( + @"-[objectByParsingPropertyList] detecting invalid format #4", + OFInvalidFormatException, + [PLIST(@"") + objectByParsingPropertyList]) + + EXPECT_EXCEPTION( + @"-[objectByParsingPropertyList] detecting invalid format #5", + OFInvalidFormatException, + [PLIST(@"") + objectByParsingPropertyList]) objc_autoreleasePoolPop(pool); } @end Index: tests/OFSetTests.m ================================================================== --- tests/OFSetTests.m +++ tests/OFSetTests.m @@ -276,14 +276,14 @@ TEST(@"Detection of mutation during Fast Enumeration", ok); TEST(@"-[valueForKey:]", [(set1 = [[setClass setWithObjects: @"a", @"ab", @"abc", @"b", nil] valueForKey: @"length"]) isEqual: [setClass setWithObjects: - [OFNumber numberWithSize: 1], [OFNumber numberWithSize: 2], - [OFNumber numberWithSize: 3], nil]] && + [OFNumber numberWithInt: 1], [OFNumber numberWithInt: 2], + [OFNumber numberWithInt: 3], nil]] && [[set1 valueForKey: @"@count"] isEqual: - [OFNumber numberWithSize: 3]]) + [OFNumber numberWithInt: 3]]) objc_autoreleasePoolPop(pool); } - (void)setTests Index: tests/OFStringTests.m ================================================================== --- tests/OFStringTests.m +++ tests/OFStringTests.m @@ -1067,28 +1067,33 @@ [C(@"c:\\..\\asd").stringByStandardizingPath isEqual: @"c:\\..\\asd"]) # endif #endif - TEST(@"-[decimalValue]", - C(@"1234").decimalValue == 1234 && - C(@"\r\n+123 ").decimalValue == 123 && - C(@"-500\t").decimalValue == -500 && - C(@"\t\t\r\n").decimalValue == 0) - - TEST(@"-[hexadecimalValue]", - C(@"123f").hexadecimalValue == 0x123f && - C(@"\t\n0xABcd\r").hexadecimalValue == 0xABCD && - C(@" xbCDE").hexadecimalValue == 0xBCDE && - C(@"$CdEf").hexadecimalValue == 0xCDEF && - C(@"\rFeh ").hexadecimalValue == 0xFE && - C(@"\r\t").hexadecimalValue == 0) - - TEST(@"-[octalValue]", - C(@"1234567").octalValue == 01234567 && - C(@"\r\n123").octalValue == 0123 && - C(@"765\t").octalValue == 0765 && C(@"\t\t\r\n").octalValue == 0) + TEST(@"-[longLongValue]", + C(@"1234").longLongValue == 1234 && + C(@"\r\n+123 ").longLongValue == 123 && + C(@"-500\t").longLongValue == -500 && + [C(@"-0x10\t") longLongValueWithBase: 0] == -0x10 && + C(@"\t\t\r\n").longLongValue == 0 && + [C(@"123f") longLongValueWithBase: 16] == 0x123f && + [C(@"\t\n0xABcd\r") longLongValueWithBase: 0] == 0xABCD && + [C(@"1234567") longLongValueWithBase: 8] == 01234567 && + [C(@"\r\n0123") longLongValueWithBase: 0] == 0123 && + [C(@"765\t") longLongValueWithBase: 8] == 0765 && + [C(@"\t\t\r\n") longLongValueWithBase: 8] == 0) + + TEST(@"-[unsignedLongLongValue]", + C(@"1234").unsignedLongLongValue == 1234 && + C(@"\r\n+123 ").unsignedLongLongValue == 123 && + C(@"\t\t\r\n").unsignedLongLongValue == 0 && + [C(@"123f") unsignedLongLongValueWithBase: 16] == 0x123f && + [C(@"\t\n0xABcd\r") unsignedLongLongValueWithBase: 0] == 0xABCD && + [C(@"1234567") unsignedLongLongValueWithBase: 8] == 01234567 && + [C(@"\r\n0123") unsignedLongLongValueWithBase: 0] == 0123 && + [C(@"765\t") unsignedLongLongValueWithBase: 8] == 0765 && + [C(@"\t\t\r\n") unsignedLongLongValueWithBase: 8] == 0) /* * These test numbers can be generated without rounding if we have IEEE * floating point numbers, thus we can use == on them. */ @@ -1107,11 +1112,11 @@ # if (!defined(OF_SOLARIS) || !defined(OF_X86)) && !defined(OF_AMIGAOS_M68K) # define INPUT @"\t-0.123456789 " # define EXPECTED -0.123456789 # else /* - * Solaris' strtod() has weird rounding on x86, but not on x86_64/ + * Solaris' strtod() has weird rounding on x86, but not on x86_64. * AmigaOS 3 with libnix has weird rounding as well. */ # define INPUT @"\t-0.125 " # define EXPECTED -0.125 # endif @@ -1122,25 +1127,21 @@ C(@"\r -INFINITY\n").doubleValue == -INFINITY && isnan(C(@" NAN\t\t").doubleValue)) #undef INPUT #undef EXPECTED - EXPECT_EXCEPTION(@"Detect invalid characters in -[decimalValue] #1", - OFInvalidFormatException, [C(@"abc") decimalValue]) - EXPECT_EXCEPTION(@"Detect invalid characters in -[decimalValue] #2", - OFInvalidFormatException, [C(@"0a") decimalValue]) - EXPECT_EXCEPTION(@"Detect invalid characters in -[decimalValue] #3", - OFInvalidFormatException, [C(@"0 1") decimalValue]) - - EXPECT_EXCEPTION(@"Detect invalid chars in -[hexadecimalValue] #1", - OFInvalidFormatException, [C(@"0xABCDEFG") hexadecimalValue]) - EXPECT_EXCEPTION(@"Detect invalid chars in -[hexadecimalValue] #2", - OFInvalidFormatException, [C(@"0x") hexadecimalValue]) - EXPECT_EXCEPTION(@"Detect invalid chars in -[hexadecimalValue] #3", - OFInvalidFormatException, [C(@"$") hexadecimalValue]) - EXPECT_EXCEPTION(@"Detect invalid chars in -[hexadecimalValue] #4", - OFInvalidFormatException, [C(@"$ ") hexadecimalValue]) + EXPECT_EXCEPTION(@"Detect invalid chars in -[longLongValue] #1", + OFInvalidFormatException, [C(@"abc") longLongValue]) + EXPECT_EXCEPTION(@"Detect invalid chars in -[longLongValue] #2", + OFInvalidFormatException, [C(@"0a") longLongValue]) + EXPECT_EXCEPTION(@"Detect invalid chars in -[longLongValue] #3", + OFInvalidFormatException, [C(@"0 1") longLongValue]) + EXPECT_EXCEPTION(@"Detect invalid chars in -[longLongValue] #4", + OFInvalidFormatException, + [C(@"0xABCDEFG") longLongValueWithBase: 0]) + EXPECT_EXCEPTION(@"Detect invalid chars in -[longLongValue] #5", + OFInvalidFormatException, [C(@"0x") longLongValueWithBase: 0]) EXPECT_EXCEPTION(@"Detect invalid chars in -[floatValue] #1", OFInvalidFormatException, [C(@"0.0a") floatValue]) EXPECT_EXCEPTION(@"Detect invalid chars in -[floatValue] #2", OFInvalidFormatException, [C(@"0 0") floatValue]) @@ -1164,21 +1165,21 @@ */ EXPECT_EXCEPTION(@"Detect invalid chars in -[doubleValue] #3", OFInvalidFormatException, [C(@"0,0") doubleValue]) #endif - EXPECT_EXCEPTION(@"Detect out of range in -[decimalValue]", + EXPECT_EXCEPTION(@"Detect out of range in -[longLongValue]", OFOutOfRangeException, - [C(@"12345678901234567890123456789012345678901234567890" + [C(@"-12345678901234567890123456789012345678901234567890" @"12345678901234567890123456789012345678901234567890") - decimalValue]) + longLongValueWithBase: 16]) - EXPECT_EXCEPTION(@"Detect out of range in -[hexadecimalValue]", + EXPECT_EXCEPTION(@"Detect out of range in -[unsignedLongLongValue]", OFOutOfRangeException, [C(@"0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF" @"0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF") - hexadecimalValue]) + unsignedLongLongValueWithBase: 16]) TEST(@"-[characters]", (ua = C(@"fööbär🀺").characters) && !memcmp(ua, ucstr + 1, sizeof(ucstr) - 8)) #ifdef OF_BIG_ENDIAN Index: tests/OFURLTests.m ================================================================== --- tests/OFURLTests.m +++ tests/OFURLTests.m @@ -154,13 +154,12 @@ TEST(@"-[password]", [u1.password isEqual: @"p@w"] && u4.password == nil) TEST(@"-[host]", [u1.host isEqual: @"ho:st"] && [u6.host isEqual: @"12:34::56:abcd"] && [u7.host isEqual: @"12:34::56:abcd"]) - TEST(@"-[port]", [u1.port isEqual: [OFNumber numberWithUInt16: 1234]] && - [u4 port] == nil && - [u7.port isEqual: [OFNumber numberWithUInt16: 234]]) + TEST(@"-[port]", u1.port.unsignedShortValue == 1234 && + [u4 port] == nil && u7.port.unsignedShortValue == 234) TEST(@"-[path]", [u1.path isEqual: @"/pa?th"] && [u4.path isEqual: @"/etc/passwd"]) TEST(@"-[pathComponents]", [u1.pathComponents isEqual: [OFArray arrayWithObjects: @"/", @"pa?th", nil]] && Index: tests/TestsAppDelegate.h ================================================================== --- tests/TestsAppDelegate.h +++ tests/TestsAppDelegate.h @@ -68,12 +68,12 @@ inModule: (OFString *)module; - (void)outputFailure: (OFString *)test inModule: (OFString *)module; @end -@interface TestsAppDelegate (OFASN1DERValueTests) -- (void)ASN1DERValueTests; +@interface TestsAppDelegate (OFASN1DERParsingTests) +- (void)ASN1DERParsingTests; @end @interface TestsAppDelegate (OFASN1DERRepresentationTests) - (void)ASN1DERRepresentationTests; @end Index: tests/TestsAppDelegate.m ================================================================== --- tests/TestsAppDelegate.m +++ tests/TestsAppDelegate.m @@ -378,11 +378,11 @@ #ifdef OF_HAVE_FILES [self serializationTests]; #endif [self JSONTests]; [self propertyListTests]; - [self ASN1DERValueTests]; + [self ASN1DERParsingTests]; [self ASN1DERRepresentationTests]; #if defined(OF_HAVE_PLUGINS) [self pluginTests]; #endif #ifdef OF_WINDOWS Index: tests/iOS.xcodeproj/project.pbxproj ================================================================== --- tests/iOS.xcodeproj/project.pbxproj +++ tests/iOS.xcodeproj/project.pbxproj @@ -304,11 +304,11 @@ LIBRARY_SEARCH_PATHS = ( "$(inherited)", "$(PROJECT_DIR)", ); OTHER_LDFLAGS = "-ObjC"; - PRODUCT_BUNDLE_IDENTIFIER = zone.heap.objfw.tests; + PRODUCT_BUNDLE_IDENTIFIER = im.nil.objfw.tests; PRODUCT_NAME = "$(TARGET_NAME)"; TARGETED_DEVICE_FAMILY = "1,2"; }; name = Debug; }; @@ -324,11 +324,11 @@ LIBRARY_SEARCH_PATHS = ( "$(inherited)", "$(PROJECT_DIR)", ); OTHER_LDFLAGS = "-ObjC"; - PRODUCT_BUNDLE_IDENTIFIER = zone.heap.objfw.tests; + PRODUCT_BUNDLE_IDENTIFIER = im.nil.objfw.tests; PRODUCT_NAME = "$(TARGET_NAME)"; TARGETED_DEVICE_FAMILY = "1,2"; }; name = Release; }; Index: tests/plugin/Info.plist.in ================================================================== --- tests/plugin/Info.plist.in +++ tests/plugin/Info.plist.in @@ -5,11 +5,11 @@ CFBundleExecutable TestPlugin CFBundleName TestPlugin CFBundleIdentifier - zone.heap.objfw.testplugin + im.nil.objfw.tests.plugin CFBundleInfoDictionaryVersion 6.0 CFBundlePackageType BNDL CFBundleVersion Index: tests/serialization.xml ================================================================== --- tests/serialization.xml +++ tests/serialization.xml @@ -15,11 +15,11 @@ Qu"xbar test - 1234 + 1234 40934a456d5cfaad asd 40934a456d5cfaad Index: utils/ofarc/LHAArchive.m ================================================================== --- utils/ofarc/LHAArchive.m +++ utils/ofarc/LHAArchive.m @@ -44,10 +44,13 @@ #ifdef OF_FILE_MANAGER_SUPPORTS_PERMISSIONS OFNumber *mode = entry.mode; if (mode == nil) return; + + mode = [OFNumber numberWithUnsignedShort: + mode.unsignedShortValue & 0777]; of_file_attributes_t attributes = [OFDictionary dictionaryWithObject: mode forKey: of_file_attribute_key_posix_permissions]; @@ -143,28 +146,28 @@ @"%04" PRIX16, entry.CRC16]; [of_stdout writeString: @"\t"]; [of_stdout writeLine: OF_LOCALIZED( @"list_compressed_size", - [@"[" - @" 'Compressed: '," - @" [" - @" {'size == 1': '1 byte'}," - @" {'': '%[size] bytes'}" - @" ]" - @"]" JSONValue], + @"[" + @" 'Compressed: '," + @" [" + @" {'size == 1': '1 byte'}," + @" {'': '%[size] bytes'}" + @" ]" + @"]".objectByParsingJSON, @"size", compressedSize)]; [of_stdout writeString: @"\t"]; [of_stdout writeLine: OF_LOCALIZED( @"list_uncompressed_size", - [@"[" - @" 'Uncompressed: '," - @" [" - @" {'size == 1': '1 byte'}," - @" {'': '%[size] bytes'}" - @" ]" - @"]" JSONValue], + @"[" + @" 'Uncompressed: '," + @" [" + @" {'size == 1': '1 byte'}," + @" {'': '%[size] bytes'}" + @" ]" + @"]".objectByParsingJSON, @"size", uncompressedSize)]; [of_stdout writeString: @"\t"]; [of_stdout writeLine: OF_LOCALIZED( @"list_compression_method", @"Compression method: %[method]", @@ -179,11 +182,11 @@ @"date", date)]; if (entry.mode != nil) { OFString *modeString = [OFString stringWithFormat: - @"%" PRIo16, entry.mode.uInt16Value]; + @"%ho", entry.mode.unsignedShortValue]; [of_stdout writeString: @"\t"]; [of_stdout writeLine: OF_LOCALIZED(@"list_mode", @"Mode: %[mode]", @"mode", modeString)]; @@ -467,20 +470,20 @@ attributes = [fileManager attributesOfItemAtPath: fileName]; type = attributes.fileType; entry = [OFMutableLHAArchiveEntry entryWithFileName: fileName]; #ifdef OF_FILE_MANAGER_SUPPORTS_PERMISSIONS - entry.mode = [OFNumber numberWithUInt16: + entry.mode = [OFNumber numberWithUnsignedLong: attributes.filePOSIXPermissions]; #endif entry.date = attributes.fileModificationDate; #ifdef OF_FILE_MANAGER_SUPPORTS_OWNER entry.UID = - [OFNumber numberWithUInt16: attributes.filePOSIXUID]; + [OFNumber numberWithUnsignedLong: attributes.filePOSIXUID]; entry.GID = - [OFNumber numberWithUInt16: attributes.filePOSIXGID]; + [OFNumber numberWithUnsignedLong: attributes.filePOSIXGID]; entry.owner = attributes.fileOwner; entry.group = attributes.fileGroup; #endif if ([type isEqual: of_file_type_directory]) @@ -487,11 +490,12 @@ entry.compressionMethod = @"-lhd-"; output = [_archive streamForWritingEntry: entry]; if ([type isEqual: of_file_type_regular]) { - uintmax_t written = 0, size = attributes.fileSize; + unsigned long long written = 0; + unsigned long long size = attributes.fileSize; int8_t percent = -1, newPercent; OFFile *input = [OFFile fileWithPath: fileName mode: @"r"]; Index: utils/ofarc/TarArchive.m ================================================================== --- utils/ofarc/TarArchive.m +++ utils/ofarc/TarArchive.m @@ -33,12 +33,13 @@ static void setPermissions(OFString *path, OFTarArchiveEntry *entry) { #ifdef OF_FILE_MANAGER_SUPPORTS_PERMISSIONS + OFNumber *mode = [OFNumber numberWithUnsignedShort: entry.mode & 0777]; of_file_attributes_t attributes = [OFDictionary - dictionaryWithObject: [OFNumber numberWithUInt16: entry.mode] + dictionaryWithObject: mode forKey: of_file_attribute_key_posix_permissions]; [[OFFileManager defaultManager] setAttributes: attributes ofItemAtPath: path]; #endif @@ -124,17 +125,17 @@ OFString *GID = [OFString stringWithFormat: @"%u", entry.GID]; [of_stdout writeString: @"\t"]; [of_stdout writeLine: OF_LOCALIZED(@"list_size", - [@"[" - @" 'Size: '," - @" [" - @" {'size == 1': '1 byte'}," - @" {'': '%[size] bytes'}" - @" ]" - @"]" JSONValue], + @"[" + @" 'Size: '," + @" [" + @" {'size == 1': '1 byte'}," + @" {'': '%[size] bytes'}" + @" ]" + @"]".objectByParsingJSON, @"size", size)]; [of_stdout writeString: @"\t"]; [of_stdout writeLine: OF_LOCALIZED(@"list_mode", @"Mode: %[mode]", @"mode", mode)]; Index: utils/ofarc/ZIPArchive.m ================================================================== --- utils/ofarc/ZIPArchive.m +++ utils/ofarc/ZIPArchive.m @@ -42,15 +42,16 @@ setPermissions(OFString *path, OFZIPArchiveEntry *entry) { #ifdef OF_FILE_MANAGER_SUPPORTS_PERMISSIONS if ((entry.versionMadeBy >> 8) == OF_ZIP_ARCHIVE_ENTRY_ATTR_COMPAT_UNIX) { - uint16_t mode = entry.versionSpecificAttributes >> 16; + OFNumber *mode = [OFNumber numberWithUnsignedShort: + (entry.versionSpecificAttributes >> 16) & 0777]; of_file_attribute_key_t key = of_file_attribute_key_posix_permissions; of_file_attributes_t attributes = [OFDictionary - dictionaryWithObject: [OFNumber numberWithUInt16: mode] + dictionaryWithObject: mode forKey: key]; [[OFFileManager defaultManager] setAttributes: attributes ofItemAtPath: path]; } @@ -136,28 +137,28 @@ localDateStringWithFormat: @"%Y-%m-%d %H:%M:%S"]; [of_stdout writeString: @"\t"]; [of_stdout writeLine: OF_LOCALIZED( @"list_compressed_size", - [@"[" - @" 'Compressed: '," - @" [" - @" {'size == 1': '1 byte'}," - @" {'': '%[size] bytes'}" - @" ]" - @"]" JSONValue], + @"[" + @" 'Compressed: '," + @" [" + @" {'size == 1': '1 byte'}," + @" {'': '%[size] bytes'}" + @" ]" + @"]".objectByParsingJSON, @"size", compressedSize)]; [of_stdout writeString: @"\t"]; [of_stdout writeLine: OF_LOCALIZED( @"list_uncompressed_size", - [@"[" - @" 'Uncompressed: '," - @" [" - @" {'size == 1': '1 byte'}," - @" {'': '%[size] bytes'}" - @" ]" - @"]" JSONValue], + @"[" + @" 'Uncompressed: '," + @" [" + @" {'size == 1': '1 byte'}," + @" {'': '%[size] bytes'}" + @" ]" + @"]".objectByParsingJSON, @"size", uncompressedSize)]; [of_stdout writeString: @"\t"]; [of_stdout writeLine: OF_LOCALIZED( @"list_compression_method", @"Compression method: %[method]", @@ -419,11 +420,11 @@ OFArray OF_GENERIC (OFString *) *components; OFString *fileName; of_file_attributes_t attributes; bool isDirectory = false; OFMutableZIPArchiveEntry *entry; - uintmax_t size; + unsigned long long size; OFStream *output; components = localFileName.pathComponents; fileName = [components componentsJoinedByString: @"/"]; @@ -456,11 +457,11 @@ [entry makeImmutable]; output = [_archive streamForWritingEntry: entry]; if (!isDirectory) { - uintmax_t written = 0; + unsigned long long written = 0; int8_t percent = -1, newPercent; OFFile *input = [OFFile fileWithPath: fileName mode: @"r"]; Index: utils/ofhttp/OFHTTP.m ================================================================== --- utils/ofhttp/OFHTTP.m +++ utils/ofhttp/OFHTTP.m @@ -26,10 +26,13 @@ #import "OFHTTPClient.h" #import "OFHTTPRequest.h" #import "OFHTTPResponse.h" #import "OFLocale.h" #import "OFOptionsParser.h" +#ifdef OF_HAVE_PLUGINS +# import "OFPlugin.h" +#endif #import "OFSandbox.h" #import "OFStdIOStream.h" #import "OFSystemInfo.h" #import "OFTCPSocket.h" #import "OFTLSSocket.h" @@ -67,11 +70,11 @@ of_http_request_method_t _method; OFMutableDictionary *_clientHeaders; OFHTTPClient *_HTTPClient; char *_buffer; OFStream *_output; - intmax_t _received, _length, _resumedFrom; + unsigned long long _received, _length, _resumedFrom; ProgressBar *_progressBar; } - (void)downloadNextURL; @end @@ -272,10 +275,21 @@ objc_autoreleasePoolPop(pool); return [fileName autorelease]; } @implementation OFHTTP +#ifdef OF_HAVE_PLUGINS ++ (void)initialize +{ + if (self != [OFHTTP class]) + return; + + /* Opportunistically try loading ObjOpenSSL and ignore any errors. */ + of_dlopen(@"objopenssl", OF_RTLD_LAZY); +} +#endif + - (instancetype)init { self = [super init]; @try { @@ -332,11 +346,12 @@ else { _body = [[OFFile alloc] initWithPath: path mode: @"r"]; @try { - uintmax_t fileSize = [[OFFileManager defaultManager] + unsigned long long fileSize = + [[OFFileManager defaultManager] attributesOfItemAtPath: path].fileSize; contentLength = [OFString stringWithFormat: @"%ju", fileSize]; [_clientHeaders setObject: contentLength @@ -374,18 +389,18 @@ @try { size_t pos = [proxy rangeOfString: @":" options: OF_STRING_SEARCH_BACKWARDS].location; OFString *host; - intmax_t port; + unsigned long long port; if (pos == OF_NOT_FOUND) @throw [OFInvalidFormatException exception]; host = [proxy substringWithRange: of_range(0, pos)]; - port = [proxy substringWithRange: - of_range(pos + 1, proxy.length - pos - 1)].decimalValue; + port = [proxy substringWithRange: of_range(pos + 1, + proxy.length - pos - 1)].unsignedLongLongValue; if (port > UINT16_MAX) @throw [OFOutOfRangeException exception]; [OFTCPSocket setSOCKS5Host: host]; @@ -719,12 +734,15 @@ [_progressBar stop]; [_progressBar draw]; [_progressBar release]; _progressBar = nil; - if (!_quiet) - [of_stdout writeString: @"\n Error!\n"]; + if (!_quiet) { + [of_stdout writeString: @"\n "]; + [of_stdout writeLine: OF_LOCALIZED(@"download_error", + @"Error!")]; + } URL = [_URLs objectAtIndex: _URLIndex - 1]; [of_stderr writeLine: OF_LOCALIZED( @"download_failed_exception", @"%[prog]: Failed to download <%[url]>!\n" @@ -783,11 +801,11 @@ if (type == nil) type = OF_LOCALIZED(@"type_unknown", @"unknown"); if (lengthString != nil) { - _length = lengthString.decimalValue; + _length = lengthString.unsignedLongLongValue; if (_resumedFrom + _length >= GIBIBYTE) { lengthString = [OFString stringWithFormat: @"%,.2f", (float)(_resumedFrom + _length) / GIBIBYTE]; @@ -810,16 +828,16 @@ @"num", lengthString); } else { lengthString = [OFString stringWithFormat: @"%jd", _resumedFrom + _length]; lengthString = OF_LOCALIZED(@"size_bytes", - [@"[" - @" [" - @" {'num == 1': '1 byte'}," - @" {'': '%[num] bytes'}" - @" ]" - @"]" JSONValue], + @"[" + @" [" + @" {'num == 1': '1 byte'}," + @" {'': '%[num] bytes'}" + @" ]" + @"]".objectByParsingJSON, @"num", lengthString); } } else lengthString = OF_LOCALIZED(@"size_unknown", @"unknown"); @@ -1008,18 +1026,19 @@ if (_currentFileName == nil) _currentFileName = [URL.path.lastPathComponent copy]; if (_continue) { @try { - uintmax_t size = [[OFFileManager defaultManager] + unsigned long long size = + [[OFFileManager defaultManager] attributesOfItemAtPath: _currentFileName].fileSize; OFString *range; - if (size > INTMAX_MAX) + if (size > ULLONG_MAX) @throw [OFOutOfRangeException exception]; - _resumedFrom = (intmax_t)size; + _resumedFrom = (unsigned long long)size; range = [OFString stringWithFormat: @"bytes=%jd-", _resumedFrom]; [clientHeaders setObject: range forKey: @"Range"]; Index: utils/ofhttp/ProgressBar.h ================================================================== --- utils/ofhttp/ProgressBar.h +++ utils/ofhttp/ProgressBar.h @@ -17,23 +17,27 @@ #import "OFObject.h" @class OFDate; @class OFTimer; + +#define BPS_WINDOW_SIZE 10 @interface ProgressBar: OFObject { - intmax_t _received, _lastReceived, _length, _resumedFrom; + unsigned long long _received, _lastReceived, _length, _resumedFrom; OFDate *_startDate, *_lastReceivedDate; OFTimer *_drawTimer, *_BPSTimer; bool _stopped; float _BPS; double _ETA; + float _BPSWindow[BPS_WINDOW_SIZE]; + size_t _BPSWindowIndex, _BPSWindowLength; } -- (instancetype)initWithLength: (intmax_t)length - resumedFrom: (intmax_t)resumedFrom; -- (void)setReceived: (intmax_t)received; +- (instancetype)initWithLength: (unsigned long long)length + resumedFrom: (unsigned long long)resumedFrom; +- (void)setReceived: (unsigned long long)received; - (void)draw; - (void)calculateBPSAndETA; - (void)stop; @end Index: utils/ofhttp/ProgressBar.m ================================================================== --- utils/ofhttp/ProgressBar.m +++ utils/ofhttp/ProgressBar.m @@ -31,12 +31,12 @@ #define KIBIBYTE (1024) #define UPDATE_INTERVAL 0.1 @implementation ProgressBar -- (instancetype)initWithLength: (intmax_t)length - resumedFrom: (intmax_t)resumedFrom +- (instancetype)initWithLength: (unsigned long long)length + resumedFrom: (unsigned long long)resumedFrom { self = [super init]; @try { void *pool = objc_autoreleasePoolPush(); @@ -76,11 +76,11 @@ [_BPSTimer release]; [super dealloc]; } -- (void)setReceived: (intmax_t)received +- (void)setReceived: (unsigned long long)received { _received = received; } - (void)_drawProgress @@ -202,16 +202,16 @@ @"num", num)]; } else { OFString *num = [OFString stringWithFormat: @"%jd", _resumedFrom + _received]; [of_stdout writeString: OF_LOCALIZED(@"progress_bytes", - [@"[" - @" [" - @" {'num == 1': '1 byte '}," - @" {'': '%[num] bytes'}" - @" ]" - @"]" JSONValue], + @"[" + @" [" + @" {'num == 1': '1 byte '}," + @" {'': '%[num] bytes'}" + @" ]" + @"]".objectByParsingJSON, @"num", num)]; } [of_stdout writeString: @" "]; @@ -254,12 +254,22 @@ [self _drawReceived]; } - (void)calculateBPSAndETA { - _BPS = (float)(_received - _lastReceived) / + _BPSWindow[_BPSWindowIndex++ % BPS_WINDOW_SIZE] = + (float)(_received - _lastReceived) / -(float)_lastReceivedDate.timeIntervalSinceNow; + + if (_BPSWindowLength < BPS_WINDOW_SIZE) + _BPSWindowLength++; + + _BPS = 0; + for (size_t i = 0; i < _BPSWindowLength; i++) + _BPS += _BPSWindow[i]; + _BPS /= _BPSWindowLength; + _ETA = (double)(_length - _received) / _BPS; _lastReceived = _received; [_lastReceivedDate release]; _lastReceivedDate = [[OFDate alloc] init]; Index: utils/ofhttp/lang/de.json ================================================================== --- utils/ofhttp/lang/de.json +++ utils/ofhttp/lang/de.json @@ -66,10 +66,11 @@ ], "download_failed": [ "%[prog]: Fehler beim Download von <%[url]>!\n", " HTTP Status-Code: %[code]" ], + "download_error": "Fehler!", "download_failed_exception": [ "%[prog]: Fehler beim Download von <%[url]>!\n", " %[exception]" ], "download_done": "Fertig!", Index: utils/ofsock/OFSock.m ================================================================== --- utils/ofsock/OFSock.m +++ utils/ofsock/OFSock.m @@ -60,11 +60,11 @@ [of_stderr writeLine: @"Need a port!"]; [OFApplication terminateWithStatus: 1]; } [sock connectToHost: URL.host - port: URL.port.uInt16Value]; + port: URL.port.shortValue]; return [OFPair pairWithFirstObject: sock secondObject: sock]; }