releng: Add SWTBot integration tests for import wizard
[deliverable/tracecompass.git] / tmf / org.eclipse.tracecompass.tmf.ui / src / org / eclipse / tracecompass / internal / tmf / ui / project / wizards / importtrace / TarInputStream.java
CommitLineData
5d5f933e
MAL
1/*******************************************************************************
2 * Copyright (c) 2004, 2015 IBM Corporation and others.
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the Eclipse Public License v1.0
5 * which accompanies this distribution, and is available at
6 * http://www.eclipse.org/legal/epl-v10.html
7 *
8 * Contributors:
9 * IBM Corporation - initial API and implementation
10 * Marc-Andre Laperle <marc-andre.laperle@ericsson.com> - Copied to Trace Compass to work around bug 501379
11 *******************************************************************************/
12package org.eclipse.tracecompass.internal.tmf.ui.project.wizards.importtrace;
13
14import java.io.FilterInputStream;
15import java.io.IOException;
16import java.io.InputStream;
17
18import org.eclipse.ui.internal.wizards.datatransfer.DataTransferMessages;
19
20/**
21 * Input stream for reading files in ustar format (tar) compatible
22 * with the specification in IEEE Std 1003.1-2001. Also supports
23 * long filenames encoded using the GNU @LongLink extension.
24 */
25@SuppressWarnings("restriction")
26public class TarInputStream extends FilterInputStream
27{
28 private int nextEntry = 0;
29 private int nextEOF = 0;
30 private int filepos = 0;
31 private long bytesread = 0;
32 private TarEntry firstEntry = null;
33 private String longLinkName = null;
34
35 /**
36 * Creates a new tar input stream on the given input stream.
37 *
38 * @param in input stream
39 * @throws TarException on Tar error (bad format, etc)
40 * @throws IOException on i/o error
41 */
42 public TarInputStream(InputStream in) throws TarException, IOException {
43 super(in);
44
45 // Read in the first TarEntry to make sure
46 // the input is a valid tar file stream.
47 firstEntry = getNextEntry();
48 }
49
50 /**
51 * Create a new tar input stream, skipping ahead to the given entry
52 * in the file.
53 *
54 * @param in input stream
55 * @param entry skips to this entry in the file
56 * @throws TarException
57 * @throws IOException
58 */
59 TarInputStream(InputStream in, TarEntry entry) throws TarException, IOException {
60 super(in);
61 skipToEntry(entry);
62 }
63
64 /**
65 * The checksum of a tar file header is simply the sum of the bytes in
66 * the header.
67 *
68 * @param header
69 * @return checksum
70 */
71 private static long headerChecksum(byte[] header) {
72 long sum = 0;
73 for(int i = 0; i < 512; i++) {
74 sum += header[i] & 0xff;
75 }
76 return sum;
77 }
78
79 /**
80 * Skips ahead to the position of the given entry in the file.
81 *
82 * @param entry
83 * @returns false if the entry has already been passed
84 * @throws TarException
85 * @throws IOException
86 */
87 boolean skipToEntry(TarEntry entry) throws TarException, IOException {
88 long bytestoskip = entry.filepos - bytesread;
89 if(bytestoskip < 0) {
90 return false;
91 }
92 while(bytestoskip > 0) {
93 long ret = in.skip(bytestoskip);
94 if(ret < 0) {
95 throw new IOException("early end of stream"); //$NON-NLS-1$
96 }
97 bytestoskip -= ret;
98 bytesread += ret;
99 }
100 filepos = entry.filepos;
101 nextEntry = 0;
102 nextEOF = 0;
103 // Read next header to seek to file data.
104 getNextEntry();
105 return true;
106 }
107
108 /**
109 * Returns true if the header checksum is correct.
110 *
111 * @param header
112 * @return true if this header has a valid checksum
113 */
114 private static boolean isValidTarHeader(byte[] header) {
115 long fileChecksum, calculatedChecksum;
116 int pos, i;
117
118 pos = 148;
119 StringBuffer checksumString = new StringBuffer();
120 for(i = 0; i < 8; i++) {
121 if(header[pos + i] == ' ') {
122 continue;
123 }
124 if(header[pos + i] == 0 || !Character.isDigit((char) header[pos + i])) {
125 break;
126 }
127 checksumString.append((char) header[pos + i]);
128 }
129 if(checksumString.length() == 0) {
130 return false;
131 }
132 if(checksumString.charAt(0) != '0') {
133 checksumString.insert(0, '0');
134 }
135 try {
136 fileChecksum = Long.decode(checksumString.toString()).longValue();
137 } catch(NumberFormatException exception) {
138 //This is not valid if it cannot be parsed
139 return false;
140 }
141
142 // Blank out the checksum.
143 for(i = 0; i < 8; i++) {
144 header[pos + i] = ' ';
145 }
146 calculatedChecksum = headerChecksum(header);
147
148 return (fileChecksum == calculatedChecksum);
149 }
150
151 /**
152 * Returns the next entry in the tar file. Does not handle
153 * GNU @LongLink extensions.
154 *
155 * @return the next entry in the tar file
156 * @throws TarException
157 * @throws IOException
158 */
159 TarEntry getNextEntryInternal() throws TarException, IOException {
160 byte[] header = new byte[512];
161 int pos = 0;
162 int i;
163
164 if(firstEntry != null) {
165 TarEntry entryReturn = firstEntry;
166 firstEntry = null;
167 return entryReturn;
168 }
169
170 while(nextEntry > 0) {
171 long ret = in.skip(nextEntry);
172 if(ret < 0) {
173 throw new IOException("early end of stream"); //$NON-NLS-1$
174 }
175 nextEntry -= ret;
176 bytesread += ret;
177 }
178
179 int bytestoread = 512;
180 while(bytestoread > 0) {
181 int ret = super.read(header, 512 - bytestoread, bytestoread);
182 if( ret < 0 ) {
183 throw new IOException("early end of stream"); //$NON-NLS-1$
184 }
185 bytestoread -= ret;
186 bytesread += ret;
187 }
188
189 // If we have a header of all zeros, this marks the end of the file.
190 if(headerChecksum(header) == 0) {
191 // We are at the end of the file.
192 if(filepos > 0) {
193 return null;
194 }
195
196 // Invalid stream.
197 throw new TarException("not in tar format"); //$NON-NLS-1$
198 }
199
200 // Validate checksum.
201 if(!isValidTarHeader(header)) {
202 throw new TarException("not in tar format"); //$NON-NLS-1$
203 }
204
205 while (pos < 100 && header[pos] != 0) {
206 pos++;
207 }
208 String name = new String(header, 0, pos, "UTF8"); //$NON-NLS-1$
209 // Prepend the prefix here.
210 pos = 345;
211 if(header[pos] != 0) {
212 while (pos < 500 && header[pos] != 0) {
213 pos++;
214 }
215 String prefix = new String(header, 345, pos - 345, "UTF8"); //$NON-NLS-1$
216 name = prefix + "/" + name; //$NON-NLS-1$
217 }
218
219 TarEntry entry;
220 if(longLinkName != null) {
221 entry = new TarEntry(longLinkName, filepos);
222 longLinkName = null;
223 } else {
224 entry = new TarEntry(name, filepos);
225 }
226 if(header[156] != 0) {
227 entry.setFileType(header[156]);
228 }
229
230 pos = 100;
231 StringBuffer mode = new StringBuffer();
232 for(i = 0; i < 8; i++) {
233 if(header[pos + i] == 0) {
234 break;
235 }
236 if(header[pos + i] == ' ') {
237 continue;
238 }
239 mode.append((char) header[pos + i]);
240 }
241 if(mode.length() > 0 && mode.charAt(0) != '0') {
242 mode.insert(0, '0');
243 }
244 try {
245 long fileMode = Long.decode(mode.toString()).longValue();
246 entry.setMode(fileMode);
247 } catch(NumberFormatException nfe) {
248 throw new TarException(DataTransferMessages.TarImport_invalid_tar_format, nfe);
249 }
250
251 pos = 100 + 24;
252 StringBuffer size = new StringBuffer();
253 for(i = 0; i < 12; i++) {
254 if(header[pos + i] == 0) {
255 break;
256 }
257 if(header[pos + i] == ' ') {
258 continue;
259 }
260 size.append((char) header[pos + i]);
261 }
262 if(size.charAt(0) != '0') {
263 size.insert(0, '0');
264 }
265 int fileSize;
266 try {
267 fileSize = Integer.decode(size.toString()).intValue();
268 } catch(NumberFormatException nfe) {
269 throw new TarException(DataTransferMessages.TarImport_invalid_tar_format, nfe);
270 }
271
272 entry.setSize(fileSize);
273 nextEOF = fileSize;
274 if(fileSize % 512 > 0) {
275 nextEntry = fileSize + (512 - (fileSize % 512));
276 } else {
277 nextEntry = fileSize;
278 }
279 filepos += (nextEntry + 512);
280 return entry;
281 }
282
283 /**
284 * Moves ahead to the next file in the tar archive and returns
285 * a TarEntry object describing it.
286 *
287 * @return the next entry in the tar file
288 * @throws TarException on Tar error (bad format, etc)
289 * @throws IOException on i/o errors
290 */
291 public TarEntry getNextEntry() throws TarException, IOException {
292 TarEntry entry = getNextEntryInternal();
293
294 if(entry != null && entry.getName().equals("././@LongLink")) { //$NON-NLS-1$
295 // This is a GNU extension for doing long filenames.
296 // We get a file called ././@LongLink which just contains
297 // the real pathname.
298 byte[] longNameData = new byte[(int) entry.getSize()];
299 int nbytesread = 0;
300 while (nbytesread < longNameData.length) {
301 int cur = read(longNameData, nbytesread, longNameData.length - nbytesread);
302 if (cur < 0) {
303 throw new IOException("early end of stream"); //$NON-NLS-1$
304 }
305 nbytesread += cur;
306 }
307
308 int pos = 0;
309 while (pos < longNameData.length && longNameData[pos] != 0) {
310 pos++;
311 }
312 longLinkName = new String(longNameData, 0, pos, "UTF8"); //$NON-NLS-1$
313 return getNextEntryInternal();
314 }
315 return entry;
316 }
317
318 @Override
319 public int read(byte[] b, int off, int len) throws IOException {
320 int lenToRead = len;
321 if(nextEOF == 0) {
322 return -1;
323 }
324 if(lenToRead > nextEOF) {
325 lenToRead = nextEOF;
326 }
327 int size = super.read(b, off, lenToRead);
328 nextEntry -= size;
329 nextEOF -= size;
330 bytesread += size;
331 return size;
332 }
333
334 @Override
335 public int read() throws IOException {
336 byte[] data = new byte[1];
337 int size = read(data, 0, 1);
338 if (size < 0) {
339 return size;
340 }
341 return data[0];
342 }
343}
This page took 0.038777 seconds and 5 git commands to generate.