Index: src/OFData+MessagePackValue.m ================================================================== --- src/OFData+MessagePackValue.m +++ src/OFData+MessagePackValue.m @@ -18,16 +18,17 @@ #include "config.h" #include #import "OFData+MessagePackValue.h" -#import "OFNumber.h" -#import "OFNull.h" -#import "OFString.h" #import "OFArray.h" +#import "OFDate.h" #import "OFDictionary.h" #import "OFMessagePackExtension.h" +#import "OFNull.h" +#import "OFNumber.h" +#import "OFString.h" #import "OFInvalidFormatException.h" int _OFData_MessagePackValue_reference; @@ -150,17 +151,68 @@ 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 uint8_t *buffer, size_t length, id *object, size_t depthLimit) { size_t count; - int8_t type; OFData *data; if (length < 1) goto error; @@ -339,18 +391,14 @@ count = buffer[1]; if (length < count + 3) goto error; - type = buffer[2]; - data = [[OFData alloc] initWithItems: buffer + 3 count: count]; @try { - *object = [OFMessagePackExtension - extensionWithType: type - data: data]; + *object = createExtension(buffer[2], data); } @finally { [data release]; } return count + 3; @@ -361,18 +409,14 @@ count = readUInt16(buffer + 1); if (length < count + 4) goto error; - type = buffer[3]; - data = [[OFData alloc] initWithItems: buffer + 4 count: count]; @try { - *object = [OFMessagePackExtension - extensionWithType: type - data: data]; + *object = createExtension(buffer[3], data); } @finally { [data release]; } return count + 4; @@ -383,103 +427,79 @@ count = readUInt32(buffer + 1); if (length < count + 6) goto error; - type = buffer[5]; - data = [[OFData alloc] initWithItems: buffer + 6 count: count]; @try { - *object = [OFMessagePackExtension - extensionWithType: type - data: data]; + *object = createExtension(buffer[5], data); } @finally { [data release]; } return count + 6; case 0xD4: /* fixext 1 */ if (length < 3) goto error; - type = buffer[1]; - data = [[OFData alloc] initWithItems: buffer + 2 count: 1]; @try { - *object = [OFMessagePackExtension - extensionWithType: type - data: data]; + *object = createExtension(buffer[1], data); } @finally { [data release]; } return 3; case 0xD5: /* fixext 2 */ if (length < 4) goto error; - type = buffer[1]; - data = [[OFData alloc] initWithItems: buffer + 2 count: 2]; @try { - *object = [OFMessagePackExtension - extensionWithType: type - data: data]; + *object = createExtension(buffer[1], data); } @finally { [data release]; } return 4; case 0xD6: /* fixext 4 */ if (length < 6) goto error; - type = buffer[1]; - data = [[OFData alloc] initWithItems: buffer + 2 count: 4]; @try { - *object = [OFMessagePackExtension - extensionWithType: type - data: data]; + *object = createExtension(buffer[1], data); } @finally { [data release]; } return 6; case 0xD7: /* fixext 8 */ if (length < 10) goto error; - type = buffer[1]; - data = [[OFData alloc] initWithItems: buffer + 2 count: 8]; @try { - *object = [OFMessagePackExtension - extensionWithType: type - data: data]; + *object = createExtension(buffer[1], data); } @finally { [data release]; } return 10; case 0xD8: /* fixext 16 */ if (length < 18) goto error; - type = buffer[1]; - data = [[OFData alloc] initWithItems: buffer + 2 count: 16]; @try { - *object = [OFMessagePackExtension - extensionWithType: type - data: data]; + *object = createExtension(buffer[1], data); } @finally { [data release]; } return 18; Index: src/OFDate.h ================================================================== --- src/OFDate.h +++ src/OFDate.h @@ -14,10 +14,11 @@ * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this * file. */ #import "OFObject.h" +#import "OFMessagePackRepresentation.h" #import "OFSerialization.h" OF_ASSUME_NONNULL_BEGIN @class OFString; @@ -26,11 +27,12 @@ /*! * @class OFDate OFDate.h ObjFW/OFDate.h * * @brief A class for storing, accessing and comparing dates. */ -@interface OFDate: OFObject +@interface OFDate: OFObject { of_time_interval_t _seconds; } #ifdef OF_HAVE_CLASS_PROPERTIES Index: src/OFDate.m ================================================================== --- src/OFDate.m +++ src/OFDate.m @@ -22,17 +22,19 @@ #include #include #import "OFDate.h" -#import "OFString.h" +#import "OFData.h" #import "OFDictionary.h" -#import "OFXMLElement.h" +#import "OFMessagePackExtension.h" #ifdef OF_HAVE_THREADS # import "OFMutex.h" #endif +#import "OFString.h" #import "OFSystemInfo.h" +#import "OFXMLElement.h" #import "OFInitializationFailedException.h" #import "OFInvalidArgumentException.h" #import "OFInvalidFormatException.h" #import "OFOutOfRangeException.h" @@ -439,10 +441,65 @@ objc_autoreleasePoolPop(pool); return [element autorelease]; } + +- (OFData *)messagePackRepresentation +{ + void *pool = objc_autoreleasePoolPush(); + int64_t seconds = (int64_t)_seconds; + uint32_t nanoseconds = (_seconds - trunc(_seconds)) * 1000000000; + OFData *ret; + + if (seconds >= 0 && seconds < 0x400000000) { + if (seconds <= UINT32_MAX && nanoseconds == 0) { + uint32_t seconds32 = (uint32_t)seconds; + OFData *data; + + seconds32 = OF_BSWAP32_IF_LE(seconds32); + data = [OFData dataWithItems: &seconds32 + count: sizeof(seconds32)]; + + ret = [[OFMessagePackExtension + extensionWithType: -1 + data: data] messagePackRepresentation]; + } else { + uint64_t combined = ((uint64_t)nanoseconds << 34) | + (uint64_t)seconds; + OFData *data; + + combined = OF_BSWAP64_IF_LE(combined); + data = [OFData dataWithItems: &combined + count: sizeof(combined)]; + + ret = [[OFMessagePackExtension + extensionWithType: -1 + data: data] messagePackRepresentation]; + } + } else { + OFMutableData *data = [OFMutableData dataWithCapacity: 12]; + + seconds = OF_BSWAP64_IF_LE(seconds); + nanoseconds = OF_BSWAP32_IF_LE(nanoseconds); + + [data addItems: &nanoseconds + count: sizeof(nanoseconds)]; + [data addItems: &seconds + count: sizeof(seconds)]; + + ret = [[OFMessagePackExtension + extensionWithType: -1 + data: data] messagePackRepresentation]; + } + + [ret retain]; + + objc_autoreleasePoolPop(pool); + + return [ret autorelease]; +} - (uint32_t)microsecond { return (uint32_t)((_seconds - floor(_seconds)) * 1000000); }