/* Copyright (C) 2000-2003 SKYRIX Software AG This file is part of OGo OGo is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. OGo is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with OGo; see the file COPYING. If not, write to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ // $Id$ #import "common.h" #import "NGUrlFormCoder.h" static inline BOOL isURLSafeChar(unsigned char _c) { if ((_c > 64) && (_c < 91)) return YES; if ((_c > 96) && (_c < 123)) return YES; if (_c == 95) return YES; if ((_c > 47) && (_c < 58)) return YES; return NO; } static inline int _valueOfHexChar(unsigned char _c) { switch (_c) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': return (_c - 48); // 0-9 (ascii-char)'0' - 48 => (int)0 case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': return (_c - 55); // A-F, A=10..F=15, 'A'=65..'F'=70 case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': return (_c - 87); // a-f, a=10..F=15, 'a'=97..'f'=102 default: return -1; } } static inline unsigned _unescapeUrl(const char *_src, unsigned _len, char *_dest) { register unsigned i, i2; for (i = 0, i2 = 0; i < _len; i++, i2++) { register char c = _src[i]; switch (c) { case '+': // encoded space _dest[i2] = ' '; break; case '%': // encoded hex ('%FF') _dest[i2] = _valueOfHexChar(_src[i + 1]) * 16 + _valueOfHexChar(_src[i + 2]); i += 2; // skip the two hexchars break; default: // normal char _dest[i2] = c; break; } } return i2; // return unescaped length } NGHashMap *NGDecodeUrlFormParameters(const char *_buffer, unsigned _len) { Class StrClass = [NSString class]; NGMutableHashMap *dict = nil; unsigned pos = 0; if (_len == 0) return nil; dict = [[NGMutableHashMap alloc] initWithCapacity:16]; do { NSString *key = nil, *value = nil; unsigned tmp, len; char buffer[_len]; /* read key */ tmp = pos; while ((pos < _len) && (_buffer[pos] != '=')) pos++; len = _unescapeUrl(&(_buffer[tmp]), (pos - tmp), buffer); if (len > 0) { key = [[StrClass allocWithZone:[dict zone]] initWithCString:buffer length:len]; } else key = @""; //NSLog(@"read key %@", key); if (pos < _len) { // value pending NSCAssert(_buffer[pos] == '=', @"invalid parser state .."); pos++; // skip '=' /* read value */ tmp = pos; while ((pos < _len) && (_buffer[pos] != '&') && (_buffer[pos] != '?')) { pos++; } len = _unescapeUrl(&(_buffer[tmp]), (pos - tmp), buffer); if (len > 0) { value = [[StrClass allocWithZone:[dict zone]] initWithCString:buffer length:len]; } else value = @""; //NSLog(@"read value: %@", value); // skip '&' if (_buffer[pos] == '&' || _buffer[pos] == '?') pos++; } if (value == nil) value = @""; /* store in dictionary */ if (key) [dict addObject:value forKey:key]; RELEASE(key); key = nil; RELEASE(value); value = nil; } while (pos < _len); return dict; } @implementation NSString(FormURLCoding) - (NSString *)stringByApplyingURLEncoding { #if 1 /* NGExtensions/NSString+misc.h */ return [self stringByEscapingURL]; #else char *buf, *encBuf; unsigned clen, i, j; if ((clen = [self cStringLength]) == 0) return self; buf = malloc(clen + 1); [self getCString:buf]; buf[clen] = '\0'; encBuf = malloc(clen * 3 + 1); for (i = 0, j = 0; i < clen; i++) { register unsigned char c = buf[i]; if (isURLSafeChar(c)) { encBuf[j] = c; j++; } else if (c == ' ') { encBuf[j] = '+'; j++; } else { sprintf(&(encBuf[j]), "%%%02X", (int)c); j += 3; } } return [NSString stringWithCString:encBuf length:j]; /* was buggy, does not release encbuf .. */ #endif } @end /* NSString(FormURLCoding) */