summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJonathan Schleifer <js@heap.zone>2018-05-26 16:43:14 +0200
committerJonathan Schleifer <js@heap.zone>2018-05-26 16:43:14 +0200
commit2d9dc8cbbb1825d69b65c5c4640c49ad42a1a031 (patch)
tree8e42a560d17599933f58bd27b9cd70c5593b06e3
parenta2b72f826fd739891399fa888c1867c00ef1a95d (diff)
MessagePack: Add support for the date extension
-rw-r--r--src/OFData+MessagePackValue.m108
-rw-r--r--src/OFDate.h4
-rw-r--r--src/OFDate.m61
3 files changed, 126 insertions, 47 deletions
diff --git a/src/OFData+MessagePackValue.m b/src/OFData+MessagePackValue.m
index 88104a59..59c90e1c 100644
--- a/src/OFData+MessagePackValue.m
+++ b/src/OFData+MessagePackValue.m
@@ -20,12 +20,13 @@
#include <string.h>
#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"
@@ -153,12 +154,63 @@ parseTable(const uint8_t *buffer, size_t length, id *object, size_t count,
return pos;
}
+static OFDate *
+createDate(OFData *data)
+{
+ switch ([data count]) {
+ case 4: {
+ uint32_t timestamp;
+
+ memcpy(&timestamp, [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)
@@ -341,14 +393,10 @@ parseObject(const uint8_t *buffer, size_t length, id *object,
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];
}
@@ -363,14 +411,10 @@ parseObject(const uint8_t *buffer, size_t length, id *object,
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];
}
@@ -385,14 +429,10 @@ parseObject(const uint8_t *buffer, size_t length, id *object,
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];
}
@@ -402,14 +442,10 @@ parseObject(const uint8_t *buffer, size_t length, id *object,
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];
}
@@ -419,14 +455,10 @@ parseObject(const uint8_t *buffer, size_t length, id *object,
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];
}
@@ -436,14 +468,10 @@ parseObject(const uint8_t *buffer, size_t length, id *object,
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];
}
@@ -453,14 +481,10 @@ parseObject(const uint8_t *buffer, size_t length, id *object,
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];
}
@@ -470,14 +494,10 @@ parseObject(const uint8_t *buffer, size_t length, id *object,
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];
}
diff --git a/src/OFDate.h b/src/OFDate.h
index 21629924..8f4fa926 100644
--- a/src/OFDate.h
+++ b/src/OFDate.h
@@ -16,6 +16,7 @@
*/
#import "OFObject.h"
+#import "OFMessagePackRepresentation.h"
#import "OFSerialization.h"
OF_ASSUME_NONNULL_BEGIN
@@ -28,7 +29,8 @@ OF_ASSUME_NONNULL_BEGIN
*
* @brief A class for storing, accessing and comparing dates.
*/
-@interface OFDate: OFObject <OFCopying, OFComparing, OFSerialization>
+@interface OFDate: OFObject <OFCopying, OFComparing, OFSerialization,
+ OFMessagePackRepresentation>
{
of_time_interval_t _seconds;
}
diff --git a/src/OFDate.m b/src/OFDate.m
index 453cb837..60ffb037 100644
--- a/src/OFDate.m
+++ b/src/OFDate.m
@@ -24,13 +24,15 @@
#include <sys/time.h>
#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"
@@ -442,6 +444,61 @@ tmAndTzToTime(struct tm *tm, int16_t *tz)
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);