001: /*
002: *
003: *
004: * Copyright 1990-2007 Sun Microsystems, Inc. All Rights Reserved.
005: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
006: *
007: * This program is free software; you can redistribute it and/or
008: * modify it under the terms of the GNU General Public License version
009: * 2 only, as published by the Free Software Foundation.
010: *
011: * This program is distributed in the hope that it will be useful, but
012: * WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014: * General Public License version 2 for more details (a copy is
015: * included at /legal/license.txt).
016: *
017: * You should have received a copy of the GNU General Public License
018: * version 2 along with this work; if not, write to the Free Software
019: * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
020: * 02110-1301 USA
021: *
022: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
023: * Clara, CA 95054 or visit www.sun.com if you need additional
024: * information or have any questions.
025: */
026:
027: package com.sun.kvem.midp.pim.formats;
028:
029: import com.sun.midp.main.Configuration;
030: import java.io.ByteArrayOutputStream;
031: import java.io.IOException;
032:
033: /**
034: * Interprets the Quoted-Printable encoding.
035: * The Quoted-Printable Encoding is defined in RFC 2045.
036: *
037: */
038: public class QuotedPrintableEncoding {
039:
040: /**
041: * Converts a quoted-printable string to a byte array.
042: * @param sdata input data to be converted
043: * @return processed data from quoted printable
044: */
045: public static byte[] fromQuotedPrintable(String sdata) {
046: ByteArrayOutputStream out = new ByteArrayOutputStream();
047: ByteArrayOutputStream whitespaceAccumulator = new ByteArrayOutputStream();
048: char[] data = sdata.toCharArray();
049: byte[] linebreak = Configuration.getProperty("file.linebreak")
050: .getBytes();
051: boolean followingEqualsSign = false;
052: for (int i = 0; i < data.length; i++) {
053: char currSym = data[i];
054: if (followingEqualsSign) {
055: switch (currSym) {
056: case '\r':
057: // RFC 2045: check for soft break (=CRLF)
058: if (i + 1 < data.length) {
059: if (data[i + 1] == '\n') {
060: // concatenate lines
061: i++;
062: break;
063: }
064: }
065: default: {
066: // inlined byte
067: if (i < data.length - 1) {
068: String charCode = sdata.substring(i, i + 2);
069: i++;
070: try {
071: out.write(Integer.parseInt(charCode, 16));
072: break;
073: } catch (NumberFormatException nfe) {
074: // illegal data. write the data as is
075: out.write('=');
076: out.write(charCode.charAt(0));
077: out.write(charCode.charAt(1));
078: }
079: } else {
080: // '=' is the penultimate character, which is also
081: // illegal. write the data as is
082: out.write('=');
083: out.write(currSym);
084: }
085: }
086: }
087: followingEqualsSign = false;
088: } else {
089: try {
090: /**
091: * RFC 2045: Control characters other than TAB, or CR and LF
092: * as parts of CRLF pairs, must not appear. The same is true
093: * for octets with decimal values greater than 126. If
094: * found in incoming quoted-printable data by a decoder, a
095: * robust implementation might exclude them from the
096: * decoded data.
097: */
098: if (((currSym < ' ') && (currSym != '\t') && (currSym != '\r'))
099: || (currSym > 126)) { // ignore
100: continue;
101: }
102: switch (currSym) {
103: case '=': {
104: out.write(whitespaceAccumulator.toByteArray());
105: whitespaceAccumulator.reset();
106: followingEqualsSign = true;
107: break;
108: }
109: case '\t':
110: case ' ':
111: whitespaceAccumulator.write(currSym);
112: break;
113: case '\r': // must be a part of CRLF (RFC 2045)
114: if (i + 1 < data.length) {
115: if (data[i + 1] == '\n') {
116: whitespaceAccumulator.reset();
117: out.write(linebreak, 0,
118: linebreak.length);
119: i++; // skip LF
120: }
121: }
122: break;
123: default: {
124: out.write(whitespaceAccumulator.toByteArray());
125: whitespaceAccumulator.reset();
126: out.write(currSym);
127: }
128: }
129: } catch (IOException e) {
130: // the compiler claims that an IOException can occur
131: // on a call to toByteArray(). The javadocs and
132: // the ByteArrayOutputStream class file claim otherwise.
133:
134: }
135: }
136: }
137: try {
138: out.write(whitespaceAccumulator.toByteArray());
139: } catch (IOException e) {
140: // same story as above.
141: }
142: return out.toByteArray();
143: }
144:
145: }
|