/** * FUSE-J: Java bindings for FUSE (Filesystem in Userspace by Miklos Szeredi (mszeredi@inf.bme.hu)) * * Copyright (C) 2003 Peter Levart (peter@select-tech.si) * * This program can be distributed under the terms of the GNU LGPL. * See the file COPYING.LIB */ package fuse.zipfs; import fuse.FuseException; import java.io.BufferedInputStream; import java.io.IOException; import java.nio.ByteBuffer; import java.util.zip.ZipEntry; import java.util.zip.ZipFile; import org.apache.commons.logging.LogFactory; import org.apache.commons.logging.Log; public class ZipEntryDataReader { private static final Log log = LogFactory.getLog(ZipEntryDataReader.class); private static final int bufferSize = 8192; private ZipFile zipFile; private ZipEntry zipEntry; private BufferedInputStream zipStream; private long zipPos; private long zipMarkPos; public ZipEntryDataReader(ZipFile zipFile, ZipEntry zipEntry) { this.zipFile = zipFile; this.zipEntry = zipEntry; } public synchronized void read(ByteBuffer bb, long offset) throws FuseException { BufferedInputStream in = getZipStream(offset, bb.capacity()); // EOF? if (in == null) return; byte[] buff = new byte[bb.capacity()]; int nread; try { nread = in.read(buff); } catch (IOException e) { throw new FuseException("IO error", e).initErrno(FuseException.EIO); } if (nread > 0) { zipPos += nread; bb.put(buff, 0, nread); } if (log.isDebugEnabled()) log.debug("read " + bb.position() + "/" + bb.capacity() + " requested bytes"); } private BufferedInputStream getZipStream(long offset, int length) throws FuseException { try { while (true) { if (zipStream == null) { zipStream = new BufferedInputStream(zipFile.getInputStream(zipEntry), bufferSize); zipPos = 0; zipStream.mark(bufferSize); zipMarkPos = 0; } if (offset == zipPos) { zipStream.mark(bufferSize); zipMarkPos = zipPos; return zipStream; } while (offset > zipPos) { zipStream.mark(bufferSize); zipMarkPos = zipPos; long nSkiped = zipStream.skip(offset - zipPos); if (nSkiped == 0) return null; // premature EOF zipPos += nSkiped; } if (offset == zipPos) return zipStream; if (offset >= zipMarkPos) { try { zipStream.reset(); zipPos = zipMarkPos; continue; } catch (IOException e) { // mark has been invalidated - can't go back } } // can't go back so much - reopen stream zipStream.close(); zipStream = null; } } catch (IOException e) { throw new FuseException("IO error", e).initErrno(FuseException.EIO); } } }