/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (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.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is part of dcm4che, an implementation of DICOM(TM) in
* Java(TM), available at http://sourceforge.net/projects/dcm4che.
*
* The Initial Developer of the Original Code is
* Agfa HealthCare.
* Portions created by the Initial Developer are Copyright (C) 2013
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* See @authors listed below.
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
package org.dcm4che3.imageio.codec.jpeg;
import java.io.IOException;
import java.util.Arrays;
import javax.imageio.stream.ImageInputStream;
import javax.imageio.stream.ImageInputStreamImpl;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* @author Gunter Zeilinger <gunterze@gmail.com>
*/
public class PatchJPEGLSImageInputStream extends ImageInputStreamImpl {
private static final Logger LOG =
LoggerFactory.getLogger(PatchJPEGLSImageInputStream.class);
private final ImageInputStream iis;
private long patchPos;
private byte[] patch;
public PatchJPEGLSImageInputStream(ImageInputStream iis,
PatchJPEGLS patchJPEGLS) throws IOException {
if (iis == null)
throw new NullPointerException("iis");
super.streamPos = iis.getStreamPosition();
super.flushedPos = iis.getFlushedPosition();
this.iis = iis;
if (patchJPEGLS == null)
return;
JPEGLSCodingParam param = patchJPEGLS.createJPEGLSCodingParam(firstBytesOf(iis));
if (param != null) {
LOG.debug("Patch JPEG-LS with {}", param);
this.patchPos = streamPos + param.getOffset();
this.patch = param.getBytes();
}
}
private byte[] firstBytesOf(ImageInputStream iis) throws IOException {
byte[] b = new byte[256];
int n, off = 0, len = b.length;
iis.mark();
while (len > 0 && (n = iis.read(b, off, len)) > 0) {
off += n;
len -= n;
}
iis.reset();
return len > 0 ? Arrays.copyOf(b, b.length - len) : b;
}
private int readAvailable(byte[] b) throws IOException {
int nbytes;
int off = 0;
int len = b.length;
while (len > 0 && (nbytes = iis.read(b, off, len)) > 0) {
off += nbytes;
len -= nbytes;
}
return off;
}
public void close() throws IOException {
super.close();
iis.close();
}
public void flushBefore(long pos) throws IOException {
super.flushBefore(pos);
iis.flushBefore(adjustStreamPosition(pos));
}
private long adjustStreamPosition(long pos) {
if (patch == null)
return pos;
long index = pos - patchPos;
return index < 0 ? pos
: index < patch.length ? patchPos
: pos - patch.length;
}
public boolean isCached() {
return iis.isCached();
}
public boolean isCachedFile() {
return iis.isCachedFile();
}
public boolean isCachedMemory() {
return iis.isCachedMemory();
}
public long length() {
try {
long len = iis.length();
return patch == null || len < 0 ? len : len + patch.length;
} catch (IOException e) {
return -1;
}
}
public int read() throws IOException {
int ch;
long index;
if (patch != null
&& (index = streamPos - patchPos) >= 0
&& index < patch.length)
ch = patch[(int) index];
else
ch = iis.read();
if (ch >= 0)
streamPos++;
return ch;
}
public int read(byte[] b, int off, int len) throws IOException {
int r = 0;
if (patch != null && streamPos < patchPos + patch.length) {
if (streamPos < patchPos) {
r = iis.read(b, off, (int) Math.min(patchPos - streamPos, len));
if (r < 0)
return r;
streamPos += r;
if (streamPos < patchPos)
return r;
off += r;
len -= r;
}
int index = (int) (patchPos - streamPos);
int r2 = (int) Math.min(patch.length - index, len);
System.arraycopy(patch, index, b, off, r2);
streamPos += r2;
r += r2;
off += r2;
len -= r2;
}
if (len > 0) {
int r3 = iis.read(b, off, len);
if (r3 < 0)
return r3;
streamPos += r3;
r += r3;
}
return r;
}
public void mark() {
super.mark();
iis.mark();
}
public void reset() throws IOException {
super.reset();
iis.reset();
}
public void seek(long pos) throws IOException {
super.seek(pos);
iis.seek(adjustStreamPosition(pos));
}
}