/********************************************************************************* * TotalCross Software Development Kit * * Copyright (C) 2000-2012 SuperWaba Ltda. * * All Rights Reserved * * * * This library and virtual machine 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. * * * * This file is covered by the GNU LESSER GENERAL PUBLIC LICENSE VERSION 3.0 * * A copy of this license is located in file license.txt at the root of this * * SDK or can be downloaded here: * * http://www.gnu.org/licenses/lgpl-3.0.txt * * * *********************************************************************************/ package totalcross.net.mail; import totalcross.io.*; import totalcross.net.*; import totalcross.sys.*; /** * Implementation of DataContentHandler that handles MIME types handled as base64 encoded byte arrays.<br> * It also handle Streams, reading from the input stream on demand to avoid excessive memory load. This will usually be * slower than reading the whole content of the stream to a byte array and using it as the Part content. * * @since TotalCross 1.13 */ public class BinaryContentHandler extends DataContentHandler { static byte[] ContentTransferEncoding = "Content-Transfer-Encoding: base64\r\n".getBytes(); private static final int bytesPerLine = 57; public void writeTo(Object obj, String mimeType, Stream stream) throws IOException { Part part = (Part) obj; String fileName = part.fileName; String disposition = (fileName != null ? Part.ATTACHMENT : part.disposition); stream.writeBytes(ContentTransferEncoding); stream.writeBytes("Content-Disposition: " + disposition + (disposition == Part.ATTACHMENT ? "; filename=\"" + fileName + "\"" : "")); stream.writeBytes(Convert.CRLF_BYTES); writeEncoded(stream, part.content); } private void writeEncoded(Stream outputStream, Object input) throws IOException { byte[] inputBytes; if (input instanceof byte[]) { inputBytes = (byte[]) input; outputStream.writeBytes(Convert.CRLF_BYTES); outputStream.writeBytes(Base64.encode(inputBytes, inputBytes.length)); outputStream.writeBytes(Convert.CRLF_BYTES); } else if (input instanceof Stream) //flsobral@tc123_45: now we use ByteArrayStream with fixed length, which should GREATLY reduce the memory usage when processing large files. { DataStream inputStream = (input instanceof DataStream) ? ((DataStream) input) : new DataStream((Stream) input, true); ByteArrayStream inputBAS = new ByteArrayStream(bytesPerLine + 1); ByteArrayStream outputBAS = new ByteArrayStream(bytesPerLine * 2); inputBytes = inputBAS.getBuffer(); byte[] encodedLineBytes = outputBAS.getBuffer(); int bytesRead; outputStream.writeBytes(Convert.CRLF_BYTES); do { bytesRead = inputStream.readBytes(inputBytes, 0, bytesPerLine); inputBAS.setPos(bytesRead); Base64.encode(inputBAS, outputBAS); outputStream.writeBytes(encodedLineBytes, 0, outputBAS.getPos()); outputStream.writeBytes(Convert.CRLF_BYTES); inputBAS.reset(); outputBAS.reset(); } while (bytesRead == bytesPerLine); outputStream.writeBytes(Convert.CRLF_BYTES); } else if (input != null) //flsobral@tc122_40: handle unknown types using toString().getBytes() { inputBytes = input.toString().getBytes(); outputStream.writeBytes(Convert.CRLF_BYTES); outputStream.writeBytes(Base64.encode(inputBytes, inputBytes.length)); outputStream.writeBytes(Convert.CRLF_BYTES); } } }