~ubuntu-branches/ubuntu/utopic/apache-mime4j/utopic-proposed

« back to all changes in this revision

Viewing changes to src/main/java/org/apache/james/mime4j/codec/QuotedPrintableEncoder.java

  • Committer: Package Import Robot
  • Author(s): David Paleino
  • Date: 2013-11-03 11:13:27 UTC
  • mfrom: (2.1.2 experimental)
  • Revision ID: package-import@ubuntu.com-20131103111327-09huep00ex05z113
Tags: 0.7.2-2
* Upload to unstable
* Fixed Vcs-* fields in debian/control
* Updated debian/watch
* Standards-Version bump to 3.9.5, no changes needed

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/****************************************************************
2
 
 * Licensed to the Apache Software Foundation (ASF) under one   *
3
 
 * or more contributor license agreements.  See the NOTICE file *
4
 
 * distributed with this work for additional information        *
5
 
 * regarding copyright ownership.  The ASF licenses this file   *
6
 
 * to you under the Apache License, Version 2.0 (the            *
7
 
 * "License"); you may not use this file except in compliance   *
8
 
 * with the License.  You may obtain a copy of the License at   *
9
 
 *                                                              *
10
 
 *   http://www.apache.org/licenses/LICENSE-2.0                 *
11
 
 *                                                              *
12
 
 * Unless required by applicable law or agreed to in writing,   *
13
 
 * software distributed under the License is distributed on an  *
14
 
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
15
 
 * KIND, either express or implied.  See the License for the    *
16
 
 * specific language governing permissions and limitations      *
17
 
 * under the License.                                           *
18
 
 ****************************************************************/
19
 
 
20
 
package org.apache.james.mime4j.codec;
21
 
 
22
 
import java.io.IOException;
23
 
import java.io.InputStream;
24
 
import java.io.OutputStream;
25
 
 
26
 
final class QuotedPrintableEncoder {
27
 
    private static final byte TAB = 0x09;
28
 
    private static final byte SPACE = 0x20;
29
 
    private static final byte EQUALS = 0x3D;
30
 
    private static final byte CR = 0x0D;
31
 
    private static final byte LF = 0x0A;
32
 
    private static final byte QUOTED_PRINTABLE_LAST_PLAIN = 0x7E;
33
 
    private static final int QUOTED_PRINTABLE_MAX_LINE_LENGTH = 76;
34
 
    private static final int QUOTED_PRINTABLE_OCTETS_PER_ESCAPE = 3;
35
 
    private static final byte[] HEX_DIGITS = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
36
 
 
37
 
    private final byte[] inBuffer;
38
 
    private final byte[] outBuffer;
39
 
    private final boolean binary;
40
 
    
41
 
    private boolean pendingSpace;
42
 
    private boolean pendingTab;
43
 
    private boolean pendingCR;
44
 
    private int nextSoftBreak;
45
 
    private int outputIndex;
46
 
    private OutputStream out;
47
 
    
48
 
    
49
 
    public QuotedPrintableEncoder(int bufferSize, boolean binary) {
50
 
        inBuffer = new byte[bufferSize];
51
 
        outBuffer = new byte[3*bufferSize];
52
 
        outputIndex = 0;
53
 
        nextSoftBreak = QUOTED_PRINTABLE_MAX_LINE_LENGTH + 1;
54
 
        out = null;
55
 
        this.binary = binary;
56
 
        pendingSpace = false;
57
 
        pendingTab = false;
58
 
        pendingCR = false;
59
 
    }
60
 
    
61
 
    void initEncoding(final OutputStream out) {
62
 
        this.out = out;
63
 
        pendingSpace = false;
64
 
        pendingTab = false;
65
 
        pendingCR = false;
66
 
        nextSoftBreak = QUOTED_PRINTABLE_MAX_LINE_LENGTH + 1;
67
 
    }
68
 
    
69
 
    void encodeChunk(byte[] buffer, int off, int len) throws IOException {
70
 
        for (int inputIndex = off; inputIndex < len + off; inputIndex++) {
71
 
            encode(buffer[inputIndex]);
72
 
        }
73
 
    }
74
 
    
75
 
    void completeEncoding() throws IOException {
76
 
        writePending();
77
 
        flushOutput();
78
 
    }
79
 
    
80
 
