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 *
10
* http://www.apache.org/licenses/LICENSE-2.0 *
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
****************************************************************/
20
package org.apache.james.mime4j.codec;
22
import java.io.IOException;
23
import java.io.InputStream;
24
import java.io.OutputStream;
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'};
37
private final byte[] inBuffer;
38
private final byte[] outBuffer;
39
private final boolean binary;
41
private boolean pendingSpace;
42
private boolean pendingTab;
43
private boolean pendingCR;
44
private int nextSoftBreak;
45
private int outputIndex;
46
private OutputStream out;
49
public QuotedPrintableEncoder(int bufferSize, boolean binary) {
50
inBuffer = new byte[bufferSize];
51
outBuffer = new byte[3*bufferSize];
53
nextSoftBreak = QUOTED_PRINTABLE_MAX_LINE_LENGTH + 1;
61
void initEncoding(final OutputStream out) {
66
nextSoftBreak = QUOTED_PRINTABLE_MAX_LINE_LENGTH + 1;
69
void encodeChunk(byte[] buffer, int off, int len) throws IOException {
70
for (int inputIndex = off; inputIndex < len + off; inputIndex++) {
71
encode(buffer[inputIndex]);
75
void completeEncoding() throws IOException {
80
public void encode(final InputStream in, final OutputStream out) throws IOException {
83
while((inputLength = in.read(inBuffer)) > -1) {
84
encodeChunk(inBuffer, 0, inputLength);
89
private void writePending() throws IOException {
92
} else if (pendingTab) {
94
} else if (pendingCR) {
100
private void clearPending() throws IOException {
101
pendingSpace = false;
106
private void encode(byte next) throws IOException {
113
// Expect either space or tab pending
117
} else if (pendingTab) {
127
} else if (next == CR) {
141
} else if (next == TAB) {
147
} else if (next < SPACE) {
149
} else if (next > QUOTED_PRINTABLE_LAST_PLAIN) {
151
} else if (next == EQUALS) {
159
private void plain(byte next) throws IOException {
160
if (--nextSoftBreak <= 1) {
166
private void escape(byte next) throws IOException {
167
if (--nextSoftBreak <= QUOTED_PRINTABLE_OCTETS_PER_ESCAPE) {
171
int nextUnsigned = next & 0xff;
175
write(HEX_DIGITS[nextUnsigned >> 4]);
177
write(HEX_DIGITS[nextUnsigned % 0x10]);
180
private void write(byte next) throws IOException {
181
outBuffer[outputIndex++] = next;
182
if (outputIndex >= outBuffer.length) {
187
private void softBreak() throws IOException {
192
private void lineBreak() throws IOException {
195
nextSoftBreak = QUOTED_PRINTABLE_MAX_LINE_LENGTH;
198
void flushOutput() throws IOException {
199
if (outputIndex < outBuffer.length) {
200
out.write(outBuffer, 0, outputIndex);
202
out.write(outBuffer);
b'\\ No newline at end of file'