]> err.no Git - sope/blob - sope-appserver/NGObjWeb/NGHttp/NGUrlFormCoder.m
increased element nesting depth
[sope] / sope-appserver / NGObjWeb / NGHttp / NGUrlFormCoder.m
1 /*
2   Copyright (C) 2000-2005 SKYRIX Software AG
3
4   This file is part of SOPE.
5
6   SOPE is free software; you can redistribute it and/or modify it under
7   the terms of the GNU Lesser General Public License as published by the
8   Free Software Foundation; either version 2, or (at your option) any
9   later version.
10
11   SOPE is distributed in the hope that it will be useful, but WITHOUT ANY
12   WARRANTY; without even the implied warranty of MERCHANTABILITY or
13   FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
14   License for more details.
15
16   You should have received a copy of the GNU Lesser General Public
17   License along with SOPE; see the file COPYING.  If not, write to the
18   Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
19   02111-1307, USA.
20 */
21
22 #include "NGUrlFormCoder.h"
23 #include "common.h"
24
25 #if !LIB_FOUNDATION_LIBRARY
26 static BOOL debugDecoding = NO;
27 #endif
28
29 static __inline__ int _valueOfHexChar(unsigned char _c) {
30   switch (_c) {
31     case '0': case '1': case '2': case '3': case '4':
32     case '5': case '6': case '7': case '8': case '9':
33       return (_c - 48); // 0-9 (ascii-char)'0' - 48 => (int)0
34       
35     case 'A': case 'B': case 'C':
36     case 'D': case 'E': case 'F':
37       return (_c - 55); // A-F, A=10..F=15, 'A'=65..'F'=70
38       
39     case 'a': case 'b': case 'c':
40     case 'd': case 'e': case 'f':
41       return (_c - 87); // a-f, a=10..F=15, 'a'=97..'f'=102
42
43     default:
44       return -1;
45   }
46 }
47
48 static __inline__ unsigned
49 _unescapeUrl(const char *_src, unsigned _len, char *_dest) 
50 {
51   register unsigned i, i2;
52
53   for (i = 0, i2 = 0; i < _len; i++, i2++) {
54     register char c = _src[i];
55     
56     switch (c) {
57       case '+': // encoded space
58         _dest[i2] = ' ';
59         break;
60           
61       case '%': // encoded hex ('%FF')
62         _dest[i2] = _valueOfHexChar(_src[i + 1]) * 16 +
63           _valueOfHexChar(_src[i + 2]);
64         i += 2; // skip the two hexchars
65         break;
66
67       default:  // normal char
68         _dest[i2] = c;
69         break;
70     }
71   }
72   return i2; // return unescaped length
73 }
74
75 static Class StrClass = Nil;
76
77 static __inline__ NSString *urlStringFromBuffer(const unsigned char *buffer,
78                                                 unsigned len)
79 {
80   // TODO: we assume ISO-Latin-1/Unicode encoding, which might be wrong
81 #if LIB_FOUNDATION_LIBRARY
82   return [[StrClass alloc] initWithCString:buffer length:len];
83 #else
84   register signed int i;
85   unichar  *s;
86   NSString *value;
87   
88   s = malloc((len + 2) * sizeof(unichar));
89   for (i = len - 1; i >= 0; i--)
90     s[i] = buffer[i];
91   value = [[StrClass alloc] initWithCharacters:s length:len];
92   if (s != NULL) free(s);
93   
94   if (debugDecoding) {
95     NSLog(@"decoded data len %d value (len=%d): %@", 
96           len, [value length], value);
97   }
98   return value;
99 #endif
100 }
101
102 NGHashMap *NGDecodeUrlFormParameters(const unsigned char *_buffer,
103                                      unsigned _len)
104 {
105   NGMutableHashMap *dict = nil;
106   unsigned pos = 0;
107   
108   if (_len == 0) return nil;
109   
110   if (StrClass == Nil) StrClass = [NSString class];
111   dict = [[NGMutableHashMap alloc] initWithCapacity:16];
112
113   do {
114     NSString *key = nil, *value = nil;
115     unsigned tmp, len;
116     char     buffer[_len];
117
118     /* read key */
119     tmp = pos;
120     while ((pos < _len) && (_buffer[pos] != '='))
121       pos++;
122
123     len = _unescapeUrl(&(_buffer[tmp]), (pos - tmp), buffer);
124     key = len > 0 ? urlStringFromBuffer(buffer, len) : @"";
125     
126     if (pos < _len) { // value pending
127       NSCAssert(_buffer[pos] == '=', @"invalid parser state ..");
128       pos++; // skip '='
129
130       /* read value */
131       tmp = pos;
132       while ((pos < _len) && (_buffer[pos] != '&') && (_buffer[pos] != '?')) {
133         pos++;
134       }
135       
136       len   = _unescapeUrl(&(_buffer[tmp]), (pos - tmp), buffer);
137       value = len > 0 ? urlStringFromBuffer(buffer, len) : @"";
138       
139       // skip '&'
140       if (_buffer[pos] == '&' || _buffer[pos] == '?') pos++;
141     }
142     
143     if (value == nil)
144       value = @"";
145
146     /* store in dictionary */
147     if (key)
148       [dict addObject:value forKey:key];
149
150     [key   release]; key   = nil;
151     [value release]; value = nil;
152   }
153   while (pos < _len);
154
155   return dict;
156 }
157
158 @implementation NSString(FormURLCoding)
159
160 - (NSString *)stringByApplyingURLEncoding {
161   /* NGExtensions/NSString+misc.h */
162   NSLog(@"Note: Called deprecated -stringByApplyingURLEncoding method "
163         @"(use -stringByEscapingURL instead)", __PRETTY_FUNCTION__);
164   return [self stringByEscapingURL];
165 }
166
167 @end /* NSString(FormURLCoding) */