/** @see javax.servlet.ServletRequest#getParameter(java.lang.String) */
    public String getParameter(String name) {
      Object o = map.get(name);
      if (!(o instanceof byte[]) && LazyList.size(o) > 0) o = LazyList.get(o, 0);

      if (o instanceof byte[]) {
        try {
          String s = new String((byte[]) o, encoding);
          return s;
        } catch (Exception e) {
          e.printStackTrace();
        }
      } else if (o != null) return String.valueOf(o);
      return null;
    }
 /** @see javax.servlet.ServletRequest#getParameterValues(java.lang.String) */
 public String[] getParameterValues(String name) {
   List l = map.getValues(name);
   if (l == null || l.size() == 0) return new String[0];
   String[] v = new String[l.size()];
   for (int i = 0; i < l.size(); i++) {
     Object o = l.get(i);
     if (o instanceof byte[]) {
       try {
         v[i] = new String((byte[]) o, encoding);
       } catch (Exception e) {
         e.printStackTrace();
       }
     } else if (o instanceof String) v[i] = (String) o;
   }
   return v;
 }
  /**
   * @see javax.servlet.Filter#doFilter(javax.servlet.ServletRequest, javax.servlet.ServletResponse,
   *     javax.servlet.FilterChain)
   */
  public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
      throws IOException, ServletException {
    HttpServletRequest srequest = (HttpServletRequest) request;
    if (srequest.getContentType() == null
        || !srequest.getContentType().startsWith("multipart/form-data")) {
      chain.doFilter(request, response);
      return;
    }

    BufferedInputStream in = new BufferedInputStream(request.getInputStream());
    String content_type = srequest.getContentType();

    // TODO - handle encodings

    String boundary = "--" + value(content_type.substring(content_type.indexOf("boundary=")));
    byte[] byteBoundary = (boundary + "--").getBytes(StringUtil.__ISO_8859_1);

    MultiMap params = new MultiMap();
    for (Iterator i = request.getParameterMap().entrySet().iterator(); i.hasNext(); ) {
      Map.Entry entry = (Map.Entry) i.next();
      Object value = entry.getValue();
      if (value instanceof String[]) params.addValues(entry.getKey(), (String[]) value);
      else params.add(entry.getKey(), value);
    }

    try {
      // Get first boundary
      byte[] bytes = TypeUtil.readLine(in);
      String line = bytes == null ? null : new String(bytes, "UTF-8");
      if (line == null || !line.equals(boundary)) {
        throw new IOException("Missing initial multi part boundary");
      }

      // Read each part
      boolean lastPart = false;
      String content_disposition = null;
      while (!lastPart) {
        while (true) {
          bytes = TypeUtil.readLine(in);
          // If blank line, end of part headers
          if (bytes == null || bytes.length == 0) break;
          line = new String(bytes, "UTF-8");

          // place part header key and value in map
          int c = line.indexOf(':', 0);
          if (c > 0) {
            String key = line.substring(0, c).trim().toLowerCase();
            String value = line.substring(c + 1, line.length()).trim();
            if (key.equals("content-disposition")) content_disposition = value;
          }
        }
        // Extract content-disposition
        boolean form_data = false;
        if (content_disposition == null) {
          throw new IOException("Missing content-disposition");
        }

        StringTokenizer tok = new StringTokenizer(content_disposition, ";");
        String name = null;
        String filename = null;
        while (tok.hasMoreTokens()) {
          String t = tok.nextToken().trim();
          String tl = t.toLowerCase();
          if (t.startsWith("form-data")) form_data = true;
          else if (tl.startsWith("name=")) name = value(t);
          else if (tl.startsWith("filename=")) filename = value(t);
        }

        // Check disposition
        if (!form_data) {
          continue;
        }

        // It is valid for reset and submit buttons to have an empty name.
        // If no name is supplied, the browser skips sending the info for that field.
        // However, if you supply the empty string as the name, the browser sends the
        // field, with name as the empty string. So, only continue this loop if we
        // have not yet seen a name field.
        if (name == null) {
          continue;
        }

        OutputStream out = null;
        File file = null;
        try {
          if (filename != null && filename.length() > 0) {
            file = File.createTempFile("MultiPart", "", tempdir);
            out = new FileOutputStream(file);
            if (_fileOutputBuffer > 0) out = new BufferedOutputStream(out, _fileOutputBuffer);
            request.setAttribute(name, file);
            params.add(name, filename);

            if (_deleteFiles) {
              file.deleteOnExit();
              ArrayList files = (ArrayList) request.getAttribute(FILES);
              if (files == null) {
                files = new ArrayList();
                request.setAttribute(FILES, files);
              }
              files.add(file);
            }

          } else out = new ByteArrayOutputStream();

          int state = -2;
          int c;
          boolean cr = false;
          boolean lf = false;

          // loop for all lines`
          while (true) {
            int b = 0;
            while ((c = (state != -2) ? state : in.read()) != -1) {
              state = -2;
              // look for CR and/or LF
              if (c == 13 || c == 10) {
                if (c == 13) state = in.read();
                break;
              }
              // look for boundary
              if (b >= 0 && b < byteBoundary.length && c == byteBoundary[b]) b++;
              else {
                // this is not a boundary
                if (cr) out.write(13);
                if (lf) out.write(10);
                cr = lf = false;
                if (b > 0) out.write(byteBoundary, 0, b);
                b = -1;
                out.write(c);
              }
            }
            // check partial boundary
            if ((b > 0 && b < byteBoundary.length - 2) || (b == byteBoundary.length - 1)) {
              if (cr) out.write(13);
              if (lf) out.write(10);
              cr = lf = false;
              out.write(byteBoundary, 0, b);
              b = -1;
            }
            // boundary match
            if (b > 0 || c == -1) {
              if (b == byteBoundary.length) lastPart = true;
              if (state == 10) state = -2;
              break;
            }
            // handle CR LF
            if (cr) out.write(13);
            if (lf) out.write(10);
            cr = (c == 13);
            lf = (c == 10 || state == 10);
            if (state == 10) state = -2;
          }
        } finally {
          out.close();
        }

        if (file == null) {
          bytes = ((ByteArrayOutputStream) out).toByteArray();
          params.add(name, bytes);
        }
      }

      // handle request
      chain.doFilter(new Wrapper(srequest, params), response);
    } finally {
      deleteFiles(request);
    }
  }
 /** @see javax.servlet.ServletRequest#getParameterNames() */
 public Enumeration getParameterNames() {
   return Collections.enumeration(map.keySet());
 }
 /** @see javax.servlet.ServletRequest#getParameterMap() */
 public Map getParameterMap() {
   return Collections.unmodifiableMap(map.toStringArrayMap());
 }