├── Tests ├── GenerateTests.sh ├── Info.plist ├── Tests.erb └── Tests.m ├── MessagePackCoder ├── MsgPackUnarchiver.h ├── MsgPackArchiver.h ├── MsgPackArchiving.h ├── MsgPackArchiver.m ├── MsgPackUnarchiver.m ├── cmp.h └── cmp.c ├── LICENSE ├── README.md └── MessagePackCoder.xcodeproj └── project.pbxproj /Tests/GenerateTests.sh: -------------------------------------------------------------------------------- 1 | erb -T "-" Tests.erb > Tests.m -------------------------------------------------------------------------------- /MessagePackCoder/MsgPackUnarchiver.h: -------------------------------------------------------------------------------- 1 | // 2 | // MsgPackUnarchiver.h 3 | // MessagePackCoder 4 | // https://github.com/swillits/messagepackcoder 5 | // 6 | // Created by Seth Willits on 12/4/14. 7 | // Copyright (c) 2014 Seth Willits. All rights reserved. 8 | // 9 | 10 | #import 11 | 12 | @interface MsgPackUnarchiver : NSCoder 13 | + (id)unarchiveObjectWithData:(NSData *)data; 14 | 15 | - (instancetype)initForReadingWithData:(NSData *)data; 16 | 17 | @end 18 | -------------------------------------------------------------------------------- /MessagePackCoder/MsgPackArchiver.h: -------------------------------------------------------------------------------- 1 | // 2 | // MsgPackArchiver.h 3 | // MessagePackCoder 4 | // https://github.com/swillits/messagepackcoder 5 | // 6 | // Created by Seth Willits on 12/4/14. 7 | // Copyright (c) 2014 Seth Willits. All rights reserved. 8 | // 9 | 10 | #import 11 | 12 | @interface MsgPackArchiver : NSCoder 13 | + (NSData *)archivedDataWithRootObject:(id)rootObject; 14 | 15 | - (instancetype)initForWritingWithMutableData:(NSMutableData *)data; 16 | - (void)finishEncoding; 17 | 18 | @end 19 | -------------------------------------------------------------------------------- /MessagePackCoder/MsgPackArchiving.h: -------------------------------------------------------------------------------- 1 | // 2 | // MsgPackArchiving.h 3 | // MessagePackCoder 4 | // https://github.com/swillits/messagepackcoder 5 | // 6 | // Created by Seth Willits on 12/4/14. 7 | // Copyright (c) 2014 Seth Willits. All rights reserved. 8 | // 9 | 10 | #import 11 | 12 | 13 | typedef enum { 14 | MsgPackArchiveTypeData = 0, 15 | MsgPackArchiveTypeObject, 16 | MsgPackArchiveTypeString, 17 | MsgPackArchiveTypeArray, 18 | MsgPackArchiveTypeDictionary, 19 | 20 | MsgPackArchiveTypeBoolean, 21 | MsgPackArchiveTypeUInt64, 22 | MsgPackArchiveTypeInt64, 23 | MsgPackArchiveTypeDouble, 24 | MsgPackArchiveTypePoint, 25 | MsgPackArchiveTypeSize, 26 | MsgPackArchiveTypeRect 27 | } MsgPackArchiveType; 28 | -------------------------------------------------------------------------------- /Tests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | com.araeliumgroup.$(PRODUCT_NAME:rfc1034identifier) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | 24 | 25 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 swillits 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | MessagePackCoder 3 | ============= 4 | 5 | The MsgPackArchiver and MsgPackUnarchiver classes are drop-in replacements for 6 | NSKeyedArchiver and NSKeyedUnarchiver, which use the MessagePack protocol for storage. 7 | 8 | 9 | Benefits 10 | ------------- 11 | MsgPackArchiver and MsgPackUnarchiver are significantly faster (multiple times) than 12 | the standard Cocoa classes and use less space to store the data, while still being 13 | NSCoder subclasses. 14 | 15 | 16 | Caveats 17 | ------------- 18 | Part of the performance gain is by the MsgPack coder explicitly handling NSString, 19 | NSArray, and NSDictionary, that is, _not_ relying on their NSCoding implementations. 20 | This means when you decode a string/array/dictionary using MsgPackUnarchiver, it will 21 | create NSString/NSArray/NSDictionary instances, not instances of your given subclass. 22 | 23 | 24 | Stability 25 | ------------- 26 | There are unit tests demonstrating the code works (at least with the given 27 | test cases) but there's no guarantee of production readiness at the moment. If you'd 28 | like to use it, please review the code and make any contributions. (This was mostly 29 | a quick hackathon project.) 30 | 31 | 32 | Requirements 33 | ------------- 34 | 35 | This project uses "CMP", which is a C implementation of the MessagePack protocol. 36 | You can find that project here: https://github.com/camgunz/cmp 37 | CMP has a friendly MIT license. 38 | 39 | There are no OS version requirements for this code, but it currently uses MRC only. 40 | 41 | 42 | 43 | License 44 | ------------- 45 | 46 | Portions not including "CMP" are copyright (c) 2014, Seth Willits 47 | 48 | Permission is hereby granted, free of charge, to any person obtaining a copy of this 49 | software and associated documentation files (the "Software"), to deal in the Software 50 | without restriction, including without limitation the rights to use, copy, modify, 51 | merge, publish, distribute, sublicense, and/or sell copies of the Software, and to 52 | permit persons to whom the Software is furnished to do so, subject to the following 53 | conditions: 54 | 55 | The above copyright notice and this permission notice shall be included in all copies 56 | or substantial portions of the Software. 57 | 58 | The Software is provided "as is", without warranty of any kind, express or implied, 59 | including but not limited to the warranties of merchantability, fitness for a 60 | particular purpose and noninfringement. In no event shall the authors or copyright 61 | holders be liable for any claim, damages or other liability, whether in an action of 62 | contract, tort or otherwise, arising from, out of or in connection with the Software 63 | or the use or other dealings in the Software. 64 | 65 | -- 66 | 67 | In plain English: do whatever you want with it, and no you do not need to give me 68 | credit in your application/documentation. 69 | 70 | 71 | -------------------------------------------------------------------------------- /MessagePackCoder/MsgPackArchiver.m: -------------------------------------------------------------------------------- 1 | // 2 | // MsgPackArchiver.m 3 | // MessagePackCoder 4 | // https://github.com/swillits/messagepackcoder 5 | // 6 | // Created by Seth Willits on 12/4/14. 7 | // Copyright (c) 2014 Seth Willits. All rights reserved. 8 | // 9 | 10 | #import 11 | #import "MsgPackArchiver.h" 12 | #import "MsgPackArchiving.h" 13 | #import "cmp.h" 14 | 15 | 16 | 17 | #define PACK_KEY_AND_TYPE(key, type) MsgPackArchiver_PackKeyAndType(self, key, type) 18 | 19 | #define PACK_KEY(key) MsgPackArchiver_PackKey(self, key) 20 | #define PACK_TYPE(type) MsgPackArchiver_PackType(self, type) 21 | 22 | #define PACK_STRING(ctx__, value__) \ 23 | { \ 24 | const char * str = (value__).UTF8String; \ 25 | size_t len = strlen(str); \ 26 | cmp_write_bin(&ctx__, str, (uint32_t)len); \ 27 | } 28 | 29 | 30 | #define PACK_DATA(ctx__, value__) \ 31 | cmp_write_bin(&ctx__, value__.bytes, (uint32_t)(value__).length); 32 | 33 | 34 | 35 | static size_t MsgPackArchiver_writer(struct cmp_ctx_s *ctx, const void *data, size_t count); 36 | 37 | 38 | 39 | 40 | 41 | @implementation MsgPackArchiver 42 | { 43 | cmp_ctx_t _ctx; 44 | NSMutableData * _data; 45 | NSMutableSet * _encodedKeys; 46 | } 47 | 48 | 49 | 50 | + (NSData *)archivedDataWithRootObject:(id)rootObject; 51 | { 52 | MsgPackArchiver * a = [[MsgPackArchiver alloc] init]; 53 | NSData * data = nil; 54 | 55 | [a encodeObject:rootObject forKey:@"ROOT"]; 56 | data = [a archivedData]; 57 | [a release]; 58 | 59 | return data; 60 | } 61 | 62 | 63 | 64 | - (instancetype)init 65 | { 66 | return [self initForWritingWithMutableData:[[[NSMutableData alloc] init] autorelease]]; 67 | } 68 | 69 | 70 | 71 | - (instancetype)initForWritingWithMutableData:(NSMutableData *)data; 72 | { 73 | if (!(self = [super init])) { 74 | return nil; 75 | } 76 | 77 | assert(data); 78 | _data = [data retain]; 79 | cmp_init(&_ctx, (void *)self, NULL, MsgPackArchiver_writer); 80 | 81 | return self; 82 | } 83 | 84 | 85 | 86 | - (void)dealloc 87 | { 88 | [_encodedKeys release]; 89 | [_data release]; 90 | [super dealloc]; 91 | } 92 | 93 | 94 | 95 | - (void)finishEncoding 96 | { 97 | 98 | } 99 | 100 | 101 | 102 | - (NSData *)archivedData 103 | { 104 | 105 | return [[_data copy] autorelease]; 106 | } 107 | 108 | 109 | 110 | 111 | #pragma mark - 112 | #pragma mark Required For All Coders 113 | 114 | - (void)encodeValueOfObjCType:(const char *)type at:(const void *)addr 115 | { 116 | [self doesNotRecognizeSelector:_cmd]; 117 | } 118 | 119 | 120 | 121 | - (void)encodeDataObject:(NSData *)data; 122 | { 123 | [self doesNotRecognizeSelector:_cmd]; 124 | } 125 | 126 | 127 | 128 | 129 | 130 | 131 | #pragma mark - 132 | #pragma mark Required for Key Coding 133 | 134 | - (BOOL)allowsKeyedCoding 135 | { 136 | return YES; 137 | } 138 | 139 | 140 | 141 | - (BOOL)containsValueForKey:(NSString *)key; 142 | { 143 | return [_encodedKeys containsObject:key]; 144 | } 145 | 146 | 147 | 148 | 149 | - (void)encodeObject:(id)obj forKey:(NSString *)key; 150 | { 151 | if (!obj) return; 152 | if (!key) [NSException raise:@"Key is nil" format:@"Blah blah blah"]; 153 | 154 | PACK_KEY(key); 155 | [self _encodeObject:obj]; 156 | } 157 | 158 | 159 | 160 | // Packs the object Type, and then the data. No key 161 | - (void)_encodeObject:(id)obj 162 | { 163 | if (!obj) return; 164 | 165 | if ([obj isKindOfClass:[NSNumber class]]) { 166 | NSNumber * num = obj; 167 | switch (num.objCType[0]) { 168 | case 'c': // char (aka BOOL) 169 | PACK_TYPE(MsgPackArchiveTypeBoolean); 170 | cmp_write_bool(&_ctx, [(NSNumber *)obj boolValue]); 171 | break; 172 | 173 | case 'i': // int 174 | case 's': // short 175 | case 'l': // long (32 bit) 176 | case 'q': // long long 177 | PACK_TYPE(MsgPackArchiveTypeInt64); 178 | cmp_write_s64(&_ctx, [(NSNumber *)obj longLongValue]); 179 | break; 180 | 181 | case 'I': // unsigned int 182 | case 'S': // unsigned short 183 | case 'L': // unsigned long 184 | case 'Q': // unsigned long long 185 | PACK_TYPE(MsgPackArchiveTypeInt64); 186 | cmp_write_s64(&_ctx, [(NSNumber *)obj longLongValue]); 187 | break; 188 | 189 | case 'f': // float 190 | case 'd': // double 191 | PACK_TYPE(MsgPackArchiveTypeDouble); 192 | cmp_write_double(&_ctx, [(NSNumber *)obj doubleValue]); 193 | break; 194 | default: 195 | [NSException raise:NSInvalidArgumentException format:@"Unhandled NSNumber objCType <%s> in MsgPackArchiver _encodeObject:", num.objCType]; 196 | break; 197 | } 198 | 199 | 200 | } else if ([obj isKindOfClass:[NSString class]]) { 201 | PACK_TYPE(MsgPackArchiveTypeString); 202 | PACK_STRING(_ctx, (NSString *)obj); 203 | 204 | } else if ([obj isKindOfClass:[NSArray class]]) { 205 | NSArray * array = obj; 206 | 207 | PACK_TYPE(MsgPackArchiveTypeArray); 208 | cmp_write_u64(&_ctx, array.count); 209 | 210 | for (id elem in array) { 211 | [self _encodeObject:elem]; 212 | } 213 | 214 | } else if ([obj isKindOfClass:[NSDictionary class]]) { 215 | NSDictionary * dictionary = obj; 216 | 217 | PACK_TYPE(MsgPackArchiveTypeDictionary); 218 | cmp_write_u64(&_ctx, dictionary.count); 219 | 220 | for (id key in dictionary.allKeys) { 221 | [self _encodeObject:key]; 222 | [self _encodeObject:[dictionary objectForKey:key]]; 223 | } 224 | 225 | } else if ([obj conformsToProtocol:@protocol(NSCoding)]) { 226 | PACK_TYPE(MsgPackArchiveTypeObject); 227 | 228 | const char * str = class_getName([obj class]); 229 | size_t len = strlen(str) + 1; // INCLUDING NULL BYTE 230 | cmp_write_bin(&_ctx, str, (uint32_t)len); 231 | { 232 | MsgPackArchiver * encoder = [[MsgPackArchiver alloc] init]; 233 | NSData * data = nil; 234 | 235 | [obj encodeWithCoder:encoder]; 236 | data = [encoder archivedData]; 237 | [encoder release]; 238 | 239 | PACK_DATA(_ctx, data); 240 | } 241 | 242 | } else { 243 | [NSException raise:@"Object does not conform to NSCoding protocol." format:@"Blah blah blah"]; 244 | } 245 | } 246 | 247 | 248 | 249 | 250 | - (void)encodeConditionalObject:(id)objv forKey:(NSString *)key; 251 | { 252 | [self doesNotRecognizeSelector:_cmd]; 253 | } 254 | 255 | 256 | 257 | - (void)encodeBool:(BOOL)boolv forKey:(NSString *)key; 258 | { 259 | PACK_KEY_AND_TYPE(key, MsgPackArchiveTypeBoolean); 260 | cmp_write_bool(&_ctx, boolv); 261 | } 262 | 263 | 264 | 265 | - (void)encodeInt:(int)intv forKey:(NSString *)key; 266 | { 267 | PACK_KEY_AND_TYPE(key, MsgPackArchiveTypeInt64); 268 | cmp_write_s64(&_ctx, (int64_t)intv); 269 | } 270 | 271 | 272 | 273 | - (void)encodeInt32:(int32_t)intv forKey:(NSString *)key; 274 | { 275 | PACK_KEY_AND_TYPE(key, MsgPackArchiveTypeInt64); 276 | cmp_write_s64(&_ctx, (int64_t)intv); 277 | } 278 | 279 | 280 | 281 | - (void)encodeInt64:(int64_t)intv forKey:(NSString *)key; 282 | { 283 | PACK_KEY_AND_TYPE(key, MsgPackArchiveTypeInt64); 284 | cmp_write_s64(&_ctx, (int64_t)intv); 285 | } 286 | 287 | 288 | 289 | - (void)encodeInteger:(NSInteger)intv forKey:(NSString *)key; 290 | { 291 | PACK_KEY_AND_TYPE(key, MsgPackArchiveTypeInt64); 292 | cmp_write_s64(&_ctx, (int64_t)intv); 293 | } 294 | 295 | 296 | 297 | - (void)encodeFloat:(float)realv forKey:(NSString *)key; 298 | { 299 | PACK_KEY_AND_TYPE(key, MsgPackArchiveTypeDouble); 300 | cmp_write_double(&_ctx, (double)realv); 301 | } 302 | 303 | 304 | 305 | - (void)encodeDouble:(double)realv forKey:(NSString *)key; 306 | { 307 | PACK_KEY_AND_TYPE(key, MsgPackArchiveTypeDouble); 308 | cmp_write_double(&_ctx, (double)realv); 309 | } 310 | 311 | 312 | 313 | - (void)encodeBytes:(const uint8_t *)bytes length:(NSUInteger)len forKey:(NSString *)key; 314 | { 315 | PACK_KEY_AND_TYPE(key, MsgPackArchiveTypeData); 316 | cmp_write_bin(&_ctx, bytes, (uint32_t)len); 317 | } 318 | 319 | 320 | 321 | - (void)encodePoint:(NSPoint)point forKey:(NSString *)key 322 | { 323 | PACK_KEY_AND_TYPE(key, MsgPackArchiveTypePoint); 324 | cmp_write_double(&_ctx, (double)point.x); 325 | cmp_write_double(&_ctx, (double)point.y); 326 | } 327 | 328 | 329 | - (void)encodeSize:(NSSize)size forKey:(NSString *)key; 330 | { 331 | PACK_KEY_AND_TYPE(key, MsgPackArchiveTypeSize); 332 | cmp_write_double(&_ctx, (double)size.width); 333 | cmp_write_double(&_ctx, (double)size.height); 334 | } 335 | 336 | 337 | - (void)encodeRect:(NSRect)rect forKey:(NSString *)key; 338 | { 339 | PACK_KEY_AND_TYPE(key, MsgPackArchiveTypeRect); 340 | cmp_write_double(&_ctx, (double)rect.origin.x); 341 | cmp_write_double(&_ctx, (double)rect.origin.y); 342 | cmp_write_double(&_ctx, (double)rect.size.width); 343 | cmp_write_double(&_ctx, (double)rect.size.height); 344 | } 345 | 346 | 347 | 348 | 349 | 350 | 351 | 352 | #pragma mark - 353 | 354 | void MsgPackArchiver_PackKeyAndType(MsgPackArchiver * self, NSString * key, MsgPackArchiveType type) 355 | { 356 | MsgPackArchiver_PackKey(self, key); 357 | MsgPackArchiver_PackType(self, type); 358 | } 359 | 360 | 361 | void MsgPackArchiver_PackKey(MsgPackArchiver * self, NSString * key) 362 | { 363 | [self->_encodedKeys addObject:key]; 364 | 365 | 366 | const char * str = key.UTF8String; 367 | size_t len = strlen(str); // + 1; // Includes NULL byte 368 | cmp_write_bin(&self->_ctx, str, (uint32_t)len); 369 | } 370 | 371 | 372 | void MsgPackArchiver_PackType(MsgPackArchiver * self, MsgPackArchiveType type) 373 | { 374 | cmp_write_s16(&self->_ctx, (unsigned short)type); 375 | } 376 | 377 | 378 | size_t MsgPackArchiver_writer(struct cmp_ctx_s *ctx, const void *data, size_t count) 379 | { 380 | MsgPackArchiver * self = (MsgPackArchiver *)ctx->buf; 381 | [self->_data appendBytes:data length:count]; 382 | return count; 383 | } 384 | 385 | 386 | @end 387 | -------------------------------------------------------------------------------- /MessagePackCoder/MsgPackUnarchiver.m: -------------------------------------------------------------------------------- 1 | // 2 | // MsgPackUnarchiver.m 3 | // MessagePackCoder 4 | // https://github.com/swillits/messagepackcoder 5 | // 6 | // Created by Seth Willits on 12/4/14. 7 | // Copyright (c) 2014 Seth Willits. All rights reserved. 8 | // 9 | 10 | #import 11 | #import "MsgPackUnarchiver.h" 12 | #import "MsgPackArchiving.h" 13 | #import "cmp.h" 14 | 15 | 16 | #define OBJ_FOR_KEY(key) \ 17 | [_decodedObjects objectForKey:key] 18 | 19 | #define UNPACK_TYPE(outType) MsgPackUnarchiver_UnpackType(self, outType) 20 | 21 | #define UNPACK(ctx__, type__, variable__, msg__) \ 22 | if (!cmp_read_ ## type__ (&ctx__, &variable__)) { \ 23 | [NSException raise:NSInternalInconsistencyException format:@"MsgPackUnarchiver: Couldn't unpack %@ because %s", msg__, cmp_strerror(&ctx__)]; \ 24 | } 25 | 26 | 27 | 28 | static bool MsgPackUnarchiver_reader(struct cmp_ctx_s *ctx, void *data, size_t limit); 29 | 30 | 31 | 32 | @implementation MsgPackUnarchiver 33 | { 34 | cmp_ctx_t _ctx; 35 | NSData * _data; 36 | 37 | const void * _dataBytes; 38 | size_t _dataLength; 39 | 40 | unsigned long long _readOffset; 41 | NSMutableDictionary * _decodedObjects; 42 | } 43 | 44 | 45 | 46 | 47 | + (id)unarchiveObjectWithData:(NSData *)data 48 | { 49 | id root = nil; 50 | 51 | @autoreleasepool { 52 | MsgPackUnarchiver * u = [[MsgPackUnarchiver alloc] initForReadingWithData:data]; 53 | root = [[u decodeObjectForKey:@"ROOT"] retain]; 54 | [u release]; 55 | } 56 | 57 | return [root autorelease]; 58 | } 59 | 60 | 61 | 62 | - (instancetype)initForReadingWithData:(NSData *)data; 63 | { 64 | if (!(self = [super init])) { 65 | return nil; 66 | } 67 | 68 | _data = [data retain]; 69 | _dataBytes = _data.bytes; 70 | _dataLength = _data.length; 71 | _decodedObjects = [[NSMutableDictionary alloc] init]; 72 | 73 | 74 | cmp_init(&_ctx, (void *)self, MsgPackUnarchiver_reader, NULL); 75 | 76 | while ((self->_readOffset < self->_dataLength)) { 77 | @autoreleasepool { 78 | NSString * key = [self unpackString]; 79 | id obj = [self _unpackTypeAndObject]; 80 | [_decodedObjects setObject:obj forKey:key]; 81 | } 82 | } 83 | 84 | return self; 85 | } 86 | 87 | 88 | 89 | - (void)dealloc 90 | { 91 | [_decodedObjects release]; 92 | [_data release]; 93 | [super dealloc]; 94 | } 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | #pragma mark - 103 | #pragma mark Required For All Coders 104 | 105 | - (void)decodeValueOfObjCType:(const char *)type at:(void *)data; 106 | { 107 | [self doesNotRecognizeSelector:_cmd]; 108 | } 109 | 110 | 111 | 112 | - (NSData *)decodeDataObject; 113 | { 114 | [self doesNotRecognizeSelector:_cmd]; 115 | return nil; 116 | } 117 | 118 | 119 | 120 | 121 | 122 | 123 | #pragma mark - 124 | #pragma mark Required for Key Coding 125 | 126 | - (BOOL)allowsKeyedCoding 127 | { 128 | return YES; 129 | } 130 | 131 | 132 | 133 | - (BOOL)containsValueForKey:(NSString *)key; 134 | { 135 | return (OBJ_FOR_KEY(key) != nil); 136 | } 137 | 138 | 139 | 140 | - (id)decodeObjectForKey:(NSString *)key; 141 | { 142 | return OBJ_FOR_KEY(key); 143 | } 144 | 145 | 146 | 147 | - (BOOL)decodeBoolForKey:(NSString *)key; 148 | { 149 | return [OBJ_FOR_KEY(key) boolValue]; 150 | } 151 | 152 | 153 | 154 | - (int)decodeIntForKey:(NSString *)key; 155 | { 156 | return [OBJ_FOR_KEY(key) intValue]; 157 | } 158 | 159 | 160 | 161 | - (int32_t)decodeInt32ForKey:(NSString *)key; 162 | { 163 | return (int32_t)[OBJ_FOR_KEY(key) longValue]; 164 | } 165 | 166 | 167 | 168 | - (int64_t)decodeInt64ForKey:(NSString *)key; 169 | { 170 | return (int64_t)[OBJ_FOR_KEY(key) longLongValue]; 171 | } 172 | 173 | 174 | 175 | - (NSInteger)decodeIntegerForKey:(NSString *)key; 176 | { 177 | return (NSInteger)[OBJ_FOR_KEY(key) integerValue]; 178 | } 179 | 180 | 181 | 182 | - (float)decodeFloatForKey:(NSString *)key; 183 | { 184 | return (float)[OBJ_FOR_KEY(key) floatValue]; 185 | } 186 | 187 | 188 | 189 | - (double)decodeDoubleForKey:(NSString *)key; 190 | { 191 | return (double)[OBJ_FOR_KEY(key) doubleValue]; 192 | } 193 | 194 | 195 | 196 | - (const uint8_t *)decodeBytesForKey:(NSString *)key returnedLength:(NSUInteger *)lengthp; 197 | { 198 | NSData * data = OBJ_FOR_KEY(key); 199 | if (lengthp) *lengthp = data.length; 200 | return data.bytes; 201 | } 202 | 203 | 204 | 205 | - (NSPoint)decodePointForKey:(NSString *)key 206 | { 207 | return [OBJ_FOR_KEY(key) pointValue]; 208 | } 209 | 210 | 211 | 212 | - (NSSize)decodeSizeForKey:(NSString *)key 213 | { 214 | return [OBJ_FOR_KEY(key) sizeValue]; 215 | } 216 | 217 | 218 | 219 | - (NSRect)decodeRectForKey:(NSString *)key 220 | { 221 | return [OBJ_FOR_KEY(key) rectValue]; 222 | } 223 | 224 | 225 | 226 | 227 | #pragma mark - 228 | 229 | bool MsgPackUnarchiver_reader(struct cmp_ctx_s *ctx, void * data, size_t limit) 230 | { 231 | MsgPackUnarchiver * self = (MsgPackUnarchiver *)ctx->buf; 232 | if (self->_readOffset + limit <= self->_dataLength) { 233 | memcpy(data, self->_dataBytes + self->_readOffset, limit); 234 | self->_readOffset += limit; 235 | return true; 236 | } 237 | return false; 238 | } 239 | 240 | 241 | 242 | static inline BOOL MsgPackUnarchiver_UnpackType(MsgPackUnarchiver * self, MsgPackArchiveType * outType) 243 | { 244 | // EOF 245 | if (self->_readOffset >= self->_dataLength) { 246 | return NO; 247 | } 248 | 249 | // Type 250 | int16_t type; 251 | UNPACK(self->_ctx, short, type, @"property type") 252 | *outType = (MsgPackArchiveType)type; 253 | 254 | return YES; 255 | } 256 | 257 | 258 | 259 | BOOL MsgPackUnarchiver_unpackRawBytes(MsgPackUnarchiver * self, const void ** outPtr, uint32_t * outLength) 260 | { 261 | if (!cmp_read_bin_size(&self->_ctx, outLength)) { 262 | [NSException raise:@"Couldn't unpack raw data because there was no message" format:@"Blah blah blah"]; 263 | return NO; 264 | } 265 | 266 | *outPtr = self->_dataBytes + self->_readOffset; 267 | self->_readOffset += *outLength; 268 | 269 | return YES; 270 | } 271 | 272 | 273 | 274 | 275 | - (id)_unpackTypeAndObject 276 | { 277 | MsgPackArchiveType type; 278 | id object = nil; 279 | 280 | UNPACK_TYPE(&type); 281 | 282 | switch (type) { 283 | case MsgPackArchiveTypeData: { 284 | uint32_t length = 0; 285 | 286 | if (!cmp_read_bin_size(&_ctx, &length)) { 287 | [NSException raise:@"Couldn't unpack raw data because there was no message" format:@"Blah blah blah"]; 288 | return nil; 289 | } 290 | 291 | NSData * data = [_data subdataWithRange:NSMakeRange(_readOffset, length)]; 292 | _readOffset += length; 293 | 294 | object = data; 295 | break; 296 | } 297 | 298 | case MsgPackArchiveTypeObject: 299 | object = [self unpackObject]; 300 | break; 301 | 302 | case MsgPackArchiveTypeString: 303 | object = [self unpackString]; 304 | break; 305 | 306 | case MsgPackArchiveTypeArray: 307 | object = [self unpackArray]; 308 | break; 309 | 310 | case MsgPackArchiveTypeDictionary: 311 | object = [self unpackDictionary]; 312 | break; 313 | 314 | case MsgPackArchiveTypeBoolean: { 315 | bool value; 316 | UNPACK(_ctx, bool, value, @"boolean"); 317 | object = @(value); 318 | break; 319 | } 320 | 321 | case MsgPackArchiveTypeUInt64: { 322 | uint64_t value; 323 | UNPACK(_ctx, u64, value, @"unsigned integer"); 324 | object = @(value); 325 | break; 326 | } 327 | 328 | case MsgPackArchiveTypeInt64: { 329 | int64_t value; 330 | UNPACK(_ctx, s64, value, @"signed integer"); 331 | object = @(value); 332 | break; 333 | } 334 | 335 | case MsgPackArchiveTypeDouble: { 336 | double value; 337 | UNPACK(_ctx, double, value, @"double"); 338 | object = @(value); 339 | break; 340 | } 341 | 342 | case MsgPackArchiveTypePoint: { 343 | NSPoint p; 344 | UNPACK(_ctx, double, p.x, @"double"); 345 | UNPACK(_ctx, double, p.y, @"double"); 346 | object = [NSValue valueWithPoint:p]; 347 | break; 348 | } 349 | 350 | case MsgPackArchiveTypeSize: { 351 | NSSize size; 352 | UNPACK(_ctx, double, size.width, @"double"); 353 | UNPACK(_ctx, double, size.height, @"double"); 354 | object = [NSValue valueWithSize:size]; 355 | break; 356 | } 357 | 358 | case MsgPackArchiveTypeRect: { 359 | NSRect rect; 360 | UNPACK(_ctx, double, rect.origin.x, @"double"); 361 | UNPACK(_ctx, double, rect.origin.y, @"double"); 362 | UNPACK(_ctx, double, rect.size.width, @"double"); 363 | UNPACK(_ctx, double, rect.size.height, @"double"); 364 | object = [NSValue valueWithRect:rect]; 365 | break; 366 | } 367 | } 368 | 369 | 370 | return object; 371 | } 372 | 373 | 374 | 375 | - (NSString *)unpackString 376 | { 377 | const void * bytes = NULL; 378 | uint32_t length = 0; 379 | 380 | if (!MsgPackUnarchiver_unpackRawBytes(self, &bytes, &length)) { 381 | return nil; 382 | } 383 | 384 | return [[[NSString alloc] initWithBytes:bytes length:length encoding:NSUTF8StringEncoding] autorelease]; 385 | } 386 | 387 | 388 | 389 | - (NSArray *)unpackArray 390 | { 391 | NSMutableArray * array = [NSMutableArray array]; 392 | uint64_t count; 393 | 394 | // Number of items in the array 395 | UNPACK(_ctx, u64, count, @"array count"); 396 | 397 | // Unpack each item 398 | for (uint64_t i = 0; i < count; i++) { 399 | id element = [self _unpackTypeAndObject]; 400 | [array addObject:element]; 401 | } 402 | 403 | 404 | return [[array copy] autorelease]; 405 | } 406 | 407 | 408 | 409 | - (NSDictionary *)unpackDictionary 410 | { 411 | NSMutableDictionary * dictionary = [NSMutableDictionary dictionary]; 412 | uint64_t count; 413 | 414 | // Number of items in the dictionary 415 | UNPACK(_ctx, u64, count, @"dictionary count"); 416 | 417 | // Unpack each item 418 | for (uint64_t i = 0; i < count; i++) { 419 | id key = [self _unpackTypeAndObject]; 420 | id value = [self _unpackTypeAndObject]; 421 | [dictionary setObject:value forKey:key]; 422 | } 423 | 424 | return [[dictionary copy] autorelease]; 425 | } 426 | 427 | 428 | 429 | 430 | - (id)unpackObject 431 | { 432 | // Class name 433 | Class class; 434 | { 435 | const void * bytes = NULL; // INCLUDES THE NULL BYTE 436 | uint32_t length = 0; 437 | if (!MsgPackUnarchiver_unpackRawBytes(self, &bytes, &length)) { 438 | return nil; 439 | } 440 | 441 | class = objc_getClass((const char *)bytes); 442 | if (!class) { 443 | return nil; 444 | } 445 | } 446 | 447 | 448 | // Object Data 449 | NSData * data = nil; 450 | { 451 | uint32_t length = 0; 452 | 453 | if (!cmp_read_bin_size(&_ctx, &length)) { 454 | [NSException raise:@"Couldn't unpack raw data because there was no message" format:@"Blah blah blah"]; 455 | return nil; 456 | } 457 | 458 | data = [NSData dataWithBytesNoCopy:(void *)(_dataBytes + _readOffset) length:length freeWhenDone:NO]; 459 | _readOffset += length; 460 | } 461 | 462 | 463 | // Unarchive the object 464 | id object = nil; 465 | @autoreleasepool { 466 | MsgPackUnarchiver * coder = [[MsgPackUnarchiver alloc] initForReadingWithData:data]; 467 | object = [[class alloc] initWithCoder:coder]; 468 | [coder release]; 469 | } 470 | 471 | return [object autorelease]; 472 | } 473 | 474 | 475 | @end 476 | -------------------------------------------------------------------------------- /Tests/Tests.erb: -------------------------------------------------------------------------------- 1 | // 2 | // Tests.m 3 | // MessagePackCoder 4 | // https://github.com/swillits/messagepackcoder 5 | // 6 | // Created by Seth Willits on 12/4/14. 7 | // Copyright (c) 2014 Seth Willits. All rights reserved. 8 | // 9 | 10 | #import 11 | #import 12 | #import "MsgPackArchiver.h" 13 | #import "MsgPackUnarchiver.h" 14 | 15 | 16 | 17 | @interface Foo : NSObject 18 | @property (strong) id empty; 19 | @property (strong) NSNull * null; 20 | @property (strong) NSString * string; 21 | @property (strong) NSNumber * number; 22 | @property (strong) NSDictionary * dictionary; 23 | @end 24 | 25 | 26 | 27 | @interface Tests : XCTestCase 28 | @end 29 | 30 | 31 | @implementation Tests 32 | 33 | - (void)setUp 34 | { 35 | [super setUp]; 36 | } 37 | 38 | - (void)tearDown 39 | { 40 | [super tearDown]; 41 | } 42 | 43 | 44 | 45 | - (void)testBytes 46 | { 47 | const char * bytes = "here are some\0'random' bytes.\0All bytes are equal!"; 48 | size_t length = 50; 49 | 50 | NSData * data1 = [NSData data]; 51 | NSData * data2 = [NSData dataWithBytesNoCopy:(void *)bytes length:length freeWhenDone:NO]; 52 | 53 | [self _testRoot:data1]; 54 | [self _testRoot:data2]; 55 | 56 | NSMutableData * mdata = [NSMutableData data]; 57 | MsgPackArchiver * a = [[MsgPackArchiver alloc] initForWritingWithMutableData:mdata]; 58 | [a encodeObject:data1 forKey:@"key0"]; 59 | [a encodeObject:data2 forKey:@"key1"]; 60 | [a finishEncoding]; 61 | 62 | MsgPackUnarchiver * u = [[MsgPackUnarchiver alloc] initForReadingWithData:mdata]; 63 | XCTAssertEqualObjects([u decodeObjectForKey:@"key0"], data1); 64 | XCTAssertEqualObjects([u decodeObjectForKey:@"key1"], data2); 65 | } 66 | 67 | 68 | <%- 69 | type_tests = [ 70 | 71 | ["Bool", :value, ["YES", "NO"]], 72 | ["Int", :value, %w{0 -1 INT_MAX INT_MIN}], 73 | ["Int32", :value, %w{0 -1 INT32_MAX INT32_MIN}], 74 | ["Int64", :value, %w{0 -1 INT64_MAX INT64_MIN}], 75 | ["Integer", :value, %w{0 -1 NSIntegerMax NSIntegerMin}], 76 | ["Float", :value, %w{0.0f -1.0f 3.14159265358979323846264338327950288419716939937510f FLT_MAX FLT_MIN}], 77 | ["Double", :value, %w{0.0 -1.0 3.14159265358979323846264338327950288419716939937510 DBL_MAX DBL_MIN}], 78 | 79 | ["Size", :size, ["NSMakeSize(0.0, 0.0)", "NSMakeSize(738.1234567, 987.6543210)", "NSMakeSize(CGFLOAT_MAX, CGFLOAT_MIN)"]], 80 | ["Point", :point, ["NSMakePoint(0.0, 0.0)", "NSMakePoint(738.1234567, 987.6543210)", "NSMakePoint(CGFLOAT_MAX, CGFLOAT_MIN)"]], 81 | ["Rect", :rect, ["NSMakeRect(0.0, 0.0, 738.1234567, 987.6543210)", "NSMakeRect(CGFLOAT_MIN, CGFLOAT_MAX, CGFLOAT_MAX, CGFLOAT_MIN)"]], 82 | 83 | ["Object", :object, [ 84 | '@""', 85 | '@"striéng"', 86 | '@"Iлtêrԉãtioԉɑlìzãtí߀л"', 87 | 'NSNull.null', 88 | '@{@"key": @"value"}', 89 | '@[@"a", @"b", @"c", @(1), @(2), @(3)]', 90 | '@{@"key": @(1324.5), @(5) : @[@"a", NSNull.null, [[[Foo alloc] init] autorelease]]}' 91 | ]] 92 | ] 93 | -%> 94 | 95 | 96 | <%- type_tests.each do |test| %> 97 | <%- value_selector = test[0] %> 98 | <%- kind = test[1] %> 99 | <%- values = test[2] %> 100 | 101 | 102 | - (void)test<%= value_selector %> 103 | { 104 | <%- values.each do |value| -%> 105 | <%- if kind == :object -%> 106 | [self _testRoot:<%= value %>]; 107 | <%- elsif kind == :value -%> 108 | [self _testRoot:@(<%= value %>)]; 109 | <%- elsif kind == :size -%> 110 | [self _testRoot:[NSValue valueWithSize:<%= value %>]]; 111 | <%- elsif kind == :point -%> 112 | [self _testRoot:[NSValue valueWithPoint:<%= value %>]]; 113 | <%- elsif kind == :rect -%> 114 | [self _testRoot:[NSValue valueWithRect:<%= value %>]]; 115 | <%- end -%> 116 | <%- end -%> 117 | 118 | NSMutableData * mdata = [NSMutableData data]; 119 | MsgPackArchiver * a = [[MsgPackArchiver alloc] initForWritingWithMutableData:mdata]; 120 | <%- value_index = 0 -%> 121 | <%- values.each do |value| -%> 122 | <%- key = "key#{value_index}" -%> 123 | <%- value_index = value_index + 1 -%> 124 | [a encode<%= value_selector %>:<%= value %> forKey:@"<%= key %>"]; 125 | <%- end -%> 126 | [a finishEncoding]; 127 | 128 | MsgPackUnarchiver * u = [[MsgPackUnarchiver alloc] initForReadingWithData:mdata]; 129 | <%- value_index = 0 -%> 130 | <%- values.each do |value| -%> 131 | <%- key = "key#{value_index}" -%> 132 | <%- value_index = value_index + 1 -%> 133 | <%- if kind == :object -%> 134 | XCTAssertEqualObjects([u decode<%= value_selector %>ForKey:@"<%= key %>"], (<%= value %>)); 135 | <%- elsif kind == :value -%> 136 | XCTAssertEqual([u decode<%= value_selector %>ForKey:@"<%= key %>"], <%= value %>); 137 | <%- elsif kind == :size -%> 138 | XCTAssert(NSEqualSizes([u decodeSizeForKey:@"<%= key %>"], <%= value %>)); 139 | <%- elsif kind == :point -%> 140 | XCTAssert(NSEqualPoints([u decodePointForKey:@"<%= key %>"], <%= value %>)); 141 | <%- elsif kind == :rect -%> 142 | XCTAssert(NSEqualRects([u decodeRectForKey:@"<%= key %>"], <%= value %>)); 143 | <%- end -%> 144 | <%- end -%> 145 | } 146 | 147 | <%- end -%> 148 | 149 | 150 | 151 | 152 | - (void)_testRoot:(id)oldRoot 153 | { 154 | NSData * data = [MsgPackArchiver archivedDataWithRootObject:oldRoot]; 155 | XCTAssertNotNil(data); 156 | 157 | id newRoot = [MsgPackUnarchiver unarchiveObjectWithData:data]; 158 | XCTAssertNotNil(newRoot); 159 | 160 | [self assertDeepCompare:oldRoot to:newRoot]; 161 | } 162 | 163 | 164 | 165 | - (void)assertDeepCompare:(id)rootA to:(id)rootB 166 | { 167 | // As long as each custom class we're testing properly implements -isEqual: and -hash, then this will do a full deep comparison 168 | // Note that we're assuming for custom classes in this testing rig, the keys encoded and decoded are also compared in -isEqual: 169 | // so that we're fairly testing whether the decoded value is equal to the value that was encoded. 170 | XCTAssert([rootA isEqual:rootB]); 171 | } 172 | 173 | 174 | 175 | 176 | 177 | 178 | #pragma mark - 179 | #pragma mark Performance Test 180 | 181 | - (void)testArchivingPerformanceNSCoder 182 | { 183 | __block NSUInteger length = 0; 184 | 185 | [self measureBlock:^{ 186 | NSMutableData * data = [NSMutableData data]; 187 | NSKeyedArchiver * archiver = [[[NSKeyedArchiver alloc] initForWritingWithMutableData:data] autorelease]; 188 | [self archiveWithCoder:archiver]; 189 | [archiver finishEncoding]; 190 | length = data.length; 191 | }]; 192 | 193 | NSLog(@"NSCoder length: %lu", length); 194 | } 195 | 196 | 197 | - (void)testArchivingPerformanceMsgPack 198 | { 199 | __block NSUInteger length = 0; 200 | 201 | [self measureBlock:^{ 202 | NSMutableData * data = [NSMutableData data]; 203 | MsgPackArchiver * archiver = [[[MsgPackArchiver alloc] initForWritingWithMutableData:data] autorelease]; 204 | [self archiveWithCoder:archiver]; 205 | [archiver finishEncoding]; 206 | length = data.length; 207 | }]; 208 | 209 | NSLog(@"MsgPack length: %lu", length); 210 | } 211 | 212 | 213 | 214 | - (void)archiveWithCoder:(NSCoder *)coder 215 | { 216 | NSMutableDictionary * dict = [NSMutableDictionary dictionary]; 217 | NSMutableArray * intArray = [NSMutableArray array]; 218 | NSMutableArray * strArray = [NSMutableArray array]; 219 | NSMutableData * data = [NSMutableData data]; 220 | 221 | for (int i = 0; i < 100000; i++) { 222 | NSString * s = [NSString stringWithFormat:@"string %d string %d string %d string %d string %d", rand(), rand(), rand(), rand(), rand()]; 223 | [coder encodeInt:i forKey:[NSString stringWithFormat:@"int_%d", i]]; 224 | [coder encodeObject:s forKey:[NSString stringWithFormat:@"string_%d", i]]; 225 | [coder encodeBool:(i % 2 == 0) forKey:[NSString stringWithFormat:@"bool_%d", i]]; 226 | [intArray addObject:@(i)]; 227 | [strArray addObject:s]; 228 | [dict setObject:[@[@(i), s] objectAtIndex:i % 2] forKey:[NSString stringWithFormat:@"key_%d", i]]; 229 | [data appendBytes:(const void *)&i length:sizeof(int)]; 230 | } 231 | 232 | [coder encodeObject:intArray forKey:@"intArray"]; 233 | [coder encodeObject:strArray forKey:@"strArray"]; 234 | [coder encodeBytes:data.bytes length:data.length forKey:@"bytes"]; 235 | [coder encodeObject:data forKey:@"data"]; 236 | [coder encodeObject:dict forKey:@"dictionary"]; 237 | } 238 | 239 | 240 | 241 | 242 | 243 | - (void)testUnarchivingPerformanceNSCoder 244 | { 245 | NSMutableData * data = [NSMutableData data]; 246 | NSKeyedArchiver * archiver = [[[NSKeyedArchiver alloc] initForWritingWithMutableData:data] autorelease]; 247 | [self archiveWithCoder:archiver]; 248 | [archiver finishEncoding]; 249 | 250 | 251 | [self measureBlock:^{ 252 | NSKeyedUnarchiver * unarchiver = [[[NSKeyedUnarchiver alloc] initForReadingWithData:data] autorelease]; 253 | [self unarchiveWithCoder:unarchiver]; 254 | }]; 255 | } 256 | 257 | 258 | - (void)testUnarchivingPerformanceMsgPack 259 | { 260 | NSMutableData * data = [NSMutableData data]; 261 | MsgPackArchiver * archiver = [[[MsgPackArchiver alloc] initForWritingWithMutableData:data] autorelease]; 262 | [self archiveWithCoder:archiver]; 263 | [archiver finishEncoding]; 264 | 265 | 266 | [self measureBlock:^{ 267 | MsgPackUnarchiver * unarchiver = [[[MsgPackUnarchiver alloc] initForReadingWithData:data] autorelease]; 268 | [self unarchiveWithCoder:unarchiver]; 269 | }]; 270 | } 271 | 272 | 273 | 274 | - (void)unarchiveWithCoder:(NSCoder *)coder 275 | { 276 | for (int i = 0; i < 1000; i++) { 277 | [coder decodeIntForKey:[NSString stringWithFormat:@"int_%d", i]]; 278 | [coder decodeObjectForKey:[NSString stringWithFormat:@"string_%d", i]]; 279 | [coder decodeBoolForKey:[NSString stringWithFormat:@"bool_%d", i]]; 280 | } 281 | 282 | 283 | [coder decodeObjectForKey:@"intArray"]; 284 | [coder decodeObjectForKey:@"strArray"]; 285 | [coder decodeBytesForKey:@"bytes" returnedLength:NULL]; 286 | [coder decodeObjectForKey:@"data"]; 287 | [coder decodeObjectForKey:@"dictionary"]; 288 | } 289 | 290 | 291 | 292 | @end 293 | 294 | 295 | 296 | 297 | 298 | 299 | 300 | #pragma mark - 301 | 302 | @implementation Foo 303 | 304 | - (id)init 305 | { 306 | if ((self = [super init])) { 307 | self.empty = nil; 308 | self.null = NSNull.null; 309 | self.string = @"Iлtêrԉãtioԉɑlìzãtí߀л"; 310 | self.number = @(53.9); 311 | self.dictionary = @{@"this" : @"is boring"}; 312 | } 313 | 314 | return self; 315 | } 316 | 317 | 318 | - (id)initWithCoder:(NSCoder *)coder 319 | { 320 | if ((self = [super init])) { 321 | self.empty = [coder decodeObjectForKey:@"empty"]; 322 | self.null = [coder decodeObjectForKey:@"null"]; 323 | self.string = [coder decodeObjectForKey:@"string"]; 324 | self.number = [coder decodeObjectForKey:@"number"]; 325 | self.dictionary = [coder decodeObjectForKey:@"dictionary"]; 326 | } 327 | 328 | return self; 329 | } 330 | 331 | 332 | - (void)encodeWithCoder:(NSCoder *)coder 333 | { 334 | [coder encodeObject:self.empty forKey:@"empty"]; 335 | [coder encodeObject:self.null forKey:@"null"]; 336 | [coder encodeObject:self.string forKey:@"string"]; 337 | [coder encodeObject:self.number forKey:@"number"]; 338 | [coder encodeObject:self.dictionary forKey:@"dictionary"]; 339 | } 340 | 341 | - (NSUInteger)hash 342 | { 343 | // We don't care about performance. 344 | return 0; 345 | } 346 | 347 | 348 | - (BOOL)isEqual:(id)obj 349 | { 350 | if (![obj isKindOfClass:[Foo class]]) { 351 | return NO; 352 | } 353 | 354 | return YES; 355 | } 356 | 357 | @end 358 | 359 | -------------------------------------------------------------------------------- /MessagePackCoder.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 5D427DE21A32316C00CAA15B /* Tests.m in Sources */ = {isa = PBXBuildFile; fileRef = 5D427DE11A32316C00CAA15B /* Tests.m */; }; 11 | 5D427DE81A3232D000CAA15B /* MsgPackArchiver.m in Sources */ = {isa = PBXBuildFile; fileRef = 5DE9053D1A31475A0025DB42 /* MsgPackArchiver.m */; }; 12 | 5D427DE91A3232D000CAA15B /* MsgPackUnarchiver.m in Sources */ = {isa = PBXBuildFile; fileRef = 5DE905401A3148520025DB42 /* MsgPackUnarchiver.m */; }; 13 | 5D427DEA1A3232D000CAA15B /* cmp.c in Sources */ = {isa = PBXBuildFile; fileRef = 5DE905451A317BBC0025DB42 /* cmp.c */; }; 14 | /* End PBXBuildFile section */ 15 | 16 | /* Begin PBXFileReference section */ 17 | 5D427DDD1A32316C00CAA15B /* Tests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = Tests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 18 | 5D427DE01A32316C00CAA15B /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 19 | 5D427DE11A32316C00CAA15B /* Tests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = Tests.m; sourceTree = ""; }; 20 | 5D427DEB1A32474A00CAA15B /* Tests.erb */ = {isa = PBXFileReference; lastKnownFileType = text; path = Tests.erb; sourceTree = ""; xcLanguageSpecificationIdentifier = ""; }; 21 | 5DE9053C1A31475A0025DB42 /* MsgPackArchiver.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MsgPackArchiver.h; sourceTree = ""; }; 22 | 5DE9053D1A31475A0025DB42 /* MsgPackArchiver.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MsgPackArchiver.m; sourceTree = ""; }; 23 | 5DE9053F1A3148520025DB42 /* MsgPackUnarchiver.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MsgPackUnarchiver.h; sourceTree = ""; }; 24 | 5DE905401A3148520025DB42 /* MsgPackUnarchiver.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MsgPackUnarchiver.m; sourceTree = ""; }; 25 | 5DE905421A314AC30025DB42 /* MsgPackArchiving.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MsgPackArchiving.h; sourceTree = ""; }; 26 | 5DE905451A317BBC0025DB42 /* cmp.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = cmp.c; sourceTree = ""; }; 27 | 5DE905461A317BBC0025DB42 /* cmp.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = cmp.h; sourceTree = ""; }; 28 | /* End PBXFileReference section */ 29 | 30 | /* Begin PBXFrameworksBuildPhase section */ 31 | 5D427DDA1A32316C00CAA15B /* Frameworks */ = { 32 | isa = PBXFrameworksBuildPhase; 33 | buildActionMask = 2147483647; 34 | files = ( 35 | ); 36 | runOnlyForDeploymentPostprocessing = 0; 37 | }; 38 | /* End PBXFrameworksBuildPhase section */ 39 | 40 | /* Begin PBXGroup section */ 41 | 5D427DDE1A32316C00CAA15B /* Tests */ = { 42 | isa = PBXGroup; 43 | children = ( 44 | 5D427DE01A32316C00CAA15B /* Info.plist */, 45 | 5D427DEB1A32474A00CAA15B /* Tests.erb */, 46 | 5D427DE11A32316C00CAA15B /* Tests.m */, 47 | ); 48 | path = Tests; 49 | sourceTree = ""; 50 | }; 51 | 5DE904F51A3146150025DB42 = { 52 | isa = PBXGroup; 53 | children = ( 54 | 5DE905001A3146150025DB42 /* MessagePackCoder */, 55 | 5D427DDE1A32316C00CAA15B /* Tests */, 56 | 5DE904FF1A3146150025DB42 /* Products */, 57 | ); 58 | sourceTree = ""; 59 | }; 60 | 5DE904FF1A3146150025DB42 /* Products */ = { 61 | isa = PBXGroup; 62 | children = ( 63 | 5D427DDD1A32316C00CAA15B /* Tests.xctest */, 64 | ); 65 | name = Products; 66 | sourceTree = ""; 67 | }; 68 | 5DE905001A3146150025DB42 /* MessagePackCoder */ = { 69 | isa = PBXGroup; 70 | children = ( 71 | 5DE9053C1A31475A0025DB42 /* MsgPackArchiver.h */, 72 | 5DE9053D1A31475A0025DB42 /* MsgPackArchiver.m */, 73 | 5DE9053F1A3148520025DB42 /* MsgPackUnarchiver.h */, 74 | 5DE905401A3148520025DB42 /* MsgPackUnarchiver.m */, 75 | 5DE905421A314AC30025DB42 /* MsgPackArchiving.h */, 76 | 5DE905461A317BBC0025DB42 /* cmp.h */, 77 | 5DE905451A317BBC0025DB42 /* cmp.c */, 78 | ); 79 | path = MessagePackCoder; 80 | sourceTree = ""; 81 | }; 82 | /* End PBXGroup section */ 83 | 84 | /* Begin PBXNativeTarget section */ 85 | 5D427DDC1A32316C00CAA15B /* Tests */ = { 86 | isa = PBXNativeTarget; 87 | buildConfigurationList = 5D427DE51A32316C00CAA15B /* Build configuration list for PBXNativeTarget "Tests" */; 88 | buildPhases = ( 89 | 5D427DD91A32316C00CAA15B /* Sources */, 90 | 5D427DDA1A32316C00CAA15B /* Frameworks */, 91 | 5D427DDB1A32316C00CAA15B /* Resources */, 92 | ); 93 | buildRules = ( 94 | ); 95 | dependencies = ( 96 | ); 97 | name = Tests; 98 | productName = Tests; 99 | productReference = 5D427DDD1A32316C00CAA15B /* Tests.xctest */; 100 | productType = "com.apple.product-type.bundle.unit-test"; 101 | }; 102 | /* End PBXNativeTarget section */ 103 | 104 | /* Begin PBXProject section */ 105 | 5DE904F61A3146150025DB42 /* Project object */ = { 106 | isa = PBXProject; 107 | attributes = { 108 | LastUpgradeCheck = 0610; 109 | ORGANIZATIONNAME = "Araelium Group"; 110 | TargetAttributes = { 111 | 5D427DDC1A32316C00CAA15B = { 112 | CreatedOnToolsVersion = 6.1; 113 | }; 114 | }; 115 | }; 116 | buildConfigurationList = 5DE904F91A3146150025DB42 /* Build configuration list for PBXProject "MessagePackCoder" */; 117 | compatibilityVersion = "Xcode 3.2"; 118 | developmentRegion = English; 119 | hasScannedForEncodings = 0; 120 | knownRegions = ( 121 | en, 122 | ); 123 | mainGroup = 5DE904F51A3146150025DB42; 124 | productRefGroup = 5DE904FF1A3146150025DB42 /* Products */; 125 | projectDirPath = ""; 126 | projectRoot = ""; 127 | targets = ( 128 | 5D427DDC1A32316C00CAA15B /* Tests */, 129 | ); 130 | }; 131 | /* End PBXProject section */ 132 | 133 | /* Begin PBXResourcesBuildPhase section */ 134 | 5D427DDB1A32316C00CAA15B /* Resources */ = { 135 | isa = PBXResourcesBuildPhase; 136 | buildActionMask = 2147483647; 137 | files = ( 138 | ); 139 | runOnlyForDeploymentPostprocessing = 0; 140 | }; 141 | /* End PBXResourcesBuildPhase section */ 142 | 143 | /* Begin PBXSourcesBuildPhase section */ 144 | 5D427DD91A32316C00CAA15B /* Sources */ = { 145 | isa = PBXSourcesBuildPhase; 146 | buildActionMask = 2147483647; 147 | files = ( 148 | 5D427DE81A3232D000CAA15B /* MsgPackArchiver.m in Sources */, 149 | 5D427DE91A3232D000CAA15B /* MsgPackUnarchiver.m in Sources */, 150 | 5D427DEA1A3232D000CAA15B /* cmp.c in Sources */, 151 | 5D427DE21A32316C00CAA15B /* Tests.m in Sources */, 152 | ); 153 | runOnlyForDeploymentPostprocessing = 0; 154 | }; 155 | /* End PBXSourcesBuildPhase section */ 156 | 157 | /* Begin XCBuildConfiguration section */ 158 | 5D427DE31A32316C00CAA15B /* Debug */ = { 159 | isa = XCBuildConfiguration; 160 | buildSettings = { 161 | CLANG_ENABLE_OBJC_ARC = NO; 162 | COMBINE_HIDPI_IMAGES = YES; 163 | FRAMEWORK_SEARCH_PATHS = ( 164 | "$(DEVELOPER_FRAMEWORKS_DIR)", 165 | "$(inherited)", 166 | ); 167 | GCC_PREPROCESSOR_DEFINITIONS = ( 168 | "DEBUG=1", 169 | "$(inherited)", 170 | ); 171 | GCC_WARN_UNUSED_FUNCTION = YES; 172 | INFOPLIST_FILE = Tests/Info.plist; 173 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; 174 | PRODUCT_NAME = "$(TARGET_NAME)"; 175 | }; 176 | name = Debug; 177 | }; 178 | 5D427DE41A32316C00CAA15B /* Release */ = { 179 | isa = XCBuildConfiguration; 180 | buildSettings = { 181 | CLANG_ENABLE_OBJC_ARC = NO; 182 | COMBINE_HIDPI_IMAGES = YES; 183 | FRAMEWORK_SEARCH_PATHS = ( 184 | "$(DEVELOPER_FRAMEWORKS_DIR)", 185 | "$(inherited)", 186 | ); 187 | GCC_WARN_UNUSED_FUNCTION = YES; 188 | INFOPLIST_FILE = Tests/Info.plist; 189 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; 190 | PRODUCT_NAME = "$(TARGET_NAME)"; 191 | }; 192 | name = Release; 193 | }; 194 | 5DE905031A3146150025DB42 /* Debug */ = { 195 | isa = XCBuildConfiguration; 196 | buildSettings = { 197 | ALWAYS_SEARCH_USER_PATHS = NO; 198 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 199 | CLANG_CXX_LIBRARY = "libc++"; 200 | CLANG_ENABLE_MODULES = YES; 201 | CLANG_WARN_BOOL_CONVERSION = YES; 202 | CLANG_WARN_CONSTANT_CONVERSION = YES; 203 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 204 | CLANG_WARN_EMPTY_BODY = YES; 205 | CLANG_WARN_ENUM_CONVERSION = YES; 206 | CLANG_WARN_INT_CONVERSION = YES; 207 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 208 | CLANG_WARN_UNREACHABLE_CODE = YES; 209 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 210 | COPY_PHASE_STRIP = NO; 211 | ENABLE_STRICT_OBJC_MSGSEND = YES; 212 | GCC_C_LANGUAGE_STANDARD = gnu99; 213 | GCC_DYNAMIC_NO_PIC = NO; 214 | GCC_OPTIMIZATION_LEVEL = 0; 215 | GCC_PREPROCESSOR_DEFINITIONS = ( 216 | "DEBUG=1", 217 | "$(inherited)", 218 | ); 219 | GCC_SYMBOLS_PRIVATE_EXTERN = NO; 220 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 221 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 222 | GCC_WARN_UNDECLARED_SELECTOR = YES; 223 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 224 | GCC_WARN_UNUSED_FUNCTION = NO; 225 | GCC_WARN_UNUSED_VARIABLE = YES; 226 | MACOSX_DEPLOYMENT_TARGET = 10.10; 227 | MTL_ENABLE_DEBUG_INFO = YES; 228 | ONLY_ACTIVE_ARCH = YES; 229 | SDKROOT = macosx; 230 | }; 231 | name = Debug; 232 | }; 233 | 5DE905041A3146150025DB42 /* Release */ = { 234 | isa = XCBuildConfiguration; 235 | buildSettings = { 236 | ALWAYS_SEARCH_USER_PATHS = NO; 237 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 238 | CLANG_CXX_LIBRARY = "libc++"; 239 | CLANG_ENABLE_MODULES = YES; 240 | CLANG_WARN_BOOL_CONVERSION = YES; 241 | CLANG_WARN_CONSTANT_CONVERSION = YES; 242 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 243 | CLANG_WARN_EMPTY_BODY = YES; 244 | CLANG_WARN_ENUM_CONVERSION = YES; 245 | CLANG_WARN_INT_CONVERSION = YES; 246 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 247 | CLANG_WARN_UNREACHABLE_CODE = YES; 248 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 249 | COPY_PHASE_STRIP = YES; 250 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 251 | ENABLE_NS_ASSERTIONS = NO; 252 | ENABLE_STRICT_OBJC_MSGSEND = YES; 253 | GCC_C_LANGUAGE_STANDARD = gnu99; 254 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 255 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 256 | GCC_WARN_UNDECLARED_SELECTOR = YES; 257 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 258 | GCC_WARN_UNUSED_FUNCTION = NO; 259 | GCC_WARN_UNUSED_VARIABLE = YES; 260 | MACOSX_DEPLOYMENT_TARGET = 10.10; 261 | MTL_ENABLE_DEBUG_INFO = NO; 262 | SDKROOT = macosx; 263 | }; 264 | name = Release; 265 | }; 266 | /* End XCBuildConfiguration section */ 267 | 268 | /* Begin XCConfigurationList section */ 269 | 5D427DE51A32316C00CAA15B /* Build configuration list for PBXNativeTarget "Tests" */ = { 270 | isa = XCConfigurationList; 271 | buildConfigurations = ( 272 | 5D427DE31A32316C00CAA15B /* Debug */, 273 | 5D427DE41A32316C00CAA15B /* Release */, 274 | ); 275 | defaultConfigurationIsVisible = 0; 276 | defaultConfigurationName = Release; 277 | }; 278 | 5DE904F91A3146150025DB42 /* Build configuration list for PBXProject "MessagePackCoder" */ = { 279 | isa = XCConfigurationList; 280 | buildConfigurations = ( 281 | 5DE905031A3146150025DB42 /* Debug */, 282 | 5DE905041A3146150025DB42 /* Release */, 283 | ); 284 | defaultConfigurationIsVisible = 0; 285 | defaultConfigurationName = Release; 286 | }; 287 | /* End XCConfigurationList section */ 288 | }; 289 | rootObject = 5DE904F61A3146150025DB42 /* Project object */; 290 | } 291 | -------------------------------------------------------------------------------- /MessagePackCoder/cmp.h: -------------------------------------------------------------------------------- 1 | // cmp.h 2 | // CMP is a C implementation of the MessagePack serialization format. 3 | // It currently implements version 5 of the MessagePack Spec. 4 | // https://github.com/camgunz/cmp 5 | // MIT License 6 | 7 | #ifndef CMP_H__ 8 | #define CMP_H__ 9 | 10 | struct cmp_ctx_s; 11 | 12 | typedef bool (*cmp_reader)(struct cmp_ctx_s *ctx, void *data, size_t limit); 13 | typedef size_t (*cmp_writer)(struct cmp_ctx_s *ctx, const void *data, 14 | size_t count); 15 | 16 | enum { 17 | CMP_TYPE_POSITIVE_FIXNUM, /* 0 */ 18 | CMP_TYPE_FIXMAP, /* 1 */ 19 | CMP_TYPE_FIXARRAY, /* 2 */ 20 | CMP_TYPE_FIXSTR, /* 3 */ 21 | CMP_TYPE_NIL, /* 4 */ 22 | CMP_TYPE_BOOLEAN, /* 5 */ 23 | CMP_TYPE_BIN8, /* 6 */ 24 | CMP_TYPE_BIN16, /* 7 */ 25 | CMP_TYPE_BIN32, /* 8 */ 26 | CMP_TYPE_EXT8, /* 9 */ 27 | CMP_TYPE_EXT16, /* 10 */ 28 | CMP_TYPE_EXT32, /* 11 */ 29 | CMP_TYPE_FLOAT, /* 12 */ 30 | CMP_TYPE_DOUBLE, /* 13 */ 31 | CMP_TYPE_UINT8, /* 14 */ 32 | CMP_TYPE_UINT16, /* 15 */ 33 | CMP_TYPE_UINT32, /* 16 */ 34 | CMP_TYPE_UINT64, /* 17 */ 35 | CMP_TYPE_SINT8, /* 18 */ 36 | CMP_TYPE_SINT16, /* 19 */ 37 | CMP_TYPE_SINT32, /* 20 */ 38 | CMP_TYPE_SINT64, /* 21 */ 39 | CMP_TYPE_FIXEXT1, /* 22 */ 40 | CMP_TYPE_FIXEXT2, /* 23 */ 41 | CMP_TYPE_FIXEXT4, /* 24 */ 42 | CMP_TYPE_FIXEXT8, /* 25 */ 43 | CMP_TYPE_FIXEXT16, /* 26 */ 44 | CMP_TYPE_STR8, /* 27 */ 45 | CMP_TYPE_STR16, /* 28 */ 46 | CMP_TYPE_STR32, /* 29 */ 47 | CMP_TYPE_ARRAY16, /* 30 */ 48 | CMP_TYPE_ARRAY32, /* 31 */ 49 | CMP_TYPE_MAP16, /* 32 */ 50 | CMP_TYPE_MAP32, /* 33 */ 51 | CMP_TYPE_NEGATIVE_FIXNUM /* 34 */ 52 | }; 53 | 54 | typedef struct cmp_ext_s { 55 | int8_t type; 56 | uint32_t size; 57 | } cmp_ext_t; 58 | 59 | union cmp_object_data_u { 60 | bool boolean; 61 | uint8_t u8; 62 | uint16_t u16; 63 | uint32_t u32; 64 | uint64_t u64; 65 | int8_t s8; 66 | int16_t s16; 67 | int32_t s32; 68 | int64_t s64; 69 | float flt; 70 | double dbl; 71 | uint32_t array_size; 72 | uint32_t map_size; 73 | uint32_t str_size; 74 | uint32_t bin_size; 75 | cmp_ext_t ext; 76 | }; 77 | 78 | typedef struct cmp_ctx_s { 79 | uint8_t error; 80 | void *buf; 81 | cmp_reader read; 82 | cmp_writer write; 83 | } cmp_ctx_t; 84 | 85 | typedef struct cmp_object_s { 86 | uint8_t type; 87 | union cmp_object_data_u as; 88 | } cmp_object_t; 89 | 90 | #ifdef __cplusplus 91 | extern "C" { 92 | #endif 93 | 94 | /* 95 | * ============================================================================ 96 | * === Main API 97 | * ============================================================================ 98 | */ 99 | 100 | /* Initializes a CMP context */ 101 | void cmp_init(cmp_ctx_t *ctx, void *buf, cmp_reader read, cmp_writer write); 102 | 103 | /* Returns CMP's version */ 104 | uint32_t cmp_version(void); 105 | 106 | /* Returns the MessagePack version employed by CMP */ 107 | uint32_t cmp_mp_version(void); 108 | 109 | /* Returns a string description of a CMP context's error */ 110 | const char* cmp_strerror(cmp_ctx_t *ctx); 111 | 112 | /* Writes a signed integer to the backend */ 113 | bool cmp_write_sint(cmp_ctx_t *ctx, int64_t d); 114 | 115 | /* Writes an unsigned integer to the backend */ 116 | bool cmp_write_uint(cmp_ctx_t *ctx, uint64_t u); 117 | 118 | /* Writes a single-precision float to the backend */ 119 | bool cmp_write_float(cmp_ctx_t *ctx, float f); 120 | 121 | /* Writes a double-precision float to the backend */ 122 | bool cmp_write_double(cmp_ctx_t *ctx, double d); 123 | 124 | /* Writes NULL to the backend */ 125 | bool cmp_write_nil(cmp_ctx_t *ctx); 126 | 127 | /* Writes true to the backend */ 128 | bool cmp_write_true(cmp_ctx_t *ctx); 129 | 130 | /* Writes false to the backend */ 131 | bool cmp_write_false(cmp_ctx_t *ctx); 132 | 133 | /* Writes a boolean value to the backend */ 134 | bool cmp_write_bool(cmp_ctx_t *ctx, bool b); 135 | 136 | /* 137 | * Writes an unsigned char's value to the backend as a boolean. This is useful 138 | * if you are using a different boolean type in your application. 139 | */ 140 | bool cmp_write_u8_as_bool(cmp_ctx_t *ctx, uint8_t b); 141 | 142 | /* 143 | * Writes a string to the backend; according to the MessagePack spec, this must 144 | * be encoded using UTF-8, but CMP leaves that job up to the programmer. 145 | */ 146 | bool cmp_write_str(cmp_ctx_t *ctx, const char *data, uint32_t size); 147 | 148 | /* 149 | * Writes the string marker to the backend. This is useful if you are writing 150 | * data in chunks instead of a single shot. 151 | */ 152 | bool cmp_write_str_marker(cmp_ctx_t *ctx, uint32_t size); 153 | 154 | /* Writes binary data to the backend */ 155 | bool cmp_write_bin(cmp_ctx_t *ctx, const void *data, uint32_t size); 156 | 157 | /* 158 | * Writes the binary data marker to the backend. This is useful if you are 159 | * writing data in chunks instead of a single shot. 160 | */ 161 | bool cmp_write_bin_marker(cmp_ctx_t *ctx, uint32_t size); 162 | 163 | /* Writes an array to the backend. */ 164 | bool cmp_write_array(cmp_ctx_t *ctx, uint32_t size); 165 | 166 | /* Writes a map to the backend. */ 167 | bool cmp_write_map(cmp_ctx_t *ctx, uint32_t size); 168 | 169 | /* Writes an extended type to the backend */ 170 | bool cmp_write_ext(cmp_ctx_t *ctx, int8_t type, uint32_t size, 171 | const void *data); 172 | 173 | /* 174 | * Writes the extended type marker to the backend. This is useful if you want 175 | * to write the type's data in chunks instead of a single shot. 176 | */ 177 | bool cmp_write_ext_marker(cmp_ctx_t *ctx, int8_t type, uint32_t size); 178 | 179 | /* Writes an object to the backend */ 180 | bool cmp_write_object(cmp_ctx_t *ctx, cmp_object_t *obj); 181 | 182 | /* Reads a signed integer that fits inside a signed char */ 183 | bool cmp_read_char(cmp_ctx_t *ctx, int8_t *c); 184 | 185 | /* Reads a signed integer that fits inside a signed short */ 186 | bool cmp_read_short(cmp_ctx_t *ctx, int16_t *s); 187 | 188 | /* Reads a signed integer that fits inside a signed int */ 189 | bool cmp_read_int(cmp_ctx_t *ctx, int32_t *i); 190 | 191 | /* Reads a signed integer that fits inside a signed long */ 192 | bool cmp_read_long(cmp_ctx_t *ctx, int64_t *d); 193 | 194 | /* Reads a signed integer */ 195 | bool cmp_read_sinteger(cmp_ctx_t *ctx, int64_t *d); 196 | 197 | /* Reads an unsigned integer that fits inside an unsigned char */ 198 | bool cmp_read_uchar(cmp_ctx_t *ctx, uint8_t *c); 199 | 200 | /* Reads an unsigned integer that fits inside an unsigned short */ 201 | bool cmp_read_ushort(cmp_ctx_t *ctx, uint16_t *s); 202 | 203 | /* Reads an unsigned integer that fits inside an unsigned int */ 204 | bool cmp_read_uint(cmp_ctx_t *ctx, uint32_t *i); 205 | 206 | /* Reads an unsigned integer that fits inside an unsigned long */ 207 | bool cmp_read_ulong(cmp_ctx_t *ctx, uint64_t *u); 208 | 209 | /* Reads an unsigned integer */ 210 | bool cmp_read_uinteger(cmp_ctx_t *ctx, uint64_t *u); 211 | 212 | /* Reads a single-precision float from the backend */ 213 | bool cmp_read_float(cmp_ctx_t *ctx, float *f); 214 | 215 | /* Reads a double-precision float from the backend */ 216 | bool cmp_read_double(cmp_ctx_t *ctx, double *d); 217 | 218 | /* "Reads" (more like "skips") a NULL value from the backend */ 219 | bool cmp_read_nil(cmp_ctx_t *ctx); 220 | 221 | /* Reads a boolean from the backend */ 222 | bool cmp_read_bool(cmp_ctx_t *ctx, bool *b); 223 | 224 | /* 225 | * Reads a boolean as an unsigned char from the backend; this is useful if your 226 | * application uses a different boolean type. 227 | */ 228 | bool cmp_read_bool_as_u8(cmp_ctx_t *ctx, uint8_t *b); 229 | 230 | /* Reads a string's size from the backend */ 231 | bool cmp_read_str_size(cmp_ctx_t *ctx, uint32_t *size); 232 | 233 | /* 234 | * Reads a string from the backend; according to the spec, the string's data 235 | * ought to be encoded using UTF-8, 236 | */ 237 | bool cmp_read_str(cmp_ctx_t *ctx, char *data, uint32_t *size); 238 | 239 | /* Reads the size of packed binary data from the backend */ 240 | bool cmp_read_bin_size(cmp_ctx_t *ctx, uint32_t *size); 241 | 242 | /* Reads packed binary data from the backend */ 243 | bool cmp_read_bin(cmp_ctx_t *ctx, void *data, uint32_t *size); 244 | 245 | /* Reads an array from the backend */ 246 | bool cmp_read_array(cmp_ctx_t *ctx, uint32_t *size); 247 | 248 | /* Reads a map from the backend */ 249 | bool cmp_read_map(cmp_ctx_t *ctx, uint32_t *size); 250 | 251 | /* Reads the extended type's marker from the backend */ 252 | bool cmp_read_ext_marker(cmp_ctx_t *ctx, int8_t *type, uint32_t *size); 253 | 254 | /* Reads an extended type from the backend */ 255 | bool cmp_read_ext(cmp_ctx_t *ctx, int8_t *type, uint32_t *size, void *data); 256 | 257 | /* Reads an object from the backend */ 258 | bool cmp_read_object(cmp_ctx_t *ctx, cmp_object_t *obj); 259 | 260 | /* 261 | * ============================================================================ 262 | * === Specific API 263 | * ============================================================================ 264 | */ 265 | 266 | bool cmp_write_pfix(cmp_ctx_t *ctx, uint8_t c); 267 | bool cmp_write_nfix(cmp_ctx_t *ctx, int8_t c); 268 | 269 | bool cmp_write_sfix(cmp_ctx_t *ctx, int8_t c); 270 | bool cmp_write_s8(cmp_ctx_t *ctx, int8_t c); 271 | bool cmp_write_s16(cmp_ctx_t *ctx, int16_t s); 272 | bool cmp_write_s32(cmp_ctx_t *ctx, int32_t i); 273 | bool cmp_write_s64(cmp_ctx_t *ctx, int64_t l); 274 | 275 | bool cmp_write_ufix(cmp_ctx_t *ctx, uint8_t c); 276 | bool cmp_write_u8(cmp_ctx_t *ctx, uint8_t c); 277 | bool cmp_write_u16(cmp_ctx_t *ctx, uint16_t s); 278 | bool cmp_write_u32(cmp_ctx_t *ctx, uint32_t i); 279 | bool cmp_write_u64(cmp_ctx_t *ctx, uint64_t l); 280 | 281 | bool cmp_write_fixstr_marker(cmp_ctx_t *ctx, uint8_t size); 282 | bool cmp_write_fixstr(cmp_ctx_t *ctx, const char *data, uint8_t size); 283 | bool cmp_write_str8_marker(cmp_ctx_t *ctx, uint8_t size); 284 | bool cmp_write_str8(cmp_ctx_t *ctx, const char *data, uint8_t size); 285 | bool cmp_write_str16_marker(cmp_ctx_t *ctx, uint16_t size); 286 | bool cmp_write_str16(cmp_ctx_t *ctx, const char *data, uint16_t size); 287 | bool cmp_write_str32_marker(cmp_ctx_t *ctx, uint32_t size); 288 | bool cmp_write_str32(cmp_ctx_t *ctx, const char *data, uint32_t size); 289 | 290 | bool cmp_write_bin8_marker(cmp_ctx_t *ctx, uint8_t size); 291 | bool cmp_write_bin8(cmp_ctx_t *ctx, const void *data, uint8_t size); 292 | bool cmp_write_bin16_marker(cmp_ctx_t *ctx, uint16_t size); 293 | bool cmp_write_bin16(cmp_ctx_t *ctx, const void *data, uint16_t size); 294 | bool cmp_write_bin32_marker(cmp_ctx_t *ctx, uint32_t size); 295 | bool cmp_write_bin32(cmp_ctx_t *ctx, const void *data, uint32_t size); 296 | 297 | bool cmp_write_fixarray(cmp_ctx_t *ctx, uint8_t size); 298 | bool cmp_write_array16(cmp_ctx_t *ctx, uint16_t size); 299 | bool cmp_write_array32(cmp_ctx_t *ctx, uint32_t size); 300 | 301 | bool cmp_write_fixmap(cmp_ctx_t *ctx, uint8_t size); 302 | bool cmp_write_map16(cmp_ctx_t *ctx, uint16_t size); 303 | bool cmp_write_map32(cmp_ctx_t *ctx, uint32_t size); 304 | 305 | bool cmp_write_fixext1_marker(cmp_ctx_t *ctx, int8_t type); 306 | bool cmp_write_fixext1(cmp_ctx_t *ctx, int8_t type, const void *data); 307 | bool cmp_write_fixext2_marker(cmp_ctx_t *ctx, int8_t type); 308 | bool cmp_write_fixext2(cmp_ctx_t *ctx, int8_t type, const void *data); 309 | bool cmp_write_fixext4_marker(cmp_ctx_t *ctx, int8_t type); 310 | bool cmp_write_fixext4(cmp_ctx_t *ctx, int8_t type, const void *data); 311 | bool cmp_write_fixext8_marker(cmp_ctx_t *ctx, int8_t type); 312 | bool cmp_write_fixext8(cmp_ctx_t *ctx, int8_t type, const void *data); 313 | bool cmp_write_fixext16_marker(cmp_ctx_t *ctx, int8_t type); 314 | bool cmp_write_fixext16(cmp_ctx_t *ctx, int8_t type, const void *data); 315 | 316 | bool cmp_write_ext8_marker(cmp_ctx_t *ctx, int8_t type, uint8_t size); 317 | bool cmp_write_ext8(cmp_ctx_t *ctx, int8_t type, uint8_t size, 318 | const void *data); 319 | bool cmp_write_ext16_marker(cmp_ctx_t *ctx, int8_t type, uint16_t size); 320 | bool cmp_write_ext16(cmp_ctx_t *ctx, int8_t type, uint16_t size, 321 | const void *data); 322 | bool cmp_write_ext32_marker(cmp_ctx_t *ctx, int8_t type, uint32_t size); 323 | bool cmp_write_ext32(cmp_ctx_t *ctx, int8_t type, uint32_t size, 324 | const void *data); 325 | 326 | bool cmp_read_pfix(cmp_ctx_t *ctx, uint8_t *c); 327 | bool cmp_read_nfix(cmp_ctx_t *ctx, int8_t *c); 328 | 329 | bool cmp_read_sfix(cmp_ctx_t *ctx, int8_t *c); 330 | bool cmp_read_s8(cmp_ctx_t *ctx, int8_t *c); 331 | bool cmp_read_s16(cmp_ctx_t *ctx, int16_t *s); 332 | bool cmp_read_s32(cmp_ctx_t *ctx, int32_t *i); 333 | bool cmp_read_s64(cmp_ctx_t *ctx, int64_t *l); 334 | 335 | bool cmp_read_ufix(cmp_ctx_t *ctx, uint8_t *c); 336 | bool cmp_read_u8(cmp_ctx_t *ctx, uint8_t *c); 337 | bool cmp_read_u16(cmp_ctx_t *ctx, uint16_t *s); 338 | bool cmp_read_u32(cmp_ctx_t *ctx, uint32_t *i); 339 | bool cmp_read_u64(cmp_ctx_t *ctx, uint64_t *l); 340 | 341 | bool cmp_read_fixext1_marker(cmp_ctx_t *ctx, int8_t *type); 342 | bool cmp_read_fixext1(cmp_ctx_t *ctx, int8_t *type, void *data); 343 | bool cmp_read_fixext2_marker(cmp_ctx_t *ctx, int8_t *type); 344 | bool cmp_read_fixext2(cmp_ctx_t *ctx, int8_t *type, void *data); 345 | bool cmp_read_fixext4_marker(cmp_ctx_t *ctx, int8_t *type); 346 | bool cmp_read_fixext4(cmp_ctx_t *ctx, int8_t *type, void *data); 347 | bool cmp_read_fixext8_marker(cmp_ctx_t *ctx, int8_t *type); 348 | bool cmp_read_fixext8(cmp_ctx_t *ctx, int8_t *type, void *data); 349 | bool cmp_read_fixext16_marker(cmp_ctx_t *ctx, int8_t *type); 350 | bool cmp_read_fixext16(cmp_ctx_t *ctx, int8_t *type, void *data); 351 | 352 | bool cmp_read_ext8_marker(cmp_ctx_t *ctx, int8_t *type, uint8_t *size); 353 | bool cmp_read_ext8(cmp_ctx_t *ctx, int8_t *type, uint8_t *size, void *data); 354 | bool cmp_read_ext16_marker(cmp_ctx_t *ctx, int8_t *type, uint16_t *size); 355 | bool cmp_read_ext16(cmp_ctx_t *ctx, int8_t *type, uint16_t *size, void *data); 356 | bool cmp_read_ext32_marker(cmp_ctx_t *ctx, int8_t *type, uint32_t *size); 357 | bool cmp_read_ext32(cmp_ctx_t *ctx, int8_t *type, uint32_t *size, void *data); 358 | 359 | /* 360 | * ============================================================================ 361 | * === Object API 362 | * ============================================================================ 363 | */ 364 | 365 | bool cmp_object_is_char(cmp_object_t *obj); 366 | bool cmp_object_is_short(cmp_object_t *obj); 367 | bool cmp_object_is_int(cmp_object_t *obj); 368 | bool cmp_object_is_long(cmp_object_t *obj); 369 | bool cmp_object_is_sinteger(cmp_object_t *obj); 370 | bool cmp_object_is_uchar(cmp_object_t *obj); 371 | bool cmp_object_is_ushort(cmp_object_t *obj); 372 | bool cmp_object_is_uint(cmp_object_t *obj); 373 | bool cmp_object_is_ulong(cmp_object_t *obj); 374 | bool cmp_object_is_uinteger(cmp_object_t *obj); 375 | bool cmp_object_is_float(cmp_object_t *obj); 376 | bool cmp_object_is_double(cmp_object_t *obj); 377 | bool cmp_object_is_nil(cmp_object_t *obj); 378 | bool cmp_object_is_bool(cmp_object_t *obj); 379 | bool cmp_object_is_str(cmp_object_t *obj); 380 | bool cmp_object_is_bin(cmp_object_t *obj); 381 | bool cmp_object_is_array(cmp_object_t *obj); 382 | bool cmp_object_is_map(cmp_object_t *obj); 383 | bool cmp_object_is_ext(cmp_object_t *obj); 384 | 385 | bool cmp_object_as_char(cmp_object_t *obj, int8_t *c); 386 | bool cmp_object_as_short(cmp_object_t *obj, int16_t *s); 387 | bool cmp_object_as_int(cmp_object_t *obj, int32_t *i); 388 | bool cmp_object_as_long(cmp_object_t *obj, int64_t *d); 389 | bool cmp_object_as_sinteger(cmp_object_t *obj, int64_t *d); 390 | bool cmp_object_as_uchar(cmp_object_t *obj, uint8_t *c); 391 | bool cmp_object_as_ushort(cmp_object_t *obj, uint16_t *s); 392 | bool cmp_object_as_uint(cmp_object_t *obj, uint32_t *i); 393 | bool cmp_object_as_ulong(cmp_object_t *obj, uint64_t *u); 394 | bool cmp_object_as_uinteger(cmp_object_t *obj, uint64_t *u); 395 | bool cmp_object_as_float(cmp_object_t *obj, float *f); 396 | bool cmp_object_as_double(cmp_object_t *obj, double *d); 397 | bool cmp_object_as_bool(cmp_object_t *obj, bool *b); 398 | bool cmp_object_as_str(cmp_object_t *obj, uint32_t *size); 399 | bool cmp_object_as_bin(cmp_object_t *obj, uint32_t *size); 400 | bool cmp_object_as_array(cmp_object_t *obj, uint32_t *size); 401 | bool cmp_object_as_map(cmp_object_t *obj, uint32_t *size); 402 | bool cmp_object_as_ext(cmp_object_t *obj, int8_t *type, uint32_t *size); 403 | 404 | #ifdef __cplusplus 405 | } /* extern "C" */ 406 | #endif 407 | 408 | #endif /* CMP_H__ */ 409 | 410 | /* vi: set et ts=2 sw=2: */ 411 | 412 | -------------------------------------------------------------------------------- /Tests/Tests.m: -------------------------------------------------------------------------------- 1 | // 2 | // Tests.m 3 | // MessagePackCoder 4 | // https://github.com/swillits/messagepackcoder 5 | // 6 | // Created by Seth Willits on 12/4/14. 7 | // Copyright (c) 2014 Seth Willits. All rights reserved. 8 | // 9 | 10 | #import 11 | #import 12 | #import "MsgPackArchiver.h" 13 | #import "MsgPackUnarchiver.h" 14 | 15 | 16 | 17 | @interface Foo : NSObject 18 | @property (strong) id empty; 19 | @property (strong) NSNull * null; 20 | @property (strong) NSString * string; 21 | @property (strong) NSNumber * number; 22 | @property (strong) NSDictionary * dictionary; 23 | @end 24 | 25 | 26 | 27 | @interface Tests : XCTestCase 28 | @end 29 | 30 | 31 | @implementation Tests 32 | 33 | - (void)setUp 34 | { 35 | [super setUp]; 36 | } 37 | 38 | - (void)tearDown 39 | { 40 | [super tearDown]; 41 | } 42 | 43 | 44 | 45 | - (void)testBytes 46 | { 47 | const char * bytes = "here are some\0'random' bytes.\0All bytes are equal!"; 48 | size_t length = 50; 49 | 50 | NSData * data1 = [NSData data]; 51 | NSData * data2 = [NSData dataWithBytesNoCopy:(void *)bytes length:length freeWhenDone:NO]; 52 | 53 | [self _testRoot:data1]; 54 | [self _testRoot:data2]; 55 | 56 | NSMutableData * mdata = [NSMutableData data]; 57 | MsgPackArchiver * a = [[MsgPackArchiver alloc] initForWritingWithMutableData:mdata]; 58 | [a encodeObject:data1 forKey:@"key0"]; 59 | [a encodeObject:data2 forKey:@"key1"]; 60 | [a finishEncoding]; 61 | 62 | MsgPackUnarchiver * u = [[MsgPackUnarchiver alloc] initForReadingWithData:mdata]; 63 | XCTAssertEqualObjects([u decodeObjectForKey:@"key0"], data1); 64 | XCTAssertEqualObjects([u decodeObjectForKey:@"key1"], data2); 65 | } 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | - (void)testBool 77 | { 78 | [self _testRoot:@(YES)]; 79 | [self _testRoot:@(NO)]; 80 | 81 | NSMutableData * mdata = [NSMutableData data]; 82 | MsgPackArchiver * a = [[MsgPackArchiver alloc] initForWritingWithMutableData:mdata]; 83 | [a encodeBool:YES forKey:@"key0"]; 84 | [a encodeBool:NO forKey:@"key1"]; 85 | [a finishEncoding]; 86 | 87 | MsgPackUnarchiver * u = [[MsgPackUnarchiver alloc] initForReadingWithData:mdata]; 88 | XCTAssertEqual([u decodeBoolForKey:@"key0"], YES); 89 | XCTAssertEqual([u decodeBoolForKey:@"key1"], NO); 90 | } 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | - (void)testInt 99 | { 100 | [self _testRoot:@(0)]; 101 | [self _testRoot:@(-1)]; 102 | [self _testRoot:@(INT_MAX)]; 103 | [self _testRoot:@(INT_MIN)]; 104 | 105 | NSMutableData * mdata = [NSMutableData data]; 106 | MsgPackArchiver * a = [[MsgPackArchiver alloc] initForWritingWithMutableData:mdata]; 107 | [a encodeInt:0 forKey:@"key0"]; 108 | [a encodeInt:-1 forKey:@"key1"]; 109 | [a encodeInt:INT_MAX forKey:@"key2"]; 110 | [a encodeInt:INT_MIN forKey:@"key3"]; 111 | [a finishEncoding]; 112 | 113 | MsgPackUnarchiver * u = [[MsgPackUnarchiver alloc] initForReadingWithData:mdata]; 114 | XCTAssertEqual([u decodeIntForKey:@"key0"], 0); 115 | XCTAssertEqual([u decodeIntForKey:@"key1"], -1); 116 | XCTAssertEqual([u decodeIntForKey:@"key2"], INT_MAX); 117 | XCTAssertEqual([u decodeIntForKey:@"key3"], INT_MIN); 118 | } 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | - (void)testInt32 127 | { 128 | [self _testRoot:@(0)]; 129 | [self _testRoot:@(-1)]; 130 | [self _testRoot:@(INT32_MAX)]; 131 | [self _testRoot:@(INT32_MIN)]; 132 | 133 | NSMutableData * mdata = [NSMutableData data]; 134 | MsgPackArchiver * a = [[MsgPackArchiver alloc] initForWritingWithMutableData:mdata]; 135 | [a encodeInt32:0 forKey:@"key0"]; 136 | [a encodeInt32:-1 forKey:@"key1"]; 137 | [a encodeInt32:INT32_MAX forKey:@"key2"]; 138 | [a encodeInt32:INT32_MIN forKey:@"key3"]; 139 | [a finishEncoding]; 140 | 141 | MsgPackUnarchiver * u = [[MsgPackUnarchiver alloc] initForReadingWithData:mdata]; 142 | XCTAssertEqual([u decodeInt32ForKey:@"key0"], 0); 143 | XCTAssertEqual([u decodeInt32ForKey:@"key1"], -1); 144 | XCTAssertEqual([u decodeInt32ForKey:@"key2"], INT32_MAX); 145 | XCTAssertEqual([u decodeInt32ForKey:@"key3"], INT32_MIN); 146 | } 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | - (void)testInt64 155 | { 156 | [self _testRoot:@(0)]; 157 | [self _testRoot:@(-1)]; 158 | [self _testRoot:@(INT64_MAX)]; 159 | [self _testRoot:@(INT64_MIN)]; 160 | 161 | NSMutableData * mdata = [NSMutableData data]; 162 | MsgPackArchiver * a = [[MsgPackArchiver alloc] initForWritingWithMutableData:mdata]; 163 | [a encodeInt64:0 forKey:@"key0"]; 164 | [a encodeInt64:-1 forKey:@"key1"]; 165 | [a encodeInt64:INT64_MAX forKey:@"key2"]; 166 | [a encodeInt64:INT64_MIN forKey:@"key3"]; 167 | [a finishEncoding]; 168 | 169 | MsgPackUnarchiver * u = [[MsgPackUnarchiver alloc] initForReadingWithData:mdata]; 170 | XCTAssertEqual([u decodeInt64ForKey:@"key0"], 0); 171 | XCTAssertEqual([u decodeInt64ForKey:@"key1"], -1); 172 | XCTAssertEqual([u decodeInt64ForKey:@"key2"], INT64_MAX); 173 | XCTAssertEqual([u decodeInt64ForKey:@"key3"], INT64_MIN); 174 | } 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | - (void)testInteger 183 | { 184 | [self _testRoot:@(0)]; 185 | [self _testRoot:@(-1)]; 186 | [self _testRoot:@(NSIntegerMax)]; 187 | [self _testRoot:@(NSIntegerMin)]; 188 | 189 | NSMutableData * mdata = [NSMutableData data]; 190 | MsgPackArchiver * a = [[MsgPackArchiver alloc] initForWritingWithMutableData:mdata]; 191 | [a encodeInteger:0 forKey:@"key0"]; 192 | [a encodeInteger:-1 forKey:@"key1"]; 193 | [a encodeInteger:NSIntegerMax forKey:@"key2"]; 194 | [a encodeInteger:NSIntegerMin forKey:@"key3"]; 195 | [a finishEncoding]; 196 | 197 | MsgPackUnarchiver * u = [[MsgPackUnarchiver alloc] initForReadingWithData:mdata]; 198 | XCTAssertEqual([u decodeIntegerForKey:@"key0"], 0); 199 | XCTAssertEqual([u decodeIntegerForKey:@"key1"], -1); 200 | XCTAssertEqual([u decodeIntegerForKey:@"key2"], NSIntegerMax); 201 | XCTAssertEqual([u decodeIntegerForKey:@"key3"], NSIntegerMin); 202 | } 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | - (void)testFloat 211 | { 212 | [self _testRoot:@(0.0f)]; 213 | [self _testRoot:@(-1.0f)]; 214 | [self _testRoot:@(3.14159265358979323846264338327950288419716939937510f)]; 215 | [self _testRoot:@(FLT_MAX)]; 216 | [self _testRoot:@(FLT_MIN)]; 217 | 218 | NSMutableData * mdata = [NSMutableData data]; 219 | MsgPackArchiver * a = [[MsgPackArchiver alloc] initForWritingWithMutableData:mdata]; 220 | [a encodeFloat:0.0f forKey:@"key0"]; 221 | [a encodeFloat:-1.0f forKey:@"key1"]; 222 | [a encodeFloat:3.14159265358979323846264338327950288419716939937510f forKey:@"key2"]; 223 | [a encodeFloat:FLT_MAX forKey:@"key3"]; 224 | [a encodeFloat:FLT_MIN forKey:@"key4"]; 225 | [a finishEncoding]; 226 | 227 | MsgPackUnarchiver * u = [[MsgPackUnarchiver alloc] initForReadingWithData:mdata]; 228 | XCTAssertEqual([u decodeFloatForKey:@"key0"], 0.0f); 229 | XCTAssertEqual([u decodeFloatForKey:@"key1"], -1.0f); 230 | XCTAssertEqual([u decodeFloatForKey:@"key2"], 3.14159265358979323846264338327950288419716939937510f); 231 | XCTAssertEqual([u decodeFloatForKey:@"key3"], FLT_MAX); 232 | XCTAssertEqual([u decodeFloatForKey:@"key4"], FLT_MIN); 233 | } 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | - (void)testDouble 242 | { 243 | [self _testRoot:@(0.0)]; 244 | [self _testRoot:@(-1.0)]; 245 | [self _testRoot:@(3.14159265358979323846264338327950288419716939937510)]; 246 | [self _testRoot:@(DBL_MAX)]; 247 | [self _testRoot:@(DBL_MIN)]; 248 | 249 | NSMutableData * mdata = [NSMutableData data]; 250 | MsgPackArchiver * a = [[MsgPackArchiver alloc] initForWritingWithMutableData:mdata]; 251 | [a encodeDouble:0.0 forKey:@"key0"]; 252 | [a encodeDouble:-1.0 forKey:@"key1"]; 253 | [a encodeDouble:3.14159265358979323846264338327950288419716939937510 forKey:@"key2"]; 254 | [a encodeDouble:DBL_MAX forKey:@"key3"]; 255 | [a encodeDouble:DBL_MIN forKey:@"key4"]; 256 | [a finishEncoding]; 257 | 258 | MsgPackUnarchiver * u = [[MsgPackUnarchiver alloc] initForReadingWithData:mdata]; 259 | XCTAssertEqual([u decodeDoubleForKey:@"key0"], 0.0); 260 | XCTAssertEqual([u decodeDoubleForKey:@"key1"], -1.0); 261 | XCTAssertEqual([u decodeDoubleForKey:@"key2"], 3.14159265358979323846264338327950288419716939937510); 262 | XCTAssertEqual([u decodeDoubleForKey:@"key3"], DBL_MAX); 263 | XCTAssertEqual([u decodeDoubleForKey:@"key4"], DBL_MIN); 264 | } 265 | 266 | 267 | 268 | 269 | 270 | 271 | 272 | - (void)testSize 273 | { 274 | [self _testRoot:[NSValue valueWithSize:NSMakeSize(0.0, 0.0)]]; 275 | [self _testRoot:[NSValue valueWithSize:NSMakeSize(738.1234567, 987.6543210)]]; 276 | [self _testRoot:[NSValue valueWithSize:NSMakeSize(CGFLOAT_MAX, CGFLOAT_MIN)]]; 277 | 278 | NSMutableData * mdata = [NSMutableData data]; 279 | MsgPackArchiver * a = [[MsgPackArchiver alloc] initForWritingWithMutableData:mdata]; 280 | [a encodeSize:NSMakeSize(0.0, 0.0) forKey:@"key0"]; 281 | [a encodeSize:NSMakeSize(738.1234567, 987.6543210) forKey:@"key1"]; 282 | [a encodeSize:NSMakeSize(CGFLOAT_MAX, CGFLOAT_MIN) forKey:@"key2"]; 283 | [a finishEncoding]; 284 | 285 | MsgPackUnarchiver * u = [[MsgPackUnarchiver alloc] initForReadingWithData:mdata]; 286 | XCTAssert(NSEqualSizes([u decodeSizeForKey:@"key0"], NSMakeSize(0.0, 0.0))); 287 | XCTAssert(NSEqualSizes([u decodeSizeForKey:@"key1"], NSMakeSize(738.1234567, 987.6543210))); 288 | XCTAssert(NSEqualSizes([u decodeSizeForKey:@"key2"], NSMakeSize(CGFLOAT_MAX, CGFLOAT_MIN))); 289 | } 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | - (void)testPoint 298 | { 299 | [self _testRoot:[NSValue valueWithPoint:NSMakePoint(0.0, 0.0)]]; 300 | [self _testRoot:[NSValue valueWithPoint:NSMakePoint(738.1234567, 987.6543210)]]; 301 | [self _testRoot:[NSValue valueWithPoint:NSMakePoint(CGFLOAT_MAX, CGFLOAT_MIN)]]; 302 | 303 | NSMutableData * mdata = [NSMutableData data]; 304 | MsgPackArchiver * a = [[MsgPackArchiver alloc] initForWritingWithMutableData:mdata]; 305 | [a encodePoint:NSMakePoint(0.0, 0.0) forKey:@"key0"]; 306 | [a encodePoint:NSMakePoint(738.1234567, 987.6543210) forKey:@"key1"]; 307 | [a encodePoint:NSMakePoint(CGFLOAT_MAX, CGFLOAT_MIN) forKey:@"key2"]; 308 | [a finishEncoding]; 309 | 310 | MsgPackUnarchiver * u = [[MsgPackUnarchiver alloc] initForReadingWithData:mdata]; 311 | XCTAssert(NSEqualPoints([u decodePointForKey:@"key0"], NSMakePoint(0.0, 0.0))); 312 | XCTAssert(NSEqualPoints([u decodePointForKey:@"key1"], NSMakePoint(738.1234567, 987.6543210))); 313 | XCTAssert(NSEqualPoints([u decodePointForKey:@"key2"], NSMakePoint(CGFLOAT_MAX, CGFLOAT_MIN))); 314 | } 315 | 316 | 317 | 318 | 319 | 320 | 321 | 322 | - (void)testRect 323 | { 324 | [self _testRoot:[NSValue valueWithRect:NSMakeRect(0.0, 0.0, 738.1234567, 987.6543210)]]; 325 | [self _testRoot:[NSValue valueWithRect:NSMakeRect(CGFLOAT_MIN, CGFLOAT_MAX, CGFLOAT_MAX, CGFLOAT_MIN)]]; 326 | 327 | NSMutableData * mdata = [NSMutableData data]; 328 | MsgPackArchiver * a = [[MsgPackArchiver alloc] initForWritingWithMutableData:mdata]; 329 | [a encodeRect:NSMakeRect(0.0, 0.0, 738.1234567, 987.6543210) forKey:@"key0"]; 330 | [a encodeRect:NSMakeRect(CGFLOAT_MIN, CGFLOAT_MAX, CGFLOAT_MAX, CGFLOAT_MIN) forKey:@"key1"]; 331 | [a finishEncoding]; 332 | 333 | MsgPackUnarchiver * u = [[MsgPackUnarchiver alloc] initForReadingWithData:mdata]; 334 | XCTAssert(NSEqualRects([u decodeRectForKey:@"key0"], NSMakeRect(0.0, 0.0, 738.1234567, 987.6543210))); 335 | XCTAssert(NSEqualRects([u decodeRectForKey:@"key1"], NSMakeRect(CGFLOAT_MIN, CGFLOAT_MAX, CGFLOAT_MAX, CGFLOAT_MIN))); 336 | } 337 | 338 | 339 | 340 | 341 | 342 | 343 | 344 | - (void)testObject 345 | { 346 | [self _testRoot:@""]; 347 | [self _testRoot:@"striéng"]; 348 | [self _testRoot:@"Iлtêrԉãtioԉɑlìzãtí߀л"]; 349 | [self _testRoot:NSNull.null]; 350 | [self _testRoot:@{@"key": @"value"}]; 351 | [self _testRoot:@[@"a", @"b", @"c", @(1), @(2), @(3)]]; 352 | [self _testRoot:@{@"key": @(1324.5), @(5) : @[@"a", NSNull.null, [[[Foo alloc] init] autorelease]]}]; 353 | 354 | NSMutableData * mdata = [NSMutableData data]; 355 | MsgPackArchiver * a = [[MsgPackArchiver alloc] initForWritingWithMutableData:mdata]; 356 | [a encodeObject:@"" forKey:@"key0"]; 357 | [a encodeObject:@"striéng" forKey:@"key1"]; 358 | [a encodeObject:@"Iлtêrԉãtioԉɑlìzãtí߀л" forKey:@"key2"]; 359 | [a encodeObject:NSNull.null forKey:@"key3"]; 360 | [a encodeObject:@{@"key": @"value"} forKey:@"key4"]; 361 | [a encodeObject:@[@"a", @"b", @"c", @(1), @(2), @(3)] forKey:@"key5"]; 362 | [a encodeObject:@{@"key": @(1324.5), @(5) : @[@"a", NSNull.null, [[[Foo alloc] init] autorelease]]} forKey:@"key6"]; 363 | [a finishEncoding]; 364 | 365 | MsgPackUnarchiver * u = [[MsgPackUnarchiver alloc] initForReadingWithData:mdata]; 366 | XCTAssertEqualObjects([u decodeObjectForKey:@"key0"], (@"")); 367 | XCTAssertEqualObjects([u decodeObjectForKey:@"key1"], (@"striéng")); 368 | XCTAssertEqualObjects([u decodeObjectForKey:@"key2"], (@"Iлtêrԉãtioԉɑlìzãtí߀л")); 369 | XCTAssertEqualObjects([u decodeObjectForKey:@"key3"], (NSNull.null)); 370 | XCTAssertEqualObjects([u decodeObjectForKey:@"key4"], (@{@"key": @"value"})); 371 | XCTAssertEqualObjects([u decodeObjectForKey:@"key5"], (@[@"a", @"b", @"c", @(1), @(2), @(3)])); 372 | XCTAssertEqualObjects([u decodeObjectForKey:@"key6"], (@{@"key": @(1324.5), @(5) : @[@"a", NSNull.null, [[[Foo alloc] init] autorelease]]})); 373 | } 374 | 375 | 376 | 377 | 378 | 379 | - (void)_testRoot:(id)oldRoot 380 | { 381 | NSData * data = [MsgPackArchiver archivedDataWithRootObject:oldRoot]; 382 | XCTAssertNotNil(data); 383 | 384 | id newRoot = [MsgPackUnarchiver unarchiveObjectWithData:data]; 385 | XCTAssertNotNil(newRoot); 386 | 387 | [self assertDeepCompare:oldRoot to:newRoot]; 388 | } 389 | 390 | 391 | 392 | - (void)assertDeepCompare:(id)rootA to:(id)rootB 393 | { 394 | // As long as each custom class we're testing properly implements -isEqual: and -hash, then this will do a full deep comparison 395 | // Note that we're assuming for custom classes in this testing rig, the keys encoded and decoded are also compared in -isEqual: 396 | // so that we're fairly testing whether the decoded value is equal to the value that was encoded. 397 | XCTAssert([rootA isEqual:rootB]); 398 | } 399 | 400 | 401 | 402 | 403 | 404 | 405 | #pragma mark - 406 | #pragma mark Performance Test 407 | 408 | - (void)testArchivingPerformanceNSCoder 409 | { 410 | __block NSUInteger length = 0; 411 | 412 | [self measureBlock:^{ 413 | NSMutableData * data = [NSMutableData data]; 414 | NSKeyedArchiver * archiver = [[[NSKeyedArchiver alloc] initForWritingWithMutableData:data] autorelease]; 415 | [self archiveWithCoder:archiver]; 416 | [archiver finishEncoding]; 417 | length = data.length; 418 | }]; 419 | 420 | NSLog(@"NSCoder length: %lu", length); 421 | } 422 | 423 | 424 | - (void)testArchivingPerformanceMsgPack 425 | { 426 | __block NSUInteger length = 0; 427 | 428 | [self measureBlock:^{ 429 | NSMutableData * data = [NSMutableData data]; 430 | MsgPackArchiver * archiver = [[[MsgPackArchiver alloc] initForWritingWithMutableData:data] autorelease]; 431 | [self archiveWithCoder:archiver]; 432 | [archiver finishEncoding]; 433 | length = data.length; 434 | }]; 435 | 436 | NSLog(@"MsgPack length: %lu", length); 437 | } 438 | 439 | 440 | 441 | - (void)archiveWithCoder:(NSCoder *)coder 442 | { 443 | NSMutableDictionary * dict = [NSMutableDictionary dictionary]; 444 | NSMutableArray * intArray = [NSMutableArray array]; 445 | NSMutableArray * strArray = [NSMutableArray array]; 446 | NSMutableData * data = [NSMutableData data]; 447 | 448 | for (int i = 0; i < 100000; i++) { 449 | NSString * s = [NSString stringWithFormat:@"string %d string %d string %d string %d string %d", rand(), rand(), rand(), rand(), rand()]; 450 | [coder encodeInt:i forKey:[NSString stringWithFormat:@"int_%d", i]]; 451 | [coder encodeObject:s forKey:[NSString stringWithFormat:@"string_%d", i]]; 452 | [coder encodeBool:(i % 2 == 0) forKey:[NSString stringWithFormat:@"bool_%d", i]]; 453 | [intArray addObject:@(i)]; 454 | [strArray addObject:s]; 455 | [dict setObject:[@[@(i), s] objectAtIndex:i % 2] forKey:[NSString stringWithFormat:@"key_%d", i]]; 456 | [data appendBytes:(const void *)&i length:sizeof(int)]; 457 | } 458 | 459 | [coder encodeObject:intArray forKey:@"intArray"]; 460 | [coder encodeObject:strArray forKey:@"strArray"]; 461 | [coder encodeBytes:data.bytes length:data.length forKey:@"bytes"]; 462 | [coder encodeObject:data forKey:@"data"]; 463 | [coder encodeObject:dict forKey:@"dictionary"]; 464 | } 465 | 466 | 467 | 468 | 469 | 470 | - (void)testUnarchivingPerformanceNSCoder 471 | { 472 | NSMutableData * data = [NSMutableData data]; 473 | NSKeyedArchiver * archiver = [[[NSKeyedArchiver alloc] initForWritingWithMutableData:data] autorelease]; 474 | [self archiveWithCoder:archiver]; 475 | [archiver finishEncoding]; 476 | 477 | 478 | [self measureBlock:^{ 479 | NSKeyedUnarchiver * unarchiver = [[[NSKeyedUnarchiver alloc] initForReadingWithData:data] autorelease]; 480 | [self unarchiveWithCoder:unarchiver]; 481 | }]; 482 | } 483 | 484 | 485 | - (void)testUnarchivingPerformanceMsgPack 486 | { 487 | NSMutableData * data = [NSMutableData data]; 488 | MsgPackArchiver * archiver = [[[MsgPackArchiver alloc] initForWritingWithMutableData:data] autorelease]; 489 | [self archiveWithCoder:archiver]; 490 | [archiver finishEncoding]; 491 | 492 | 493 | [self measureBlock:^{ 494 | MsgPackUnarchiver * unarchiver = [[[MsgPackUnarchiver alloc] initForReadingWithData:data] autorelease]; 495 | [self unarchiveWithCoder:unarchiver]; 496 | }]; 497 | } 498 | 499 | 500 | 501 | - (void)unarchiveWithCoder:(NSCoder *)coder 502 | { 503 | for (int i = 0; i < 1000; i++) { 504 | [coder decodeIntForKey:[NSString stringWithFormat:@"int_%d", i]]; 505 | [coder decodeObjectForKey:[NSString stringWithFormat:@"string_%d", i]]; 506 | [coder decodeBoolForKey:[NSString stringWithFormat:@"bool_%d", i]]; 507 | } 508 | 509 | 510 | [coder decodeObjectForKey:@"intArray"]; 511 | [coder decodeObjectForKey:@"strArray"]; 512 | [coder decodeBytesForKey:@"bytes" returnedLength:NULL]; 513 | [coder decodeObjectForKey:@"data"]; 514 | [coder decodeObjectForKey:@"dictionary"]; 515 | } 516 | 517 | 518 | 519 | @end 520 | 521 | 522 | 523 | 524 | 525 | 526 | 527 | #pragma mark - 528 | 529 | @implementation Foo 530 | 531 | - (id)init 532 | { 533 | if ((self = [super init])) { 534 | self.empty = nil; 535 | self.null = NSNull.null; 536 | self.string = @"Iлtêrԉãtioԉɑlìzãtí߀л"; 537 | self.number = @(53.9); 538 | self.dictionary = @{@"this" : @"is boring"}; 539 | } 540 | 541 | return self; 542 | } 543 | 544 | 545 | - (id)initWithCoder:(NSCoder *)coder 546 | { 547 | if ((self = [super init])) { 548 | self.empty = [coder decodeObjectForKey:@"empty"]; 549 | self.null = [coder decodeObjectForKey:@"null"]; 550 | self.string = [coder decodeObjectForKey:@"string"]; 551 | self.number = [coder decodeObjectForKey:@"number"]; 552 | self.dictionary = [coder decodeObjectForKey:@"dictionary"]; 553 | } 554 | 555 | return self; 556 | } 557 | 558 | 559 | - (void)encodeWithCoder:(NSCoder *)coder 560 | { 561 | [coder encodeObject:self.empty forKey:@"empty"]; 562 | [coder encodeObject:self.null forKey:@"null"]; 563 | [coder encodeObject:self.string forKey:@"string"]; 564 | [coder encodeObject:self.number forKey:@"number"]; 565 | [coder encodeObject:self.dictionary forKey:@"dictionary"]; 566 | } 567 | 568 | - (NSUInteger)hash 569 | { 570 | // We don't care about performance. 571 | return 0; 572 | } 573 | 574 | 575 | - (BOOL)isEqual:(id)obj 576 | { 577 | if (![obj isKindOfClass:[Foo class]]) { 578 | return NO; 579 | } 580 | 581 | return YES; 582 | } 583 | 584 | @end 585 | 586 | -------------------------------------------------------------------------------- /MessagePackCoder/cmp.c: -------------------------------------------------------------------------------- 1 | // cmp.c 2 | // CMP is a C implementation of the MessagePack serialization format. 3 | // It currently implements version 5 of the MessagePack Spec. 4 | // https://github.com/camgunz/cmp 5 | // MIT License 6 | 7 | #include 8 | #include 9 | #include 10 | 11 | #include "cmp.h" 12 | 13 | static const uint32_t version = 10; 14 | static const uint32_t mp_version = 5; 15 | 16 | enum { 17 | POSITIVE_FIXNUM_MARKER = 0x00, 18 | FIXMAP_MARKER = 0x80, 19 | FIXARRAY_MARKER = 0x90, 20 | FIXSTR_MARKER = 0xA0, 21 | NIL_MARKER = 0xC0, 22 | FALSE_MARKER = 0xC2, 23 | TRUE_MARKER = 0xC3, 24 | BIN8_MARKER = 0xC4, 25 | BIN16_MARKER = 0xC5, 26 | BIN32_MARKER = 0xC6, 27 | EXT8_MARKER = 0xC7, 28 | EXT16_MARKER = 0xC8, 29 | EXT32_MARKER = 0xC9, 30 | FLOAT_MARKER = 0xCA, 31 | DOUBLE_MARKER = 0xCB, 32 | U8_MARKER = 0xCC, 33 | U16_MARKER = 0xCD, 34 | U32_MARKER = 0xCE, 35 | U64_MARKER = 0xCF, 36 | S8_MARKER = 0xD0, 37 | S16_MARKER = 0xD1, 38 | S32_MARKER = 0xD2, 39 | S64_MARKER = 0xD3, 40 | FIXEXT1_MARKER = 0xD4, 41 | FIXEXT2_MARKER = 0xD5, 42 | FIXEXT4_MARKER = 0xD6, 43 | FIXEXT8_MARKER = 0xD7, 44 | FIXEXT16_MARKER = 0xD8, 45 | STR8_MARKER = 0xD9, 46 | STR16_MARKER = 0xDA, 47 | STR32_MARKER = 0xDB, 48 | ARRAY16_MARKER = 0xDC, 49 | ARRAY32_MARKER = 0xDD, 50 | MAP16_MARKER = 0xDE, 51 | MAP32_MARKER = 0xDF, 52 | NEGATIVE_FIXNUM_MARKER = 0xE0 53 | }; 54 | 55 | enum { 56 | FIXARRAY_SIZE = 0xF, 57 | FIXMAP_SIZE = 0xF, 58 | FIXSTR_SIZE = 0x1F 59 | }; 60 | 61 | enum { 62 | ERROR_NONE, 63 | STR_DATA_LENGTH_TOO_LONG_ERROR, 64 | BIN_DATA_LENGTH_TOO_LONG_ERROR, 65 | ARRAY_LENGTH_TOO_LONG_ERROR, 66 | MAP_LENGTH_TOO_LONG_ERROR, 67 | INPUT_VALUE_TOO_LARGE_ERROR, 68 | FIXED_VALUE_WRITING_ERROR, 69 | TYPE_MARKER_READING_ERROR, 70 | TYPE_MARKER_WRITING_ERROR, 71 | DATA_READING_ERROR, 72 | DATA_WRITING_ERROR, 73 | EXT_TYPE_READING_ERROR, 74 | EXT_TYPE_WRITING_ERROR, 75 | INVALID_TYPE_ERROR, 76 | LENGTH_READING_ERROR, 77 | LENGTH_WRITING_ERROR, 78 | ERROR_MAX 79 | }; 80 | 81 | const char *cmp_error_messages[ERROR_MAX + 1] = { 82 | "No Error", 83 | "Specified string data length is too long (> 0xFFFFFFFF)", 84 | "Specified binary data length is too long (> 0xFFFFFFFF)", 85 | "Specified array length is too long (> 0xFFFFFFFF)", 86 | "Specified map length is too long (> 0xFFFFFFFF)", 87 | "Input value is too large", 88 | "Error writing fixed value", 89 | "Error reading type marker", 90 | "Error writing type marker", 91 | "Error reading packed data", 92 | "Error writing packed data", 93 | "Error reading ext type", 94 | "Error writing ext type", 95 | "Invalid type", 96 | "Error reading size", 97 | "Error writing size", 98 | "Max Error" 99 | }; 100 | 101 | static const int32_t _i = 1; 102 | #define is_bigendian() ((*(char *)&_i) == 0) 103 | 104 | static uint16_t be16(uint16_t x) { 105 | char *b = (char *)&x; 106 | 107 | if (!is_bigendian()) { 108 | char swap = 0; 109 | 110 | swap = b[0]; 111 | b[0] = b[1]; 112 | b[1] = swap; 113 | } 114 | 115 | return x; 116 | } 117 | 118 | static uint32_t be32(uint32_t x) { 119 | char *b = (char *)&x; 120 | 121 | if (!is_bigendian()) { 122 | char swap = 0; 123 | 124 | swap = b[0]; 125 | b[0] = b[3]; 126 | b[3] = swap; 127 | 128 | swap = b[1]; 129 | b[1] = b[2]; 130 | b[2] = swap; 131 | } 132 | 133 | return x; 134 | } 135 | 136 | static uint64_t be64(uint64_t x) { 137 | char *b = (char *)&x; 138 | 139 | if (!is_bigendian()) { 140 | char swap = 0; 141 | 142 | swap = b[0]; 143 | b[0] = b[7]; 144 | b[7] = swap; 145 | 146 | swap = b[1]; 147 | b[1] = b[6]; 148 | b[6] = swap; 149 | 150 | swap = b[2]; 151 | b[2] = b[5]; 152 | b[5] = swap; 153 | 154 | swap = b[3]; 155 | b[3] = b[4]; 156 | b[4] = swap; 157 | } 158 | 159 | return x; 160 | } 161 | 162 | static float befloat(float x) { 163 | char *b = (char *)&x; 164 | 165 | if (!is_bigendian()) { 166 | char swap = 0; 167 | 168 | swap = b[0]; 169 | b[0] = b[3]; 170 | b[3] = swap; 171 | 172 | swap = b[1]; 173 | b[1] = b[2]; 174 | b[2] = swap; 175 | } 176 | 177 | return x; 178 | } 179 | 180 | static double bedouble(double x) { 181 | char *b = (char *)&x; 182 | 183 | if (!is_bigendian()) { 184 | char swap = 0; 185 | 186 | swap = b[0]; 187 | b[0] = b[7]; 188 | b[7] = swap; 189 | 190 | swap = b[1]; 191 | b[1] = b[6]; 192 | b[6] = swap; 193 | 194 | swap = b[2]; 195 | b[2] = b[5]; 196 | b[5] = swap; 197 | 198 | swap = b[3]; 199 | b[3] = b[4]; 200 | b[4] = swap; 201 | } 202 | 203 | return x; 204 | } 205 | 206 | static bool read_byte(cmp_ctx_t *ctx, uint8_t *x) { 207 | return ctx->read(ctx, x, sizeof(uint8_t)); 208 | } 209 | 210 | static bool write_byte(cmp_ctx_t *ctx, uint8_t x) { 211 | return (ctx->write(ctx, &x, sizeof(uint8_t)) == (sizeof(uint8_t))); 212 | } 213 | 214 | static bool read_type_marker(cmp_ctx_t *ctx, uint8_t *marker) { 215 | if (read_byte(ctx, marker)) 216 | return true; 217 | 218 | ctx->error = TYPE_MARKER_READING_ERROR; 219 | return false; 220 | } 221 | 222 | static bool write_type_marker(cmp_ctx_t *ctx, uint8_t marker) { 223 | if (write_byte(ctx, marker)) 224 | return true; 225 | 226 | ctx->error = TYPE_MARKER_WRITING_ERROR; 227 | return false; 228 | } 229 | 230 | static bool write_fixed_value(cmp_ctx_t *ctx, uint8_t value) { 231 | if (write_byte(ctx, value)) 232 | return true; 233 | 234 | ctx->error = FIXED_VALUE_WRITING_ERROR; 235 | return false; 236 | } 237 | 238 | void cmp_init(cmp_ctx_t *ctx, void *buf, cmp_reader read, cmp_writer write) { 239 | ctx->error = ERROR_NONE; 240 | ctx->buf = buf; 241 | ctx->read = read; 242 | ctx->write = write; 243 | } 244 | 245 | uint32_t cmp_version(void) { 246 | return version; 247 | } 248 | 249 | uint32_t cmp_mp_version(void) { 250 | return mp_version; 251 | } 252 | 253 | const char* cmp_strerror(cmp_ctx_t *ctx) { 254 | if (ctx->error > ERROR_NONE && ctx->error < ERROR_MAX) 255 | return cmp_error_messages[ctx->error]; 256 | 257 | return ""; 258 | } 259 | 260 | bool cmp_write_pfix(cmp_ctx_t *ctx, uint8_t c) { 261 | if (c <= 0x7F) 262 | return write_fixed_value(ctx, c); 263 | 264 | ctx->error = INPUT_VALUE_TOO_LARGE_ERROR; 265 | return false; 266 | } 267 | 268 | bool cmp_write_nfix(cmp_ctx_t *ctx, int8_t c) { 269 | if (c >= -32 && c <= -1) 270 | return write_fixed_value(ctx, c); 271 | 272 | ctx->error = INPUT_VALUE_TOO_LARGE_ERROR; 273 | return false; 274 | } 275 | 276 | bool cmp_write_sfix(cmp_ctx_t *ctx, int8_t c) { 277 | if (c >= 0) 278 | return cmp_write_pfix(ctx, c); 279 | if (c >= -32 && c <= -1) 280 | return cmp_write_nfix(ctx, c); 281 | 282 | ctx->error = INPUT_VALUE_TOO_LARGE_ERROR; 283 | return false; 284 | } 285 | 286 | bool cmp_write_s8(cmp_ctx_t *ctx, int8_t c) { 287 | if (!write_type_marker(ctx, S8_MARKER)) 288 | return false; 289 | 290 | return ctx->write(ctx, &c, sizeof(int8_t)); 291 | } 292 | 293 | bool cmp_write_s16(cmp_ctx_t *ctx, int16_t s) { 294 | if (!write_type_marker(ctx, S16_MARKER)) 295 | return false; 296 | 297 | s = be16(s); 298 | 299 | return ctx->write(ctx, &s, sizeof(int16_t)); 300 | } 301 | 302 | bool cmp_write_s32(cmp_ctx_t *ctx, int32_t i) { 303 | if (!write_type_marker(ctx, S32_MARKER)) 304 | return false; 305 | 306 | i = be32(i); 307 | 308 | return ctx->write(ctx, &i, sizeof(int32_t)); 309 | } 310 | 311 | bool cmp_write_s64(cmp_ctx_t *ctx, int64_t l) { 312 | if (!write_type_marker(ctx, S64_MARKER)) 313 | return false; 314 | 315 | l = be64(l); 316 | 317 | return ctx->write(ctx, &l, sizeof(int64_t)); 318 | } 319 | 320 | bool cmp_write_sint(cmp_ctx_t *ctx, int64_t d) { 321 | if (d >= 0) 322 | return cmp_write_uint(ctx, d); 323 | if (d >= -32) 324 | return cmp_write_nfix(ctx, d); 325 | if (d >= -128) 326 | return cmp_write_s8(ctx, d); 327 | if (d >= -32768) 328 | return cmp_write_s16(ctx, d); 329 | if (d >= (-2147483647 - 1)) 330 | return cmp_write_s32(ctx, (int32_t)d); 331 | 332 | return cmp_write_s64(ctx, d); 333 | } 334 | 335 | bool cmp_write_ufix(cmp_ctx_t *ctx, uint8_t c) { 336 | return cmp_write_pfix(ctx, c); 337 | } 338 | 339 | bool cmp_write_u8(cmp_ctx_t *ctx, uint8_t c) { 340 | if (!write_type_marker(ctx, U8_MARKER)) 341 | return false; 342 | 343 | return ctx->write(ctx, &c, sizeof(uint8_t)); 344 | } 345 | 346 | bool cmp_write_u16(cmp_ctx_t *ctx, uint16_t s) { 347 | if (!write_type_marker(ctx, U16_MARKER)) 348 | return false; 349 | 350 | s = be16(s); 351 | 352 | return ctx->write(ctx, &s, sizeof(uint16_t)); 353 | } 354 | 355 | bool cmp_write_u32(cmp_ctx_t *ctx, uint32_t i) { 356 | if (!write_type_marker(ctx, U32_MARKER)) 357 | return false; 358 | 359 | i = be32(i); 360 | 361 | return ctx->write(ctx, &i, sizeof(uint32_t)); 362 | } 363 | 364 | bool cmp_write_u64(cmp_ctx_t *ctx, uint64_t l) { 365 | if (!write_type_marker(ctx, U64_MARKER)) 366 | return false; 367 | 368 | l = be64(l); 369 | 370 | return ctx->write(ctx, &l, sizeof(uint64_t)); 371 | } 372 | 373 | bool cmp_write_uint(cmp_ctx_t *ctx, uint64_t u) { 374 | if (u <= 0x7F) 375 | return cmp_write_pfix(ctx, u); 376 | if (u <= 0xFF) 377 | return cmp_write_u8(ctx, u); 378 | if (u <= 0xFFFF) 379 | return cmp_write_u16(ctx, u); 380 | if (u <= 0xFFFFFFFF) 381 | return cmp_write_u32(ctx, (uint32_t)u); 382 | 383 | return cmp_write_u64(ctx, u); 384 | } 385 | 386 | bool cmp_write_float(cmp_ctx_t *ctx, float f) { 387 | if (!write_type_marker(ctx, FLOAT_MARKER)) 388 | return false; 389 | 390 | f = befloat(f); 391 | 392 | return ctx->write(ctx, &f, sizeof(float)); 393 | } 394 | 395 | bool cmp_write_double(cmp_ctx_t *ctx, double d) { 396 | if (!write_type_marker(ctx, DOUBLE_MARKER)) 397 | return false; 398 | 399 | d = bedouble(d); 400 | 401 | return ctx->write(ctx, &d, sizeof(double)); 402 | } 403 | 404 | bool cmp_write_nil(cmp_ctx_t *ctx) { 405 | return write_type_marker(ctx, NIL_MARKER); 406 | } 407 | 408 | bool cmp_write_true(cmp_ctx_t *ctx) { 409 | return write_type_marker(ctx, TRUE_MARKER); 410 | } 411 | 412 | bool cmp_write_false(cmp_ctx_t *ctx) { 413 | return write_type_marker(ctx, FALSE_MARKER); 414 | } 415 | 416 | bool cmp_write_bool(cmp_ctx_t *ctx, bool b) { 417 | if (b) 418 | return cmp_write_true(ctx); 419 | 420 | return cmp_write_false(ctx); 421 | } 422 | 423 | bool cmp_write_u8_as_bool(cmp_ctx_t *ctx, uint8_t b) { 424 | if (b) 425 | return cmp_write_true(ctx); 426 | 427 | return cmp_write_false(ctx); 428 | } 429 | 430 | bool cmp_write_fixstr_marker(cmp_ctx_t *ctx, uint8_t size) { 431 | if (size <= FIXSTR_SIZE) 432 | return write_fixed_value(ctx, FIXSTR_MARKER | size); 433 | 434 | ctx->error = INPUT_VALUE_TOO_LARGE_ERROR; 435 | return false; 436 | } 437 | 438 | bool cmp_write_fixstr(cmp_ctx_t *ctx, const char *data, uint8_t size) { 439 | if (!cmp_write_fixstr_marker(ctx, size)) 440 | return false; 441 | 442 | if (size == 0) 443 | return true; 444 | 445 | if (ctx->write(ctx, data, size)) 446 | return true; 447 | 448 | ctx->error = DATA_WRITING_ERROR; 449 | return false; 450 | } 451 | 452 | bool cmp_write_str8_marker(cmp_ctx_t *ctx, uint8_t size) { 453 | if (!write_type_marker(ctx, STR8_MARKER)) 454 | return false; 455 | 456 | if (ctx->write(ctx, &size, sizeof(uint8_t))) 457 | return true; 458 | 459 | ctx->error = LENGTH_WRITING_ERROR; 460 | return false; 461 | } 462 | 463 | bool cmp_write_str8(cmp_ctx_t *ctx, const char *data, uint8_t size) { 464 | if (!cmp_write_str8_marker(ctx, size)) 465 | return false; 466 | 467 | if (size == 0) 468 | return true; 469 | 470 | if (ctx->write(ctx, data, size)) 471 | return true; 472 | 473 | ctx->error = DATA_WRITING_ERROR; 474 | return false; 475 | } 476 | 477 | bool cmp_write_str16_marker(cmp_ctx_t *ctx, uint16_t size) { 478 | if (!write_type_marker(ctx, STR16_MARKER)) 479 | return false; 480 | 481 | size = be16(size); 482 | 483 | if (ctx->write(ctx, &size, sizeof(uint16_t))) 484 | return true; 485 | 486 | ctx->error = LENGTH_WRITING_ERROR; 487 | return false; 488 | } 489 | 490 | bool cmp_write_str16(cmp_ctx_t *ctx, const char *data, uint16_t size) { 491 | if (!cmp_write_str16_marker(ctx, size)) 492 | return false; 493 | 494 | if (size == 0) 495 | return true; 496 | 497 | if (ctx->write(ctx, data, size)) 498 | return true; 499 | 500 | ctx->error = DATA_WRITING_ERROR; 501 | return false; 502 | } 503 | 504 | bool cmp_write_str32_marker(cmp_ctx_t *ctx, uint32_t size) { 505 | if (!write_type_marker(ctx, STR32_MARKER)) 506 | return false; 507 | 508 | size = be32(size); 509 | 510 | if (ctx->write(ctx, &size, sizeof(uint32_t))) 511 | return true; 512 | 513 | ctx->error = LENGTH_WRITING_ERROR; 514 | return false; 515 | } 516 | 517 | bool cmp_write_str32(cmp_ctx_t *ctx, const char *data, uint32_t size) { 518 | if (!cmp_write_str32_marker(ctx, size)) 519 | return false; 520 | 521 | if (size == 0) 522 | return true; 523 | 524 | if (ctx->write(ctx, data, size)) 525 | return true; 526 | 527 | ctx->error = DATA_WRITING_ERROR; 528 | return false; 529 | } 530 | 531 | bool cmp_write_str_marker(cmp_ctx_t *ctx, uint32_t size) { 532 | if (size <= FIXSTR_SIZE) 533 | return cmp_write_fixstr_marker(ctx, size); 534 | if (size <= 0xFF) 535 | return cmp_write_str8_marker(ctx, size); 536 | if (size <= 0xFFFF) 537 | return cmp_write_str16_marker(ctx, size); 538 | 539 | return cmp_write_str32_marker(ctx, size); 540 | } 541 | 542 | bool cmp_write_str(cmp_ctx_t *ctx, const char *data, uint32_t size) { 543 | if (size <= FIXSTR_SIZE) 544 | return cmp_write_fixstr(ctx, data, size); 545 | if (size <= 0xFF) 546 | return cmp_write_str8(ctx, data, size); 547 | if (size <= 0xFFFF) 548 | return cmp_write_str16(ctx, data, size); 549 | 550 | return cmp_write_str32(ctx, data, size); 551 | } 552 | 553 | bool cmp_write_bin8_marker(cmp_ctx_t *ctx, uint8_t size) { 554 | if (!write_type_marker(ctx, BIN8_MARKER)) 555 | return false; 556 | 557 | if (ctx->write(ctx, &size, sizeof(uint8_t))) 558 | return true; 559 | 560 | ctx->error = LENGTH_WRITING_ERROR; 561 | return false; 562 | } 563 | 564 | bool cmp_write_bin8(cmp_ctx_t *ctx, const void *data, uint8_t size) { 565 | if (!cmp_write_bin8_marker(ctx, size)) 566 | return false; 567 | 568 | if (size == 0) 569 | return true; 570 | 571 | if (ctx->write(ctx, data, size)) 572 | return true; 573 | 574 | ctx->error = DATA_WRITING_ERROR; 575 | return false; 576 | } 577 | 578 | bool cmp_write_bin16_marker(cmp_ctx_t *ctx, uint16_t size) { 579 | if (!write_type_marker(ctx, BIN16_MARKER)) 580 | return false; 581 | 582 | size = be16(size); 583 | 584 | if (ctx->write(ctx, &size, sizeof(uint16_t))) 585 | return true; 586 | 587 | ctx->error = LENGTH_WRITING_ERROR; 588 | return false; 589 | } 590 | 591 | bool cmp_write_bin16(cmp_ctx_t *ctx, const void *data, uint16_t size) { 592 | if (!cmp_write_bin16_marker(ctx, size)) 593 | return false; 594 | 595 | if (size == 0) 596 | return true; 597 | 598 | if (ctx->write(ctx, data, size)) 599 | return true; 600 | 601 | ctx->error = DATA_WRITING_ERROR; 602 | return false; 603 | } 604 | 605 | bool cmp_write_bin32_marker(cmp_ctx_t *ctx, uint32_t size) { 606 | if (!write_type_marker(ctx, BIN32_MARKER)) 607 | return false; 608 | 609 | size = be32(size); 610 | 611 | if (ctx->write(ctx, &size, sizeof(uint32_t))) 612 | return true; 613 | 614 | ctx->error = LENGTH_WRITING_ERROR; 615 | return false; 616 | } 617 | 618 | bool cmp_write_bin32(cmp_ctx_t *ctx, const void *data, uint32_t size) { 619 | if (!cmp_write_bin32_marker(ctx, size)) 620 | return false; 621 | 622 | if (size == 0) 623 | return true; 624 | 625 | if (ctx->write(ctx, data, size)) 626 | return true; 627 | 628 | ctx->error = DATA_WRITING_ERROR; 629 | return false; 630 | } 631 | 632 | bool cmp_write_bin_marker(cmp_ctx_t *ctx, uint32_t size) { 633 | if (size <= 0xFF) 634 | return cmp_write_bin8_marker(ctx, size); 635 | if (size <= 0xFFFF) 636 | return cmp_write_bin16_marker(ctx, size); 637 | 638 | return cmp_write_bin32_marker(ctx, size); 639 | } 640 | 641 | bool cmp_write_bin(cmp_ctx_t *ctx, const void *data, uint32_t size) { 642 | if (size <= 0xFF) 643 | return cmp_write_bin8(ctx, data, size); 644 | if (size <= 0xFFFF) 645 | return cmp_write_bin16(ctx, data, size); 646 | 647 | return cmp_write_bin32(ctx, data, size); 648 | } 649 | 650 | bool cmp_write_fixarray(cmp_ctx_t *ctx, uint8_t size) { 651 | if (size <= FIXARRAY_SIZE) 652 | return write_fixed_value(ctx, FIXARRAY_MARKER | size); 653 | 654 | ctx->error = INPUT_VALUE_TOO_LARGE_ERROR; 655 | return false; 656 | } 657 | 658 | bool cmp_write_array16(cmp_ctx_t *ctx, uint16_t size) { 659 | if (!write_type_marker(ctx, ARRAY16_MARKER)) 660 | return false; 661 | 662 | size = be16(size); 663 | 664 | if (ctx->write(ctx, &size, sizeof(uint16_t))) 665 | return true; 666 | 667 | ctx->error = LENGTH_WRITING_ERROR; 668 | return false; 669 | } 670 | 671 | bool cmp_write_array32(cmp_ctx_t *ctx, uint32_t size) { 672 | if (!write_type_marker(ctx, ARRAY32_MARKER)) 673 | return false; 674 | 675 | size = be32(size); 676 | 677 | if (ctx->write(ctx, &size, sizeof(uint32_t))) 678 | return true; 679 | 680 | ctx->error = LENGTH_WRITING_ERROR; 681 | return false; 682 | } 683 | 684 | bool cmp_write_array(cmp_ctx_t *ctx, uint32_t size) { 685 | if (size <= FIXARRAY_SIZE) 686 | return cmp_write_fixarray(ctx, size); 687 | if (size <= 0xFFFF) 688 | return cmp_write_array16(ctx, size); 689 | 690 | return cmp_write_array32(ctx, size); 691 | } 692 | 693 | bool cmp_write_fixmap(cmp_ctx_t *ctx, uint8_t size) { 694 | if (size <= FIXMAP_SIZE) 695 | return write_fixed_value(ctx, FIXMAP_MARKER | size); 696 | 697 | ctx->error = INPUT_VALUE_TOO_LARGE_ERROR; 698 | return false; 699 | } 700 | 701 | bool cmp_write_map16(cmp_ctx_t *ctx, uint16_t size) { 702 | if (!write_type_marker(ctx, MAP16_MARKER)) 703 | return false; 704 | 705 | size = be16(size); 706 | 707 | if (ctx->write(ctx, &size, sizeof(uint16_t))) 708 | return true; 709 | 710 | ctx->error = LENGTH_WRITING_ERROR; 711 | return false; 712 | } 713 | 714 | bool cmp_write_map32(cmp_ctx_t *ctx, uint32_t size) { 715 | if (!write_type_marker(ctx, MAP32_MARKER)) 716 | return false; 717 | 718 | size = be32(size); 719 | 720 | if (ctx->write(ctx, &size, sizeof(uint32_t))) 721 | return true; 722 | 723 | ctx->error = LENGTH_WRITING_ERROR; 724 | return false; 725 | } 726 | 727 | bool cmp_write_map(cmp_ctx_t *ctx, uint32_t size) { 728 | if (size <= FIXMAP_SIZE) 729 | return cmp_write_fixmap(ctx, size); 730 | if (size <= 0xFFFF) 731 | return cmp_write_map16(ctx, size); 732 | 733 | return cmp_write_map32(ctx, size); 734 | } 735 | 736 | bool cmp_write_fixext1_marker(cmp_ctx_t *ctx, int8_t type) { 737 | if (!write_type_marker(ctx, FIXEXT1_MARKER)) 738 | return false; 739 | 740 | if (ctx->write(ctx, &type, sizeof(int8_t))) 741 | return true; 742 | 743 | ctx->error = EXT_TYPE_WRITING_ERROR; 744 | return false; 745 | } 746 | 747 | bool cmp_write_fixext1(cmp_ctx_t *ctx, int8_t type, const void *data) { 748 | if (!cmp_write_fixext1_marker(ctx, type)) 749 | return false; 750 | 751 | if (ctx->write(ctx, data, 1)) 752 | return true; 753 | 754 | ctx->error = DATA_WRITING_ERROR; 755 | return false; 756 | } 757 | 758 | bool cmp_write_fixext2_marker(cmp_ctx_t *ctx, int8_t type) { 759 | if (!write_type_marker(ctx, FIXEXT2_MARKER)) 760 | return false; 761 | 762 | if (ctx->write(ctx, &type, sizeof(int8_t))) 763 | return true; 764 | 765 | ctx->error = EXT_TYPE_WRITING_ERROR; 766 | return false; 767 | } 768 | 769 | bool cmp_write_fixext2(cmp_ctx_t *ctx, int8_t type, const void *data) { 770 | if (!cmp_write_fixext2_marker(ctx, type)) 771 | return false; 772 | 773 | if (ctx->write(ctx, data, 2)) 774 | return true; 775 | 776 | ctx->error = DATA_WRITING_ERROR; 777 | return false; 778 | } 779 | 780 | bool cmp_write_fixext4_marker(cmp_ctx_t *ctx, int8_t type) { 781 | if (!write_type_marker(ctx, FIXEXT4_MARKER)) 782 | return false; 783 | 784 | if (ctx->write(ctx, &type, sizeof(int8_t))) 785 | return true; 786 | 787 | ctx->error = EXT_TYPE_WRITING_ERROR; 788 | return false; 789 | } 790 | 791 | bool cmp_write_fixext4(cmp_ctx_t *ctx, int8_t type, const void *data) { 792 | if (!cmp_write_fixext4_marker(ctx, type)) 793 | return false; 794 | 795 | if (ctx->write(ctx, data, 4)) 796 | return true; 797 | 798 | ctx->error = DATA_WRITING_ERROR; 799 | return false; 800 | } 801 | 802 | bool cmp_write_fixext8_marker(cmp_ctx_t *ctx, int8_t type) { 803 | if (!write_type_marker(ctx, FIXEXT8_MARKER)) 804 | return false; 805 | 806 | if (ctx->write(ctx, &type, sizeof(int8_t))) 807 | return true; 808 | 809 | ctx->error = EXT_TYPE_WRITING_ERROR; 810 | return false; 811 | } 812 | 813 | bool cmp_write_fixext8(cmp_ctx_t *ctx, int8_t type, const void *data) { 814 | if (!cmp_write_fixext8_marker(ctx, type)) 815 | return false; 816 | 817 | if (ctx->write(ctx, data, 8)) 818 | return true; 819 | 820 | ctx->error = DATA_WRITING_ERROR; 821 | return false; 822 | } 823 | 824 | bool cmp_write_fixext16_marker(cmp_ctx_t *ctx, int8_t type) { 825 | if (!write_type_marker(ctx, FIXEXT16_MARKER)) 826 | return false; 827 | 828 | if (ctx->write(ctx, &type, sizeof(int8_t))) 829 | return true; 830 | 831 | ctx->error = EXT_TYPE_WRITING_ERROR; 832 | return false; 833 | } 834 | 835 | bool cmp_write_fixext16(cmp_ctx_t *ctx, int8_t type, const void *data) { 836 | if (!cmp_write_fixext16_marker(ctx, type)) 837 | return false; 838 | 839 | if (ctx->write(ctx, data, 16)) 840 | return true; 841 | 842 | ctx->error = DATA_WRITING_ERROR; 843 | return false; 844 | } 845 | 846 | bool cmp_write_ext8_marker(cmp_ctx_t *ctx, int8_t type, uint8_t size) { 847 | if (!write_type_marker(ctx, EXT8_MARKER)) 848 | return false; 849 | 850 | if (!ctx->write(ctx, &size, sizeof(uint8_t))) { 851 | ctx->error = LENGTH_WRITING_ERROR; 852 | return false; 853 | } 854 | 855 | if (ctx->write(ctx, &type, sizeof(int8_t))) 856 | return true; 857 | 858 | ctx->error = EXT_TYPE_WRITING_ERROR; 859 | return false; 860 | } 861 | 862 | bool cmp_write_ext8(cmp_ctx_t *ctx, int8_t tp, uint8_t sz, const void *data) { 863 | if (!cmp_write_ext8_marker(ctx, tp, sz)) 864 | return false; 865 | 866 | if (ctx->write(ctx, data, sz)) 867 | return true; 868 | 869 | ctx->error = DATA_WRITING_ERROR; 870 | return false; 871 | } 872 | 873 | bool cmp_write_ext16_marker(cmp_ctx_t *ctx, int8_t type, uint16_t size) { 874 | if (!write_type_marker(ctx, EXT16_MARKER)) 875 | return false; 876 | 877 | size = be16(size); 878 | 879 | if (!ctx->write(ctx, &size, sizeof(uint16_t))) { 880 | ctx->error = LENGTH_WRITING_ERROR; 881 | return false; 882 | } 883 | 884 | if (ctx->write(ctx, &type, sizeof(int8_t))) 885 | return true; 886 | 887 | ctx->error = EXT_TYPE_WRITING_ERROR; 888 | return false; 889 | } 890 | 891 | bool cmp_write_ext16(cmp_ctx_t *ctx, int8_t tp, uint16_t sz, const void *data) { 892 | if (!cmp_write_ext16_marker(ctx, tp, sz)) 893 | return false; 894 | 895 | if (ctx->write(ctx, data, sz)) 896 | return true; 897 | 898 | ctx->error = DATA_WRITING_ERROR; 899 | return false; 900 | } 901 | 902 | bool cmp_write_ext32_marker(cmp_ctx_t *ctx, int8_t type, uint32_t size) { 903 | if (!write_type_marker(ctx, EXT32_MARKER)) 904 | return false; 905 | 906 | size = be32(size); 907 | 908 | if (!ctx->write(ctx, &size, sizeof(uint32_t))) { 909 | ctx->error = LENGTH_WRITING_ERROR; 910 | return false; 911 | } 912 | 913 | if (ctx->write(ctx, &type, sizeof(int8_t))) 914 | return true; 915 | 916 | ctx->error = EXT_TYPE_WRITING_ERROR; 917 | return false; 918 | } 919 | 920 | bool cmp_write_ext32(cmp_ctx_t *ctx, int8_t tp, uint32_t sz, const void *data) { 921 | if (!cmp_write_ext32_marker(ctx, tp, sz)) 922 | return false; 923 | 924 | if (ctx->write(ctx, data, sz)) 925 | return true; 926 | 927 | ctx->error = DATA_WRITING_ERROR; 928 | return false; 929 | } 930 | 931 | bool cmp_write_ext_marker(cmp_ctx_t *ctx, int8_t tp, uint32_t sz) { 932 | if (sz == 1) 933 | return cmp_write_fixext1_marker(ctx, tp); 934 | if (sz == 2) 935 | return cmp_write_fixext2_marker(ctx, tp); 936 | if (sz == 4) 937 | return cmp_write_fixext4_marker(ctx, tp); 938 | if (sz == 8) 939 | return cmp_write_fixext8_marker(ctx, tp); 940 | if (sz == 16) 941 | return cmp_write_fixext16_marker(ctx, tp); 942 | if (sz <= 0xFF) 943 | return cmp_write_ext8_marker(ctx, tp, sz); 944 | if (sz <= 0xFFFF) 945 | return cmp_write_ext16_marker(ctx, tp, sz); 946 | 947 | return cmp_write_ext32_marker(ctx, tp, sz); 948 | } 949 | 950 | bool cmp_write_ext(cmp_ctx_t *ctx, int8_t tp, uint32_t sz, const void *data) { 951 | if (sz == 1) 952 | return cmp_write_fixext1(ctx, tp, data); 953 | if (sz == 2) 954 | return cmp_write_fixext2(ctx, tp, data); 955 | if (sz == 4) 956 | return cmp_write_fixext4(ctx, tp, data); 957 | if (sz == 8) 958 | return cmp_write_fixext8(ctx, tp, data); 959 | if (sz == 16) 960 | return cmp_write_fixext16(ctx, tp, data); 961 | if (sz <= 0xFF) 962 | return cmp_write_ext8(ctx, tp, sz, data); 963 | if (sz <= 0xFFFF) 964 | return cmp_write_ext16(ctx, tp, sz, data); 965 | 966 | return cmp_write_ext32(ctx, tp, sz, data); 967 | } 968 | 969 | bool cmp_write_object(cmp_ctx_t *ctx, cmp_object_t *obj) { 970 | switch(obj->type) { 971 | case CMP_TYPE_POSITIVE_FIXNUM: 972 | return cmp_write_pfix(ctx, obj->as.u8); 973 | case CMP_TYPE_FIXMAP: 974 | return cmp_write_fixmap(ctx, obj->as.map_size); 975 | case CMP_TYPE_FIXARRAY: 976 | return cmp_write_fixarray(ctx, obj->as.array_size); 977 | case CMP_TYPE_FIXSTR: 978 | return cmp_write_fixstr_marker(ctx, obj->as.str_size); 979 | case CMP_TYPE_NIL: 980 | return cmp_write_nil(ctx); 981 | case CMP_TYPE_BOOLEAN: 982 | if (obj->as.boolean) 983 | return cmp_write_true(ctx); 984 | return cmp_write_false(ctx); 985 | case CMP_TYPE_BIN8: 986 | return cmp_write_bin8_marker(ctx, obj->as.bin_size); 987 | case CMP_TYPE_BIN16: 988 | return cmp_write_bin16_marker(ctx, obj->as.bin_size); 989 | case CMP_TYPE_BIN32: 990 | return cmp_write_bin32_marker(ctx, obj->as.bin_size); 991 | case CMP_TYPE_EXT8: 992 | return cmp_write_ext8_marker(ctx, obj->as.ext.type, obj->as.ext.size); 993 | case CMP_TYPE_EXT16: 994 | return cmp_write_ext16_marker(ctx, obj->as.ext.type, obj->as.ext.size); 995 | case CMP_TYPE_EXT32: 996 | return cmp_write_ext32_marker(ctx, obj->as.ext.type, obj->as.ext.size); 997 | case CMP_TYPE_FLOAT: 998 | return cmp_write_float(ctx, obj->as.flt); 999 | case CMP_TYPE_DOUBLE: 1000 | return cmp_write_double(ctx, obj->as.dbl); 1001 | case CMP_TYPE_UINT8: 1002 | return cmp_write_u8(ctx, obj->as.u8); 1003 | case CMP_TYPE_UINT16: 1004 | return cmp_write_u16(ctx, obj->as.u16); 1005 | case CMP_TYPE_UINT32: 1006 | return cmp_write_u32(ctx, obj->as.u32); 1007 | case CMP_TYPE_UINT64: 1008 | return cmp_write_u64(ctx, obj->as.u64); 1009 | case CMP_TYPE_SINT8: 1010 | return cmp_write_s8(ctx, obj->as.s8); 1011 | case CMP_TYPE_SINT16: 1012 | return cmp_write_s16(ctx, obj->as.s16); 1013 | case CMP_TYPE_SINT32: 1014 | return cmp_write_s32(ctx, obj->as.s32); 1015 | case CMP_TYPE_SINT64: 1016 | return cmp_write_s64(ctx, obj->as.s64); 1017 | case CMP_TYPE_FIXEXT1: 1018 | return cmp_write_fixext1_marker(ctx, obj->as.ext.type); 1019 | case CMP_TYPE_FIXEXT2: 1020 | return cmp_write_fixext2_marker(ctx, obj->as.ext.type); 1021 | case CMP_TYPE_FIXEXT4: 1022 | return cmp_write_fixext4_marker(ctx, obj->as.ext.type); 1023 | case CMP_TYPE_FIXEXT8: 1024 | return cmp_write_fixext8_marker(ctx, obj->as.ext.type); 1025 | case CMP_TYPE_FIXEXT16: 1026 | return cmp_write_fixext16_marker(ctx, obj->as.ext.type); 1027 | case CMP_TYPE_STR8: 1028 | return cmp_write_str8_marker(ctx, obj->as.str_size); 1029 | case CMP_TYPE_STR16: 1030 | return cmp_write_str16_marker(ctx, obj->as.str_size); 1031 | case CMP_TYPE_STR32: 1032 | return cmp_write_str32_marker(ctx, obj->as.str_size); 1033 | case CMP_TYPE_ARRAY16: 1034 | return cmp_write_array16(ctx, obj->as.array_size); 1035 | case CMP_TYPE_ARRAY32: 1036 | return cmp_write_array32(ctx, obj->as.array_size); 1037 | case CMP_TYPE_MAP16: 1038 | return cmp_write_map16(ctx, obj->as.map_size); 1039 | case CMP_TYPE_MAP32: 1040 | return cmp_write_map32(ctx, obj->as.map_size); 1041 | case CMP_TYPE_NEGATIVE_FIXNUM: 1042 | return cmp_write_nfix(ctx, obj->as.s8); 1043 | default: 1044 | ctx->error = INVALID_TYPE_ERROR; 1045 | return false; 1046 | } 1047 | } 1048 | 1049 | bool cmp_read_pfix(cmp_ctx_t *ctx, uint8_t *c) { 1050 | cmp_object_t obj; 1051 | 1052 | if (!cmp_read_object(ctx, &obj)) 1053 | return false; 1054 | 1055 | if (obj.type != CMP_TYPE_POSITIVE_FIXNUM) { 1056 | ctx->error = INVALID_TYPE_ERROR; 1057 | return false; 1058 | } 1059 | 1060 | *c = obj.as.u8; 1061 | return true; 1062 | } 1063 | 1064 | bool cmp_read_nfix(cmp_ctx_t *ctx, int8_t *c) { 1065 | cmp_object_t obj; 1066 | 1067 | if (!cmp_read_object(ctx, &obj)) 1068 | return false; 1069 | 1070 | if (obj.type != CMP_TYPE_NEGATIVE_FIXNUM) { 1071 | ctx->error = INVALID_TYPE_ERROR; 1072 | return false; 1073 | } 1074 | 1075 | *c = obj.as.s8; 1076 | return true; 1077 | } 1078 | 1079 | bool cmp_read_sfix(cmp_ctx_t *ctx, int8_t *c) { 1080 | cmp_object_t obj; 1081 | 1082 | if (!cmp_read_object(ctx, &obj)) 1083 | return false; 1084 | 1085 | switch (obj.type) { 1086 | case CMP_TYPE_POSITIVE_FIXNUM: 1087 | case CMP_TYPE_NEGATIVE_FIXNUM: 1088 | *c = obj.as.s8; 1089 | return true; 1090 | default: 1091 | ctx->error = INVALID_TYPE_ERROR; 1092 | return false; 1093 | } 1094 | } 1095 | 1096 | bool cmp_read_s8(cmp_ctx_t *ctx, int8_t *c) { 1097 | cmp_object_t obj; 1098 | 1099 | if (!cmp_read_object(ctx, &obj)) 1100 | return false; 1101 | 1102 | if (obj.type != CMP_TYPE_SINT8) { 1103 | ctx->error = INVALID_TYPE_ERROR; 1104 | return false; 1105 | } 1106 | 1107 | *c = obj.as.s8; 1108 | return true; 1109 | } 1110 | 1111 | bool cmp_read_s16(cmp_ctx_t *ctx, int16_t *s) { 1112 | cmp_object_t obj; 1113 | 1114 | if (!cmp_read_object(ctx, &obj)) 1115 | return false; 1116 | 1117 | if (obj.type != CMP_TYPE_SINT16) { 1118 | ctx->error = INVALID_TYPE_ERROR; 1119 | return false; 1120 | } 1121 | 1122 | *s = obj.as.s16; 1123 | return true; 1124 | } 1125 | 1126 | bool cmp_read_s32(cmp_ctx_t *ctx, int32_t *i) { 1127 | cmp_object_t obj; 1128 | 1129 | if (!cmp_read_object(ctx, &obj)) 1130 | return false; 1131 | 1132 | if (obj.type != CMP_TYPE_SINT32) { 1133 | ctx->error = INVALID_TYPE_ERROR; 1134 | return false; 1135 | } 1136 | 1137 | *i = obj.as.s32; 1138 | return true; 1139 | } 1140 | 1141 | bool cmp_read_s64(cmp_ctx_t *ctx, int64_t *l) { 1142 | cmp_object_t obj; 1143 | 1144 | if (!cmp_read_object(ctx, &obj)) 1145 | return false; 1146 | 1147 | if (obj.type != CMP_TYPE_SINT64) { 1148 | ctx->error = INVALID_TYPE_ERROR; 1149 | return false; 1150 | } 1151 | 1152 | *l = obj.as.s64; 1153 | return true; 1154 | } 1155 | 1156 | bool cmp_read_char(cmp_ctx_t *ctx, int8_t *c) { 1157 | cmp_object_t obj; 1158 | 1159 | if (!cmp_read_object(ctx, &obj)) 1160 | return false; 1161 | 1162 | switch (obj.type) { 1163 | case CMP_TYPE_POSITIVE_FIXNUM: 1164 | case CMP_TYPE_NEGATIVE_FIXNUM: 1165 | case CMP_TYPE_SINT8: 1166 | *c = obj.as.s8; 1167 | return true; 1168 | case CMP_TYPE_UINT8: 1169 | if (obj.as.u8 <= 127) { 1170 | *c = obj.as.u8; 1171 | return true; 1172 | } 1173 | default: 1174 | ctx->error = INVALID_TYPE_ERROR; 1175 | return false; 1176 | } 1177 | } 1178 | 1179 | bool cmp_read_short(cmp_ctx_t *ctx, int16_t *s) { 1180 | cmp_object_t obj; 1181 | 1182 | if (!cmp_read_object(ctx, &obj)) 1183 | return false; 1184 | 1185 | switch (obj.type) { 1186 | case CMP_TYPE_POSITIVE_FIXNUM: 1187 | case CMP_TYPE_NEGATIVE_FIXNUM: 1188 | case CMP_TYPE_SINT8: 1189 | *s = obj.as.s8; 1190 | return true; 1191 | case CMP_TYPE_UINT8: 1192 | *s = obj.as.u8; 1193 | return true; 1194 | case CMP_TYPE_SINT16: 1195 | *s = obj.as.s16; 1196 | return true; 1197 | case CMP_TYPE_UINT16: 1198 | if (obj.as.u16 <= 32767) { 1199 | *s = obj.as.u16; 1200 | return true; 1201 | } 1202 | default: 1203 | ctx->error = INVALID_TYPE_ERROR; 1204 | return false; 1205 | } 1206 | } 1207 | 1208 | bool cmp_read_int(cmp_ctx_t *ctx, int32_t *i) { 1209 | cmp_object_t obj; 1210 | 1211 | if (!cmp_read_object(ctx, &obj)) 1212 | return false; 1213 | 1214 | switch (obj.type) { 1215 | case CMP_TYPE_POSITIVE_FIXNUM: 1216 | case CMP_TYPE_NEGATIVE_FIXNUM: 1217 | case CMP_TYPE_SINT8: 1218 | *i = obj.as.s8; 1219 | return true; 1220 | case CMP_TYPE_UINT8: 1221 | *i = obj.as.u8; 1222 | return true; 1223 | case CMP_TYPE_SINT16: 1224 | *i = obj.as.s16; 1225 | return true; 1226 | case CMP_TYPE_UINT16: 1227 | *i = obj.as.u16; 1228 | return true; 1229 | case CMP_TYPE_SINT32: 1230 | *i = obj.as.s32; 1231 | return true; 1232 | case CMP_TYPE_UINT32: 1233 | if (obj.as.u32 <= 2147483647) { 1234 | *i = obj.as.u32; 1235 | return true; 1236 | } 1237 | default: 1238 | ctx->error = INVALID_TYPE_ERROR; 1239 | return false; 1240 | } 1241 | } 1242 | 1243 | bool cmp_read_long(cmp_ctx_t *ctx, int64_t *d) { 1244 | cmp_object_t obj; 1245 | 1246 | if (!cmp_read_object(ctx, &obj)) 1247 | return false; 1248 | 1249 | switch (obj.type) { 1250 | case CMP_TYPE_POSITIVE_FIXNUM: 1251 | case CMP_TYPE_NEGATIVE_FIXNUM: 1252 | case CMP_TYPE_SINT8: 1253 | *d = obj.as.s8; 1254 | return true; 1255 | case CMP_TYPE_UINT8: 1256 | *d = obj.as.u8; 1257 | return true; 1258 | case CMP_TYPE_SINT16: 1259 | *d = obj.as.s16; 1260 | return true; 1261 | case CMP_TYPE_UINT16: 1262 | *d = obj.as.u16; 1263 | return true; 1264 | case CMP_TYPE_SINT32: 1265 | *d = obj.as.s32; 1266 | return true; 1267 | case CMP_TYPE_UINT32: 1268 | *d = obj.as.u32; 1269 | return true; 1270 | case CMP_TYPE_SINT64: 1271 | *d = obj.as.s64; 1272 | return true; 1273 | case CMP_TYPE_UINT64: 1274 | if (obj.as.u64 <= 9223372036854775807) { 1275 | *d = obj.as.u64; 1276 | return true; 1277 | } 1278 | default: 1279 | ctx->error = INVALID_TYPE_ERROR; 1280 | return false; 1281 | } 1282 | } 1283 | 1284 | bool cmp_read_sinteger(cmp_ctx_t *ctx, int64_t *d) { 1285 | return cmp_read_long(ctx, d); 1286 | } 1287 | 1288 | bool cmp_read_ufix(cmp_ctx_t *ctx, uint8_t *c) { 1289 | cmp_object_t obj; 1290 | 1291 | if (!cmp_read_object(ctx, &obj)) 1292 | return false; 1293 | 1294 | if (obj.type != CMP_TYPE_NEGATIVE_FIXNUM) { 1295 | ctx->error = INVALID_TYPE_ERROR; 1296 | return false; 1297 | } 1298 | 1299 | *c = obj.as.u8; 1300 | return true; 1301 | } 1302 | 1303 | bool cmp_read_u8(cmp_ctx_t *ctx, uint8_t *c) { 1304 | cmp_object_t obj; 1305 | 1306 | if (!cmp_read_object(ctx, &obj)) 1307 | return false; 1308 | 1309 | if (obj.type != CMP_TYPE_UINT8) { 1310 | ctx->error = INVALID_TYPE_ERROR; 1311 | return false; 1312 | } 1313 | 1314 | *c = obj.as.u8; 1315 | return true; 1316 | } 1317 | 1318 | bool cmp_read_u16(cmp_ctx_t *ctx, uint16_t *s) { 1319 | cmp_object_t obj; 1320 | 1321 | if (!cmp_read_object(ctx, &obj)) 1322 | return false; 1323 | 1324 | if (obj.type != CMP_TYPE_UINT16) { 1325 | ctx->error = INVALID_TYPE_ERROR; 1326 | return false; 1327 | } 1328 | 1329 | *s = obj.as.u16; 1330 | return true; 1331 | } 1332 | 1333 | bool cmp_read_u32(cmp_ctx_t *ctx, uint32_t *i) { 1334 | cmp_object_t obj; 1335 | 1336 | if (!cmp_read_object(ctx, &obj)) 1337 | return false; 1338 | 1339 | if (obj.type != CMP_TYPE_UINT32) { 1340 | ctx->error = INVALID_TYPE_ERROR; 1341 | return false; 1342 | } 1343 | 1344 | *i = obj.as.u32; 1345 | return true; 1346 | } 1347 | 1348 | bool cmp_read_u64(cmp_ctx_t *ctx, uint64_t *l) { 1349 | cmp_object_t obj; 1350 | 1351 | if (!cmp_read_object(ctx, &obj)) 1352 | return false; 1353 | 1354 | if (obj.type != CMP_TYPE_UINT64) { 1355 | ctx->error = INVALID_TYPE_ERROR; 1356 | return false; 1357 | } 1358 | 1359 | *l = obj.as.u64; 1360 | return true; 1361 | } 1362 | 1363 | bool cmp_read_uchar(cmp_ctx_t *ctx, uint8_t *c) { 1364 | cmp_object_t obj; 1365 | 1366 | if (!cmp_read_object(ctx, &obj)) 1367 | return false; 1368 | 1369 | switch (obj.type) { 1370 | case CMP_TYPE_POSITIVE_FIXNUM: 1371 | case CMP_TYPE_UINT8: 1372 | *c = obj.as.u8; 1373 | return true; 1374 | default: 1375 | ctx->error = INVALID_TYPE_ERROR; 1376 | return false; 1377 | } 1378 | } 1379 | 1380 | bool cmp_read_ushort(cmp_ctx_t *ctx, uint16_t *s) { 1381 | cmp_object_t obj; 1382 | 1383 | if (!cmp_read_object(ctx, &obj)) 1384 | return false; 1385 | 1386 | switch (obj.type) { 1387 | case CMP_TYPE_POSITIVE_FIXNUM: 1388 | case CMP_TYPE_UINT8: 1389 | *s = obj.as.u8; 1390 | return true; 1391 | case CMP_TYPE_UINT16: 1392 | *s = obj.as.u16; 1393 | return true; 1394 | default: 1395 | ctx->error = INVALID_TYPE_ERROR; 1396 | return false; 1397 | } 1398 | } 1399 | 1400 | bool cmp_read_uint(cmp_ctx_t *ctx, uint32_t *i) { 1401 | cmp_object_t obj; 1402 | 1403 | if (!cmp_read_object(ctx, &obj)) 1404 | return false; 1405 | 1406 | switch (obj.type) { 1407 | case CMP_TYPE_POSITIVE_FIXNUM: 1408 | case CMP_TYPE_UINT8: 1409 | *i = obj.as.u8; 1410 | return true; 1411 | case CMP_TYPE_UINT16: 1412 | *i = obj.as.u16; 1413 | return true; 1414 | case CMP_TYPE_UINT32: 1415 | *i = obj.as.u32; 1416 | return true; 1417 | default: 1418 | ctx->error = INVALID_TYPE_ERROR; 1419 | return false; 1420 | } 1421 | } 1422 | 1423 | bool cmp_read_ulong(cmp_ctx_t *ctx, uint64_t *u) { 1424 | cmp_object_t obj; 1425 | 1426 | if (!cmp_read_object(ctx, &obj)) 1427 | return false; 1428 | 1429 | switch (obj.type) { 1430 | case CMP_TYPE_POSITIVE_FIXNUM: 1431 | case CMP_TYPE_UINT8: 1432 | *u = obj.as.u8; 1433 | return true; 1434 | case CMP_TYPE_UINT16: 1435 | *u = obj.as.u16; 1436 | return true; 1437 | case CMP_TYPE_UINT32: 1438 | *u = obj.as.u32; 1439 | return true; 1440 | case CMP_TYPE_UINT64: 1441 | *u = obj.as.u64; 1442 | return true; 1443 | default: 1444 | ctx->error = INVALID_TYPE_ERROR; 1445 | return false; 1446 | } 1447 | } 1448 | 1449 | bool cmp_read_uinteger(cmp_ctx_t *ctx, uint64_t *d) { 1450 | return cmp_read_ulong(ctx, d); 1451 | } 1452 | 1453 | bool cmp_read_float(cmp_ctx_t *ctx, float *f) { 1454 | cmp_object_t obj; 1455 | 1456 | if (!cmp_read_object(ctx, &obj)) 1457 | return false; 1458 | 1459 | if (obj.type != CMP_TYPE_FLOAT) { 1460 | ctx->error = INVALID_TYPE_ERROR; 1461 | return false; 1462 | } 1463 | 1464 | *f = obj.as.flt; 1465 | 1466 | return true; 1467 | } 1468 | 1469 | bool cmp_read_double(cmp_ctx_t *ctx, double *d) { 1470 | cmp_object_t obj; 1471 | 1472 | if (!cmp_read_object(ctx, &obj)) 1473 | return false; 1474 | 1475 | if (obj.type != CMP_TYPE_DOUBLE) { 1476 | ctx->error = INVALID_TYPE_ERROR; 1477 | return false; 1478 | } 1479 | 1480 | *d = obj.as.dbl; 1481 | 1482 | return true; 1483 | } 1484 | 1485 | bool cmp_read_nil(cmp_ctx_t *ctx) { 1486 | cmp_object_t obj; 1487 | 1488 | if (!cmp_read_object(ctx, &obj)) 1489 | return false; 1490 | 1491 | if (obj.type == CMP_TYPE_NIL) 1492 | return true; 1493 | 1494 | ctx->error = INVALID_TYPE_ERROR; 1495 | return false; 1496 | } 1497 | 1498 | bool cmp_read_bool(cmp_ctx_t *ctx, bool *b) { 1499 | cmp_object_t obj; 1500 | 1501 | if (!cmp_read_object(ctx, &obj)) 1502 | return false; 1503 | 1504 | if (obj.type != CMP_TYPE_BOOLEAN) { 1505 | ctx->error = INVALID_TYPE_ERROR; 1506 | return false; 1507 | } 1508 | 1509 | if (obj.as.boolean) 1510 | *b = true; 1511 | else 1512 | *b = false; 1513 | 1514 | return true; 1515 | } 1516 | 1517 | bool cmp_read_bool_as_u8(cmp_ctx_t *ctx, uint8_t *b) { 1518 | cmp_object_t obj; 1519 | 1520 | if (!cmp_read_object(ctx, &obj)) 1521 | return false; 1522 | 1523 | if (obj.type != CMP_TYPE_BOOLEAN) { 1524 | ctx->error = INVALID_TYPE_ERROR; 1525 | return false; 1526 | } 1527 | 1528 | if (obj.as.boolean) 1529 | *b = 1; 1530 | else 1531 | *b = 0; 1532 | 1533 | return true; 1534 | } 1535 | 1536 | bool cmp_read_str_size(cmp_ctx_t *ctx, uint32_t *size) { 1537 | cmp_object_t obj; 1538 | 1539 | if (!cmp_read_object(ctx, &obj)) 1540 | return false; 1541 | 1542 | switch (obj.type) { 1543 | case CMP_TYPE_FIXSTR: 1544 | case CMP_TYPE_STR8: 1545 | case CMP_TYPE_STR16: 1546 | case CMP_TYPE_STR32: 1547 | *size = obj.as.str_size; 1548 | return true; 1549 | default: 1550 | ctx->error = INVALID_TYPE_ERROR; 1551 | return false; 1552 | } 1553 | } 1554 | 1555 | bool cmp_read_str(cmp_ctx_t *ctx, char *data, uint32_t *size) { 1556 | uint32_t str_size = 0; 1557 | 1558 | if (!cmp_read_str_size(ctx, &str_size)) 1559 | return false; 1560 | 1561 | if ((str_size + 1) > *size) { 1562 | *size = str_size; 1563 | ctx->error = STR_DATA_LENGTH_TOO_LONG_ERROR; 1564 | return false; 1565 | } 1566 | 1567 | if (!ctx->read(ctx, data, str_size)) { 1568 | ctx->error = DATA_READING_ERROR; 1569 | return false; 1570 | } 1571 | 1572 | data[str_size] = 0; 1573 | 1574 | *size = str_size; 1575 | return true; 1576 | } 1577 | 1578 | bool cmp_read_bin_size(cmp_ctx_t *ctx, uint32_t *size) { 1579 | cmp_object_t obj; 1580 | 1581 | if (!cmp_read_object(ctx, &obj)) 1582 | return false; 1583 | 1584 | switch (obj.type) { 1585 | case CMP_TYPE_BIN8: 1586 | case CMP_TYPE_BIN16: 1587 | case CMP_TYPE_BIN32: 1588 | *size = obj.as.bin_size; 1589 | return true; 1590 | default: 1591 | ctx->error = INVALID_TYPE_ERROR; 1592 | return false; 1593 | } 1594 | } 1595 | 1596 | bool cmp_read_bin(cmp_ctx_t *ctx, void *data, uint32_t *size) { 1597 | uint32_t bin_size = 0; 1598 | 1599 | if (!cmp_read_bin_size(ctx, &bin_size)) 1600 | return false; 1601 | 1602 | if (bin_size > *size) { 1603 | ctx->error = BIN_DATA_LENGTH_TOO_LONG_ERROR; 1604 | return false; 1605 | } 1606 | 1607 | if (!ctx->read(ctx, data, bin_size)) { 1608 | ctx->error = DATA_READING_ERROR; 1609 | return false; 1610 | } 1611 | 1612 | *size = bin_size; 1613 | return true; 1614 | } 1615 | 1616 | bool cmp_read_array(cmp_ctx_t *ctx, uint32_t *size) { 1617 | cmp_object_t obj; 1618 | 1619 | if (!cmp_read_object(ctx, &obj)) 1620 | return false; 1621 | 1622 | switch (obj.type) { 1623 | case CMP_TYPE_FIXARRAY: 1624 | case CMP_TYPE_ARRAY16: 1625 | case CMP_TYPE_ARRAY32: 1626 | *size = obj.as.array_size; 1627 | return true; 1628 | default: 1629 | ctx->error = INVALID_TYPE_ERROR; 1630 | return false; 1631 | } 1632 | } 1633 | 1634 | bool cmp_read_map(cmp_ctx_t *ctx, uint32_t *size) { 1635 | cmp_object_t obj; 1636 | 1637 | if (!cmp_read_object(ctx, &obj)) 1638 | return false; 1639 | 1640 | switch (obj.type) { 1641 | case CMP_TYPE_FIXMAP: 1642 | case CMP_TYPE_MAP16: 1643 | case CMP_TYPE_MAP32: 1644 | *size = obj.as.map_size; 1645 | return true; 1646 | default: 1647 | ctx->error = INVALID_TYPE_ERROR; 1648 | return false; 1649 | } 1650 | } 1651 | 1652 | bool cmp_read_fixext1_marker(cmp_ctx_t *ctx, int8_t *type) { 1653 | cmp_object_t obj; 1654 | 1655 | if (!cmp_read_object(ctx, &obj)) 1656 | return false; 1657 | 1658 | if (obj.type != CMP_TYPE_FIXEXT1) { 1659 | ctx->error = INVALID_TYPE_ERROR; 1660 | return false; 1661 | } 1662 | 1663 | *type = obj.as.ext.type; 1664 | return true; 1665 | } 1666 | 1667 | bool cmp_read_fixext1(cmp_ctx_t *ctx, int8_t *type, void *data) { 1668 | if (!cmp_read_fixext1_marker(ctx, type)) 1669 | return false; 1670 | 1671 | if (ctx->read(ctx, data, 1)) 1672 | return true; 1673 | 1674 | ctx->error = DATA_READING_ERROR; 1675 | return false; 1676 | } 1677 | 1678 | bool cmp_read_fixext2_marker(cmp_ctx_t *ctx, int8_t *type) { 1679 | cmp_object_t obj; 1680 | 1681 | if (!cmp_read_object(ctx, &obj)) 1682 | return false; 1683 | 1684 | if (obj.type != CMP_TYPE_FIXEXT2) { 1685 | ctx->error = INVALID_TYPE_ERROR; 1686 | return false; 1687 | } 1688 | 1689 | *type = obj.as.ext.type; 1690 | return true; 1691 | } 1692 | 1693 | bool cmp_read_fixext2(cmp_ctx_t *ctx, int8_t *type, void *data) { 1694 | if (!cmp_read_fixext2_marker(ctx, type)) 1695 | return false; 1696 | 1697 | if (ctx->read(ctx, data, 2)) 1698 | return true; 1699 | 1700 | ctx->error = DATA_READING_ERROR; 1701 | return false; 1702 | } 1703 | 1704 | bool cmp_read_fixext4_marker(cmp_ctx_t *ctx, int8_t *type) { 1705 | cmp_object_t obj; 1706 | 1707 | if (!cmp_read_object(ctx, &obj)) 1708 | return false; 1709 | 1710 | if (obj.type != CMP_TYPE_FIXEXT4) { 1711 | ctx->error = INVALID_TYPE_ERROR; 1712 | return false; 1713 | } 1714 | 1715 | *type = obj.as.ext.type; 1716 | return true; 1717 | } 1718 | 1719 | bool cmp_read_fixext4(cmp_ctx_t *ctx, int8_t *type, void *data) { 1720 | if (!cmp_read_fixext4_marker(ctx, type)) 1721 | return false; 1722 | 1723 | if (ctx->read(ctx, data, 4)) 1724 | return true; 1725 | 1726 | ctx->error = DATA_READING_ERROR; 1727 | return false; 1728 | } 1729 | 1730 | bool cmp_read_fixext8_marker(cmp_ctx_t *ctx, int8_t *type) { 1731 | cmp_object_t obj; 1732 | 1733 | if (!cmp_read_object(ctx, &obj)) 1734 | return false; 1735 | 1736 | if (obj.type != CMP_TYPE_FIXEXT8) { 1737 | ctx->error = INVALID_TYPE_ERROR; 1738 | return false; 1739 | } 1740 | 1741 | *type = obj.as.ext.type; 1742 | return true; 1743 | } 1744 | 1745 | bool cmp_read_fixext8(cmp_ctx_t *ctx, int8_t *type, void *data) { 1746 | if (!cmp_read_fixext8_marker(ctx, type)) 1747 | return false; 1748 | 1749 | if (ctx->read(ctx, data, 8)) 1750 | return true; 1751 | 1752 | ctx->error = DATA_READING_ERROR; 1753 | return false; 1754 | } 1755 | 1756 | bool cmp_read_fixext16_marker(cmp_ctx_t *ctx, int8_t *type) { 1757 | cmp_object_t obj; 1758 | 1759 | if (!cmp_read_object(ctx, &obj)) 1760 | return false; 1761 | 1762 | if (obj.type != CMP_TYPE_FIXEXT16) { 1763 | ctx->error = INVALID_TYPE_ERROR; 1764 | return false; 1765 | } 1766 | 1767 | *type = obj.as.ext.type; 1768 | return true; 1769 | } 1770 | 1771 | bool cmp_read_fixext16(cmp_ctx_t *ctx, int8_t *type, void *data) { 1772 | if (!cmp_read_fixext16_marker(ctx, type)) 1773 | return false; 1774 | 1775 | if (ctx->read(ctx, data, 16)) 1776 | return true; 1777 | 1778 | ctx->error = DATA_READING_ERROR; 1779 | return false; 1780 | } 1781 | 1782 | bool cmp_read_ext8_marker(cmp_ctx_t *ctx, int8_t *type, uint8_t *size) { 1783 | cmp_object_t obj; 1784 | 1785 | if (!cmp_read_object(ctx, &obj)) 1786 | return false; 1787 | 1788 | if (obj.type != CMP_TYPE_EXT8) { 1789 | ctx->error = INVALID_TYPE_ERROR; 1790 | return false; 1791 | } 1792 | 1793 | *type = obj.as.ext.type; 1794 | *size = obj.as.ext.size; 1795 | 1796 | return true; 1797 | } 1798 | 1799 | bool cmp_read_ext8(cmp_ctx_t *ctx, int8_t *type, uint8_t *size, void *data) { 1800 | if (!cmp_read_ext8_marker(ctx, type, size)) 1801 | return false; 1802 | 1803 | if (ctx->read(ctx, data, *size)) 1804 | return true; 1805 | 1806 | ctx->error = DATA_READING_ERROR; 1807 | return false; 1808 | } 1809 | 1810 | bool cmp_read_ext16_marker(cmp_ctx_t *ctx, int8_t *type, uint16_t *size) { 1811 | cmp_object_t obj; 1812 | 1813 | if (!cmp_read_object(ctx, &obj)) 1814 | return false; 1815 | 1816 | if (obj.type != CMP_TYPE_EXT16) { 1817 | ctx->error = INVALID_TYPE_ERROR; 1818 | return false; 1819 | } 1820 | 1821 | *type = obj.as.ext.type; 1822 | *size = obj.as.ext.size; 1823 | 1824 | return true; 1825 | } 1826 | 1827 | bool cmp_read_ext16(cmp_ctx_t *ctx, int8_t *type, uint16_t *size, void *data) { 1828 | if (!cmp_read_ext16_marker(ctx, type, size)) 1829 | return false; 1830 | 1831 | if (ctx->read(ctx, data, *size)) 1832 | return true; 1833 | 1834 | ctx->error = DATA_READING_ERROR; 1835 | return false; 1836 | } 1837 | 1838 | bool cmp_read_ext32_marker(cmp_ctx_t *ctx, int8_t *type, uint32_t *size) { 1839 | cmp_object_t obj; 1840 | 1841 | if (!cmp_read_object(ctx, &obj)) 1842 | return false; 1843 | 1844 | if (obj.type != CMP_TYPE_EXT32) { 1845 | ctx->error = INVALID_TYPE_ERROR; 1846 | return false; 1847 | } 1848 | 1849 | *type = obj.as.ext.type; 1850 | *size = obj.as.ext.size; 1851 | 1852 | return true; 1853 | } 1854 | 1855 | bool cmp_read_ext32(cmp_ctx_t *ctx, int8_t *type, uint32_t *size, void *data) { 1856 | if (!cmp_read_ext32_marker(ctx, type, size)) 1857 | return false; 1858 | 1859 | if (ctx->read(ctx, data, *size)) 1860 | return true; 1861 | 1862 | ctx->error = DATA_READING_ERROR; 1863 | return false; 1864 | } 1865 | 1866 | bool cmp_read_ext_marker(cmp_ctx_t *ctx, int8_t *type, uint32_t *size) { 1867 | cmp_object_t obj; 1868 | 1869 | if (!cmp_read_object(ctx, &obj)) 1870 | return false; 1871 | 1872 | switch (obj.type) { 1873 | case CMP_TYPE_FIXEXT1: 1874 | case CMP_TYPE_FIXEXT2: 1875 | case CMP_TYPE_FIXEXT4: 1876 | case CMP_TYPE_FIXEXT8: 1877 | case CMP_TYPE_FIXEXT16: 1878 | case CMP_TYPE_EXT8: 1879 | case CMP_TYPE_EXT16: 1880 | case CMP_TYPE_EXT32: 1881 | *type = obj.as.ext.type; 1882 | *size = obj.as.ext.size; 1883 | return true; 1884 | default: 1885 | ctx->error = INVALID_TYPE_ERROR; 1886 | return false; 1887 | } 1888 | } 1889 | 1890 | bool cmp_read_ext(cmp_ctx_t *ctx, int8_t *type, uint32_t *size, void *data) { 1891 | if (!cmp_read_ext_marker(ctx, type, size)) 1892 | return false; 1893 | 1894 | if (ctx->read(ctx, data, *size)) 1895 | return true; 1896 | 1897 | ctx->error = DATA_READING_ERROR; 1898 | return false; 1899 | } 1900 | 1901 | bool cmp_read_object(cmp_ctx_t *ctx, cmp_object_t *obj) { 1902 | uint8_t type_marker = 0; 1903 | 1904 | if (!read_type_marker(ctx, &type_marker)) 1905 | return false; 1906 | 1907 | if (type_marker <= 0x7F) { 1908 | obj->type = CMP_TYPE_POSITIVE_FIXNUM; 1909 | obj->as.u8 = type_marker; 1910 | } 1911 | else if (type_marker <= 0x8F) { 1912 | obj->type = CMP_TYPE_FIXMAP; 1913 | obj->as.map_size = type_marker & FIXMAP_SIZE; 1914 | } 1915 | else if (type_marker <= 0x9F) { 1916 | obj->type = CMP_TYPE_FIXARRAY; 1917 | obj->as.array_size = type_marker & FIXARRAY_SIZE; 1918 | } 1919 | else if (type_marker <= 0xBF) { 1920 | obj->type = CMP_TYPE_FIXSTR; 1921 | obj->as.str_size = type_marker & FIXSTR_SIZE; 1922 | } 1923 | else if (type_marker == NIL_MARKER) { 1924 | obj->type = CMP_TYPE_NIL; 1925 | obj->as.u8 = 0; 1926 | } 1927 | else if (type_marker == FALSE_MARKER) { 1928 | obj->type = CMP_TYPE_BOOLEAN; 1929 | obj->as.boolean = false; 1930 | } 1931 | else if (type_marker == TRUE_MARKER) { 1932 | obj->type = CMP_TYPE_BOOLEAN; 1933 | obj->as.boolean = true; 1934 | } 1935 | else if (type_marker == BIN8_MARKER) { 1936 | obj->type = CMP_TYPE_BIN8; 1937 | if (!ctx->read(ctx, &obj->as.u8, sizeof(uint8_t))) { 1938 | ctx->error = LENGTH_READING_ERROR; 1939 | return false; 1940 | } 1941 | obj->as.bin_size = obj->as.u8; 1942 | } 1943 | else if (type_marker == BIN16_MARKER) { 1944 | obj->type = CMP_TYPE_BIN16; 1945 | if (!ctx->read(ctx, &obj->as.u16, sizeof(uint16_t))) { 1946 | ctx->error = LENGTH_READING_ERROR; 1947 | return false; 1948 | } 1949 | obj->as.bin_size = be16(obj->as.u16); 1950 | } 1951 | else if (type_marker == BIN32_MARKER) { 1952 | obj->type = CMP_TYPE_BIN32; 1953 | if (!ctx->read(ctx, &obj->as.u32, sizeof(uint32_t))) { 1954 | ctx->error = LENGTH_READING_ERROR; 1955 | return false; 1956 | } 1957 | obj->as.bin_size = be32(obj->as.u32); 1958 | } 1959 | else if (type_marker == EXT8_MARKER) { 1960 | uint8_t ext_size; 1961 | int8_t ext_type; 1962 | 1963 | obj->type = CMP_TYPE_EXT8; 1964 | if (!ctx->read(ctx, &ext_size, sizeof(uint8_t))) { 1965 | ctx->error = LENGTH_READING_ERROR; 1966 | return false; 1967 | } 1968 | if (!ctx->read(ctx, &ext_type, sizeof(int8_t))) { 1969 | ctx->error = EXT_TYPE_READING_ERROR; 1970 | return false; 1971 | } 1972 | obj->as.ext.size = ext_size; 1973 | obj->as.ext.type = ext_type; 1974 | } 1975 | else if (type_marker == EXT16_MARKER) { 1976 | int8_t ext_type; 1977 | uint16_t ext_size; 1978 | 1979 | obj->type = CMP_TYPE_EXT16; 1980 | if (!ctx->read(ctx, &ext_size, sizeof(uint16_t))) { 1981 | ctx->error = LENGTH_READING_ERROR; 1982 | return false; 1983 | } 1984 | if (!ctx->read(ctx, &ext_type, sizeof(int8_t))) { 1985 | ctx->error = EXT_TYPE_READING_ERROR; 1986 | return false; 1987 | } 1988 | obj->as.ext.size = be16(ext_size); 1989 | obj->as.ext.type = ext_type; 1990 | } 1991 | else if (type_marker == EXT32_MARKER) { 1992 | int8_t ext_type; 1993 | uint32_t ext_size; 1994 | 1995 | obj->type = CMP_TYPE_EXT32; 1996 | if (!ctx->read(ctx, &ext_size, sizeof(uint32_t))) { 1997 | ctx->error = LENGTH_READING_ERROR; 1998 | return false; 1999 | } 2000 | if (!ctx->read(ctx, &ext_type, sizeof(int8_t))) { 2001 | ctx->error = EXT_TYPE_READING_ERROR; 2002 | return false; 2003 | } 2004 | obj->as.ext.size = be32(ext_size); 2005 | obj->as.ext.type = ext_type; 2006 | } 2007 | else if (type_marker == FLOAT_MARKER) { 2008 | obj->type = CMP_TYPE_FLOAT; 2009 | if (!ctx->read(ctx, &obj->as.flt, sizeof(float))) { 2010 | ctx->error = DATA_READING_ERROR; 2011 | return false; 2012 | } 2013 | obj->as.flt = befloat(obj->as.flt); 2014 | } 2015 | else if (type_marker == DOUBLE_MARKER) { 2016 | obj->type = CMP_TYPE_DOUBLE; 2017 | if (!ctx->read(ctx, &obj->as.dbl, sizeof(double))) { 2018 | ctx->error = DATA_READING_ERROR; 2019 | return false; 2020 | } 2021 | obj->as.dbl = bedouble(obj->as.dbl); 2022 | } 2023 | else if (type_marker == U8_MARKER) { 2024 | obj->type = CMP_TYPE_UINT8; 2025 | if (!ctx->read(ctx, &obj->as.u8, sizeof(uint8_t))) { 2026 | ctx->error = DATA_READING_ERROR; 2027 | return false; 2028 | } 2029 | } 2030 | else if (type_marker == U16_MARKER) { 2031 | obj->type = CMP_TYPE_UINT16; 2032 | if (!ctx->read(ctx, &obj->as.u16, sizeof(uint16_t))) { 2033 | ctx->error = DATA_READING_ERROR; 2034 | return false; 2035 | } 2036 | obj->as.u16 = be16(obj->as.u16); 2037 | } 2038 | else if (type_marker == U32_MARKER) { 2039 | obj->type = CMP_TYPE_UINT32; 2040 | if (!ctx->read(ctx, &obj->as.u32, sizeof(uint32_t))) { 2041 | ctx->error = DATA_READING_ERROR; 2042 | return false; 2043 | } 2044 | obj->as.u32 = be32(obj->as.u32); 2045 | } 2046 | else if (type_marker == U64_MARKER) { 2047 | obj->type = CMP_TYPE_UINT64; 2048 | if (!ctx->read(ctx, &obj->as.u64, sizeof(uint64_t))) { 2049 | ctx->error = DATA_READING_ERROR; 2050 | return false; 2051 | } 2052 | obj->as.u64 = be64(obj->as.u64); 2053 | } 2054 | else if (type_marker == S8_MARKER) { 2055 | obj->type = CMP_TYPE_SINT8; 2056 | if (!ctx->read(ctx, &obj->as.s8, sizeof(int8_t))) { 2057 | ctx->error = DATA_READING_ERROR; 2058 | return false; 2059 | } 2060 | } 2061 | else if (type_marker == S16_MARKER) { 2062 | obj->type = CMP_TYPE_SINT16; 2063 | if (!ctx->read(ctx, &obj->as.s16, sizeof(int16_t))) { 2064 | ctx->error = DATA_READING_ERROR; 2065 | return false; 2066 | } 2067 | obj->as.s16 = be16(obj->as.s16); 2068 | } 2069 | else if (type_marker == S32_MARKER) { 2070 | obj->type = CMP_TYPE_SINT32; 2071 | if (!ctx->read(ctx, &obj->as.s32, sizeof(int32_t))) { 2072 | ctx->error = DATA_READING_ERROR; 2073 | return false; 2074 | } 2075 | obj->as.s32 = be32(obj->as.s32); 2076 | } 2077 | else if (type_marker == S64_MARKER) { 2078 | obj->type = CMP_TYPE_SINT64; 2079 | if (!ctx->read(ctx, &obj->as.s64, sizeof(int64_t))) { 2080 | ctx->error = DATA_READING_ERROR; 2081 | return false; 2082 | } 2083 | obj->as.s64 = be64(obj->as.s64); 2084 | } 2085 | else if (type_marker == FIXEXT1_MARKER) { 2086 | obj->type = CMP_TYPE_FIXEXT1; 2087 | if (!ctx->read(ctx, &obj->as.ext.type, sizeof(int8_t))) { 2088 | ctx->error = EXT_TYPE_READING_ERROR; 2089 | return false; 2090 | } 2091 | obj->as.ext.size = 1; 2092 | } 2093 | else if (type_marker == FIXEXT2_MARKER) { 2094 | obj->type = CMP_TYPE_FIXEXT2; 2095 | if (!ctx->read(ctx, &obj->as.ext.type, sizeof(int8_t))) { 2096 | ctx->error = EXT_TYPE_READING_ERROR; 2097 | return false; 2098 | } 2099 | obj->as.ext.size = 2; 2100 | } 2101 | else if (type_marker == FIXEXT4_MARKER) { 2102 | obj->type = CMP_TYPE_FIXEXT4; 2103 | if (!ctx->read(ctx, &obj->as.ext.type, sizeof(int8_t))) { 2104 | ctx->error = EXT_TYPE_READING_ERROR; 2105 | return false; 2106 | } 2107 | obj->as.ext.size = 4; 2108 | } 2109 | else if (type_marker == FIXEXT8_MARKER) { 2110 | obj->type = CMP_TYPE_FIXEXT8; 2111 | if (!ctx->read(ctx, &obj->as.ext.type, sizeof(int8_t))) { 2112 | ctx->error = EXT_TYPE_READING_ERROR; 2113 | return false; 2114 | } 2115 | obj->as.ext.size = 8; 2116 | } 2117 | else if (type_marker == FIXEXT16_MARKER) { 2118 | obj->type = CMP_TYPE_FIXEXT16; 2119 | if (!ctx->read(ctx, &obj->as.ext.type, sizeof(int8_t))) { 2120 | ctx->error = EXT_TYPE_READING_ERROR; 2121 | return false; 2122 | } 2123 | obj->as.ext.size = 16; 2124 | } 2125 | else if (type_marker == STR8_MARKER) { 2126 | obj->type = CMP_TYPE_STR8; 2127 | if (!ctx->read(ctx, &obj->as.u8, sizeof(uint8_t))) { 2128 | ctx->error = DATA_READING_ERROR; 2129 | return false; 2130 | } 2131 | obj->as.str_size = obj->as.u8; 2132 | } 2133 | else if (type_marker == STR16_MARKER) { 2134 | obj->type = CMP_TYPE_STR16; 2135 | if (!ctx->read(ctx, &obj->as.u16, sizeof(uint16_t))) { 2136 | ctx->error = DATA_READING_ERROR; 2137 | return false; 2138 | } 2139 | obj->as.str_size = be16(obj->as.u16); 2140 | } 2141 | else if (type_marker == STR32_MARKER) { 2142 | obj->type = CMP_TYPE_STR32; 2143 | if (!ctx->read(ctx, &obj->as.u32, sizeof(uint32_t))) { 2144 | ctx->error = DATA_READING_ERROR; 2145 | return false; 2146 | } 2147 | obj->as.str_size = be32(obj->as.u32); 2148 | } 2149 | else if (type_marker == ARRAY16_MARKER) { 2150 | obj->type = CMP_TYPE_ARRAY16; 2151 | if (!ctx->read(ctx, &obj->as.u16, sizeof(uint16_t))) { 2152 | ctx->error = DATA_READING_ERROR; 2153 | return false; 2154 | } 2155 | obj->as.array_size = be16(obj->as.u16); 2156 | } 2157 | else if (type_marker == ARRAY32_MARKER) { 2158 | obj->type = CMP_TYPE_ARRAY32; 2159 | if (!ctx->read(ctx, &obj->as.u32, sizeof(uint32_t))) { 2160 | ctx->error = DATA_READING_ERROR; 2161 | return false; 2162 | } 2163 | obj->as.array_size = be32(obj->as.u32); 2164 | } 2165 | else if (type_marker == MAP16_MARKER) { 2166 | obj->type = CMP_TYPE_MAP16; 2167 | if (!ctx->read(ctx, &obj->as.u16, sizeof(uint16_t))) { 2168 | ctx->error = DATA_READING_ERROR; 2169 | return false; 2170 | } 2171 | obj->as.map_size = be16(obj->as.u16); 2172 | } 2173 | else if (type_marker == MAP32_MARKER) { 2174 | obj->type = CMP_TYPE_MAP32; 2175 | if (!ctx->read(ctx, &obj->as.u32, sizeof(uint32_t))) { 2176 | ctx->error = DATA_READING_ERROR; 2177 | return false; 2178 | } 2179 | obj->as.map_size = be32(obj->as.u32); 2180 | } 2181 | else if (type_marker >= NEGATIVE_FIXNUM_MARKER) { 2182 | obj->type = CMP_TYPE_NEGATIVE_FIXNUM; 2183 | obj->as.s8 = type_marker; 2184 | } 2185 | else { 2186 | ctx->error = INVALID_TYPE_ERROR; 2187 | return false; 2188 | } 2189 | 2190 | return true; 2191 | } 2192 | 2193 | bool cmp_object_is_char(cmp_object_t *obj) { 2194 | switch (obj->type) { 2195 | case CMP_TYPE_NEGATIVE_FIXNUM: 2196 | case CMP_TYPE_SINT8: 2197 | return true; 2198 | default: 2199 | return false; 2200 | } 2201 | } 2202 | 2203 | bool cmp_object_is_short(cmp_object_t *obj) { 2204 | switch (obj->type) { 2205 | case CMP_TYPE_NEGATIVE_FIXNUM: 2206 | case CMP_TYPE_SINT8: 2207 | case CMP_TYPE_SINT16: 2208 | return true; 2209 | default: 2210 | return false; 2211 | } 2212 | } 2213 | 2214 | bool cmp_object_is_int(cmp_object_t *obj) { 2215 | switch (obj->type) { 2216 | case CMP_TYPE_NEGATIVE_FIXNUM: 2217 | case CMP_TYPE_SINT8: 2218 | case CMP_TYPE_SINT16: 2219 | case CMP_TYPE_SINT32: 2220 | return true; 2221 | default: 2222 | return false; 2223 | } 2224 | } 2225 | 2226 | bool cmp_object_is_long(cmp_object_t *obj) { 2227 | switch (obj->type) { 2228 | case CMP_TYPE_NEGATIVE_FIXNUM: 2229 | case CMP_TYPE_SINT8: 2230 | case CMP_TYPE_SINT16: 2231 | case CMP_TYPE_SINT32: 2232 | case CMP_TYPE_SINT64: 2233 | return true; 2234 | default: 2235 | return false; 2236 | } 2237 | } 2238 | 2239 | bool cmp_object_is_sinteger(cmp_object_t *obj) { 2240 | return cmp_object_is_long(obj); 2241 | } 2242 | 2243 | bool cmp_object_is_uchar(cmp_object_t *obj) { 2244 | switch (obj->type) { 2245 | case CMP_TYPE_POSITIVE_FIXNUM: 2246 | case CMP_TYPE_UINT8: 2247 | return true; 2248 | default: 2249 | return false; 2250 | } 2251 | } 2252 | 2253 | bool cmp_object_is_ushort(cmp_object_t *obj) { 2254 | switch (obj->type) { 2255 | case CMP_TYPE_POSITIVE_FIXNUM: 2256 | case CMP_TYPE_UINT8: 2257 | return true; 2258 | case CMP_TYPE_UINT16: 2259 | return true; 2260 | default: 2261 | return false; 2262 | } 2263 | } 2264 | 2265 | bool cmp_object_is_uint(cmp_object_t *obj) { 2266 | switch (obj->type) { 2267 | case CMP_TYPE_POSITIVE_FIXNUM: 2268 | case CMP_TYPE_UINT8: 2269 | case CMP_TYPE_UINT16: 2270 | case CMP_TYPE_UINT32: 2271 | return true; 2272 | default: 2273 | return false; 2274 | } 2275 | } 2276 | 2277 | bool cmp_object_is_ulong(cmp_object_t *obj) { 2278 | switch (obj->type) { 2279 | case CMP_TYPE_POSITIVE_FIXNUM: 2280 | case CMP_TYPE_UINT8: 2281 | case CMP_TYPE_UINT16: 2282 | case CMP_TYPE_UINT32: 2283 | case CMP_TYPE_UINT64: 2284 | return true; 2285 | default: 2286 | return false; 2287 | } 2288 | } 2289 | 2290 | bool cmp_object_is_uinteger(cmp_object_t *obj) { 2291 | return cmp_object_is_ulong(obj); 2292 | } 2293 | 2294 | bool cmp_object_is_float(cmp_object_t *obj) { 2295 | if (obj->type == CMP_TYPE_FLOAT) 2296 | return true; 2297 | 2298 | return false; 2299 | } 2300 | 2301 | bool cmp_object_is_double(cmp_object_t *obj) { 2302 | if (obj->type == CMP_TYPE_DOUBLE) 2303 | return true; 2304 | 2305 | return false; 2306 | } 2307 | 2308 | bool cmp_object_is_nil(cmp_object_t *obj) { 2309 | if (obj->type == CMP_TYPE_NIL) 2310 | return true; 2311 | 2312 | return false; 2313 | } 2314 | 2315 | bool cmp_object_is_bool(cmp_object_t *obj) { 2316 | if (obj->type == CMP_TYPE_BOOLEAN) 2317 | return true; 2318 | 2319 | return false; 2320 | } 2321 | 2322 | bool cmp_object_is_str(cmp_object_t *obj) { 2323 | switch (obj->type) { 2324 | case CMP_TYPE_FIXSTR: 2325 | case CMP_TYPE_STR8: 2326 | case CMP_TYPE_STR16: 2327 | case CMP_TYPE_STR32: 2328 | return true; 2329 | default: 2330 | return false; 2331 | } 2332 | } 2333 | 2334 | bool cmp_object_is_bin(cmp_object_t *obj) { 2335 | switch (obj->type) { 2336 | case CMP_TYPE_BIN8: 2337 | case CMP_TYPE_BIN16: 2338 | case CMP_TYPE_BIN32: 2339 | return true; 2340 | default: 2341 | return false; 2342 | } 2343 | } 2344 | 2345 | bool cmp_object_is_array(cmp_object_t *obj) { 2346 | switch (obj->type) { 2347 | case CMP_TYPE_FIXARRAY: 2348 | case CMP_TYPE_ARRAY16: 2349 | case CMP_TYPE_ARRAY32: 2350 | return true; 2351 | default: 2352 | return false; 2353 | } 2354 | } 2355 | 2356 | bool cmp_object_is_map(cmp_object_t *obj) { 2357 | switch (obj->type) { 2358 | case CMP_TYPE_FIXMAP: 2359 | case CMP_TYPE_MAP16: 2360 | case CMP_TYPE_MAP32: 2361 | return true; 2362 | default: 2363 | return false; 2364 | } 2365 | } 2366 | 2367 | bool cmp_object_is_ext(cmp_object_t *obj) { 2368 | switch (obj->type) { 2369 | case CMP_TYPE_FIXEXT1: 2370 | case CMP_TYPE_FIXEXT2: 2371 | case CMP_TYPE_FIXEXT4: 2372 | case CMP_TYPE_FIXEXT8: 2373 | case CMP_TYPE_FIXEXT16: 2374 | case CMP_TYPE_EXT8: 2375 | case CMP_TYPE_EXT16: 2376 | case CMP_TYPE_EXT32: 2377 | return true; 2378 | default: 2379 | return false; 2380 | } 2381 | } 2382 | 2383 | bool cmp_object_as_char(cmp_object_t *obj, int8_t *c) { 2384 | switch (obj->type) { 2385 | case CMP_TYPE_POSITIVE_FIXNUM: 2386 | case CMP_TYPE_NEGATIVE_FIXNUM: 2387 | case CMP_TYPE_SINT8: 2388 | *c = obj->as.s8; 2389 | return true; 2390 | case CMP_TYPE_UINT8: 2391 | if (obj->as.u8 <= 127) { 2392 | *c = obj->as.s8; 2393 | return true; 2394 | } 2395 | } 2396 | 2397 | return false; 2398 | } 2399 | 2400 | bool cmp_object_as_short(cmp_object_t *obj, int16_t *s) { 2401 | switch (obj->type) { 2402 | case CMP_TYPE_POSITIVE_FIXNUM: 2403 | case CMP_TYPE_NEGATIVE_FIXNUM: 2404 | case CMP_TYPE_SINT8: 2405 | *s = obj->as.s8; 2406 | return true; 2407 | case CMP_TYPE_UINT8: 2408 | *s = obj->as.u8; 2409 | return true; 2410 | case CMP_TYPE_SINT16: 2411 | *s = obj->as.s16; 2412 | return true; 2413 | case CMP_TYPE_UINT16: 2414 | if (obj->as.u16 <= 32767) { 2415 | *s = obj->as.u16; 2416 | return true; 2417 | } 2418 | } 2419 | 2420 | return false; 2421 | } 2422 | 2423 | bool cmp_object_as_int(cmp_object_t *obj, int32_t *i) { 2424 | switch (obj->type) { 2425 | case CMP_TYPE_POSITIVE_FIXNUM: 2426 | case CMP_TYPE_NEGATIVE_FIXNUM: 2427 | case CMP_TYPE_SINT8: 2428 | *i = obj->as.s8; 2429 | return true; 2430 | case CMP_TYPE_UINT8: 2431 | *i = obj->as.u8; 2432 | return true; 2433 | case CMP_TYPE_SINT16: 2434 | *i = obj->as.s16; 2435 | return true; 2436 | case CMP_TYPE_UINT16: 2437 | *i = obj->as.u16; 2438 | return true; 2439 | case CMP_TYPE_SINT32: 2440 | *i = obj->as.s32; 2441 | return true; 2442 | case CMP_TYPE_UINT32: 2443 | if (obj->as.u32 <= 2147483647) { 2444 | *i = obj->as.u32; 2445 | return true; 2446 | } 2447 | } 2448 | 2449 | return false; 2450 | } 2451 | 2452 | bool cmp_object_as_long(cmp_object_t *obj, int64_t *d) { 2453 | switch (obj->type) { 2454 | case CMP_TYPE_POSITIVE_FIXNUM: 2455 | case CMP_TYPE_NEGATIVE_FIXNUM: 2456 | case CMP_TYPE_SINT8: 2457 | *d = obj->as.s8; 2458 | return true; 2459 | case CMP_TYPE_UINT8: 2460 | *d = obj->as.u8; 2461 | return true; 2462 | case CMP_TYPE_SINT16: 2463 | *d = obj->as.s16; 2464 | return true; 2465 | case CMP_TYPE_UINT16: 2466 | *d = obj->as.u16; 2467 | return true; 2468 | case CMP_TYPE_SINT32: 2469 | *d = obj->as.s32; 2470 | return true; 2471 | case CMP_TYPE_UINT32: 2472 | *d = obj->as.u32; 2473 | return true; 2474 | case CMP_TYPE_SINT64: 2475 | *d = obj->as.s64; 2476 | return true; 2477 | case CMP_TYPE_UINT64: 2478 | if (obj->as.u64 <= 9223372036854775807) { 2479 | *d = obj->as.u64; 2480 | return true; 2481 | } 2482 | } 2483 | 2484 | return false; 2485 | } 2486 | 2487 | bool cmp_object_as_sinteger(cmp_object_t *obj, int64_t *d) { 2488 | return cmp_object_as_long(obj, d); 2489 | } 2490 | 2491 | bool cmp_object_as_uchar(cmp_object_t *obj, uint8_t *c) { 2492 | switch (obj->type) { 2493 | case CMP_TYPE_POSITIVE_FIXNUM: 2494 | case CMP_TYPE_UINT8: 2495 | *c = obj->as.u8; 2496 | return true; 2497 | } 2498 | 2499 | return false; 2500 | } 2501 | 2502 | bool cmp_object_as_ushort(cmp_object_t *obj, uint16_t *s) { 2503 | switch (obj->type) { 2504 | case CMP_TYPE_POSITIVE_FIXNUM: 2505 | case CMP_TYPE_UINT8: 2506 | *s = obj->as.u8; 2507 | return true; 2508 | case CMP_TYPE_UINT16: 2509 | *s = obj->as.u16; 2510 | return true; 2511 | } 2512 | 2513 | return false; 2514 | } 2515 | 2516 | bool cmp_object_as_uint(cmp_object_t *obj, uint32_t *i) { 2517 | switch (obj->type) { 2518 | case CMP_TYPE_POSITIVE_FIXNUM: 2519 | case CMP_TYPE_UINT8: 2520 | *i = obj->as.u8; 2521 | return true; 2522 | case CMP_TYPE_UINT16: 2523 | *i = obj->as.u16; 2524 | return true; 2525 | case CMP_TYPE_UINT32: 2526 | *i = obj->as.u32; 2527 | return true; 2528 | } 2529 | 2530 | return false; 2531 | } 2532 | 2533 | bool cmp_object_as_ulong(cmp_object_t *obj, uint64_t *u) { 2534 | switch (obj->type) { 2535 | case CMP_TYPE_POSITIVE_FIXNUM: 2536 | case CMP_TYPE_UINT8: 2537 | *u = obj->as.u8; 2538 | return true; 2539 | case CMP_TYPE_UINT16: 2540 | *u = obj->as.u16; 2541 | return true; 2542 | case CMP_TYPE_UINT32: 2543 | *u = obj->as.u32; 2544 | return true; 2545 | case CMP_TYPE_UINT64: 2546 | *u = obj->as.u64; 2547 | return true; 2548 | } 2549 | 2550 | return false; 2551 | } 2552 | 2553 | bool cmp_object_as_uinteger(cmp_object_t *obj, uint64_t *d) { 2554 | return cmp_object_as_ulong(obj, d); 2555 | } 2556 | 2557 | bool cmp_object_as_float(cmp_object_t *obj, float *f) { 2558 | if (obj->type == CMP_TYPE_FLOAT) { 2559 | *f = obj->as.flt; 2560 | return true; 2561 | } 2562 | 2563 | return false; 2564 | } 2565 | 2566 | bool cmp_object_as_double(cmp_object_t *obj, double *d) { 2567 | if (obj->type == CMP_TYPE_DOUBLE) { 2568 | *d = obj->as.dbl; 2569 | return true; 2570 | } 2571 | 2572 | return false; 2573 | } 2574 | 2575 | bool cmp_object_as_bool(cmp_object_t *obj, bool *b) { 2576 | if (obj->type == CMP_TYPE_BOOLEAN) { 2577 | if (obj->as.boolean) 2578 | *b = true; 2579 | else 2580 | *b = false; 2581 | 2582 | return true; 2583 | } 2584 | 2585 | return false; 2586 | } 2587 | 2588 | bool cmp_object_as_str(cmp_object_t *obj, uint32_t *size) { 2589 | switch (obj->type) { 2590 | case CMP_TYPE_FIXSTR: 2591 | case CMP_TYPE_STR8: 2592 | case CMP_TYPE_STR16: 2593 | case CMP_TYPE_STR32: 2594 | *size = obj->as.str_size; 2595 | return true; 2596 | } 2597 | 2598 | return false; 2599 | } 2600 | 2601 | bool cmp_object_as_bin(cmp_object_t *obj, uint32_t *size) { 2602 | switch (obj->type) { 2603 | case CMP_TYPE_BIN8: 2604 | case CMP_TYPE_BIN16: 2605 | case CMP_TYPE_BIN32: 2606 | *size = obj->as.bin_size; 2607 | return true; 2608 | } 2609 | 2610 | return false; 2611 | } 2612 | 2613 | bool cmp_object_as_array(cmp_object_t *obj, uint32_t *size) { 2614 | switch (obj->type) { 2615 | case CMP_TYPE_FIXARRAY: 2616 | case CMP_TYPE_ARRAY16: 2617 | case CMP_TYPE_ARRAY32: 2618 | *size = obj->as.array_size; 2619 | return true; 2620 | } 2621 | 2622 | return false; 2623 | } 2624 | 2625 | bool cmp_object_as_map(cmp_object_t *obj, uint32_t *size) { 2626 | switch (obj->type) { 2627 | case CMP_TYPE_FIXMAP: 2628 | case CMP_TYPE_MAP16: 2629 | case CMP_TYPE_MAP32: 2630 | *size = obj->as.map_size; 2631 | return true; 2632 | } 2633 | 2634 | return false; 2635 | } 2636 | 2637 | bool cmp_object_as_ext(cmp_object_t *obj, int8_t *type, uint32_t *size) { 2638 | switch (obj->type) { 2639 | case CMP_TYPE_FIXEXT1: 2640 | case CMP_TYPE_FIXEXT2: 2641 | case CMP_TYPE_FIXEXT4: 2642 | case CMP_TYPE_FIXEXT8: 2643 | case CMP_TYPE_FIXEXT16: 2644 | case CMP_TYPE_EXT8: 2645 | case CMP_TYPE_EXT16: 2646 | case CMP_TYPE_EXT32: 2647 | *type = obj->as.ext.type; 2648 | *size = obj->as.ext.size; 2649 | return true; 2650 | } 2651 | 2652 | return false; 2653 | } 2654 | 2655 | /* vi: set et ts=2 sw=2: */ 2656 | 2657 | --------------------------------------------------------------------------------