| /******************************************************************************* |
| * 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 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) |
| */ |
| 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[]) |
| */ |
| 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) |
| */ |
| 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); |
| } |
| |
| } |