Source code: com/tripi/asp/util/Tools.java
1 /**
2 * ArrowHead ASP Server
3 * This is a source file for the ArrowHead ASP Server - an 100% Java
4 * VBScript interpreter and ASP server.
5 *
6 * For more information, see http://www.tripi.com/arrowhead
7 *
8 * Copyright (C) 2002 Terence Haddock
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 *
24 */
25 package com.tripi.asp.util;
26
27 import java.util.ArrayList;
28 import java.util.Enumeration;
29 import java.util.HashMap;
30 import java.util.Iterator;
31 import java.util.List;
32 import java.util.Map;
33 import java.util.Vector;
34
35 import jregex.Pattern;
36
37 import org.apache.log4j.Category;
38
39 import com.tripi.asp.AspCollection;
40 import com.tripi.asp.AspException;
41 import com.tripi.asp.AspNestedException;
42 import com.tripi.asp.AspReadOnlyException;
43 import com.tripi.asp.Constants;
44 import com.tripi.asp.SimpleMap;
45 import com.tripi.asp.SimpleReference;
46 import com.tripi.asp.Types;
47 import com.tripi.asp.UndefinedValueNode;
48
49 public class Tools
50 {
51 /** Debugging category */
52 private static Category DBG = Category.getInstance(Tools.class);
53
54 /**
55 * This function parses a query string. The keys and values
56 * are left un-decoded so post-processing can occur.
57 * @param queryString query string to parse
58 * @return map of key -> list of values
59 */
60 public static Map parseQueryString(String queryString)
61 {
62 if (DBG.isDebugEnabled())
63 {
64 DBG.debug("Parse: " + queryString);
65 try {
66 String testString = new String(
67 queryString.getBytes("ISO8859-1"), "UTF-8");
68 DBG.debug("Test: " + testString);
69 } catch (Exception ex) {
70 DBG.error(ex);
71 }
72 }
73 HashMap map = new HashMap();
74 if (queryString == null) return map;
75
76 final Pattern tokP = new Pattern("&");
77 String[] arr=tokP.tokenizer(queryString).split();
78 for (int i =0; i < arr.length; i++)
79 {
80 String paramValue = arr[i];
81 if (DBG.isDebugEnabled()) {
82 DBG.debug("ParamValue: " + paramValue);
83 }
84 int eqIndex = paramValue.indexOf('=');
85 String param, value;
86 if (eqIndex == -1) {
87 param = paramValue;
88 value = "";
89 } else {
90 param = paramValue.substring(0, eqIndex);
91 value = paramValue.substring(eqIndex + 1);
92 }
93
94 if (DBG.isDebugEnabled()) {
95 DBG.debug("Param: " + param);
96 DBG.debug("Value: " + value);
97 }
98 if (map.containsKey(param)) {
99 List oldValue = (List)map.get(param);
100 oldValue.add(value);
101 } else {
102 List theList = new ArrayList();
103 theList.add(value);
104 map.put(param, theList);
105 }
106 }
107 return map;
108 }
109
110 private static String fixValue(String value, boolean bDecode)
111 throws AspException
112 {
113 String retValue;
114 if (bDecode)
115 {
116 retValue = urlDecode(value);
117 } else {
118 retValue = value;
119 }
120 if (DBG.isDebugEnabled()) DBG.debug("Decoding value: " + retValue);
121 try {
122 retValue = new String(retValue.getBytes("ISO8859-1"), "UTF-8");
123 } catch (Exception ex)
124 {
125 throw new AspNestedException(ex);
126 }
127 if (DBG.isDebugEnabled()) DBG.debug("Value: " + retValue);
128 return retValue;
129 }
130
131 private static void testFixValue(String value)
132 {
133 try {
134 String testString = new String(
135 value.getBytes("ISO8859-1"), "UTF-8");
136 DBG.debug("Value: " + value);
137 DBG.debug("Value(UTF-8): " + testString);
138 } catch (Exception ex) {
139 DBG.error(ex);
140 }
141 }
142
143 public static void convertToMultiValue(AspCollection contents,
144 Map paramValues, boolean bDecodeValues) throws AspException
145 {
146 Iterator e = paramValues.keySet().iterator();
147 while (e.hasNext())
148 {
149 String key = (String)e.next();
150 Object valuesObj = paramValues.get(key);
151 String keyDec = fixValue(key, bDecodeValues);
152
153 Object contentsValue = contents.get(keyDec);
154 if (contentsValue instanceof UndefinedValueNode)
155 {
156 MultiValue multiValue = new MultiValue();
157 contents.put(keyDec, multiValue);
158 contentsValue = multiValue;
159 }
160 if (valuesObj instanceof List)
161 {
162 List values = (List)valuesObj;
163 for (int i = 0; i < values.size(); i++)
164 {
165 String value = (String)values.get(i);
166 String valDec = fixValue(value, bDecodeValues);
167
168 ((MultiValue)contentsValue).add(valDec);
169 }
170 } else if (valuesObj instanceof String[])
171 {
172 String values[] = (String[])valuesObj;
173 for (int i = 0; i < values.length; i++)
174 {
175 String valDec = fixValue(values[i], bDecodeValues);
176
177 ((MultiValue)contentsValue).add(valDec);
178 }
179 } else {
180 String valDec = fixValue(valuesObj.toString(), bDecodeValues);
181
182 ((MultiValue)contentsValue).add(valDec);
183 }
184 }
185 }
186
187 public static boolean isHex(char ch)
188 {
189 if ((ch >= '0') && (ch <= '9')) return true;
190 if ((ch >= 'a') && (ch <= 'f')) return true;
191 if ((ch >= 'A') && (ch <= 'F')) return true;
192 return false;
193 }
194
195 public static String urlDecode(String paramsEncoded)
196 {
197 StringBuffer str = new StringBuffer();
198 int i = 0;
199
200 while (i < paramsEncoded.length())
201 {
202 if (paramsEncoded.charAt(i)=='%') {
203 if (paramsEncoded.length()<(i+3)) {
204 str.append(paramsEncoded.charAt(i));
205 } else {
206 String hexStr = paramsEncoded.substring(i+1, i+3);
207 if (isHex(hexStr.charAt(0)) && isHex(hexStr.charAt(1)))
208 {
209 char chVal = (char)Integer.parseInt(hexStr, 16);
210 str.append(chVal);
211 i+=2;
212 } else {
213 str.append(paramsEncoded.charAt(i));
214 }
215 }
216 } else if (paramsEncoded.charAt(i)=='+') {
217 str.append(' ');
218 } else {
219 str.append(paramsEncoded.charAt(i));
220 }
221 i++;
222 }
223 return str.toString();
224 }
225
226
227 /**
228 * MultiValue is a class which can store multiple values for
229 * a single object.
230 */
231 public static class MultiValue implements SimpleReference, SimpleMap
232 {
233 /** List of values */
234 Vector values;
235
236 /** String representation of the whole list */
237 String wholeValue;
238
239 /** count of items in the array of values, publically
240 accessible to the ASP code. */
241 public int count;
242
243 /**
244 * Constructor, initially created with no values.
245 */
246 public MultiValue()
247 {
248 values = new Vector();
249 wholeValue = "";
250 count = 0;
251 }
252
253 /**
254 * Adds a value to this multiple value list.
255 * @param value New value to add.
256 */
257 void add(String value)
258 {
259 values.add(value);
260 if (!wholeValue.equals("")) wholeValue += ", ";
261 wholeValue+=value;
262 count++;
263 }
264
265 /**
266 * Obtains the list of keys for this multi value.
267 * This function is used in the For Each ... statement.
268 * @return Enumeration of values in this multi value.
269 * @see SimpleMap#getKeys
270 */
271 public Enumeration getKeys()
272 {
273 return values.elements();
274 }
275
276 /**
277 * SimpleMap read function to obtain a multi value at
278 * the specified index. <b>TODO</b> 1-based or 0-based?
279 * @param value key of multi value to obtain, will
280 * be converted to integer.
281 * @return value at the specified index.
282 * @throws AspException on error, mosting array index out of bounds.
283 * @see SimpleMap#get
284 */
285 public Object get(Object value) throws AspException
286 {
287 int iVal = Types.coerceToInteger(value).intValue();
288 if (iVal < 1 || iVal > count) {
289 throw new AspException("Array index out of bound: " + iVal);
290 }
291 return values.get(iVal - 1);
292 }
293
294 /**
295 * SimpleMap write function to store a value at a specified
296 * index. This function always throws AspReadOnlyException
297 * since Request.QueryString(i) is read-only.
298 * @param key Key of object to store.
299 * @param value Value of object to store.
300 * @throws AspException always throws AspReadOnlyException
301 * @see SimpleMap#put
302 */
303 public void put(Object key, Object value) throws AspException
304 {
305 throw new AspReadOnlyException("Request.QueryString");
306 }
307
308 /**
309 * SimpleReference method to obtain the first value of this
310 * multi value list.
311 * @return first value of this multi value list.
312 * @throws AspException on error
313 * @see SimpleReference#getValue
314 */
315 public Object getValue() throws AspException
316 {
317 if (values.size()==0)
318 return Constants.undefinedValueNode;
319 return wholeValue;
320 }
321
322 /**
323 * SimpleReference method to set the value of this multi value
324 * list. Always throws AspReadOnlyException
325 * @param obj New value
326 * @throws AspException always throws AspReadOnlyException
327 */
328 public void setValue(Object obj) throws AspException
329 {
330 throw new AspReadOnlyException("Request.QueryString");
331 }
332
333 /**
334 * Converts this multi value class to string, for debugging.
335 * @return string value of this query string value class
336 */
337 public String toString()
338 {
339 return "{MultiValue(" + values + ")}";
340 }
341 }
342 }
343