/* * MultiFileOutputStream.java * * Copyright (c) 2011, The University of Sheffield. * * Valentin Tablan, 26 Apr 2011 * * $Id$ */ package gate.mimir.util; import java.io.BufferedInputStream; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.io.UnsupportedEncodingException; import java.util.Arrays; import java.util.zip.CRC32; /** * An input stream that concatenates the bytes from a list of input files, that * it opens one after another. */ public class MultiFileInputStream extends InputStream { private File inputDirectory; private String[] inputFileNames; private int seqNumber = -1; private InputStream currentInputStream; private File currentInputFile; private boolean closed = false; private CRC32 crc; public MultiFileInputStream(File inputDirectory, String[] inputFileNames) throws IOException { this.inputDirectory = inputDirectory; this.inputFileNames = inputFileNames; crc = new CRC32(); // check the signature try { byte[] specimen = "MMFA".getBytes("UTF-8"); byte[] signature = new byte[specimen.length]; read(signature, 0, specimen.length); if(!Arrays.equals(specimen, signature)) { throw new IOException("The supplied archive files are not a valid " + "Mimir multi-file archive!"); } } catch(UnsupportedEncodingException e) { throw new RuntimeException("This JVM does not support UTF-8!"); } } protected boolean nextFile() throws IOException { if(currentInputStream != null) { currentInputStream.close(); } seqNumber++; if(seqNumber < inputFileNames.length) { currentInputFile = new File(inputDirectory, inputFileNames[seqNumber]); currentInputStream = new BufferedInputStream( new FileInputStream(currentInputFile)); return true; } else { return false; } } @Override public int read() throws IOException { if(closed) throw new IOException("Input stream already closed!"); // did we just start? if(currentInputStream == null) { if(!nextFile()) return -1; } int res = currentInputStream.read(); if(res == -1) { // we just finished a file if(nextFile()) { res = currentInputStream.read(); if(res != -1) crc.update(res); } return res; } else { crc.update(res); return res; } } @Override public int read(byte[] b, int off, int len) throws IOException { if(closed) throw new IOException("Input stream already closed!"); // did we just start? if(currentInputStream == null) { if(!nextFile()) return -1; } int res = currentInputStream.read(b, off, len); if(res == -1) { // we just finished a file if(nextFile()) { res = currentInputStream.read(b, off, len); if(res != -1) crc.update(b, off, res); return res; } else { return -1; } } else { crc.update(b, off, res); return res; } } public long getCRC() { return crc.getValue(); } @Override public int available() throws IOException { if(closed) throw new IOException("Input stream already closed!"); if(currentInputStream == null) { if(!nextFile()) return 0; } return currentInputStream.available(); } @Override public void close() throws IOException { if(!closed) { if(currentInputStream != null) currentInputStream.close(); closed = true; } } @Override public boolean markSupported() { return false; } }