Skip to main content
aboutsummaryrefslogtreecommitdiffstats
blob: ea2abef3c7d3984ab043111f6c9f4eea976e1354 (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
/*******************************************************************************
 * 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);
	}

}

Back to the top