Skip to main content
aboutsummaryrefslogtreecommitdiffstats
blob: ad36088435b6eac7378a8ace3e70dcb77c821434 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
/*******************************************************************************
 * 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.*;
import org.eclipse.equinox.p2.sar.DirectByteArrayOutputStream;

/**
 * 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.Closeable#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);
	}

}

Back to the top