KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > columba > ristretto > coder > QuotedPrintableEncoderInputStream


1 /* ***** BEGIN LICENSE BLOCK *****
2  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
3  *
4  * The contents of this file are subject to the Mozilla Public License Version
5  * 1.1 (the "License"); you may not use this file except in compliance with
6  * the License. You may obtain a copy of the License at
7  * http://www.mozilla.org/MPL/
8  *
9  * Software distributed under the License is distributed on an "AS IS" basis,
10  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
11  * for the specific language governing rights and limitations under the
12  * License.
13  *
14  * The Original Code is Ristretto Mail API.
15  *
16  * The Initial Developers of the Original Code are
17  * Timo Stich and Frederik Dietz.
18  * Portions created by the Initial Developers are Copyright (C) 2004
19  * All Rights Reserved.
20  *
21  * Contributor(s):
22  *
23  * Alternatively, the contents of this file may be used under the terms of
24  * either the GNU General Public License Version 2 or later (the "GPL"), or
25  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
26  * in which case the provisions of the GPL or the LGPL are applicable instead
27  * of those above. If you wish to allow use of your version of this file only
28  * under the terms of either the GPL or the LGPL, and not to allow others to
29  * use your version of this file under the terms of the MPL, indicate your
30  * decision by deleting the provisions above and replace them with the notice
31  * and other provisions required by the GPL or the LGPL. If you do not delete
32  * the provisions above, a recipient may use your version of this file under
33  * the terms of any one of the MPL, the GPL or the LGPL.
34  *
35  * ***** END LICENSE BLOCK ***** */

36 package org.columba.ristretto.coder;
37
38 import java.io.FilterInputStream JavaDoc;
39 import java.io.IOException JavaDoc;
40 import java.io.InputStream JavaDoc;
41 import java.nio.IntBuffer JavaDoc;
42
43
44 /**
45  * FilterInputStream that encodes a characterstream in quoted-printable.
46  * <br>
47  * <b>Note:</b> The input is transformed to canonical form before encoding.
48  * (lineendings are converted to CRLF)
49  * <br>
50  * <b>RFC(s):</b> 2045
51  *
52  * @author Timo Stich <tstich@users.sourceforge.net>
53  */

54 public class QuotedPrintableEncoderInputStream extends FilterInputStream JavaDoc {
55
56     private static final char[] hexTable =
57         {
58             '0',
59             '1',
60             '2',
61             '3',
62             '4',
63             '5',
64             '6',
65             '7',
66             '8',
67             '9',
68             'A',
69             'B',
70             'C',
71             'D',
72             'E',
73             'F' };
74
75     private IntBuffer JavaDoc outBytes;
76
77     private int pos;
78     private int available;
79     private int lineLength;
80
81     /**
82      * Constructs a QuotedPrintableEncoderInputStream.
83      *
84      * @param arg0 the characterstream that will be encoded
85      */

86     public QuotedPrintableEncoderInputStream(InputStream JavaDoc arg0) {
87         super(arg0);
88
89         outBytes = IntBuffer.allocate(10);
90
91     }
92
93     
94     /**
95      * The next char is read from the inputstream and
96      * is encoded in quoted-printable if necessary.
97      * See RFC 2045 for details on how quoted-printable
98      * decoding works.
99      *
100      * @return the number of output characters.
101      * @throws IOException
102      */

103     private int processNextInput() throws IOException JavaDoc {
104         outBytes.clear();
105         int read = in.read();
106
107         if (read == -1)
108             return -1;
109
110         // chars must be encoded when not :
111
// 33 <= c <=60; 62 <= c <= 126 (literal characters)
112
// c = {9,32} but not at the end of a line or if they are char at linePos 74
113
// because a soft linebreak will follow (whitespaces)
114
// c = {\r,\n} (linebreak)
115
if (read == '\t' || read == ' ') {
116             // if linelength == 73 always encode the WS
117
if (lineLength >= 74) {
118                 outBytes.put('=');
119                 outBytes.put(toHexString(read));
120                 lineLength += 3;
121             } else {
122                 // Check the next character
123
int next = in.read();
124                 if (next != -1) {
125                     // if it is a CRLF encode the WS
126
if (next == '\r' || next == '\n') {
127                         outBytes.put('=');
128                         outBytes.put(toHexString(read));
129                         lineLength += 3;
130                     } else {
131                         // else no need to encode the WS
132
outBytes.put( read );
133                         lineLength++;
134                     }
135                     
136                     // set the second read character to read
137
// so the following code will handle the
138
// encoding of it
139
read = next;
140                 }
141             }
142         }
143         
144         // Check if read must be encoded
145
if (read >= 33 && read != 61 && read <= 126) {
146             outBytes.put(read);
147             lineLength++;
148         } else if( read == '\r' ){
149             outBytes.put('\r');
150             outBytes.put('\n');
151             // On \r a \n MUST follow -> we added it already
152
in.read();
153             lineLength = 0;
154         } else if( read == '\n' ){
155             // Normalize the stream and convert \n to \r\n
156
outBytes.put('\r');
157             outBytes.put('\n');
158             lineLength = 0;
159         } else {
160             outBytes.put('=');
161             outBytes.put(toHexString(read));
162             lineLength += 3;
163         }
164         
165         // Insert Softlinebreak if the linelength > 74
166
if( lineLength >= 74) {
167             outBytes.put('=');
168             outBytes.put('\r');
169             outBytes.put('\n');
170             lineLength = 0;
171         }
172         
173         return outBytes.position();
174     }
175     
176     /**
177      * @see java.io.InputStream#read()
178      */

179     public int read() throws IOException JavaDoc {
180         if( pos == available ) {
181             available = processNextInput();
182             pos = 0;
183         }
184         
185         if( available == -1) return -1;
186         
187         return outBytes.get(pos++);
188     }
189     
190     /**
191      * @see java.io.InputStream#read(byte[], int, int)
192      */

193     public int read(byte[] arg0, int arg1, int arg2) throws IOException JavaDoc {
194         int next;
195         for( int i=0; i<arg2; i++) {
196             next = read();
197             if( next == -1 ) {
198                 if( i == 0 ) {
199                     return -1;
200                 } else {
201                     return i;
202                 }
203             }
204             arg0[arg1+i] = (byte) next;
205         }
206         return arg2;
207     }
208     
209
210     /**
211      * Converts a byte-value into a hex number
212      *
213      * @param in
214      * @return the hex number
215      */

216     private int[] toHexString(int in) {
217         int[] result = new int[2];
218         int value;
219         if (in < 0) {
220             value = 0x080 | (0x07f & in);
221         } else {
222             value = in;
223         }
224
225         int hi = value / 16;
226         int lo = value % 16;
227         result[0] = hexTable[hi];
228         result[1] = hexTable[lo];
229         return result;
230     }
231
232 }
233
Popular Tags