Index: ObjFW.xcodeproj/project.pbxproj ================================================================== --- ObjFW.xcodeproj/project.pbxproj +++ ObjFW.xcodeproj/project.pbxproj @@ -360,10 +360,12 @@ 4BB4B54A16776094002A2DCE /* OFHTTPClientTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 4BB4B54916776094002A2DCE /* OFHTTPClientTests.m */; }; 4BB524C1143D1E4E0085FBCC /* OFProcess.h in Headers */ = {isa = PBXBuildFile; fileRef = 4BB524BF143D1E4E0085FBCC /* OFProcess.h */; settings = {ATTRIBUTES = (Public, ); }; }; 4BB524C2143D1E4E0085FBCC /* OFProcess.m in Sources */ = {isa = PBXBuildFile; fileRef = 4BB524C0143D1E4E0085FBCC /* OFProcess.m */; settings = {ATTRIBUTES = (Public, ); }; }; 4BC090441584F6760040640F /* OFInvalidJSONException.h in Headers */ = {isa = PBXBuildFile; fileRef = 4BC090421584F6760040640F /* OFInvalidJSONException.h */; settings = {ATTRIBUTES = (Public, ); }; }; 4BC090451584F6760040640F /* OFInvalidJSONException.m in Sources */ = {isa = PBXBuildFile; fileRef = 4BC090431584F6760040640F /* OFInvalidJSONException.m */; }; + 4BCAA9AF1772432F003EF859 /* OFMessagePackExtension.h in Headers */ = {isa = PBXBuildFile; fileRef = 4BCAA9AD1772432E003EF859 /* OFMessagePackExtension.h */; }; + 4BCAA9B01772432F003EF859 /* OFMessagePackExtension.m in Sources */ = {isa = PBXBuildFile; fileRef = 4BCAA9AE1772432E003EF859 /* OFMessagePackExtension.m */; }; 4BD653C5143B8489006182F0 /* OFTCPSocket+SOCKS5.h in Headers */ = {isa = PBXBuildFile; fileRef = 4BD653C3143B8489006182F0 /* OFTCPSocket+SOCKS5.h */; settings = {ATTRIBUTES = (); }; }; 4BD653C6143B8489006182F0 /* OFTCPSocket+SOCKS5.m in Sources */ = {isa = PBXBuildFile; fileRef = 4BD653C4143B8489006182F0 /* OFTCPSocket+SOCKS5.m */; }; 4BD77FDE176E4BC40031C497 /* OFUnboundPrefixException.h in Headers */ = {isa = PBXBuildFile; fileRef = 4BD77FDC176E4BC40031C497 /* OFUnboundPrefixException.h */; settings = {ATTRIBUTES = (Public, ); }; }; 4BD77FDF176E4BC40031C497 /* OFUnboundPrefixException.m in Sources */ = {isa = PBXBuildFile; fileRef = 4BD77FDD176E4BC40031C497 /* OFUnboundPrefixException.m */; }; 4BD98C03133814220048DD5B /* objfw-defs.h in Headers */ = {isa = PBXBuildFile; fileRef = 4BD98C011338140B0048DD5B /* objfw-defs.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -788,10 +790,12 @@ 4BB524C0143D1E4E0085FBCC /* OFProcess.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OFProcess.m; path = src/OFProcess.m; sourceTree = ""; }; 4BBA36C411406AB700CBA3AC /* atomic.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = atomic.h; path = src/atomic.h; sourceTree = ""; }; 4BBA36C511406AB700CBA3AC /* macros.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = macros.h; path = src/macros.h; sourceTree = ""; }; 4BC090421584F6760040640F /* OFInvalidJSONException.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OFInvalidJSONException.h; path = src/exceptions/OFInvalidJSONException.h; sourceTree = ""; }; 4BC090431584F6760040640F /* OFInvalidJSONException.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OFInvalidJSONException.m; path = src/exceptions/OFInvalidJSONException.m; sourceTree = ""; }; + 4BCAA9AD1772432E003EF859 /* OFMessagePackExtension.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OFMessagePackExtension.h; path = src/OFMessagePackExtension.h; sourceTree = ""; }; + 4BCAA9AE1772432E003EF859 /* OFMessagePackExtension.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OFMessagePackExtension.m; path = src/OFMessagePackExtension.m; sourceTree = ""; }; 4BD653C3143B8489006182F0 /* OFTCPSocket+SOCKS5.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "OFTCPSocket+SOCKS5.h"; path = "src/OFTCPSocket+SOCKS5.h"; sourceTree = ""; }; 4BD653C4143B8489006182F0 /* OFTCPSocket+SOCKS5.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = "OFTCPSocket+SOCKS5.m"; path = "src/OFTCPSocket+SOCKS5.m"; sourceTree = ""; }; 4BD77FDC176E4BC40031C497 /* OFUnboundPrefixException.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OFUnboundPrefixException.h; path = src/exceptions/OFUnboundPrefixException.h; sourceTree = ""; }; 4BD77FDD176E4BC40031C497 /* OFUnboundPrefixException.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OFUnboundPrefixException.m; path = src/exceptions/OFUnboundPrefixException.m; sourceTree = ""; }; 4BD86D801237A6C600ED9912 /* OFBlock.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OFBlock.h; path = src/OFBlock.h; sourceTree = SOURCE_ROOT; }; @@ -1129,10 +1133,12 @@ 4B6743F9163C395900EB1E59 /* OFLocking.h */, 4B3B0796166978780044E634 /* OFMapTable.h */, 4B3B0797166978780044E634 /* OFMapTable.m */, 4BF1BCC211C9663F0025511F /* OFMD5Hash.h */, 4BF1BCC311C9663F0025511F /* OFMD5Hash.m */, + 4BCAA9AD1772432E003EF859 /* OFMessagePackExtension.h */, + 4BCAA9AE1772432E003EF859 /* OFMessagePackExtension.m */, 4B879A8B177231F000EBCEA4 /* OFMessagePackRepresentation.h */, 4B67996F1099E7C50041064A /* OFMutableArray.h */, 4B6799701099E7C50041064A /* OFMutableArray.m */, 4B2B3E77140D430500EC2F7C /* OFMutableArray_adjacent.h */, 4B2B3E78140D430500EC2F7C /* OFMutableArray_adjacent.m */, @@ -1533,10 +1539,11 @@ 4B64D6EF1425381E007BDFB1 /* OFStreamObserver_poll.h in Headers */, 4B64D6F11425381E007BDFB1 /* OFStreamObserver_select.h in Headers */, 4B552554147AA5DB0003BF47 /* OFString_UTF8.h in Headers */, 4BD653C5143B8489006182F0 /* OFTCPSocket+SOCKS5.h in Headers */, 4BDF37B51338055600F9A81A /* config.h in Headers */, + 4BCAA9AF1772432F003EF859 /* OFMessagePackExtension.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXHeadersBuildPhase section */ @@ -1739,10 +1746,11 @@ 4B3D238F1337FC0D00DD29B8 /* OFConstantString.m in Sources */, 4B45355413DCFE1E0037AB4D /* OFCountedSet.m in Sources */, 4BA85BCB140ECCE800E91D51 /* OFCountedSet_hashtable.m in Sources */, 4B3D23901337FC0D00DD29B8 /* OFDataArray.m in Sources */, 4B3D23911337FC0D00DD29B8 /* OFDataArray+Hashing.m in Sources */, + 4B879A8D177231F000EBCEA4 /* OFDataArray+MessagePackValue.m in Sources */, 4B3D23921337FC0D00DD29B8 /* OFDate.m in Sources */, 4B3D23931337FC0D00DD29B8 /* OFDictionary.m in Sources */, 4B2B3E80140D430500EC2F7C /* OFDictionary_hashtable.m in Sources */, 4B3D23941337FC0D00DD29B8 /* OFEnumerator.m in Sources */, 4B3D23961337FC0D00DD29B8 /* OFFile.m in Sources */, @@ -1752,10 +1760,11 @@ 4BB4B54716775FF4002A2DCE /* OFHTTPServer.m in Sources */, 4BA49D9113DB113B00381CDB /* OFIntrospection.m in Sources */, 4B3D23991337FC0D00DD29B8 /* OFList.m in Sources */, 4B3B0799166978780044E634 /* OFMapTable.m in Sources */, 4B3D239A1337FC0D00DD29B8 /* OFMD5Hash.m in Sources */, + 4BCAA9B01772432F003EF859 /* OFMessagePackExtension.m in Sources */, 4B3D239B1337FC0D00DD29B8 /* OFMutableArray.m in Sources */, 4B2B3E82140D430500EC2F7C /* OFMutableArray_adjacent.m in Sources */, 4B3D239C1337FC0D00DD29B8 /* OFMutableDictionary.m in Sources */, 4B2B3E84140D430500EC2F7C /* OFMutableDictionary_hashtable.m in Sources */, 4B39844813D3AFB400E6F825 /* OFMutableSet.m in Sources */, @@ -1869,11 +1878,10 @@ 4BD77FDF176E4BC40031C497 /* OFUnboundPrefixException.m in Sources */, 4B6743F6163C384A00EB1E59 /* OFUnlockFailedException.m in Sources */, 4B17FFB2133A3664003E6DCD /* OFUnsupportedProtocolException.m in Sources */, 4BA4846315CC9F1E00D75360 /* OFUnsupportedVersionException.m in Sources */, 4B55A117133AC24600B58A93 /* OFWriteFailedException.m in Sources */, - 4B879A8D177231F000EBCEA4 /* OFDataArray+MessagePackValue.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; 4BF33AEC133807310059CEF7 /* Sources */ = { isa = PBXSourcesBuildPhase; Index: src/Makefile ================================================================== --- src/Makefile +++ src/Makefile @@ -23,10 +23,11 @@ OFFile.m \ OFIntrospection.m \ OFList.m \ OFMapTable.m \ OFMD5Hash.m \ + OFMessagePackExtension.m \ OFMutableArray.m \ OFMutableDictionary.m \ OFMutableSet.m \ OFMutableString.m \ OFNull.m \ Index: src/OFDataArray+MessagePackValue.m ================================================================== --- src/OFDataArray+MessagePackValue.m +++ src/OFDataArray+MessagePackValue.m @@ -19,10 +19,11 @@ #import "OFNull.h" #import "OFDataArray.h" #import "OFString.h" #import "OFArray.h" #import "OFDictionary.h" +#import "OFMessagePackExtension.h" #import "OFInvalidFormatException.h" #import "autorelease.h" #import "macros.h" @@ -139,10 +140,12 @@ static size_t parse_object(const uint8_t *buffer, size_t length, id *object) { size_t i, count; + int8_t type; + OFDataArray *data; if (length < 1) goto error; /* positive fixint */ @@ -282,12 +285,11 @@ count = buffer[1]; if (length < count + 2) goto error; - *object = [OFDataArray dataArrayWithItemSize: 1 - capacity: count]; + *object = [OFDataArray dataArrayWithCapacity: count]; [*object addItems: buffer + 2 count: count]; return count + 2; case 0xC5: /* bin 16 */ @@ -297,12 +299,11 @@ count = read_uint16(buffer + 1); if (length < count + 3) goto error; - *object = [OFDataArray dataArrayWithItemSize: 1 - capacity: count]; + *object = [OFDataArray dataArrayWithCapacity: count]; [*object addItems: buffer + 3 count: count]; return count + 3; case 0xC6: /* bin 32 */ @@ -312,16 +313,182 @@ count = read_uint32(buffer + 1); if (length < count + 5) goto error; - *object = [OFDataArray dataArrayWithItemSize: 1 - capacity: count]; + *object = [OFDataArray dataArrayWithCapacity: count]; [*object addItems: buffer + 5 count: count]; return count + 5; + /* Extensions */ + case 0xC7: /* ext 8 */ + if (length < 3) + goto error; + + count = buffer[1]; + + if (length < count + 3) + goto error; + + type = buffer[2]; + + data = [[OFDataArray alloc] initWithCapacity: count]; + @try { + [data addItems: buffer + 3 + count: count]; + + *object = [OFMessagePackExtension + extensionWithType: type + data: data]; + } @finally { + [data release]; + } + + return count + 3; + case 0xC8: /* ext 16 */ + if (length < 4) + goto error; + + count = read_uint16(buffer + 1); + + if (length < count + 4) + goto error; + + type = buffer[3]; + + data = [[OFDataArray alloc] initWithCapacity: count]; + @try { + [data addItems: buffer + 4 + count: count]; + + *object = [OFMessagePackExtension + extensionWithType: type + data: data]; + } @finally { + [data release]; + } + + return count + 4; + case 0xC9: /* ext 32 */ + if (length < 6) + goto error; + + count = read_uint32(buffer + 1); + + if (length < count + 6) + goto error; + + type = buffer[5]; + + data = [[OFDataArray alloc] initWithCapacity: count]; + @try { + [data addItems: buffer + 6 + count: count]; + + *object = [OFMessagePackExtension + extensionWithType: type + data: data]; + } @finally { + [data release]; + } + + return count + 6; + case 0xD4: /* fixext 1 */ + if (length < 3) + goto error; + + type = buffer[1]; + + data = [[OFDataArray alloc] initWithCapacity: 1]; + @try { + [data addItem: buffer + 2]; + + *object = [OFMessagePackExtension + extensionWithType: type + data: data]; + } @finally { + [data release]; + } + + return 3; + case 0xD5: /* fixext 2 */ + if (length < 4) + goto error; + + type = buffer[1]; + + data = [[OFDataArray alloc] initWithCapacity: 2]; + @try { + [data addItems: buffer + 2 + count: 2]; + + *object = [OFMessagePackExtension + extensionWithType: type + data: data]; + } @finally { + [data release]; + } + + return 4; + case 0xD6: /* fixtext 4 */ + if (length < 6) + goto error; + + type = buffer[1]; + + data = [[OFDataArray alloc] initWithCapacity: 4]; + @try { + [data addItems: buffer + 2 + count: 4]; + + *object = [OFMessagePackExtension + extensionWithType: type + data: data]; + } @finally { + [data release]; + } + + return 6; + case 0xD7: /* fixtext 8 */ + if (length < 10) + goto error; + + type = buffer[1]; + + data = [[OFDataArray alloc] initWithCapacity: 8]; + @try { + [data addItems: buffer + 2 + count: 8]; + + *object = [OFMessagePackExtension + extensionWithType: type + data: data]; + } @finally { + [data release]; + } + + return 10; + case 0xD8: /* fixext 16 */ + if (length < 18) + goto error; + + type = buffer[1]; + + data = [[OFDataArray alloc] initWithCapacity: 16]; + @try { + [data addItems: buffer + 2 + count: 16]; + + *object = [OFMessagePackExtension + extensionWithType: type + data: data]; + } @finally { + [data release]; + } + + return 18; /* Strings */ case 0xD9: /* str 8 */ if (length < 2) goto error; Index: src/OFMapTable.h ================================================================== --- src/OFMapTable.h +++ src/OFMapTable.h @@ -17,11 +17,11 @@ #import "OFObject.h" #import "OFEnumerator.h" /*! @file */ -/** +/*! * @brief A struct describing the functions to be used by the map table. */ typedef struct of_map_table_functions_t { /// The function to retain keys / values void* (*retain)(void *value); @@ -55,11 +55,11 @@ typedef void* (^of_map_table_replace_block_t)(void *key, void *value); #endif @class OFMapTableEnumerator; -/** +/*! * @brief A class similar to OFDictionary, but providing more options how keys * and values should be retained, released, compared and hashed. */ @interface OFMapTable: OFObject { @@ -206,18 +206,18 @@ * @param block The block which returns a new value for each value */ - (void)replaceValuesUsingBlock: (of_map_table_replace_block_t)block; #endif -/** +/*! * @brief Returns the key functions used by the map table. * * @return The key functions used by the map table */ - (of_map_table_functions_t)keyFunctions; -/** +/*! * @brief Returns the value functions used by the map table. * * @return The value functions used by the map table */ - (of_map_table_functions_t)valueFunctions; ADDED src/OFMessagePackExtension.h Index: src/OFMessagePackExtension.h ================================================================== --- src/OFMessagePackExtension.h +++ src/OFMessagePackExtension.h @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013 + * Jonathan Schleifer + * + * All rights reserved. + * + * This file is part of ObjFW. It may be distributed under the terms of the + * Q Public License 1.0, which can be found in the file LICENSE.QPL included in + * the packaging of this file. + * + * Alternatively, it may be distributed under the terms of the GNU General + * Public License, either version 2 or 3, which can be found in the file + * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this + * file. + */ + +#import "OFObject.h" +#import "OFMessagePackRepresentation.h" + +@class OFDataArray; + +/*! + * @brief A class for representing the MessagePack extension type. + */ +@interface OFMessagePackExtension: OFObject +{ + int8_t _type; + OFDataArray *_data; +} + +#ifdef OF_HAVE_PROPERTIES +@property (readonly) int8_t type; +@property (readonly, retain) OFDataArray *data; +#endif + +/*! + * @brief Creates a new OFMessagePackRepresentation with the specified type and + * data. + * + * @param type The MessagePack extension type + * @param data The data for the extension + * @return A new, autoreleased OFMessagePackRepresentation + */ ++ (instancetype)extensionWithType: (int8_t)type + data: (OFDataArray*)data; + +/*! + * @brief Initializes an already allocated OFMessagePackRepresentation with the + * specified type and data. + * + * @param type The MessagePack extension type + * @param data The data for the extension + * @return An initialized OFMessagePackRepresentation + */ +- initWithType: (int8_t)type + data: (OFDataArray*)data; + +/*! + * @brief Returns the MessagePack extension type. + * + * @return The MessagePack extension type + */ +- (int8_t)type; + +/*! + * @brief Returns the data of the extension. + * + * @return The data of the extension + */ +- (OFDataArray*)data; +@end ADDED src/OFMessagePackExtension.m Index: src/OFMessagePackExtension.m ================================================================== --- src/OFMessagePackExtension.m +++ src/OFMessagePackExtension.m @@ -0,0 +1,224 @@ +/* + * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013 + * Jonathan Schleifer + * + * All rights reserved. + * + * This file is part of ObjFW. It may be distributed under the terms of the + * Q Public License 1.0, which can be found in the file LICENSE.QPL included in + * the packaging of this file. + * + * Alternatively, it may be distributed under the terms of the GNU General + * Public License, either version 2 or 3, which can be found in the file + * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this + * file. + */ + +#include "config.h" + +#include + +#import "OFMessagePackExtension.h" +#import "OFDataArray.h" +#import "OFString.h" + +#import "OFInvalidArgumentException.h" + +#import "macros.h" + +@implementation OFMessagePackExtension ++ (instancetype)extensionWithType: (int8_t)type + data: (OFDataArray*)data +{ + return [[[self alloc] initWithType: type + data: data] autorelease]; +} + +- init +{ + @try { + [self doesNotRecognizeSelector: _cmd]; + } @catch (id e) { + [self release]; + @throw e; + } + + abort(); +} + +- initWithType: (int8_t)type + data: (OFDataArray*)data +{ + self = [super init]; + + @try { + if (data == nil || [data itemSize] != 1) + @throw [OFInvalidArgumentException + exceptionWithClass: [self class] + selector: _cmd]; + + _type = type; + _data = [data retain]; + } @catch (id e) { + [self release]; + @throw e; + } + + return self; +} + +- (void)dealloc +{ + [_data release]; + + [super dealloc]; +} + +- (int8_t)type +{ + return _type; +} + +- (OFDataArray*)data +{ + OF_GETTER(_data, true) +} + +- (OFDataArray*)messagePackRepresentation +{ + OFDataArray *ret; + int8_t prefix; + size_t count = [_data count]; + + if (count == 1) { + ret = [OFDataArray dataArrayWithCapacity: 3]; + + prefix = 0xD4; + [ret addItem: &prefix]; + + [ret addItem: &_type]; + } else if (count == 2) { + ret = [OFDataArray dataArrayWithCapacity: 4]; + + prefix = 0xD5; + [ret addItem: &prefix]; + + [ret addItem: &_type]; + } else if (count == 4) { + ret = [OFDataArray dataArrayWithCapacity: 6]; + + prefix = 0xD6; + [ret addItem: &prefix]; + + [ret addItem: &_type]; + } else if (count == 8) { + ret = [OFDataArray dataArrayWithCapacity: 10]; + + prefix = 0xD7; + [ret addItem: &prefix]; + + [ret addItem: &_type]; + } else if (count == 16) { + ret = [OFDataArray dataArrayWithCapacity: 18]; + + prefix = 0xD8; + [ret addItem: &prefix]; + + [ret addItem: &_type]; + } else if (count < 0x100) { + uint8_t length; + + ret = [OFDataArray dataArrayWithCapacity: count + 3]; + + prefix = 0xC7; + [ret addItem: &prefix]; + + length = (uint8_t)count; + [ret addItem: &length]; + + [ret addItem: &_type]; + } else if (count < 0x10000) { + uint16_t length; + + ret = [OFDataArray dataArrayWithCapacity: count + 4]; + + prefix = 0xC8; + [ret addItem: &prefix]; + + length = OF_BSWAP16((uint16_t)count); + [ret addItems: &length + count: 2]; + + [ret addItem: &_type]; + } else { + uint32_t length; + + ret = [OFDataArray dataArrayWithCapacity: count + 6]; + + prefix = 0xC9; + [ret addItem: &prefix]; + + length = OF_BSWAP32((uint32_t)count); + [ret addItems: &length + count: 4]; + + [ret addItem: &_type]; + } + + [ret addItems: [_data items] + count: [_data count]]; + + return ret; +} + +- (OFString*)description +{ + return [OFString stringWithFormat: @"", + _type, _data]; +} + +- (bool)isEqual: (id)object +{ + OFMessagePackExtension *extension; + + if (![object isKindOfClass: [OFMessagePackExtension class]]) + return false; + + extension = object; + + if (extension->_type != _type || ![extension->_data isEqual: _data]) + return false; + + return true; +} + +- (uint32_t)hash +{ + uint32_t hash; + + OF_HASH_INIT(hash); + + OF_HASH_ADD(hash, (uint8_t)_type); + OF_HASH_ADD_HASH(hash, [_data hash]); + + OF_HASH_FINALIZE(hash); + + return hash; +} + +- copy +{ + OFMessagePackExtension *ret; + OFDataArray *data; + + data = [_data copy]; + @try { + ret = [[OFMessagePackExtension alloc] initWithType: _type + data: data]; + } @finally { + [data release]; + } + + return ret; +} +@end Index: src/ObjFW.h ================================================================== --- src/ObjFW.h +++ src/ObjFW.h @@ -75,11 +75,11 @@ #import "OFXMLComment.h" #import "OFXMLProcessingInstructions.h" #import "OFXMLParser.h" #import "OFXMLElementBuilder.h" -#import "OFSerialization.h" +#import "OFMessagePackExtension.h" #import "OFApplication.h" #import "OFSystemInfo.h" #import "OFTimer.h" #import "OFRunLoop.h"