diff -r cb15fc6cc038 -r 9a2e5d103695 jaxws/src/java.xml.soap/share/classes/com/sun/xml/internal/messaging/saaj/packaging/mime/internet/BMMimeMultipart.java --- a/jaxws/src/java.xml.soap/share/classes/com/sun/xml/internal/messaging/saaj/packaging/mime/internet/BMMimeMultipart.java Thu Jan 15 11:18:14 2015 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,765 +0,0 @@ -/* - * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -/* - * @(#)MimeMultipart.java 1.31 03/01/29 - */ - - - -package com.sun.xml.internal.messaging.saaj.packaging.mime.internet; - -import java.io.*; -import java.util.BitSet; - -import javax.activation.DataSource; - -import com.sun.xml.internal.messaging.saaj.packaging.mime.*; -import com.sun.xml.internal.messaging.saaj.packaging.mime.util.*; - -import com.sun.xml.internal.messaging.saaj.util.ByteOutputStream; - -/** - * The MimeMultipart class is an implementation of the abstract Multipart - * class that uses MIME conventions for the multipart data.

- * - * A MimeMultipart is obtained from a MimePart whose primary type - * is "multipart" (by invoking the part's getContent() method) - * or it can be created by a client as part of creating a new MimeMessage.

- * - * The default multipart subtype is "mixed". The other multipart - * subtypes, such as "alternative", "related", and so on, can be - * implemented as subclasses of MimeMultipart with additional methods - * to implement the additional semantics of that type of multipart - * content. The intent is that service providers, mail JavaBean writers - * and mail clients will write many such subclasses and their Command - * Beans, and will install them into the JavaBeans Activation - * Framework, so that any JavaMail implementation and its clients can - * transparently find and use these classes. Thus, a MIME multipart - * handler is treated just like any other type handler, thereby - * decoupling the process of providing multipart handlers from the - * JavaMail API. Lacking these additional MimeMultipart subclasses, - * all subtypes of MIME multipart data appear as MimeMultipart objects.

- * - * An application can directly construct a MIME multipart object of any - * subtype by using the MimeMultipart(String subtype) - * constructor. For example, to create a "multipart/alternative" object, - * use new MimeMultipart("alternative"). - * - */ - -//TODO: cleanup the SharedInputStream handling -public class BMMimeMultipart extends MimeMultipart { - - /* - * When true it indicates parsing hasnt been done at all - */ - private boolean begining = true; - - int[] bcs = new int[256]; - int[] gss = null; - private static final int BUFFER_SIZE = 4096; - private byte[] buffer = new byte[BUFFER_SIZE]; - private byte[] prevBuffer = new byte[BUFFER_SIZE]; - private BitSet lastPartFound = new BitSet(1); - - // cached inputstream which is possibly partially consumed - private InputStream in = null; - private String boundary = null; - // current stream position, set to -1 on EOF - int b = 0; - - // property to indicate if lazyAttachments is ON - private boolean lazyAttachments = false; - - /** - * Default constructor. An empty MimeMultipart object - * is created. Its content type is set to "multipart/mixed". - * A unique boundary string is generated and this string is - * setup as the "boundary" parameter for the - * contentType field.

