-
Notifications
You must be signed in to change notification settings - Fork 60
/
Copy pathMessagePackParser.m
107 lines (99 loc) · 4.25 KB
/
MessagePackParser.m
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
//
// MessagePackParser.m
// Fetch TV Remote
//
// Created by Chris Hulbert on 23/06/11.
// Copyright 2011 Digital Five. All rights reserved.
//
#import "MessagePackParser.h"
@implementation MessagePackParser
// This function returns a parsed object that you have the responsibility to release/autorelease (see 'create rule' in apple docs)
+(id) createUnpackedObject:(msgpack_object)obj rawHandling:(MPRawHandling)rawHandling {
switch (obj.type) {
case MSGPACK_OBJECT_BOOLEAN:
return [[NSNumber alloc] initWithBool:obj.via.boolean];
case MSGPACK_OBJECT_POSITIVE_INTEGER:
return [[NSNumber alloc] initWithUnsignedLongLong:obj.via.u64];
case MSGPACK_OBJECT_NEGATIVE_INTEGER:
return [[NSNumber alloc] initWithLongLong:obj.via.i64];
case MSGPACK_OBJECT_DOUBLE:
return [[NSNumber alloc] initWithDouble:obj.via.dec];
case MSGPACK_OBJECT_RAW:
{
if (rawHandling == MPRawsAsNSData) {
return [[NSData alloc] initWithBytes:obj.via.raw.ptr length:obj.via.raw.size];
}
NSString *res = [[NSString alloc] initWithBytes:obj.via.raw.ptr
length:obj.via.raw.size
encoding:NSUTF8StringEncoding];
if (res) {
return res;
}
switch (rawHandling) {
case MPRawsAsNSString_NSNullOnFail:
return [NSNull null];
case MPRawsAsNSString_ExceptionOnFail:
[NSException raise:@"Invalid string encountered"
format:@"Raw bytes did not decode into utf8"];
return res;
case MPRawsAsNSString_NSDataOnFail: {
return [[NSData alloc] initWithBytes:obj.via.raw.ptr length:obj.via.raw.size];
case MPRawsAsNSData: //suppress compiler warning
return res;
}
}
}
case MSGPACK_OBJECT_ARRAY:
{
NSMutableArray *arr = [[NSMutableArray alloc] initWithCapacity:obj.via.array.size];
msgpack_object* const pend = obj.via.array.ptr + obj.via.array.size;
for(msgpack_object *p= obj.via.array.ptr;p < pend;p++){
id newArrayItem = [self createUnpackedObject:*p rawHandling:rawHandling];
[arr addObject:newArrayItem];
#if !__has_feature(objc_arc)
[newArrayItem release];
#endif
}
return arr;
}
case MSGPACK_OBJECT_MAP:
{
NSMutableDictionary *dict = [[NSMutableDictionary alloc] initWithCapacity:obj.via.map.size];
msgpack_object_kv* const pend = obj.via.map.ptr + obj.via.map.size;
for(msgpack_object_kv* p = obj.via.map.ptr; p < pend; p++){
id key = [self createUnpackedObject:p->key rawHandling:rawHandling];
id val = [self createUnpackedObject:p->val rawHandling:rawHandling];
[dict setValue:val forKey:key];
#if !__has_feature(objc_arc)
[key release];
[val release];
#endif
}
return dict;
}
case MSGPACK_OBJECT_NIL:
return [NSNull null]; // Since nsnull is a system singleton, we don't have to worry about ownership of it
default:
[NSException raise:@"Unsupported object type"
format:@"Unrecognized msgpack object type %d", obj.type];
return [NSNull null]; // suppress compiler warning
}
}
+ (id)parseData:(NSData*)data rawHandling:(MPRawHandling)rawHandling {
msgpack_unpacked msg;
msgpack_unpacked_init(&msg);
bool success = msgpack_unpack_next(&msg, data.bytes, data.length, NULL); // Parse it into C-land
// Convert from C-land to Obj-c-land
id results = success ? [self createUnpackedObject:msg.data rawHandling:rawHandling] : nil;
msgpack_unpacked_destroy(&msg); // Free the parser
#if !__has_feature(objc_arc)
return [results autorelease];
#else
return results;
#endif
}
// Parse the given messagepack data into a NSDictionary or NSArray typically
+ (id)parseData:(NSData*)data {
return [self parseData:data rawHandling:MPRawsAsNSString_ExceptionOnFail];
}
@end