Index: src/Makefile ================================================================== --- src/Makefile +++ src/Makefile @@ -21,10 +21,11 @@ OFSocket.m \ OFStream.m \ OFString.m \ OFTCPSocket.m \ OFThread.m \ + OFURLEncoding.m \ OFXMLFactory.m \ ${ASPRINTF_C} INCLUDESTMP = ${SRCS:.c=.h} INCLUDES = ${INCLUDESTMP:.m=.h} \ Index: src/OFDictionary.h ================================================================== --- src/OFDictionary.h +++ src/OFDictionary.h @@ -85,5 +85,7 @@ * * \param hashsize The new hash size for the dictionary */ - changeHashSize: (int)hashsize; @end + +#import "OFIterator.h" Index: src/OFDictionary.m ================================================================== --- src/OFDictionary.m +++ src/OFDictionary.m @@ -17,11 +17,14 @@ #import "OFIterator.h" #import "OFExceptions.h" #import "OFMacros.h" /* Reference for static linking */ -void _reference_to_OFIterator_in_OFDictionary() { [OFIterator class]; } +void _reference_to_OFIterator_in_OFDictionary() +{ + _OFIterator_reference = 1; +} @implementation OFDictionary + dictionary; { return [[[OFDictionary alloc] init] autorelease]; Index: src/OFIterator.h ================================================================== --- src/OFIterator.h +++ src/OFIterator.h @@ -10,10 +10,12 @@ */ #import "OFObject.h" #import "OFList.h" #import "OFDictionary.h" + +extern int _OFIterator_reference; /** * The OFIterator class provides methods to iterate through objects. */ @interface OFIterator: OFObject Index: src/OFIterator.m ================================================================== --- src/OFIterator.m +++ src/OFIterator.m @@ -12,10 +12,13 @@ #import "config.h" #import "OFIterator.h" #import "OFDictionary.h" #import "OFExceptions.h" + +/* Reference for static linking */ +int _OFIterator_reference; @implementation OFIterator - initWithData: (OFList**)data_ andSize: (size_t)size_ { Index: src/OFString.h ================================================================== --- src/OFString.h +++ src/OFString.h @@ -160,5 +160,6 @@ - (OFArray*)splitWithDelimiter: (OFString*)delimiter; @end #import "OFConstString.h" #import "OFMutableString.h" +#import "OFURLEncoding.h" Index: src/OFString.m ================================================================== --- src/OFString.m +++ src/OFString.m @@ -15,12 +15,19 @@ #include #include #import "OFString.h" #import "OFAutoreleasePool.h" +#import "OFURLEncoding.h" #import "OFExceptions.h" #import "OFMacros.h" + +/* Reference for static linking */ +void _reference_to_OFURLEncoding_in_OFString() +{ + _OFURLEncoding_reference = 1; +}; @implementation OFString + string { return [[[OFMutableString alloc] init] autorelease]; ADDED src/OFURLEncoding.h Index: src/OFURLEncoding.h ================================================================== --- src/OFURLEncoding.h +++ src/OFURLEncoding.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2008 - 2009 + * Jonathan Schleifer + * + * All rights reserved. + * + * This file is part of libobjfw. It may be distributed under the terms of the + * Q Public License 1.0, which can be found in the file LICENSE included in + * the packaging of this file. + */ + +#import "OFMutableString.h" + +extern int _OFURLEncoding_reference; + +/** + * The OFURLEncoding category provides an easy way to encode and decode strings + * for URLs. + */ +@interface OFString (OFURLEncoding) +/** + * Encodes a string for use in a URL. + * + * \return A new, autoreleased string + */ +- (OFString*)urlencode; + +/** + * Decodes a string used in a URL. + * + * \return A new, autoreleased string + */ +- (OFString*)urldecode; +@end ADDED src/OFURLEncoding.m Index: src/OFURLEncoding.m ================================================================== --- src/OFURLEncoding.m +++ src/OFURLEncoding.m @@ -0,0 +1,126 @@ +/* + * Copyright (c) 2008 - 2009 + * Jonathan Schleifer + * + * All rights reserved. + * + * This file is part of libobjfw. It may be distributed under the terms of the + * Q Public License 1.0, which can be found in the file LICENSE included in + * the packaging of this file. + */ + +#import "config.h" + +#include +#include +#include +#include + +#import "OFURLEncoding.h" +#import "OFExceptions.h" + +/* Reference for static linking */ +int _OFURLEncoding_reference; + +@implementation OFString (OFURLEncoding) +- (OFString*)urlencode +{ + const char *s; + char *ret_c; + size_t i; + OFString *ret; + + s = string; + + /* + * Worst case: 3 times longer than before. + * Oh, and we can't use [self allocWithSize:] here as self might be a + * @"" literal. + */ + if ((ret_c = malloc((length * 3) + 1)) == NULL) + @throw [OFNoMemException newWithClass: isa + andSize: (length * 3) + 1]; + + for (i = 0; *s != '\0'; s++) { + if (isalnum(*s) || *s == '-' || *s == '_' || *s == '.') + ret_c[i++] = *s; + else { + char buf[3]; + snprintf(buf, 3, "%02X", *s); + ret_c[i++] = '%'; + ret_c[i++] = buf[0]; + ret_c[i++] = buf[1]; + } + } + ret_c[i] = '\0'; + + @try { + ret = [OFString stringWithCString: ret_c]; + } @finally { + free(ret_c); + } + + return ret; +} + +- (OFString*)urldecode +{ + const char *s; + char *ret_c, c; + size_t i; + int st; + OFString *ret; + + s = string; + + if ((ret_c = malloc(length + 1)) == NULL) + @throw [OFNoMemException newWithClass: isa + andSize: length + 1]; + + for (st = 0, i = 0, c = 0; *s; s++) { + switch (st) { + case 0: + if (*s == '%') + st = 1; + else + ret_c[i++] = *s; + break; + case 1: + case 2: + if (*s >= '0' && *s <= '9') + c += (*s - '0') * (st == 1 ? 16 : 1); + else if (*s >= 'A' && *s <= 'F') + c += (*s - 'A' + 10) * (st == 1 ? 16 : 1); + else if (*s >= 'a' && *s <= 'f') + c += (*s - 'a' + 10) * (st == 1 ? 16 : 1); + else { + free(ret_c); + @throw [OFInvalidEncodingException + newWithClass: isa]; + } + + if (++st == 3) { + ret_c[i++] = c; + st = 0; + c = 0; + } + + break; + } + } + ret_c[i] = '\0'; + + if (st) { + free(ret_c); + @throw [OFInvalidEncodingException newWithClass: isa]; + } + + @try { + ret = [OFString stringWithCString: ret_c]; + } @finally { + free(ret_c); + } + + return ret; +} +@end Index: tests/OFDictionary/OFDictionary.m ================================================================== --- tests/OFDictionary/OFDictionary.m +++ tests/OFDictionary/OFDictionary.m @@ -14,11 +14,10 @@ #include #include #import "OFAutoreleasePool.h" #import "OFDictionary.h" -#import "OFIterator.h" #import "OFString.h" #import "OFExceptions.h" int main() Index: tests/OFString/OFString.m ================================================================== --- tests/OFString/OFString.m +++ tests/OFString/OFString.m @@ -23,11 +23,11 @@ #define ZD "%zd" #else #define ZD "%u" #endif -#define NUM_TESTS 21 +#define NUM_TESTS 25 #define SUCCESS \ printf("\r\033[1;%dmTests successful: " ZD "/%d\033[0m", \ (i == NUM_TESTS - 1 ? 32 : 33), i + 1, NUM_TESTS); \ fflush(stdout); #define FAIL \ @@ -107,9 +107,14 @@ CHECK([[a object: j++] isEqual: @""]) CHECK([[a object: j++] isEqual: @"baz"]) CHECK([[a object: j++] isEqual: @""]) CHECK([[a object: j++] isEqual: @""]) + CHECK([[@"foo\"ba'_$" urlencode] isEqual: @"foo%22ba%27_%24"]) + CHECK([[@"foo%20bar%22%24" urldecode] isEqual: @"foo bar\"$"]) + CHECK_EXCEPT([@"foo%bar" urldecode], OFInvalidEncodingException) + CHECK_EXCEPT([@"foo%FFbar" urldecode], OFInvalidEncodingException) + puts(""); return 0; }