com.hfg.util.mime.ContentTransferEncoding Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of com_hfg Show documentation
Show all versions of com_hfg Show documentation
com.hfg xml, html, svg, and bioinformatics utility library
package com.hfg.util.mime;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Base64;
import java.util.List;
import java.util.Map;
import com.hfg.exception.ProgrammingException;
import com.hfg.util.HexUtil;
import com.hfg.util.StringBuilderPlus;
import com.hfg.util.collection.OrderedMap;
//------------------------------------------------------------------------------
/**
Standard types of MIME content transfer encoding.
@author J. Alex Taylor, hairyfatguy.com
*/
//------------------------------------------------------------------------------
// com.hfg XML/HTML Coding Library
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library 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
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
// J. Alex Taylor, President, Founder, CEO, COO, CFO, OOPS hairyfatguy.com
// [email protected]
//------------------------------------------------------------------------------
public class ContentTransferEncoding
{
private String mName;
private static Map sValueMap = new OrderedMap<>(5);
public static final ContentTransferEncoding BASE64 = new ContentTransferEncoding("BASE64");
public static final ContentTransferEncoding QUOTED_PRINTABLE = new ContentTransferEncoding("QUOTED-PRINTABLE");
public static final ContentTransferEncoding EIGHT_BIT = new ContentTransferEncoding("8BIT");
public static final ContentTransferEncoding SEVEN_BIT = new ContentTransferEncoding("7BIT");
public static final ContentTransferEncoding BINARY = new ContentTransferEncoding("BINARY");
private static final int MAX_ENCODING_LINE_LENGTH = 76;
private static final String CRLF = "\r\n";
//--------------------------------------------------------------------------
private ContentTransferEncoding(String inValue)
{
mName = inValue;
sValueMap.put(inValue.toUpperCase(), this);
}
//--------------------------------------------------------------------------
public String toString()
{
return name();
}
//--------------------------------------------------------------------------
public String name()
{
return mName;
}
//--------------------------------------------------------------------------
public static ContentTransferEncoding valueOf(String inValue)
{
return sValueMap.get(inValue.toUpperCase());
}
//--------------------------------------------------------------------------
public static List values(String inValue)
{
return new ArrayList<>(sValueMap.values());
}
//--------------------------------------------------------------------------
public byte[] encode(byte[] inBytes)
throws IOException
{
byte[] outBytes = inBytes;
if (this.equals(BASE64))
{
outBytes = base64Encode(inBytes);
}
else if (this.equals(QUOTED_PRINTABLE))
{
outBytes = quotedPrintableEncode(inBytes);
}
return outBytes;
}
//--------------------------------------------------------------------------
private byte[] base64Encode(byte[] inBytes)
{
String encodedString = Base64.getEncoder().encodeToString(inBytes);
StringBuilderPlus buffer = new StringBuilderPlus().setDelimiter(CRLF);
int i = 0;
while (i < encodedString.length())
{
int limit = i + MAX_ENCODING_LINE_LENGTH;
if (limit > encodedString.length())
{
limit = encodedString.length();
}
buffer.delimitedAppend(encodedString.substring(i, limit));
i = limit;
}
return buffer.toString().getBytes();
}
//--------------------------------------------------------------------------
// RFC 2045
private byte[] quotedPrintableEncode(byte[] inBytes)
throws IOException
{
ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
int currentLineLength = 0;
int previousByte = -1;
for (byte theByte : inBytes)
{
if (theByte == '\n')
{
currentLineLength = 0; // Reset the line length
byteStream.write(theByte);
}
else if (theByte == '\r')
{
if (previousByte == ' ')
{
byteStream.write('=');
}
byteStream.write(theByte);
}
else if (theByte == ' '
|| theByte == '\t')
{
if (MAX_ENCODING_LINE_LENGTH - currentLineLength == 1)
{
byteStream.write('=');
byteStream.write(CRLF.getBytes());
currentLineLength = 0; // Reset the line length
}
byteStream.write(theByte);
currentLineLength++;
if (MAX_ENCODING_LINE_LENGTH - currentLineLength < 2)
{
byteStream.write('=');
byteStream.write(CRLF.getBytes());
currentLineLength = 0; // Reset the line length
}
}
else if (theByte < 32
|| theByte == 33 // '!'
|| theByte == 35 // '#'
|| theByte == 36 // '$'
|| theByte == 61 // '='
|| theByte == 94 // '^'
|| theByte == 96 // '`'
|| theByte > 122)
{
if (MAX_ENCODING_LINE_LENGTH - currentLineLength < 4)
{
byteStream.write('=');
byteStream.write(CRLF.getBytes());
currentLineLength = 0; // Reset the line length
}
byteStream.write('=');
byteStream.write(Character.toUpperCase(Character.forDigit((theByte >> 4) & 0xF, 16)));
byteStream.write(Character.toUpperCase(Character.forDigit(theByte & 0xF, 16)));
currentLineLength+=3;
}
else
{
if (MAX_ENCODING_LINE_LENGTH - currentLineLength < 2)
{
byteStream.write('=');
byteStream.write(CRLF.getBytes());
currentLineLength = 0; // Reset the line length
}
byteStream.write(theByte);
currentLineLength++;
}
previousByte = theByte;
}
return byteStream.toByteArray();
}
}