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 * http://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
018 package org.apache.commons.codec.binary;
019
020 import java.io.FilterInputStream;
021 import java.io.IOException;
022 import java.io.InputStream;
023
024 /**
025 * Abstract superclass for Base-N input streams.
026 *
027 * @since 1.5
028 */
029 public class BaseNCodecInputStream extends FilterInputStream {
030
031 private final boolean doEncode;
032
033 private final BaseNCodec baseNCodec;
034
035 private final byte[] singleByte = new byte[1];
036
037 protected BaseNCodecInputStream(InputStream in, BaseNCodec baseNCodec, boolean doEncode) {
038 super(in);
039 this.doEncode = doEncode;
040 this.baseNCodec = baseNCodec;
041 }
042
043 /**
044 * Reads one <code>byte</code> from this input stream.
045 *
046 * @return the byte as an integer in the range 0 to 255. Returns -1 if EOF has been reached.
047 * @throws IOException
048 * if an I/O error occurs.
049 */
050 public int read() throws IOException {
051 int r = read(singleByte, 0, 1);
052 while (r == 0) {
053 r = read(singleByte, 0, 1);
054 }
055 if (r > 0) {
056 return singleByte[0] < 0 ? 256 + singleByte[0] : singleByte[0];
057 }
058 return -1;
059 }
060
061 /**
062 * Attempts to read <code>len</code> bytes into the specified <code>b</code> array starting at <code>offset</code>
063 * from this InputStream.
064 *
065 * @param b
066 * destination byte array
067 * @param offset
068 * where to start writing the bytes
069 * @param len
070 * maximum number of bytes to read
071 *
072 * @return number of bytes read
073 * @throws IOException
074 * if an I/O error occurs.
075 * @throws NullPointerException
076 * if the byte array parameter is null
077 * @throws IndexOutOfBoundsException
078 * if offset, len or buffer size are invalid
079 */
080 public int read(byte b[], int offset, int len) throws IOException {
081 if (b == null) {
082 throw new NullPointerException();
083 } else if (offset < 0 || len < 0) {
084 throw new IndexOutOfBoundsException();
085 } else if (offset > b.length || offset + len > b.length) {
086 throw new IndexOutOfBoundsException();
087 } else if (len == 0) {
088 return 0;
089 } else {
090 int readLen = 0;
091 /*
092 Rationale for while-loop on (readLen == 0):
093 -----
094 Base32.readResults() usually returns > 0 or EOF (-1). In the
095 rare case where it returns 0, we just keep trying.
096
097 This is essentially an undocumented contract for InputStream
098 implementors that want their code to work properly with
099 java.io.InputStreamReader, since the latter hates it when
100 InputStream.read(byte[]) returns a zero. Unfortunately our
101 readResults() call must return 0 if a large amount of the data
102 being decoded was non-base32, so this while-loop enables proper
103 interop with InputStreamReader for that scenario.
104 -----
105 This is a fix for CODEC-101
106 */
107 while (readLen == 0) {
108 if (!baseNCodec.hasData()) {
109 byte[] buf = new byte[doEncode ? 4096 : 8192];
110 int c = in.read(buf);
111 if (doEncode) {
112 baseNCodec.encode(buf, 0, c);
113 } else {
114 baseNCodec.decode(buf, 0, c);
115 }
116 }
117 readLen = baseNCodec.readResults(b, offset, len);
118 }
119 return readLen;
120 }
121 }
122 /**
123 * {@inheritDoc}
124 *
125 * @return false
126 */
127 public boolean markSupported() {
128 return false; // not an easy job to support marks
129 }
130
131 }