package utils;
import java.io.*;
import java.util.*;
import javax.servlet.*;
public class MultipartFormReader
{
private final int READY = 0;
private final int FILENAME = 1;
private final int NAME = 2;
private final int BINDATA = 3;
private final int TXTDATA = 4;
public MultipartFormReader() {;}
/**
* Parses the ServletInputStream of encoding multipart/form-data and separates it into name value pairs. The name-value pairs
* are stored in the map
argument. There are a couple of this to be aware of. This class is not a replacement for
* the ServletRequest class but augments it. It should only be used in the case where the client is issuing an HTTP POST request
* and the form-encoding is multipart/form-data.
*
*
In the event the HTTP POST request contains binary data --for example, when someone
* wants to upload data to your servlet-- it is stored as a byte array. You can retrieve the binary data by calling the get method
* on the map
object you passed in as a parameter.
*
i.e.: byte[] uploadedImage = (byte[]) map.get( "fieldname" );
* There is no limit to the amount of binary data that can be uploaded and retrieved. * *
For those situations where the HTTP POST request contains list data (i.e. checkboxes, multiple selection lists), the list data
* is stored in a java.util.List
object. This is equivalent to the javax.servlet.ServletRequest
's
* public String[] getParameterValues( java.lang.String )
method.
*
i.e.: java.util.List checkboxItems = (java.util.List)map.get( "fieldname" );
*
* @param request A ServletRequest
object.
* @param map The Map
will be populated with the name value pairs of the HTML form's content.
* It works pretty much like the HttpServletRequest
class except it can handle multipart/form-data.
*/
public void read( ServletRequest request, Map map ) throws IOException
{
byte[] bytes = new byte[ 2048 ];
int state = 0;
int eof = 0;
/* Get the separator for this request's form data. It is necessary for parsing this request's form data. */
String boundary = request.getContentType();
int pos = boundary.indexOf( "=" );
boundary = boundary.substring( pos + 1 );
boundary = "--" + boundary;
String fieldName = null;
String fieldValue = null;
ServletInputStream sStream = request.getInputStream();
ByteArrayOutputStream dataBuffer = new ByteArrayOutputStream();
eof = sStream.readLine( bytes, 0, 2048 );
map.clear();
state = 0;
while( -1 != eof )
{
String filter = new String( bytes, 0, eof );
if( filter.startsWith( boundary ) )
{
state = READY;
if( null != fieldName )
{
if( null != fieldValue )
{
Object o = map.get( fieldName );
Object val = fieldValue.substring( 0, fieldValue.length() - 2 );
if( null == o )
map.put( fieldName, val );
else
{
if( o instanceof List )
((List)o).add( val );
else
{
List list = new ArrayList();
list.add( o );
list.add( val );
map.put( fieldName, list );
}
}
}
else if( dataBuffer.size() > 2 )
{
map.put( fieldName, dataBuffer.toByteArray() );
}
fieldName = null;
fieldValue = null;
dataBuffer.reset();
}
}
else if( filter.startsWith( "Content-Disposition: form-data" ) && state == READY )
{
StringTokenizer tokenizer = new StringTokenizer( filter, ";=\"" );
while( tokenizer.hasMoreTokens() )
{
String token = tokenizer.nextToken().trim();
if( token.startsWith( "name" ) )
{
fieldName = tokenizer.nextToken().trim();
state = NAME;
}
else if( token.startsWith( "filename" ) )
{
state = FILENAME;
break;
}
}
}
else if( filter.equals( "\r\n" ) && state == FILENAME ) state = BINDATA;
else if( filter.equals("\r\n" ) && state == NAME ) state = TXTDATA;
else if( state == TXTDATA ) fieldValue = fieldValue == null ? filter : fieldValue + filter;
else if( state == BINDATA ) dataBuffer.write( bytes, 0, eof );
eof = sStream.readLine( bytes, 0, 2048 );
}// Parsing stops here. The Map should now contain all of the form's data.
sStream.close();
}
/**
* A utility method that saves you the trouble of having to create a Map object and passing it to the other read method.
*
* @param request The ServletRequest object
*
* @return A java.util.HashMap containing the name-value pairs of the HTTP POST's form data
*/
public HashMap read( ServletRequest request ) throws IOException
{
HashMap hash = new HashMap();
this.read( request, hash );
return hash;
}
}