/* * Copyright (c) 2008 - 2009 * Jonathan Schleifer <js@webkeks.org> * * 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. */ #include "config.h" #include <stdio.h> #include <stdlib.h> #include <string.h> #include <ctype.h> #import "OFURLEncoding.h" #import "OFExceptions.h" /* Reference for static linking */ int _OFURLEncoding_reference; @implementation OFString (OFURLEncoding) - (OFString*)urlEncodedString { 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 [OFOutOfMemoryException 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*)urlDecodedString { const char *s; char *ret_c, c; size_t i; int st; OFString *ret; s = string; if ((ret_c = malloc(length + 1)) == NULL) @throw [OFOutOfMemoryException 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