Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ public int read() throws IOException {
} else if (a == '\r') {
// Expecting LF. This forms a soft linebreak to be ignored.
int b = in.read();
if (b != '\n')
if (b != '\n' && b != -1)
/* Not really confirming QP encoding, but
* lets allow this as well.
*/
Expand All @@ -106,7 +106,15 @@ public int read() throws IOException {
return -1;
} else {
ba[0] = (byte) a;
ba[1] = (byte) in.read();
int b = in.read();
if (b == -1) {
// '=' followed by a single character at EOF; not a valid
// encoded atom. Push back the real character and return
// '=' literally, without inventing a second byte.
((PushbackInputStream) in).unread(a);
return c;
}
ba[1] = (byte) b;
try {
return ASCIIUtility.parseInt(ba, 0, 2, 16);
} catch (NumberFormatException nex) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
/*
* Copyright (c) 1997, 2023 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0, which is available at
* http://www.eclipse.org/legal/epl-2.0.
*
* This Source Code may also be made available under the following Secondary
* Licenses when the conditions for such availability set forth in the
* Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
* version 2 with the GNU Classpath Exception, which is available at
* https://www.gnu.org/software/classpath/license.html.
*
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
*/

package org.eclipse.angus.mail.util;

import org.junit.Test;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;

import static org.junit.Assert.assertArrayEquals;

/**
* Test quoted-printable decoder.
*/

public class QPDecoderStreamTest {

private static byte[] decode(byte[] in) throws Exception {
InputStream qp = new QPDecoderStream(new ByteArrayInputStream(in));
ByteArrayOutputStream bos = new ByteArrayOutputStream();
int c;
while ((c = qp.read()) != -1)
bos.write(c);
qp.close();
return bos.toByteArray();
}

/**
* A valid encoded atom decodes to the corresponding byte.
*/
@Test
public void testDecodeAtom() throws Exception {
assertArrayEquals(new byte[]{'A'}, decode(new byte[]{'=', '4', '1'}));
}

/**
* An '=' followed by a single hex digit at EOF must not add a byte that
* wasn't in the input. The truncated atom is passed through literally.
*/
@Test
public void testTruncatedAtomAtEOF() throws Exception {
assertArrayEquals(new byte[]{'=', '4'}, decode(new byte[]{'=', '4'}));
assertArrayEquals(new byte[]{'h', 'i', '=', '4'},
decode(new byte[]{'h', 'i', '=', '4'}));
}

/**
* An '=' followed by CR at EOF (a truncated soft line break) must not add
* a byte that wasn't in the input.
*/
@Test
public void testTruncatedSoftBreakAtEOF() throws Exception {
assertArrayEquals(new byte[0], decode(new byte[]{'=', '\r'}));
assertArrayEquals(new byte[]{'A'}, decode(new byte[]{'A', '=', '\r'}));
}
}