/*
*
*
* Copyright 1990-2009 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
*
* This program 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.
*
* This program 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 at /legal/license.txt).
*
* 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 Sun Microsystems, Inc., 4150 Network Circle, Santa
* Clara, CA 95054 or visit www.sun.com if you need additional
* information or have any questions.
*/
package com.sun.j2me.pim.formats;
import com.sun.j2me.main.Configuration;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
/**
* Interprets the Quoted-Printable encoding.
* The Quoted-Printable Encoding is defined in RFC 2045.
*
*/
public class QuotedPrintableEncoding {
/**
* Converts a quoted-printable string to a byte array.
* @param sdata input data to be converted
* @return processed data from quoted printable
*/
public static byte[] fromQuotedPrintable(String sdata) {
ByteArrayOutputStream out = new ByteArrayOutputStream();
ByteArrayOutputStream whitespaceAccumulator =
new ByteArrayOutputStream();
char[] data = sdata.toCharArray();
String lb = Configuration.getProperty("file.linebreak");
if (lb == null) {
lb = "\r";
}
byte[] linebreak = lb.getBytes();
boolean followingEqualsSign = false;
for (int i = 0; i < data.length; i++) {
char currSym = data[i];
if (followingEqualsSign) {
switch (currSym) {
case '\r':
// RFC 2045: check for soft break (=CRLF)
if (i + 1 < data.length) {
if (data[i + 1] == '\n') {
// concatenate lines
i++;
break;
}
}
default: {
// inlined byte
if (i < data.length - 1) {
String charCode = sdata.substring(i, i + 2);
i ++;
try {
out.write(Integer.parseInt(charCode, 16));
break;
} catch (NumberFormatException nfe) {
// illegal data. write the data as is
out.write('=');
out.write(charCode.charAt(0));
out.write(charCode.charAt(1));
}
} else {
// '=' is the penultimate character, which is also
// illegal. write the data as is
out.write('=');
out.write(currSym);
}
}
}
followingEqualsSign = false;
} else {
try {
/**
* RFC 2045: Control characters other than TAB, or CR and LF
* as parts of CRLF pairs, must not appear. The same is true
* for octets with decimal values greater than 126. If
* found in incoming quoted-printable data by a decoder, a
* robust implementation might exclude them from the
* decoded data.
*/
if (((currSym < ' ') &&
(currSym != '\t') &&
(currSym != '\r')) ||
(currSym > 126)) { // ignore
continue;
}
switch (currSym) {
case '=': {
out.write(whitespaceAccumulator.toByteArray());
whitespaceAccumulator.reset();
followingEqualsSign = true;
break;
}
case '\t':
case ' ':
whitespaceAccumulator.write(currSym);
break;
case '\r': // must be a part of CRLF (RFC 2045)
if (i + 1 < data.length) {
if (data[i + 1] == '\n') {
whitespaceAccumulator.reset();
out.write(linebreak, 0, linebreak.length);
i ++; // skip LF
}
}
break;
default: {
out.write(whitespaceAccumulator.toByteArray());
whitespaceAccumulator.reset();
out.write(currSym);
}
}
} catch (IOException e) {
// the compiler claims that an IOException can occur
// on a call to toByteArray(). The javadocs and
// the ByteArrayOutputStream class file claim otherwise.
}
}
}
try {
out.write(whitespaceAccumulator.toByteArray());
} catch (IOException e) {
// same story as above.
}
return out.toByteArray();
}
}