/******************************************************************************* * Copyright (c) 2007 compeople AG and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * compeople AG (Stefan Liebig) - initial API and implementation * IBM Corporation - bug fixes and enhancements *******************************************************************************/ package org.eclipse.equinox.internal.p2.sar; import java.io.*; /** * The SarInputStream reads a streaming archive as an InputStream. Methods are * provided to position at each successive entry in the archive, and the read * each entry as a normal input stream using read(). */ public class SarInputStream extends InputStream { private final DataInputStream dataInputStream; private final int version; private InputStream contentStream; /** * Constructor for SarInputStream. * * @param inputStream * the input stream to use * @throws IOException */ public SarInputStream(InputStream inputStream) throws IOException { this.dataInputStream = new DataInputStream(inputStream); // SarFile marker String marker = readString(); if (!marker.equals(SarConstants.SARFILE_MARKER)) { throw new IOException("Does not contain org.eclipse.equinox.p2.sar marker."); } // SarFile version version = dataInputStream.readInt(); if (version != SarConstants.SARFILE_VERSION) { throw new IOException("Unsupported version."); } } /** * Closes this stream. * * @throws IOException * on error */ public void close() throws IOException { dataInputStream.close(); } /** * Since we do not support marking just yet, we return false. * * @return False. */ public boolean markSupported() { return false; } /** * Since we do not support marking just yet, we do nothing. * * @param markLimit * The limit to mark. */ public void mark(int markLimit) { // nothing } /** * Since we do not support marking just yet, we do nothing. */ public void reset() { // nothing } /** * Get the next entry in this org.eclipse.equinox.p2.sar archive. This will skip * over any remaining data in the current entry, if there is one, and place * the input stream at the header of the next entry, and read the header and * instantiate a new SarEntry from the header bytes and return that entry. * If there are no more entries in the archive, null will be returned to * indicate that the end of the archive has been reached. * * @return the next SarEntry in the archive, or null. * @throws IOException * on error */ public SarEntry getNextEntry() throws IOException { SarEntry sarEntry = new SarEntry(this); if (sarEntry.isEof()) return null; byte[] content = readBytes(); contentStream = new ByteArrayInputStream(content); return sarEntry; } /** * Close the entry. * * @throws IOException */ public void closeEntry() throws IOException { contentStream.close(); } /** * @return String * @throws IOException */ String readString() throws IOException { byte[] bytes = readBytes(); if (bytes == null) return null; return new String(bytes, SarConstants.DEFAULT_ENCODING); } /** * @return byte[] * @throws IOException */ byte[] readBytes() throws IOException { int length = dataInputStream.readInt(); if (length == -1) return null; byte[] bytes = new byte[length]; dataInputStream.readFully(bytes, 0, length); return bytes; } /** * @return int * @throws IOException */ int readInt() throws IOException { return dataInputStream.readInt(); } /** * @return boolean * @throws IOException */ boolean readBoolean() throws IOException { return dataInputStream.readBoolean(); } /** * @return long * @throws IOException */ long readLong() throws IOException { return dataInputStream.readLong(); } /** * Reads a byte from the current tar archive entry. * * This method simply calls read( byte[], int, int ). * * @return The byte read, or -1 at EOF. * @throws IOException * on error */ public int read() throws IOException { return contentStream.read(); } /** * Reads bytes from the current tar archive entry. * * This method is aware of the boundaries of the current entry in the * archive and will deal with them as if they were this stream's start and * EOF. * * @param buffer * The buffer into which to place bytes read. * @param offset * The offset at which to place bytes read. * @param numToRead * The number of bytes to read. * @return The number of bytes read, or -1 at EOF. * @throws IOException * on error */ public int read(byte[] buffer, int offset, int numToRead) throws IOException { return contentStream.read(buffer, offset, numToRead); } }