    public void encode(final InputStream in, final OutputStream out) throws IOException {
81
 
        initEncoding(out);
82
 
        int inputLength;
83
 
        while((inputLength = in.read(inBuffer)) > -1) {
84
 
            encodeChunk(inBuffer, 0, inputLength);
85
 
        }
86
 
        completeEncoding();
87
 
    }
88
 
    
89
 
    private void writePending() throws IOException {
90
 
        if (pendingSpace) {
91
 
            plain(SPACE);
92
 
        } else if (pendingTab) {
93
 
            plain(TAB);
94
 
        } else if (pendingCR) {
95
 
            plain(CR);
96
 
        }
97
 
        clearPending();
98
 
    }
99
 
    
100
 
    private void clearPending() throws IOException {
101
 
        pendingSpace  = false;
102
 
        pendingTab = false;
103
 
        pendingCR = false;
104
 
    }
105
 
    
106
 
    private void encode(byte next) throws IOException {
107
 
        if (next == LF) {
108
 
            if (binary) {
109
 
                writePending();
110
 
                escape(next);
111
 
            } else {
112
 
                if (pendingCR) {
113
 
                    // Expect either space or tab pending 
114
 
                    // but not both
115
 
                    if (pendingSpace) {
116
 
                        escape(SPACE);
117
 
                    } else if (pendingTab) {
118
 
                        escape(TAB);
119
 
                    }
120
 
                    lineBreak();
121
 
                    clearPending();
122
 
                } else {
123
 
                    writePending();
124
 
                    plain(next);
125
 
                }
126
 
            }
127
 
        } else if (next == CR) {
128
 
            if (binary)  {
129
 
                escape(next);
130
 
            } else {
131
 
                pendingCR = true;
132
 
            }
133
 
        } else {
134
 
            writePending();
135
 
            if (next == SPACE) {
136
 
                if (binary)  {
137
 
                    escape(next);
138
 
                } else {
139
 
                    pendingSpace = true;
140
 
                }
141
 
            } else if (next == TAB) {
142
 
                if (binary)  {
143
 
                    escape(next);
144
 
                } else {
145
 
                    pendingTab = true;
146
 
                }
147
 
            } else if (next < SPACE) {
148
 
                escape(next);
149
 
            } else if (next > QUOTED_PRINTABLE_LAST_PLAIN) {
150
 
                escape(next);
151
 
            } else if (next == EQUALS) {
152
 
                escape(next);
153
 
            } else {
154
 
                plain(next);
155
 
            }
156
 
        }
157
 
    }
158
 
    
159
 
    private void plain(byte next) throws IOException {
160
 
        if (--nextSoftBreak <= 1) {
161
 
            softBreak();
162
 
        }
163
 
        write(next);
164
 
    }
165
 
    
166
 
    private void escape(byte next) throws IOException {
167
 
        if (--nextSoftBreak <= QUOTED_PRINTABLE_OCTETS_PER_ESCAPE) {
168
 
            softBreak();
169
 
        }
170
 
        
171
 
        int nextUnsigned = next & 0xff;
172
 
        
173
 
        write(EQUALS);
174
 
        --nextSoftBreak;
175
 
        write(HEX_DIGITS[nextUnsigned >> 4]);
176
 
        --nextSoftBreak;
177
 
        write(HEX_DIGITS[nextUnsigned % 0x10]);
178
 
    }
179
 
    
180
 
    private void write(byte next) throws IOException {
181
 
        outBuffer[outputIndex++] = next;
182
 
        if (outputIndex >= outBuffer.length) {
183
 
            flushOutput();
184
 
        }
185
 
    }
186
 
    
187
 
    private void softBreak() throws IOException {
188
 
        write(EQUALS);
189
 
        lineBreak();
190
 
    }
191
 
 
192
 
    private void lineBreak() throws IOException {
193
 
        write(CR);
194
 
        write(LF);
195
 
        nextSoftBreak = QUOTED_PRINTABLE_MAX_LINE_LENGTH;
196
 
    }
197
 
    
198
 
    void flushOutput() throws IOException {
199
 
        if (outputIndex < outBuffer.length) {
200
 
            out.write(outBuffer, 0, outputIndex);
201
 
        } else {
202
 
            out.write(outBuffer);
203
 
        }
204
 
        outputIndex = 0;
205
 
    }
206
 
}
 
 
b'\\ No newline at end of file'