00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017 package org.apache.commons.codec.net;
00018
00019 import java.io.ByteArrayOutputStream;
00020 import java.io.UnsupportedEncodingException;
00021 import java.util.BitSet;
00022 import org.apache.commons.codec.BinaryDecoder;
00023 import org.apache.commons.codec.BinaryEncoder;
00024 import org.apache.commons.codec.DecoderException;
00025 import org.apache.commons.codec.EncoderException;
00026 import org.apache.commons.codec.StringDecoder;
00027 import org.apache.commons.codec.StringEncoder;
00028
00059 public class QuotedPrintableCodec implements BinaryEncoder, BinaryDecoder, StringEncoder, StringDecoder {
00063 private String charset = StringEncodings.UTF8;
00064
00068 private static final BitSet PRINTABLE_CHARS = new BitSet(256);
00069
00070 private static byte ESCAPE_CHAR = '=';
00071
00072 private static byte TAB = 9;
00073
00074 private static byte SPACE = 32;
00075
00076 static {
00077
00078 for (int i = 33; i <= 60; i++) {
00079 PRINTABLE_CHARS.set(i);
00080 }
00081 for (int i = 62; i <= 126; i++) {
00082 PRINTABLE_CHARS.set(i);
00083 }
00084 PRINTABLE_CHARS.set(TAB);
00085 PRINTABLE_CHARS.set(SPACE);
00086 }
00087
00091 public QuotedPrintableCodec() {
00092 super();
00093 }
00094
00101 public QuotedPrintableCodec(String charset) {
00102 super();
00103 this.charset = charset;
00104 }
00105
00114 private static final void encodeQuotedPrintable(int b, ByteArrayOutputStream buffer) {
00115 buffer.write(ESCAPE_CHAR);
00116 char hex1 = Character.toUpperCase(Character.forDigit((b >> 4) & 0xF, 16));
00117 char hex2 = Character.toUpperCase(Character.forDigit(b & 0xF, 16));
00118 buffer.write(hex1);
00119 buffer.write(hex2);
00120 }
00121
00136 public static final byte[] encodeQuotedPrintable(BitSet printable, byte[] bytes) {
00137 if (bytes == null) {
00138 return null;
00139 }
00140 if (printable == null) {
00141 printable = PRINTABLE_CHARS;
00142 }
00143 ByteArrayOutputStream buffer = new ByteArrayOutputStream();
00144 for (int i = 0; i < bytes.length; i++) {
00145 int b = bytes[i];
00146 if (b < 0) {
00147 b = 256 + b;
00148 }
00149 if (printable.get(b)) {
00150 buffer.write(b);
00151 } else {
00152 encodeQuotedPrintable(b, buffer);
00153 }
00154 }
00155 return buffer.toByteArray();
00156 }
00157
00173 public static final byte[] decodeQuotedPrintable(byte[] bytes) throws DecoderException {
00174 if (bytes == null) {
00175 return null;
00176 }
00177 ByteArrayOutputStream buffer = new ByteArrayOutputStream();
00178 for (int i = 0; i < bytes.length; i++) {
00179 int b = bytes[i];
00180 if (b == ESCAPE_CHAR) {
00181 try {
00182 int u = Character.digit((char) bytes[++i], 16);
00183 int l = Character.digit((char) bytes[++i], 16);
00184 if (u == -1 || l == -1) {
00185 throw new DecoderException("Invalid quoted-printable encoding");
00186 }
00187 buffer.write((char) ((u << 4) + l));
00188 } catch (ArrayIndexOutOfBoundsException e) {
00189 throw new DecoderException("Invalid quoted-printable encoding");
00190 }
00191 } else {
00192 buffer.write(b);
00193 }
00194 }
00195 return buffer.toByteArray();
00196 }
00197
00210 public byte[] encode(byte[] bytes) {
00211 return encodeQuotedPrintable(PRINTABLE_CHARS, bytes);
00212 }
00213
00229 public byte[] decode(byte[] bytes) throws DecoderException {
00230 return decodeQuotedPrintable(bytes);
00231 }
00232
00250 public String encode(String pString) throws EncoderException {
00251 if (pString == null) {
00252 return null;
00253 }
00254 try {
00255 return encode(pString, getDefaultCharset());
00256 } catch (UnsupportedEncodingException e) {
00257 throw new EncoderException(e.getMessage());
00258 }
00259 }
00260
00275 public String decode(String pString, String charset) throws DecoderException, UnsupportedEncodingException {
00276 if (pString == null) {
00277 return null;
00278 }
00279 return new String(decode(pString.getBytes(StringEncodings.US_ASCII)), charset);
00280 }
00281
00295 public String decode(String pString) throws DecoderException {
00296 if (pString == null) {
00297 return null;
00298 }
00299 try {
00300 return decode(pString, getDefaultCharset());
00301 } catch (UnsupportedEncodingException e) {
00302 throw new DecoderException(e.getMessage());
00303 }
00304 }
00305
00316 public Object encode(Object pObject) throws EncoderException {
00317 if (pObject == null) {
00318 return null;
00319 } else if (pObject instanceof byte[]) {
00320 return encode((byte[]) pObject);
00321 } else if (pObject instanceof String) {
00322 return encode((String) pObject);
00323 } else {
00324 throw new EncoderException("Objects of type "
00325 + pObject.getClass().getName()
00326 + " cannot be quoted-printable encoded");
00327 }
00328 }
00329
00341 public Object decode(Object pObject) throws DecoderException {
00342 if (pObject == null) {
00343 return null;
00344 } else if (pObject instanceof byte[]) {
00345 return decode((byte[]) pObject);
00346 } else if (pObject instanceof String) {
00347 return decode((String) pObject);
00348 } else {
00349 throw new DecoderException("Objects of type "
00350 + pObject.getClass().getName()
00351 + " cannot be quoted-printable decoded");
00352 }
00353 }
00354
00360 public String getDefaultCharset() {
00361 return this.charset;
00362 }
00363
00381 public String encode(String pString, String charset) throws UnsupportedEncodingException {
00382 if (pString == null) {
00383 return null;
00384 }
00385 return new String(encode(pString.getBytes(charset)), StringEncodings.US_ASCII);
00386 }
00387 }