@@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2024 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 @@ -11,70 +11,47 @@ * 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. */ -#define OF_NUMBER_M - #include "config.h" #include #import "OFNumber.h" -#import "OFString.h" -#import "OFXMLElement.h" -#import "OFXMLAttribute.h" +#import "OFConcreteNumber.h" #import "OFData.h" +#import "OFString.h" +#import "OFTaggedPointerNumber.h" #import "OFInvalidArgumentException.h" #import "OFInvalidFormatException.h" #import "OFOutOfRangeException.h" @interface OFNumber () -+ (instancetype)of_alloc; - (OFString *) of_JSONRepresentationWithOptions: (OFJSONRepresentationOptions)options depth: (size_t)depth; @end -@interface OFNumberPlaceholder: OFNumber -@end - -@interface OFNumberSingleton: OFNumber -@end - -#ifdef OF_OBJFW_RUNTIME -enum Tag { - tagChar, - tagShort, - tagInt, - tagLong, - tagLongLong, - tagUnsignedChar, - tagUnsignedShort, - tagUnsignedInt, - tagUnsignedLong, - tagUnsignedLongLong, -}; -static const uint_fast8_t tagBits = 4; -static const uintptr_t tagMask = 0xF; - -@interface OFTaggedPointerNumber: OFNumberSingleton -@end -#endif +@interface OFPlaceholderNumber: OFNumber +@end + +@interface OFConcreteNumberSingleton: OFConcreteNumber +@end static struct { Class isa; } placeholder; -#define SINGLETON(var, sel, val) \ - static OFNumberSingleton *var; \ - \ - static void \ - var##Init(void) \ - { \ - var = [[OFNumberSingleton alloc] sel val]; \ +#define SINGLETON(var, sel, val) \ + static OFConcreteNumberSingleton *var; \ + \ + static void \ + var##Init(void) \ + { \ + var = [[OFConcreteNumberSingleton alloc] sel val]; \ } SINGLETON(falseNumber, initWithBool:, false) SINGLETON(trueNumber, initWithBool:, true) SINGLETON(charZeroNumber, initWithChar:, 0) SINGLETON(shortZeroNumber, initWithShort:, 0) @@ -88,28 +65,19 @@ SINGLETON(unsignedLongLongZeroNumber, initWithUnsignedLongLong:, 0) SINGLETON(floatZeroNumber, initWithFloat:, 0) SINGLETON(doubleZeroNumber, initWithDouble:, 0) #undef SINGLETON -#ifdef OF_OBJFW_RUNTIME -static int numberTag; -#endif - static bool isUnsigned(OFNumber *number) { switch (*number.objCType) { case 'B': - return true; case 'C': - return true; case 'S': - return true; case 'I': - return true; case 'L': - return true; case 'Q': return true; default: return false; } @@ -118,17 +86,13 @@ static bool isSigned(OFNumber *number) { switch (*number.objCType) { case 'c': - return true; case 's': - return true; case 'i': - return true; case 'l': - return true; case 'q': return true; default: return false; } @@ -137,19 +101,18 @@ static bool isFloat(OFNumber *number) { switch (*number.objCType) { case 'f': - return true; case 'd': return true; default: return false; } } -@implementation OFNumberPlaceholder +@implementation OFPlaceholderNumber - (instancetype)initWithBool: (bool)value { if (value) { static OFOnceControl onceControl = OFOnceControlInitValue; OFOnce(&onceControl, trueNumberInit); @@ -170,192 +133,187 @@ if (value == 0) { static OFOnceControl onceControl = OFOnceControlInitValue; OFOnce(&onceControl, charZeroNumberInit); return (id)charZeroNumber; #ifdef OF_OBJFW_RUNTIME - } else if ((unsigned char)value <= (UINTPTR_MAX >> tagBits)) { - id ret = objc_createTaggedPointer(numberTag, - ((uintptr_t)(unsigned char)value << tagBits) | tagChar); + } else if ((unsigned char)value <= + (UINTPTR_MAX >> OFTaggedPointerNumberTagBits)) { + id ret = [OFTaggedPointerNumber numberWithChar: value]; if (ret != nil) return ret; #endif } - return (id)[[OFNumber of_alloc] initWithChar: value]; + return (id)[[OFConcreteNumber alloc] initWithChar: value]; } - (instancetype)initWithShort: (short)value { if (value == 0) { static OFOnceControl onceControl = OFOnceControlInitValue; OFOnce(&onceControl, shortZeroNumberInit); return (id)shortZeroNumber; #ifdef OF_OBJFW_RUNTIME - } else if ((unsigned short)value <= (UINTPTR_MAX >> tagBits)) { - id ret = objc_createTaggedPointer(numberTag, - ((uintptr_t)(unsigned short)value << tagBits) | tagShort); + } else if ((unsigned short)value <= + (UINTPTR_MAX >> OFTaggedPointerNumberTagBits)) { + id ret = [OFTaggedPointerNumber numberWithShort: value]; if (ret != nil) return ret; #endif } - return (id)[[OFNumber of_alloc] initWithShort: value]; + return (id)[[OFConcreteNumber alloc] initWithShort: value]; } - (instancetype)initWithInt: (int)value { if (value == 0) { static OFOnceControl onceControl = OFOnceControlInitValue; OFOnce(&onceControl, intZeroNumberInit); return (id)intZeroNumber; #ifdef OF_OBJFW_RUNTIME - } else if ((unsigned int)value <= (UINTPTR_MAX >> tagBits)) { - id ret = objc_createTaggedPointer(numberTag, - ((uintptr_t)(unsigned int)value << tagBits) | tagInt); + } else if ((unsigned int)value <= + (UINTPTR_MAX >> OFTaggedPointerNumberTagBits)) { + id ret = [OFTaggedPointerNumber numberWithInt: value]; if (ret != nil) return ret; #endif } - return (id)[[OFNumber of_alloc] initWithInt: value]; + return (id)[[OFConcreteNumber alloc] initWithInt: value]; } - (instancetype)initWithLong: (long)value { if (value == 0) { static OFOnceControl onceControl = OFOnceControlInitValue; OFOnce(&onceControl, longZeroNumberInit); return (id)longZeroNumber; #ifdef OF_OBJFW_RUNTIME - } else if ((unsigned long)value <= (UINTPTR_MAX >> tagBits)) { - id ret = objc_createTaggedPointer(numberTag, - ((uintptr_t)(unsigned long)value << tagBits) | tagLong); + } else if ((unsigned long)value <= + (UINTPTR_MAX >> OFTaggedPointerNumberTagBits)) { + id ret = [OFTaggedPointerNumber numberWithLong: value]; if (ret != nil) return ret; #endif } - return (id)[[OFNumber of_alloc] initWithLong: value]; + return (id)[[OFConcreteNumber alloc] initWithLong: value]; } - (instancetype)initWithLongLong: (long long)value { if (value == 0) { static OFOnceControl onceControl = OFOnceControlInitValue; OFOnce(&onceControl, longLongZeroNumberInit); return (id)longLongZeroNumber; #ifdef OF_OBJFW_RUNTIME - } else if ((unsigned long long)value <= (UINTPTR_MAX >> tagBits)) { - id ret = objc_createTaggedPointer(numberTag, - ((uintptr_t)(unsigned long long)value << tagBits) | - tagLongLong); + } else if ((unsigned long long)value <= + (UINTPTR_MAX >> OFTaggedPointerNumberTagBits)) { + id ret = [OFTaggedPointerNumber numberWithLongLong: value]; if (ret != nil) return ret; #endif } - return (id)[[OFNumber of_alloc] initWithLongLong: value]; + return (id)[[OFConcreteNumber alloc] initWithLongLong: value]; } - (instancetype)initWithUnsignedChar: (unsigned char)value { if (value == 0) { static OFOnceControl onceControl = OFOnceControlInitValue; OFOnce(&onceControl, unsignedCharZeroNumberInit); return (id)unsignedCharZeroNumber; #ifdef OF_OBJFW_RUNTIME - } else if (value <= (UINTPTR_MAX >> tagBits)) { - id ret = objc_createTaggedPointer(numberTag, - ((uintptr_t)value << tagBits) | tagUnsignedChar); + } else if (value <= (UINTPTR_MAX >> OFTaggedPointerNumberTagBits)) { + id ret = [OFTaggedPointerNumber numberWithUnsignedChar: value]; if (ret != nil) return ret; #endif } - return (id)[[OFNumber of_alloc] initWithUnsignedChar: value]; + return (id)[[OFConcreteNumber alloc] initWithUnsignedChar: value]; } - (instancetype)initWithUnsignedShort: (unsigned short)value { if (value == 0) { static OFOnceControl onceControl = OFOnceControlInitValue; OFOnce(&onceControl, unsignedShortZeroNumberInit); return (id)unsignedShortZeroNumber; #ifdef OF_OBJFW_RUNTIME - } else if (value <= (UINTPTR_MAX >> tagBits)) { - id ret = objc_createTaggedPointer(numberTag, - ((uintptr_t)value << tagBits) | tagUnsignedShort); + } else if (value <= (UINTPTR_MAX >> OFTaggedPointerNumberTagBits)) { + id ret = [OFTaggedPointerNumber numberWithUnsignedShort: value]; if (ret != nil) return ret; #endif } - return (id)[[OFNumber of_alloc] initWithUnsignedShort: value]; + return (id)[[OFConcreteNumber alloc] initWithUnsignedShort: value]; } - (instancetype)initWithUnsignedInt: (unsigned int)value { if (value == 0) { static OFOnceControl onceControl = OFOnceControlInitValue; OFOnce(&onceControl, unsignedIntZeroNumberInit); return (id)unsignedIntZeroNumber; #ifdef OF_OBJFW_RUNTIME - } else if (value <= (UINTPTR_MAX >> tagBits)) { - id ret = objc_createTaggedPointer(numberTag, - ((uintptr_t)value << tagBits) | tagUnsignedInt); + } else if (value <= (UINTPTR_MAX >> OFTaggedPointerNumberTagBits)) { + id ret = [OFTaggedPointerNumber numberWithUnsignedInt: value]; if (ret != nil) return ret; #endif } - return (id)[[OFNumber of_alloc] initWithUnsignedInt: value]; + return (id)[[OFConcreteNumber alloc] initWithUnsignedInt: value]; } - (instancetype)initWithUnsignedLong: (unsigned long)value { if (value == 0) { static OFOnceControl onceControl = OFOnceControlInitValue; OFOnce(&onceControl, unsignedLongZeroNumberInit); return (id)unsignedLongZeroNumber; #ifdef OF_OBJFW_RUNTIME - } else if (value <= (UINTPTR_MAX >> tagBits)) { - id ret = objc_createTaggedPointer(numberTag, - ((uintptr_t)value << tagBits) | tagUnsignedLong); + } else if (value <= (UINTPTR_MAX >> OFTaggedPointerNumberTagBits)) { + id ret = [OFTaggedPointerNumber numberWithUnsignedLong: value]; if (ret != nil) return ret; #endif } - return (id)[[OFNumber of_alloc] initWithUnsignedLong: value]; + return (id)[[OFConcreteNumber alloc] initWithUnsignedLong: value]; } - (instancetype)initWithUnsignedLongLong: (unsigned long long)value { if (value == 0) { static OFOnceControl onceControl = OFOnceControlInitValue; OFOnce(&onceControl, unsignedLongLongZeroNumberInit); return (id)unsignedLongLongZeroNumber; #ifdef OF_OBJFW_RUNTIME - } else if (value <= (UINTPTR_MAX >> tagBits)) { - id ret = objc_createTaggedPointer(numberTag, - ((uintptr_t)value << tagBits) | tagUnsignedLongLong); + } else if (value <= (UINTPTR_MAX >> OFTaggedPointerNumberTagBits)) { + id ret = [OFTaggedPointerNumber + numberWithUnsignedLongLong: value]; if (ret != nil) return ret; #endif } - return (id)[[OFNumber of_alloc] initWithUnsignedLongLong: value]; + return (id)[[OFConcreteNumber alloc] initWithUnsignedLongLong: value]; } - (instancetype)initWithFloat: (float)value { if (value == 0) { @@ -362,11 +320,11 @@ static OFOnceControl onceControl = OFOnceControlInitValue; OFOnce(&onceControl, floatZeroNumberInit); return (id)floatZeroNumber; } - return (id)[[OFNumber of_alloc] initWithFloat: value]; + return (id)[[OFConcreteNumber alloc] initWithFloat: value]; } - (instancetype)initWithDouble: (double)value { if (value == 0) { @@ -373,137 +331,28 @@ static OFOnceControl onceControl = OFOnceControlInitValue; OFOnce(&onceControl, doubleZeroNumberInit); return (id)doubleZeroNumber; } - return (id)[[OFNumber of_alloc] initWithDouble: value]; -} - -- (instancetype)initWithSerialization: (OFXMLElement *)element -{ - return (id)[[OFNumber of_alloc] initWithSerialization: element]; + return (id)[[OFConcreteNumber alloc] initWithDouble: value]; } #ifdef __clang__ # pragma clang diagnostic pop #endif -@end - -@implementation OFNumberSingleton -- (instancetype)autorelease -{ - return self; -} - -- (instancetype)retain -{ - return self; -} - -- (void)release -{ -} - -- (unsigned int)retainCount -{ - return OFMaxRetainCount; -} -@end - -#ifdef OF_OBJFW_RUNTIME -@implementation OFTaggedPointerNumber -- (const char *)objCType -{ - uintptr_t value = object_getTaggedPointerValue(self); - - switch (value & tagMask) { - case tagChar: - return @encode(signed char); - case tagShort: - return @encode(short); - case tagInt: - return @encode(int); - case tagLong: - return @encode(long); - case tagLongLong: - return @encode(long long); - case tagUnsignedChar: - return @encode(unsigned char); - case tagUnsignedShort: - return @encode(unsigned short); - case tagUnsignedInt: - return @encode(unsigned int); - case tagUnsignedLong: - return @encode(unsigned long); - case tagUnsignedLongLong: - return @encode(unsigned long long); - default: - @throw [OFInvalidArgumentException exception]; - } -} - -# define RETURN_VALUE \ - uintptr_t value = object_getTaggedPointerValue(self); \ - \ - switch (value & tagMask) { \ - case tagChar: \ - return (signed char)(unsigned char)(value >> tagBits); \ - case tagShort: \ - return (short)(unsigned short)(value >> tagBits); \ - case tagInt: \ - return (int)(unsigned int)(value >> tagBits); \ - case tagLong: \ - return (long)(unsigned long)(value >> tagBits); \ - case tagLongLong: \ - return (long long)(unsigned long long)(value >> tagBits); \ - case tagUnsignedChar: \ - return (unsigned char)(value >> tagBits); \ - case tagUnsignedShort: \ - return (unsigned short)(value >> tagBits); \ - case tagUnsignedInt: \ - return (unsigned int)(value >> tagBits); \ - case tagUnsignedLong: \ - return (unsigned long)(value >> tagBits); \ - case tagUnsignedLongLong: \ - return (unsigned long long)(value >> tagBits); \ - default: \ - @throw [OFInvalidArgumentException exception]; \ - } -- (long long)longLongValue -{ - RETURN_VALUE -} - -- (unsigned long long)unsignedLongLongValue -{ - RETURN_VALUE -} - -- (double)doubleValue -{ - RETURN_VALUE -} -@end -# undef RETURN_VALUE -#endif + +OF_SINGLETON_METHODS +@end + +@implementation OFConcreteNumberSingleton +OF_SINGLETON_METHODS +@end @implementation OFNumber + (void)initialize { - if (self != [OFNumber class]) - return; - - placeholder.isa = [OFNumberPlaceholder class]; - -#ifdef OF_OBJFW_RUNTIME - numberTag = - objc_registerTaggedPointerClass([OFTaggedPointerNumber class]); -#endif -} - -+ (instancetype)of_alloc -{ - return [super alloc]; + if (self == [OFNumber class]) + object_setClass((id)&placeholder, [OFPlaceholderNumber class]); } + (instancetype)alloc { if (self == [OFNumber class]) @@ -510,16 +359,10 @@ return (id)&placeholder; return [super alloc]; } -+ (instancetype)valueWithBytes: (const void *)bytes - objCType: (const char *)objCType -{ - OF_UNRECOGNIZED_SELECTOR -} - + (instancetype)valueWithPointer: (const void *)pointer { OF_UNRECOGNIZED_SELECTOR } @@ -611,300 +454,89 @@ + (instancetype)numberWithDouble: (double)value { return [[[self alloc] initWithDouble: value] autorelease]; } -- (instancetype)init -{ - OF_INVALID_INIT_METHOD -} - -- (instancetype)initWithBytes: (const void *)bytes - objCType: (const char *)objCType -{ - OF_INVALID_INIT_METHOD -} - - (instancetype)initWithBool: (bool)value { - self = [super init]; - - _value.unsigned_ = value; - _typeEncoding = @encode(bool); - - return self; + return [self initWithBytes: &value objCType: @encode(bool)]; } - (instancetype)initWithChar: (signed char)value { - self = [super init]; - - _value.signed_ = value; - _typeEncoding = @encode(signed char); - - return self; + return [self initWithBytes: &value objCType: @encode(signed char)]; } - (instancetype)initWithShort: (short)value { - self = [super init]; - - _value.signed_ = value; - _typeEncoding = @encode(short); - - return self; + return [self initWithBytes: &value objCType: @encode(short)]; } - (instancetype)initWithInt: (int)value { - self = [super init]; - - _value.signed_ = value; - _typeEncoding = @encode(int); - - return self; + return [self initWithBytes: &value objCType: @encode(int)]; } - (instancetype)initWithLong: (long)value { - self = [super init]; - - _value.signed_ = value; - _typeEncoding = @encode(long); - - return self; + return [self initWithBytes: &value objCType: @encode(long)]; } - (instancetype)initWithLongLong: (long long)value { - self = [super init]; - - _value.signed_ = value; - _typeEncoding = @encode(long long); - - return self; + return [self initWithBytes: &value objCType: @encode(long long)]; } - (instancetype)initWithUnsignedChar: (unsigned char)value { - self = [super init]; - - _value.unsigned_ = value; - _typeEncoding = @encode(unsigned long); - - return self; + return [self initWithBytes: &value objCType: @encode(unsigned char)]; } - (instancetype)initWithUnsignedShort: (unsigned short)value { - self = [super init]; - - _value.unsigned_ = value; - _typeEncoding = @encode(unsigned short); - - return self; + return [self initWithBytes: &value objCType: @encode(unsigned short)]; } - (instancetype)initWithUnsignedInt: (unsigned int)value { - self = [super init]; - - _value.unsigned_ = value; - _typeEncoding = @encode(unsigned int); - - return self; + return [self initWithBytes: &value objCType: @encode(unsigned int)]; } - (instancetype)initWithUnsignedLong: (unsigned long)value { - self = [super init]; - - _value.unsigned_ = value; - _typeEncoding = @encode(unsigned long); - - return self; + return [self initWithBytes: &value objCType: @encode(unsigned long)]; } - (instancetype)initWithUnsignedLongLong: (unsigned long long)value { - self = [super init]; - - _value.unsigned_ = value; - _typeEncoding = @encode(unsigned long long); - - return self; -} - -- (instancetype)initWithPtrDiff: (ptrdiff_t)value -{ - self = [super init]; - - _value.signed_ = value; - _typeEncoding = @encode(ptrdiff_t); - - return self; -} - -- (instancetype)initWithIntPtr: (intptr_t)value -{ - self = [super init]; - - _value.signed_ = value; - _typeEncoding = @encode(intptr_t); - - return self; -} - -- (instancetype)initWithUIntPtr: (uintptr_t)value -{ - self = [super init]; - - _value.unsigned_ = value; - _typeEncoding = @encode(uintptr_t); - - return self; + return [self initWithBytes: &value + objCType: @encode(unsigned long long)]; } - (instancetype)initWithFloat: (float)value { - self = [super init]; - - _value.float_ = value; - _typeEncoding = @encode(float); - - return self; + return [self initWithBytes: &value objCType: @encode(float)]; } - (instancetype)initWithDouble: (double)value { - self = [super init]; - - _value.float_ = value; - _typeEncoding = @encode(double); - - return self; -} - -- (instancetype)initWithSerialization: (OFXMLElement *)element -{ - self = [super init]; - - @try { - void *pool = objc_autoreleasePoolPush(); - OFString *typeString; - - if (![element.name isEqual: @"OFNumber"] || - ![element.namespace isEqual: OFSerializationNS]) - @throw [OFInvalidArgumentException exception]; - - typeString = [element attributeForName: @"type"].stringValue; - - if ([typeString isEqual: @"bool"]) { - OFString *stringValue = element.stringValue; - if ([stringValue isEqual: @"true"]) - self = [self initWithBool: true]; - else if ([stringValue isEqual: @"false"]) - self = [self initWithBool: false]; - else - @throw [OFInvalidArgumentException exception]; - } else if ([typeString isEqual: @"float"]) { - unsigned long long value = - [element unsignedLongLongValueWithBase: 16]; - - if (value > UINT64_MAX) - @throw [OFOutOfRangeException exception]; - - self = [self initWithDouble: OFFromBigEndianDouble( - OFRawUInt64ToDouble(OFToBigEndian64(value)))]; - } else if ([typeString isEqual: @"signed"]) - self = [self initWithLongLong: element.longLongValue]; - else if ([typeString isEqual: @"unsigned"]) - self = [self initWithUnsignedLongLong: - element.unsignedLongLongValue]; - else - @throw [OFInvalidArgumentException exception]; - - objc_autoreleasePoolPop(pool); - } @catch (id e) { - [self release]; - @throw e; - } - - return self; -} - -- (const char *)objCType -{ - return _typeEncoding; -} - -- (void)getValue: (void *)value size: (size_t)size -{ - switch (*self.objCType) { -#define CASE(enc, type, property) \ - case enc: { \ - type tmp = (type)self.property; \ - \ - if (size != sizeof(type)) \ - @throw [OFOutOfRangeException exception]; \ - \ - memcpy(value, &tmp, size); \ - break; \ - } - CASE('B', bool, unsignedLongLongValue) - CASE('c', signed char, longLongValue) - CASE('s', short, longLongValue) - CASE('i', int, longLongValue) - CASE('l', long, longLongValue) - CASE('q', long long, longLongValue) - CASE('C', unsigned char, unsignedLongLongValue) - CASE('S', unsigned short, unsignedLongLongValue) - CASE('I', unsigned int, unsignedLongLongValue) - CASE('L', unsigned long, unsignedLongLongValue) - CASE('Q', unsigned long long, unsignedLongLongValue) - CASE('f', float, doubleValue) - CASE('d', double, doubleValue) -#undef CASE - default: - @throw [OFInvalidFormatException exception]; - } + return [self initWithBytes: &value objCType: @encode(double)]; } - (long long)longLongValue { - if (isFloat(self)) - return _value.float_; - else if (isSigned(self)) - return _value.signed_; - else if (isUnsigned(self)) - return _value.unsigned_; - else - @throw [OFInvalidFormatException exception]; + OF_UNRECOGNIZED_SELECTOR } - (unsigned long long)unsignedLongLongValue { - if (isFloat(self)) - return _value.float_; - else if (isSigned(self)) - return _value.signed_; - else if (isUnsigned(self)) - return _value.unsigned_; - else - @throw [OFInvalidFormatException exception]; + OF_UNRECOGNIZED_SELECTOR } - (double)doubleValue { - if (isFloat(self)) - return _value.float_; - else if (isSigned(self)) - return _value.signed_; - else if (isUnsigned(self)) - return _value.unsigned_; - else - @throw [OFInvalidFormatException exception]; + OF_UNRECOGNIZED_SELECTOR } - (bool)boolValue { return (bool)self.unsignedLongLongValue; @@ -1064,11 +696,11 @@ return [self stringValue]; } - (OFString *)stringValue { - if (*self.objCType == 'B') + if (self.objCType[0] == 'B' && self.objCType[1] == '\0') return (self.boolValue ? @"true" : @"false"); if (isFloat(self)) return [OFString stringWithFormat: @"%g", self.doubleValue]; if (isSigned(self)) return [OFString stringWithFormat: @"%lld", self.longLongValue]; @@ -1077,42 +709,10 @@ self.unsignedLongLongValue]; @throw [OFInvalidFormatException exception]; } -- (OFXMLElement *)XMLElementBySerializing -{ - void *pool = objc_autoreleasePoolPush(); - OFXMLElement *element; - - element = [OFXMLElement elementWithName: @"OFNumber" - namespace: OFSerializationNS - stringValue: self.description]; - - if (*self.objCType == 'B') - [element addAttributeWithName: @"type" stringValue: @"bool"]; - else if (isFloat(self)) { - [element addAttributeWithName: @"type" stringValue: @"float"]; - element.stringValue = [OFString - stringWithFormat: @"%016" PRIx64, - OFFromBigEndian64(OFDoubleToRawUInt64(OFToBigEndianDouble( - self.doubleValue)))]; - } else if (isSigned(self)) - [element addAttributeWithName: @"type" stringValue: @"signed"]; - else if (isUnsigned(self)) - [element addAttributeWithName: @"type" - stringValue: @"unsigned"]; - else - @throw [OFInvalidFormatException exception]; - - [element retain]; - - objc_autoreleasePoolPop(pool); - - return [element autorelease]; -} - - (OFString *)JSONRepresentation { return [self of_JSONRepresentationWithOptions: 0 depth: 0]; } @@ -1126,11 +726,11 @@ of_JSONRepresentationWithOptions: (OFJSONRepresentationOptions)options depth: (size_t)depth { double doubleValue; - if (*self.objCType == 'B') + if (self.objCType[0] == 'B' && self.objCType[1] == '\0') return (self.boolValue ? @"true" : @"false"); doubleValue = self.doubleValue; if (isinf(doubleValue)) { if (options & OFJSONRepresentationOptionJSON5) { @@ -1147,10 +747,13 @@ - (OFData *)messagePackRepresentation { OFMutableData *data; const char *typeEncoding = self.objCType; + + if (typeEncoding[0] == '\0' || typeEncoding[1] != '\0') + @throw [OFInvalidFormatException exception]; if (*typeEncoding == 'B') { uint8_t type = (self.boolValue ? 0xC3 : 0xC2); data = [OFMutableData dataWithItems: &type count: 1]; } else if (*typeEncoding == 'f') {