// =========================================================================== // $Id: UrlEncoded.java,v 1.15.2.10 2003/06/04 04:48:00 starksm Exp $ package org.mortbay.util; import java.io.UnsupportedEncodingException; import java.util.Iterator; import java.util.Map; /* ------------------------------------------------------------ */ /** Handles coding of MIME "x-www-form-urlencoded". * This class handles the encoding and decoding for either * the query string of a URL or the content of a POST HTTP request. * *

Notes

* The hashtable either contains String single values, vectors * of String or arrays of Strings. * * This class is only partially synchronised. In particular, simple * get operations are not protected from concurrent updates. * * @see java.net.URLEncoder * @version $Id: UrlEncoded.java,v 1.15.2.10 2003/06/04 04:48:00 starksm Exp $ * @author Greg Wilkins (gregw) */ public class UrlEncoded extends MultiMap { /* ----------------------------------------------------------------- */ public UrlEncoded(UrlEncoded url) { super(url); } /* ----------------------------------------------------------------- */ public UrlEncoded() { super(6); } /* ----------------------------------------------------------------- */ public UrlEncoded(String s) { super(6); decode(s,StringUtil.__ISO_8859_1); } /* ----------------------------------------------------------------- */ public UrlEncoded(String s, String charset) { super(6); decode(s,charset); } /* ----------------------------------------------------------------- */ public void decode(String query) { decodeTo(query,this,StringUtil.__ISO_8859_1); } /* ----------------------------------------------------------------- */ public void decode(String query,String charset) { decodeTo(query,this,charset); } /* -------------------------------------------------------------- */ /** Encode Hashtable with % encoding. */ public String encode() { return encode(StringUtil.__ISO_8859_1,false); } /* -------------------------------------------------------------- */ /** Encode Hashtable with % encoding. */ public String encode(String charset) { return encode(charset,false); } /* -------------------------------------------------------------- */ /** Encode Hashtable with % encoding. * @param equalsForNullValue if True, then an '=' is always used, even * for parameters without a value. e.g. "blah?a=&b=&c=". */ public synchronized String encode(String charset, boolean equalsForNullValue) { if (charset==null) charset=StringUtil.__ISO_8859_1; StringBuffer result = new StringBuffer(128); synchronized(result) { Iterator iter = entrySet().iterator(); while(iter.hasNext()) { Map.Entry entry = (Map.Entry)iter.next(); String key = entry.getKey().toString(); Object list = entry.getValue(); int s=LazyList.size(list); if (s==0) { result.append(encodeString(key,charset)); if(equalsForNullValue) result.append('='); } else { for (int i=0;i0) result.append('&'); Object val=LazyList.get(list,i); result.append(encodeString(key,charset)); if (val!=null) { String str=val.toString(); if (str.length()>0) { result.append('='); result.append(encodeString(str,charset)); } else if (equalsForNullValue) result.append('='); } else if (equalsForNullValue) result.append('='); } } if (iter.hasNext()) result.append('&'); } return result.toString(); } } /* -------------------------------------------------------------- */ /* Decoded parameters to Map. * @param content the string containing the encoded parameters * @param url The dictionary to add the parameters to */ public static void decodeTo(String content,MultiMap map) { decodeTo(content,map,StringUtil.__ISO_8859_1); } /* -------------------------------------------------------------- */ /** Decoded parameters to Map. * @param content the string containing the encoded parameters */ public static void decodeTo(String content, MultiMap map, String charset) { if (charset==null) charset=StringUtil.__ISO_8859_1; synchronized(map) { String key = null; String value = null; int mark=-1; boolean encoded=false; for (int i=0;i0xff) throw new IllegalArgumentException("Not decoded"); if (c=='+') { if (buf==null) { buf=new StringBuffer(length); for (int j=0;j0) { try {buf.append(new String(bytes,0,n,charset));} catch(UnsupportedEncodingException e) {buf.append(new String(bytes,0,n));} n=0; } buf.append(' '); } else if (c=='%' && (i+2)='a' && cn<='z') b=(byte)(10+cn-'a'); else if (cn>='A' && cn<='Z') b=(byte)(10+cn-'A'); else b=(byte)(cn-'0'); cn = encoded.charAt(offset+i+2); if (cn>='a' && cn<='z') b=(byte)(b*16+10+cn-'a'); else if (cn>='A' && cn<='Z') b=(byte)(b*16+10+cn-'A'); else b=(byte)(b*16+cn-'0'); if (buf==null) { buf=new StringBuffer(length); for (int j=0;j0) { try {buf.append(new String(bytes,0,n,charset));} catch(UnsupportedEncodingException e) {buf.append(new String(bytes,0,n));} n=0; } buf.append(c); } } if (buf==null) { if (offset==0 && encoded.length()==length) return encoded; return encoded.substring(offset,offset+length); } if (n>0) { try {buf.append(new String(bytes,0,n,charset));} catch(UnsupportedEncodingException e) {buf.append(new String(bytes,0,n));} } return buf.toString(); } /* ------------------------------------------------------------ */ /** Perform URL encoding. * Assumes 8859 charset * @param string * @return encoded string. */ public static String encodeString(String string) { return encodeString(string,StringUtil.__ISO_8859_1); } /* ------------------------------------------------------------ */ /** Perform URL encoding. * @param string * @return encoded string. */ public static String encodeString(String string,String charset) { if (charset==null) charset=StringUtil.__ISO_8859_1; byte[] bytes=null; try { bytes=string.getBytes(charset); } catch(UnsupportedEncodingException e) { Code.warning(e); bytes=string.getBytes(); } int len=bytes.length; byte[] encoded= new byte[bytes.length*3]; int n=0; boolean noEncode=true; for (int i=0;i='a' && b<='z' || b>='A' && b<='Z' || b>='0' && b<='9') { encoded[n++]=b; } else { noEncode=false; encoded[n++]=(byte)'%'; byte nibble= (byte) ((b&0xf0)>>4); if (nibble>=10) encoded[n++]=(byte)('A'+nibble-10); else encoded[n++]=(byte)('0'+nibble); nibble= (byte) (b&0xf); if (nibble>=10) encoded[n++]=(byte)('A'+nibble-10); else encoded[n++]=(byte)('0'+nibble); } } if (noEncode) return string; try { return new String(encoded,0,n,charset); } catch(UnsupportedEncodingException e) { Code.warning(e); return new String(encoded,0,n); } } /* ------------------------------------------------------------ */ /** */ public Object clone() { return new UrlEncoded(this); } }