/*
* Copyright 2013
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
* implied. See the License for the specific language governing
* permissions and limitations under the License.
*/
package org.openntf.domino.utils;
import java.io.IOException;
import java.io.InputStream;
import lotus.domino.NotesException;
import lotus.domino.Stream;
/**
* Utility enum as a carrier for Stream-centric static properties and methods.
*
*/
public enum Streams {
;
public static class MIMEBufferedInputStream extends InputStream {
private static final int DEFAULT_BUFFER_SIZE = 16384;
private static final boolean FORCE_READ = false;
// private static int instanceCount = 0;
private Stream is;
private byte[] buffer;
private int length;
private int buffered;
private int bufferPos;
public static InputStream get(final Stream source) {
return source != null ? new MIMEBufferedInputStream(source) : null;
}
public MIMEBufferedInputStream(final Stream is, final int size) {
try {
this.is = is;
this.buffer = new byte[size];
this.length = is.getBytes();
} catch (NotesException ne) {
DominoUtils.handleException(ne);
throw new RuntimeException(MIMEBufferedInputStream.class.getName() + " Constructor Failure");
}
// instanceCount++;
// if (++instanceCount % 1000 == 0) {
// System.out.println("Created " + instanceCount + " MIMEInputStream objects...");
// }
}
public MIMEBufferedInputStream(final Stream is) {
this(is, DEFAULT_BUFFER_SIZE);
}
public boolean isEOF() throws IOException {
return getNextByteCount() == 0;
}
@Override
public int read() throws IOException {
if (bufferPos == buffered) {
//we've read to the end of the buffer byte-by-byte.
//time to refill...
buffered = getNextByteCount();
buffer = Streams.readStream(is, buffered);
bufferPos = 0;
if (buffered <= 0) {
buffered = 0;
return -1;
}
}
return buffer[bufferPos++] & 0xFF;
}
@Override
public int read(final byte[] array) throws IOException {
return read(array, 0, array.length);
}
@Override
public int read(final byte[] array, int off, int length) throws IOException {
if (FORCE_READ) {
int read = 0;
while (read < length) {
int r = _read(array, off, length);
if (r < 0) {
return read > 0 ? read : r;
}
off += r;
length -= r;
read += r;
}
return read;
} else {
return _read(array, off, length);
}
}
private int getNextByteCount() {
int remaining;
int position = Streams.getStreamPosition(is);
if (position < 0) {
return 0;
}
remaining = length - position;
return (remaining < buffer.length) ? remaining : buffer.length;
}
private int _read(final byte[] array, final int off, final int length) throws IOException {
int avail = buffered - bufferPos;
if (avail == 0) {
buffered = getNextByteCount();
buffer = Streams.readStream(is, buffered);
avail = buffered;
bufferPos = 0;
if (buffered <= 0) {
buffered = 0;
return -1;
}
}
int toRead = length < avail ? length : avail;
System.arraycopy(buffer, bufferPos, array, off, toRead);
bufferPos += toRead;
return toRead;
}
@Override
public long skip(long n) throws IOException {
if (FORCE_READ) {
long skip = 0;
while (skip < n) {
long r = _skip(n);
if (r < 0) {
return skip > 0 ? skip : r;
}
n -= r;
skip += r;
}
return skip;
} else {
return _skip(n);
}
}
private long _skip(final long n) throws IOException {
int avail = buffered - bufferPos;
if (avail > 0) {
if (n < avail) {
bufferPos += n;
return n;
}
bufferPos = buffered;
return avail;
}
final int position = Streams.getStreamPosition(is);
if (position < 0) {
throw new IOException("Unable to get Stream Position");
}
long newPos = position + n;
if (newPos > length) {
return 0;
} else {
int intPos = Integer.parseInt(Long.toString(newPos));
if (!Streams.setStreamPosition(is, intPos)) {
throw new IOException("Unable to set Stream Position to " + newPos);
}
return n;
}
}
@Override
public int available() throws IOException {
final int position = Streams.getStreamPosition(is);
if (position < 0) {
throw new IOException("Unable to get Stream Position");
}
return length - position;
}
@Override
public void close() throws IOException {
try {
is.close();
} catch (NotesException ne) {
DominoUtils.handleException(ne);
throw new IOException("Unable to close stream");
}
}
@Override
public void mark(final int int0) {
}
@Override
public void reset() throws IOException {
}
@Override
public boolean markSupported() {
return false;
}
}
public static int getStreamBytes(final Stream stream) {
try {
return stream.getBytes();
} catch (NotesException ne) {
DominoUtils.handleException(ne);
}
return 0;
}
public static byte[] readStream(final Stream stream) {
try {
return stream.read();
} catch (NotesException ne) {
DominoUtils.handleException(ne);
return null;
}
}
public static byte[] readStream(final Stream stream, final int length) {
try {
return stream.read(length);
} catch (NotesException ne) {
DominoUtils.handleException(ne);
return null;
}
}
public static int getStreamPosition(final Stream stream) {
try {
return stream.getPosition();
} catch (NotesException ne) {
DominoUtils.handleException(ne);
return -1;
}
}
public static boolean setStreamPosition(final Stream stream, final int position) {
try {
stream.setPosition(position);
return true;
} catch (NotesException ne) {
DominoUtils.handleException(ne);
return false;
}
}
}