- * - * MimeBodyParts may be added later. - */ - public BMMimeMultipart() { - super(); - //this("mixed"); - } - - /** - * Construct a MimeMultipart object of the given subtype. - * A unique boundary string is generated and this string is - * setup as the "boundary" parameter for the - * contentType field.

- * - * MimeBodyParts may be added later. - */ - public BMMimeMultipart(String subtype) { - super(subtype); - /* - * Compute a boundary string. - String boundary = UniqueValue.getUniqueBoundaryValue(); - ContentType cType = new ContentType("multipart", subtype, null); - contentType.setParameter("boundary", boundary); - */ - } - - /** - * Constructs a MimeMultipart object and its bodyparts from the - * given DataSource.

- * - * This constructor handles as a special case the situation where the - * given DataSource is a MultipartDataSource object. In this case, this - * method just invokes the superclass (i.e., Multipart) constructor - * that takes a MultipartDataSource object.

- * - * Otherwise, the DataSource is assumed to provide a MIME multipart - * byte stream. The parsed flag is set to false. When - * the data for the body parts are needed, the parser extracts the - * "boundary" parameter from the content type of this DataSource, - * skips the 'preamble' and reads bytes till the terminating - * boundary and creates MimeBodyParts for each part of the stream. - * - * @param ds DataSource, can be a MultipartDataSource - */ - public BMMimeMultipart(DataSource ds, ContentType ct) - throws MessagingException { - super(ds,ct); - boundary = ct.getParameter("boundary"); - /* - if (ds instanceof MultipartDataSource) { - // ask super to do this for us. - setMultipartDataSource((MultipartDataSource)ds); - return; - } - - // 'ds' was not a MultipartDataSource, we have - // to parse this ourself. - parsed = false; - this.ds = ds; - if (ct==null) - contentType = new ContentType(ds.getContentType()); - else - contentType = ct; - */ - - } - - public InputStream initStream() throws MessagingException { - - if (in == null) { - try { - in = ds.getInputStream(); - if (!(in instanceof ByteArrayInputStream) && - !(in instanceof BufferedInputStream) && - !(in instanceof SharedInputStream)) - in = new BufferedInputStream(in); - } catch (Exception ex) { - throw new MessagingException("No inputstream from datasource"); - } - - if (!in.markSupported()) { - throw new MessagingException( - "InputStream does not support Marking"); - } - } - return in; - } - - /** - * Parse the InputStream from our DataSource, constructing the - * appropriate MimeBodyParts. The parsed flag is - * set to true, and if true on entry nothing is done. This - * method is called by all other methods that need data for - * the body parts, to make sure the data has been parsed. - * - * @since JavaMail 1.2 - */ - protected void parse() throws MessagingException { - if (parsed) - return; - - initStream(); - - SharedInputStream sin = null; - if (in instanceof SharedInputStream) { - sin = (SharedInputStream)in; - } - - String bnd = "--" + boundary; - byte[] bndbytes = ASCIIUtility.getBytes(bnd); - try { - parse(in, bndbytes, sin); - } catch (IOException ioex) { - throw new MessagingException("IO Error", ioex); - } catch (Exception ex) { - throw new MessagingException("Error", ex); - } - - parsed = true; - } - - public boolean lastBodyPartFound() { - return lastPartFound.get(0); - } - - public MimeBodyPart getNextPart( - InputStream stream, byte[] pattern, SharedInputStream sin) - throws Exception { - - if (!stream.markSupported()) { - throw new Exception("InputStream does not support Marking"); - } - - if (begining) { - compile(pattern); - if (!skipPreamble(stream, pattern, sin)) { - throw new Exception( - "Missing Start Boundary, or boundary does not start on a new line"); - } - begining = false; - } - - if (lastBodyPartFound()) { - throw new Exception("No parts found in Multipart InputStream"); - } - - if (sin != null) { - long start = sin.getPosition(); - b = readHeaders(stream); - if (b == -1) { - throw new Exception( - "End of Stream encountered while reading part headers"); - } - long[] v = new long[1]; - v[0] = -1; // just to ensure the code later sets it correctly - b = readBody(stream, pattern, v, null, sin); - // looks like this check has to be disabled - // it is allowed to have Mime Package without closing boundary - if (!ignoreMissingEndBoundary) { - if ((b == -1) && !lastBodyPartFound()) { - throw new MessagingException("Missing End Boundary for Mime Package : EOF while skipping headers"); - } - } - long end = v[0]; - MimeBodyPart mbp = createMimeBodyPart(sin.newStream(start, end)); - addBodyPart(mbp); - return mbp; - - } else { - InternetHeaders headers = createInternetHeaders(stream); - ByteOutputStream baos = new ByteOutputStream(); - b = readBody(stream, pattern, null,baos, null); - // looks like this check has to be disabled - // in the old impl it is allowed to have Mime Package - // without closing boundary - if (!ignoreMissingEndBoundary) { - if ((b == -1) && !lastBodyPartFound()) { - throw new MessagingException("Missing End Boundary for Mime Package : EOF while skipping headers"); - } - } - MimeBodyPart mbp = createMimeBodyPart( - headers, baos.getBytes(), baos.getCount()); - addBodyPart(mbp); - return mbp; - } - - } - - public boolean parse( - InputStream stream, byte[] pattern, SharedInputStream sin) - throws Exception { - - while (!lastPartFound.get(0) && (b != -1)) { - getNextPart(stream, pattern, sin); - } - return true; - } - - private int readHeaders(InputStream is) throws Exception { - // if the headers are to end properly then there has to be CRLF - // actually we just need to mark the start and end positions - int b = is.read(); - while(b != -1) { - // when it is a shared input stream no need to copy - if (b == '\r') { - b = is.read(); - if (b == '\n') { - b = is.read(); - if (b == '\r') { - b = is.read(); - if (b == '\n') { - return b; - } else { - continue; - } - } else { - continue; - } - } else { - continue; - } - } - b = is.read(); - } - if (b == -1) { - throw new Exception( - "End of inputstream while reading Mime-Part Headers"); - } - return b; - } - - private int readBody( - InputStream is, byte[] pattern, long[] posVector, - ByteOutputStream baos, SharedInputStream sin) - throws Exception { - if (!find(is, pattern, posVector, baos, sin)) { - throw new Exception( - "Missing boundary delimitier while reading Body Part"); - } - return b; - } - - private boolean skipPreamble( - InputStream is, byte[] pattern, SharedInputStream sin) - throws Exception { - if (!find(is, pattern, sin)) { - return false; - } - if (lastPartFound.get(0)) { - throw new Exception( - "Found closing boundary delimiter while trying to skip preamble"); - } - return true; - } - - - public int readNext(InputStream is, byte[] buff, int patternLength, - BitSet eof, long[] posVector, SharedInputStream sin) - throws Exception { - - int bufferLength = is.read(buffer, 0, patternLength); - if (bufferLength == -1) { - eof.flip(0); - } else if (bufferLength < patternLength) { - //repeatedly read patternLength - bufferLength - int temp = 0; - long pos = 0; - int i = bufferLength; - for (; i < patternLength; i++) { - if (sin != null) { - pos = sin.getPosition(); - } - temp = is.read(); - if (temp == -1) { - eof.flip(0); - if (sin != null) { - posVector[0] = pos; - } - break; - } - buffer[i] = (byte)temp; - } - bufferLength=i; - } - return bufferLength; - } - - public boolean find(InputStream is, byte[] pattern, SharedInputStream sin) - throws Exception { - int i; - int l = pattern.length; - int lx = l -1; - BitSet eof = new BitSet(1); - long[] posVector = new long[1]; - - while (true) { - is.mark(l); - readNext(is, buffer, l, eof, posVector, sin); - if (eof.get(0)) { - // End of stream - return false; - } - - /* - if (bufferLength < l) { - //is.reset(); - return false; - }*/ - - for(i = lx; i >= 0; i--) { - if (buffer[i] != pattern[i]) { - break; - } - } - - if (i < 0) { - // found the boundary, skip *LWSP-char and CRLF - if (!skipLWSPAndCRLF(is)) { - throw new Exception("Boundary does not terminate with CRLF"); - } - return true; - } - - int s = Math.max(i + 1 - bcs[buffer[i] & 0x7f], gss[i]); - is.reset(); - is.skip(s); - } - } - - public boolean find( - InputStream is, byte[] pattern, long[] posVector, - ByteOutputStream out, SharedInputStream sin) throws Exception { - int i; - int l = pattern.length; - int lx = l -1; - int bufferLength = 0; - int s = 0; - long endPos = -1; - byte[] tmp = null; - - boolean first = true; - BitSet eof = new BitSet(1); - - while (true) { - is.mark(l); - if (!first) { - tmp = prevBuffer; - prevBuffer = buffer; - buffer = tmp; - } - if (sin != null) { - endPos = sin.getPosition(); - } - - bufferLength = readNext(is, buffer, l, eof, posVector, sin); - - if (bufferLength == -1) { - // End of stream - // looks like it is allowed to not have a closing boundary - //return false; - //if (sin != null) { - // posVector[0] = endPos; - //} - b = -1; - if ((s == l) && (sin == null)) { - out.write(prevBuffer, 0, s); - } - return true; - } - - if (bufferLength < l) { - if (sin != null) { - //endPos = sin.getPosition(); - //posVector[0] = endPos; - } else { - // looks like it is allowed to not have a closing boundary - // in the old implementation - out.write(buffer, 0, bufferLength); - } - // looks like it is allowed to not have a closing boundary - // in the old implementation - //return false; - b = -1; - return true; - } - - for(i = lx; i >= 0; i--) { - if (buffer[i] != pattern[i]) { - break; - } - } - - if (i < 0) { - if (s > 0) { - //looks like the earlier impl allowed just an LF - // so if s == 1 : it must be an LF - // if s == 2 : it must be a CR LF - if (s <= 2) { - //it could be "some-char\n" so write some-char - if (s == 2) { - if (prevBuffer[1] == '\n') { - if (prevBuffer[0] != '\r' && prevBuffer[0] != '\n') { - out.write(prevBuffer,0,1); - } - if (sin != null) { - posVector[0] = endPos; - } - - } else { - throw new Exception( - "Boundary characters encountered in part Body " + - "without a preceeding CRLF"); - } - - } else if (s==1) { - if (prevBuffer[0] != '\n') { - throw new Exception( - "Boundary characters encountered in part Body " + - "without a preceeding CRLF"); - }else { - if (sin != null) { - posVector[0] = endPos; - } - } - } - - } else if (s > 2) { - if ((prevBuffer[s-2] == '\r') && (prevBuffer[s-1] == '\n')) { - if (sin != null) { - posVector[0] = endPos - 2; - } else { - out.write(prevBuffer, 0, s - 2); - } - } else if (prevBuffer[s-1] == '\n') { - //old impl allowed just a \n - if (sin != null) { - posVector[0] = endPos - 1; - } else { - out.write(prevBuffer, 0, s - 1); - } - } else { - throw new Exception( - "Boundary characters encountered in part Body " + - "without a preceeding CRLF"); - } - } - } - // found the boundary, skip *LWSP-char and CRLF - if (!skipLWSPAndCRLF(is)) { - //throw new Exception( - // "Boundary does not terminate with CRLF"); - } - return true; - } - - if ((s > 0) && (sin == null)) { - if (prevBuffer[s-1] == (byte)13) { - // if buffer[0] == (byte)10 - if (buffer[0] == (byte)10) { - int j; - for(j = lx-1; j > 0; j--) { - if (buffer[j+1] != pattern[j]) { - break; - } - } - if (j == 0) { - // matched the pattern excluding the last char of the pattern - // so dont write the CR into stream - out.write(prevBuffer,0,s-1); - } else { - out.write(prevBuffer,0,s); - } - } else { - out.write(prevBuffer, 0, s); - } - } else { - out.write(prevBuffer, 0, s); - } - } - - s = Math.max(i + 1 - bcs[buffer[i] & 0x7f], gss[i]); - is.reset(); - is.skip(s); - if (first) { - first = false; - } - } - } - - private boolean skipLWSPAndCRLF(InputStream is) throws Exception { - - b = is.read(); - //looks like old impl allowed just a \n as well - if (b == '\n') { - return true; - } - - if (b == '\r') { - b = is.read(); - //skip any multiple '\r' "\r\n" --> "\r\r\n" on Win2k - if (b == '\r') { - b = is.read(); - } - if (b == '\n') { - return true; - } else { - throw new Exception( - "transport padding after a Mime Boundary should end in a CRLF, found CR only"); - } - } - - if (b == '-') { - b = is.read(); - if (b != '-') { - throw new Exception( - "Unexpected singular '-' character after Mime Boundary"); - } else { - //System.out.println("Last Part Found"); - lastPartFound.flip(0); - // read the next char - b = is.read(); - } - } - - while ((b != -1) && ((b == ' ') || (b == '\t'))) { - b = is.read(); - if (b == '\n') { - return true; - } - if (b == '\r') { - b = is.read(); - //skip any multiple '\r': "\r\n" --> "\r\r\n" on Win2k - if (b == '\r') { - b = is.read(); - } - if (b == '\n') { - return true; - } - } - } - - if (b == -1) { - // the last boundary need not have CRLF - if (!lastPartFound.get(0)) { - throw new Exception( - "End of Multipart Stream before encountering closing boundary delimiter"); - } - return true; - } - return false; - } - - private void compile(byte[] pattern) { - int l = pattern.length; - - int i; - int j; - - // Copied from J2SE 1.4 regex code - // java.util.regex.Pattern.java - - // Initialise Bad Character Shift table - for (i = 0; i < l; i++) { - bcs[pattern[i]] = i + 1; - } - - // Initialise Good Suffix Shift table - gss = new int[l]; - NEXT: for (i = l; i > 0; i--) { - // j is the beginning index of suffix being considered - for (j = l - 1; j >= i; j--) { - // Testing for good suffix - if (pattern[j] == pattern[j - i]) { - // pattern[j..len] is a good suffix - gss[j - 1] = i; - } else { - // No match. The array has already been - // filled up with correct values before. - continue NEXT; - } - } - while (j > 0) { - gss[--j] = i; - } - } - gss[l - 1] = 1; - } - - - /** - * Iterates through all the parts and outputs each Mime part - * separated by a boundary. - */ - - public void writeTo(OutputStream os) - throws IOException, MessagingException { - - // inputStream was not null - if (in != null) { - contentType.setParameter("boundary", this.boundary); - } - - String bnd = "--" + contentType.getParameter("boundary"); - for (int i = 0; i < parts.size(); i++) { - OutputUtil.writeln(bnd, os); // put out boundary - ((MimeBodyPart)parts.get(i)).writeTo(os); - OutputUtil.writeln(os); // put out empty line - } - - if (in != null) { - OutputUtil.writeln(bnd, os); // put out boundary - if ((os instanceof ByteOutputStream) && lazyAttachments) { - ((ByteOutputStream) os).write(in); - } else { - ByteOutputStream baos = null; - try { - baos = new ByteOutputStream(in.available()); - baos.write(in); - baos.writeTo(os); - // reset the inputstream so that we can support a - // getAttachment later - in = baos.newInputStream(); - } finally { - if (baos != null) - baos.close(); - } - } - - // this will endup writing the end boundary - } else { - // put out last boundary - OutputUtil.writeAsAscii(bnd, os); - OutputUtil.writeAsAscii("--", os); - } - } - - public void setInputStream(InputStream is) { - this.in = is; - } - - public InputStream getInputStream() { - return this.in; - } - - public void setBoundary(String bnd) { - this.boundary = bnd; - if (this.contentType != null) { - this.contentType.setParameter("boundary", bnd); - } - } - public String getBoundary() { - return this.boundary; - } - - public boolean isEndOfStream() { - return (b == -1); - } - - public void setLazyAttachments(boolean flag) { - lazyAttachments = flag; - } - -}