/* * `gnu.iou' * Copyright (C) 2006 John Pritchard. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License, or (at your option) any later version. * * This program 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 * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA * 02111-1307 USA */ package gnu.iou; /** * <p> Handling code <code>application/x-www-form-urlencoded</code> </p> * * @author John Pritchard (john@syntelos.org) */ public abstract class url { public final static String decode( String source){ if (null == source) return null; else return decode( source, source.toCharArray(), 0, source.length()); } public final static String decode( char[] source, int ofs, int many){ if (null == source || 0 > ofs || 1 > many) return null; else return decode( null, source, ofs, many); } /** * @param origin Possibly non- null origin of the character array * source, can be returned if the character array source has * nothing to decode * @param source Must be non- null * @param ofs Must be valid * @param many Must be valid */ public final static String decode( String origin, char[] source, int ofs, int many){ chbuf re = new chbuf(many); char ch; for (int cc = ofs, len = (ofs+many); cc < len; cc++){ ch = source[cc]; if ( '%' == ch){ cc += 1; if (cc < len && (cc+1) < len) re.append( char_decode( source, cc)); cc += 1; } else re.append(ch); } if (null != origin && re.length() == origin.length()) return origin; else return re.toString(); } public final static String encode( String source){ if (null == source) return null; else return encode( source, source.toCharArray(), 0, source.length()); } public final static String encode( char[] source, int ofs, int many){ if (null == source || 0 > ofs || 1 > many) return null; else return encode( null, source, ofs, many); } /** * @param origin Possibly non- null origin of the character array * source, can be returned if the character array source has * nothing to encode * @param source Must be non- null * @param ofs Must be valid * @param many Must be valid * @return Encode everything but the set of alpha numeric ASCII characters */ public final static String encode( String origin, char[] source, int ofs, int many){ chbuf re = new chbuf(many); char ch; char[] encbuf = new char[3]; enc: for (int cc = ofs, len = (ofs+many); cc < len; cc++){ ch = source[cc]; switch(ch){ case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'g': case 'h': case 'i': case 'j': case 'k': case 'l': case 'm': case 'n': case 'o': case 'p': case 'q': case 'r': case 's': case 't': case 'u': case 'v': case 'w': case 'x': case 'y': case 'z': case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G': case 'H': case 'I': case 'J': case 'K': case 'L': case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R': case 'S': case 'T': case 'U': case 'V': case 'W': case 'X': case 'Y': case 'Z': case '.': case '/': case '-': case '_': re.append(ch); continue enc; default: char_encode(ch,encbuf,0); re.append(encbuf,0,3); continue enc; } } if (null != origin && re.length() == origin.length()) return origin; else return re.toString(); } /** * Two ASCII hex digits into one character value * @param cary Character array source of two (ASCII) hex digits * must not be null. Accepts <code>ofs</code> pointing to '%', or * to the first hex char. * @param ofs Offset into character array source for two (ASCII) * hex digits must be valid, length for this offset and one more * must be valid. */ public final static char char_decode( char[] cary, int ofs){ int many = ((null != cary)?(cary.length):(0)); boolean fin = false; if ( 0 > ofs) ofs = 0; char re = (char)0; int ch; parse: for ( int cc = ofs, len = many; cc < len; cc++){ ch = cary[cc]; switch(ch){ case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': if (fin){ re += (char)(ch-'0'); return re; } else { fin = true; re += (char)((ch-'0')<<4); continue parse; } case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': if (fin){ re += (char)((ch-'a')+10); return re; } else { fin = true; re += (char)(((ch-'a')+10)<<4); continue parse; } case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': if (fin){ re += (char)((ch-'A')+10); return re; } else { fin = true; re += (char)(((ch-'A')+10)<<4); continue parse; } case '%': continue parse; default: break parse; } } throw new IllegalArgumentException(String.valueOf(ofs)); } private final static char[] hexchars = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' }; /** * @param ch Character value to encode into <code>'%'</code> and two hex digits * @param target Character array for hex digits * @param ofs Offset into character array for three characters must * be valid, and array length for one more offset must be valid */ public final static void char_encode( char ch, char[] target, int ofs){ int value = ch; target[ofs++] = '%'; target[ofs++] = hexchars[(value>>4)&0xf]; target[ofs] = hexchars[(value&0xf)]; return; } /** * <p> Parse query string into map. </p> */ public final static objmap querystring( String query){ return querystring(null,query); } /** * <p> Parse query string into map. </p> */ public final static objmap querystring( objmap dict, String query){ if (null == query) return dict; else { char[] string = query.toCharArray(); int string_len = string.length; if (1 > string_len) return dict; else { if (null == dict) dict = new objmap(); // int idx = 0; String name = null, value = null; for (int scan = 0; scan < string_len; scan++){ switch(string[scan]){ case '&': value = new java.lang.String(string,idx,(scan-idx)); idx = (scan+1); dict.put(name,value); name = null; value = null; break; case '=': name = new java.lang.String(string,idx,(scan-idx)); idx = (scan+1); break; default: break; } } /* * Tail case */ if (0 < idx && null != name){ value = new java.lang.String(string,idx,(string_len-idx)); dict.put(name,value); } return dict; } } } }