--- /dev/null
+// MultipartInputStream.java\r
+// $Id: MultipartInputStream.java,v 1.1 2010/06/15 12:26:32 smhuang Exp $\r
+// (c) COPYRIGHT MIT and INRIA, 1996.\r
+// Please first read the full copyright statement in file COPYRIGHT.html\r
+\r
+package org.w3c.www.mime ;\r
+\r
+import java.io.BufferedInputStream;\r
+import java.io.IOException;\r
+import java.io.InputStream;\r
+\r
+/**\r
+ * A class to handle multipart MIME input streams. See RC 1521.\r
+ * This class handles multipart input streams, as defined by the RFC 1521. \r
+ * It prvides a sequential interface to all MIME parts, and for each part\r
+ * it delivers a suitable InputStream for getting its body.\r
+ */\r
+\r
+public class MultipartInputStream extends InputStream {\r
+ InputStream in = null;\r
+ byte boundary[] = null ;\r
+ byte buffer[] = null ;\r
+ boolean partEnd = false ;\r
+ boolean fileEnd = false ;\r
+\r
+ // Read boundary bytes of input in buffer\r
+ // Return true if enough bytes available, false otherwise.\r
+\r
+ private final boolean readBoundaryBytes() \r
+ throws IOException\r
+ {\r
+ int pos = 0;\r
+ while ( pos < buffer.length ) {\r
+ int got = in.read(buffer, pos, buffer.length-pos);\r
+ if ( got < 0 ) \r
+ return false;\r
+ pos += got;\r
+ }\r
+ return true;\r
+ }\r
+\r
+ // Skip to next input boundary, set stream at begining of content:\r
+ // Returns true if boundary was found, false otherwise.\r
+\r
+ protected boolean skipToBoundary() \r
+ throws IOException\r
+ {\r
+ int ch = in.read() ;\r
+ skip:\r
+ while ( ch != -1 ) {\r
+ if ( ch != '-' ) {\r
+ ch = in.read() ;\r
+ continue ;\r
+ }\r
+ if ((ch = in.read()) != '-') \r
+ continue ;\r
+ in.mark(boundary.length) ;\r
+ if ( ! readBoundaryBytes() ) {\r
+ in.reset();\r
+ ch = in.read();\r
+ continue skip;\r
+ }\r
+ for (int i = 0 ; i < boundary.length ; i++) {\r
+ if ( buffer[i] != boundary[i] ) {\r
+ in.reset() ;\r
+ ch = in.read() ;\r
+ continue skip ;\r
+ }\r
+ }\r
+ // FIXME: should we check for a properly syntaxed part, which\r
+ // means that we should expect '\r\n'. For now, we just skip\r
+ // as much as we can.\r
+ if ( (ch = in.read()) == '\r' ) {\r
+ ch = in.read() ;\r
+ } \r
+ in.mark(3);\r
+ if( in.read() == '-' ) { // check fileEnd!\r
+ if( in.read() == '\r' && in.read() == '\n' ) {\r
+ fileEnd = true ;\r
+ return false ;\r
+ }\r
+ }\r
+ in.reset();\r
+ return true ;\r
+ }\r
+ fileEnd = true ;\r
+ return false ;\r
+ }\r
+\r
+ /**\r
+ * Read one byte of data from the current part.\r
+ * @return A byte of data, or <strong>-1</strong> if end of file.\r
+ * @exception IOException If some IO error occured.\r
+ */\r
+\r
+ public int read()\r
+ throws IOException \r
+ {\r
+ int ch ;\r
+ if ( partEnd )\r
+ return -1 ;\r
+ switch (ch = in.read()) {\r
+ case '\r':\r
+ // check for a boundary \r
+ in.mark(boundary.length+3) ;\r
+ int c1 = in.read() ;\r
+ int c2 = in.read() ;\r
+ int c3 = in.read() ;\r
+ if ((c1 == '\n') && (c2 == '-') && (c3 == '-')) {\r
+ if ( ! readBoundaryBytes() ) {\r
+ in.reset();\r
+ return ch;\r
+ }\r
+ for (int i = 0 ; i < boundary.length ; i++) {\r
+ if ( buffer[i] != boundary[i] ) {\r
+ in.reset() ;\r
+ return ch ;\r
+ }\r
+ }\r
+ partEnd = true ;\r
+ if ( (ch = in.read()) == '\r' ) {\r
+ in.read() ;\r
+ } else if (ch == '-') {\r
+ // FIXME, check the second hyphen\r
+ if (in.read() == '-')\r
+ fileEnd = true ;\r
+ } else {\r
+ fileEnd = (ch == -1);\r
+ }\r
+ return -1 ;\r
+ } else {\r
+ in.reset () ;\r
+ return ch ;\r
+ }\r
+ // not reached\r
+ case -1:\r
+ fileEnd = true ;\r
+ return -1 ;\r
+ default:\r
+ return ch ;\r
+ }\r
+ }\r
+\r
+ /**\r
+ * Read n bytes of data from the current part.\r
+ * @return the number of bytes data, read or <strong>-1</strong> \r
+ * if end of file.\r
+ * @exception IOException If some IO error occured.\r
+ */\r
+ public int read (byte b[], int off, int len)\r
+ throws IOException \r
+ {\r
+ int got = 0 ;\r
+ int ch ;\r
+\r
+ while ( got < len ) {\r
+ if ((ch = read()) == -1)\r
+ return (got == 0) ? -1 : got ;\r
+ b[off+(got++)] = (byte) (ch & 0xFF) ;\r
+ }\r
+ return got ;\r
+ }\r
+\r
+ public long skip (long n) \r
+ throws IOException \r
+ {\r
+ while ((--n >= 0) && (read() != -1))\r
+ ;\r
+ return n ;\r
+ }\r
+\r
+ public int available ()\r
+ throws IOException\r
+ {\r
+ return in.available();\r
+ }\r
+\r
+ /**\r
+ * Switch to the next available part of data.\r
+ * One can interrupt the current part, and use this method to switch\r
+ * to next part before current part was totally read.\r
+ * @return A boolean <strong>true</strong> if there next partis ready,\r
+ * or <strong>false</strong> if this was the last part.\r
+ */\r
+\r
+ public boolean nextInputStream() \r
+ throws IOException\r
+ {\r
+ if ( fileEnd ) {\r
+ return false ;\r
+ }\r
+ if ( ! partEnd ) { \r
+ return skipToBoundary() ;\r
+ } else {\r
+ partEnd = false ;\r
+ return true ;\r
+ }\r
+ }\r
+\r
+ /**\r
+ * Construct a new multipart input stream.\r
+ * @param in The initial (multipart) input stream.\r
+ * @param boundary The input stream MIME boundary.\r
+ */\r
+\r
+ public MultipartInputStream (InputStream in, byte boundary[]) {\r
+ this.in = (in.markSupported() \r
+ ? in \r
+ : new BufferedInputStream(in, boundary.length+4));\r
+ this.boundary = boundary ;\r
+ this.buffer = new byte[boundary.length] ;\r
+ this.partEnd = false ;\r
+ this.fileEnd = false ;\r
+ }\r
+\r
+}\r