blob: a8ade797e183764db6711b6f85e8b8367b667cde [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2007, 2018 compeople AG and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* 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 SarOutputStream writes a stream archive as an OutputStream. Methods are
* provided to put entries, and then write their contents by writing to this
* stream using write().
*/
public class SarOutputStream extends OutputStream {
private boolean finished;
private final DataOutputStream dataOutputStream;
private final DirectByteArrayOutputStream entryContent;
/**
* @param outputStream
* @throws IOException
*/
public SarOutputStream(OutputStream outputStream) throws IOException {
dataOutputStream = new DataOutputStream(outputStream);
entryContent = new DirectByteArrayOutputStream(16 * 1024);
writeString(SarConstants.SARFILE_MARKER);
dataOutputStream.writeInt(SarConstants.SARFILE_VERSION);
finished = false;
}
/**
* Ends the SAR archive and closes the underlying OutputStream.
*
* @see java.io.OutputStream#close()
*/
@Override
public void close() throws IOException {
finish();
super.close();
}
/**
* Finish this SAR archive but does not close the underlying output stream.
*
* @throws IOException
*/
public void finish() throws IOException {
if (finished)
return;
writeEOFRecord();
finished = true;
}
/**
* Put an entry on the output stream. This writes the entry's header record and
* positions the output stream for writing the contents of the entry. Once this
* method is called, the stream is ready for calls to write() to write the
* entry's contents. Once the contents are written, closeEntry() <B>MUST </B> be
* called to ensure that all buffered data is completely written to the output
* stream.
*
* @param entry the SarEntry to be written to the archive.
* @throws IOException
*/
public void putNextEntry(SarEntry entry) throws IOException {
entry.writeTo(this);
}
/**
* Close an entry. This method MUST be called for all file entries that contain
* data. The reason is that we must buffer data written to the stream in order
* to satisfy the buffer's record based writes. Thus, there may be data
* fragments still being assembled that must be written to the output stream
* before this entry is closed and the next entry written.
*
* @throws IOException
*/
public void closeEntry() throws IOException {
writeBytes(entryContent.getBuffer(), entryContent.getBufferLength());
entryContent.reset();
}
/**
* @param s
* @throws IOException
*/
void writeString(String s) throws IOException {
byte[] bytes = null;
if (s != null)
bytes = s.getBytes(SarConstants.DEFAULT_ENCODING);
writeBytes(bytes);
}
/**
* @param bytes
* @throws IOException
*/
void writeBytes(byte[] bytes) throws IOException {
writeBytes(bytes, bytes != null ? bytes.length : -1);
}
/**
* @param bytes
* @throws IOException
*/
void writeBytes(byte[] bytes, int length) throws IOException {
if (bytes != null) {
dataOutputStream.writeInt(length);
dataOutputStream.write(bytes, 0, length);
} else {
dataOutputStream.writeInt(-1);
}
}
/**
* @param v
* @throws IOException
*/
void writeInt(int v) throws IOException {
dataOutputStream.writeInt(v);
}
/**
* @param bool
* @throws IOException
*/
public void writeBool(boolean bool) throws IOException {
dataOutputStream.writeBoolean(bool);
}
/**
* @param v
* @throws IOException
*/
void writeLong(long v) throws IOException {
dataOutputStream.writeLong(v);
}
/**
* Writes a byte to the current org.eclipse.equinox.p2.sar archive entry.
*
* @param b the byte written.
* @throws IOException
*
* @see java.io.OutputStream#write(int)
*/
@Override
public void write(int b) throws IOException {
byte[] bytes = new byte[1];
bytes[0] = (byte) b;
entryContent.write(bytes);
}
/**
* Writes bytes to the current org.eclipse.equinox.p2.sar archive entry.
*
* @param bytes The buffer to write to the archive.
* @throws IOException
*
* @see java.io.OutputStream#write(byte[])
*/
@Override
public void write(byte[] bytes) throws IOException {
entryContent.write(bytes, 0, bytes.length);
}
/**
* Writes bytes to the current org.eclipse.equinox.p2.sar archive entry.
*
* @param bytes The buffer to write to the archive.
* @param offset The offset in the buffer from which to get bytes.
* @param numToWrite The number of bytes to write.
*
* @throws IOException
*
* @see java.io.OutputStream#write(byte[], int, int)
*/
@Override
public void write(byte[] bytes, int offset, int numToWrite) throws IOException {
entryContent.write(bytes, offset, numToWrite);
}
/**
* Write an EOF (end of archive) entry to the org.eclipse.equinox.p2.sar
* archive.
*
* @throws IOException
*/
private void writeEOFRecord() throws IOException {
SarEntry eofEntry = new SarEntry();
eofEntry.writeTo(this);
}
}