001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * https://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017 018package org.apache.commons.codec.binary; 019 020import java.io.InputStream; 021 022import org.apache.commons.codec.CodecPolicy; 023import org.apache.commons.codec.binary.BaseNCodecInputStream.AbstracBuilder; // NOPMD: Required by ECJ (Eclipse) 024 025/** 026 * Provides Base64 decoding in a streaming fashion (unlimited size). When encoding the default lineLength is 76 characters and the default lineEnding is CRLF, 027 * but these can be overridden by using the appropriate constructor. 028 * <p> 029 * The default behavior of the Base64InputStream is to DECODE, whereas the default behavior of the Base64OutputStream is to ENCODE, but this behavior can be 030 * overridden by using a different constructor. 031 * </p> 032 * <p> 033 * This class implements section <cite>6.8. Base64 Content-Transfer-Encoding</cite> from RFC 2045 <cite>Multipurpose Internet Mail Extensions (MIME) Part One: 034 * Format of Internet Message Bodies</cite> by Freed and Borenstein. 035 * </p> 036 * <p> 037 * Since this class operates directly on byte streams, and not character streams, it is hard-coded to only encode/decode character encodings which are 038 * compatible with the lower 127 ASCII chart (ISO-8859-1, Windows-1252, UTF-8, etc). 039 * </p> 040 * <p> 041 * You can set the decoding behavior when the input bytes contain leftover trailing bits that cannot be created by a valid encoding. These can be bits that are 042 * unused from the final character or entire characters. The default mode is lenient decoding. 043 * </p> 044 * <ul> 045 * <li>Lenient: Any trailing bits are composed into 8-bit bytes where possible. The remainder are discarded. 046 * <li>Strict: The decoding will raise an {@link IllegalArgumentException} if trailing bits are not part of a valid encoding. Any unused bits from the final 047 * character must be zero. Impossible counts of entire final characters are not allowed. 048 * </ul> 049 * <p> 050 * When strict decoding is enabled it is expected that the decoded bytes will be re-encoded to a byte array that matches the original, i.e. no changes occur on 051 * the final character. This requires that the input bytes use the same padding and alphabet as the encoder. 052 * </p> 053 * 054 * @see Base64 055 * @see <a href="https://www.ietf.org/rfc/rfc2045.txt">RFC 2045</a> 056 * @since 1.4 057 */ 058public class Base64InputStream extends BaseNCodecInputStream<Base64, Base64InputStream, Base64InputStream.Builder> { 059 060 /** 061 * Builds instances of Base64InputStream. 062 */ 063 public static class Builder extends AbstracBuilder<Base64InputStream, Base64, Builder> { 064 065 /** 066 * Constructs a new instance. 067 */ 068 public Builder() { 069 // empty 070 } 071 072 @Override 073 public Base64InputStream get() { 074 return new Base64InputStream(this); 075 } 076 077 @Override 078 protected Base64 newBaseNCodec() { 079 return new Base64(); 080 } 081 } 082 083 /** 084 * Constructs a new Builder. 085 * 086 * @return a new Builder. 087 */ 088 public static Builder builder() { 089 return new Builder(); 090 } 091 092 private Base64InputStream(final Builder builder) { 093 super(builder); 094 } 095 096 /** 097 * Constructs a Base64InputStream such that all data read is Base64-decoded from the original provided InputStream. 098 * 099 * @param inputStream InputStream to wrap. 100 */ 101 public Base64InputStream(final InputStream inputStream) { 102 super(builder().setInputStream(inputStream)); 103 } 104 105 /** 106 * Constructs a Base64InputStream such that all data read is either Base64-encoded or Base64-decoded from the original provided InputStream. 107 * 108 * @param inputStream InputStream to wrap. 109 * @param encode true if we should encode all data read from us, false if we should decode. 110 * @deprecated Use {@link #builder()} and {@link Builder}. 111 */ 112 @Deprecated 113 public Base64InputStream(final InputStream inputStream, final boolean encode) { 114 super(builder().setInputStream(inputStream).setEncode(encode)); 115 } 116 117 /** 118 * Constructs a Base64InputStream such that all data read is either Base64-encoded or Base64-decoded from the original provided InputStream. 119 * 120 * @param inputStream InputStream to wrap. 121 * @param encode true if we should encode all data read from us, false if we should decode. 122 * @param lineLength If doEncode is true, each line of encoded data will contain lineLength characters (rounded down to the nearest multiple of 4). If 123 * lineLength <= 0, the encoded data is not divided into lines. If doEncode is false, lineLength is ignored. 124 * @param lineSeparator If doEncode is true, each line of encoded data will be terminated with this byte sequence (for example \r\n). If lineLength <= 0, 125 * the lineSeparator is not used. If doEncode is false lineSeparator is ignored. 126 * @deprecated Use {@link #builder()} and {@link Builder}. 127 */ 128 @Deprecated 129 public Base64InputStream(final InputStream inputStream, final boolean encode, final int lineLength, final byte[] lineSeparator) { 130 super(builder().setInputStream(inputStream).setEncode(encode) 131 .setBaseNCodec(Base64.builder().setLineLength(lineLength).setLineSeparator(lineSeparator).get())); 132 } 133 134 /** 135 * Constructs a Base64InputStream such that all data read is either Base64-encoded or Base64-decoded from the original provided InputStream. 136 * 137 * @param inputStream InputStream to wrap. 138 * @param encode true if we should encode all data read from us, false if we should decode. 139 * @param lineLength If doEncode is true, each line of encoded data will contain lineLength characters (rounded down to the nearest multiple of 4). If 140 * lineLength <= 0, the encoded data is not divided into lines. If doEncode is false, lineLength is ignored. 141 * @param lineSeparator If doEncode is true, each line of encoded data will be terminated with this byte sequence (for example \r\n). If lineLength <= 142 * 0, the lineSeparator is not used. If doEncode is false lineSeparator is ignored. 143 * @param decodingPolicy The decoding policy. 144 * @since 1.15 145 * @deprecated Use {@link #builder()} and {@link Builder}. 146 */ 147 @Deprecated 148 public Base64InputStream(final InputStream inputStream, final boolean encode, final int lineLength, final byte[] lineSeparator, 149 final CodecPolicy decodingPolicy) { 150 super(builder().setInputStream(inputStream).setEncode(encode) 151 .setBaseNCodec(Base64.builder().setLineLength(lineLength).setLineSeparator(lineSeparator).setDecodingPolicy(decodingPolicy).get())); 152 } 153}