Commit | Line | Data |
---|---|---|
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 | * Remy Chi Jian Suen <remy.suen@gmail.com> - Bug 243347 TarFile should not throw NPE in finalize() | |
11 | * Marc-Andre Laperle <marc-andre.laperle@ericsson.com> - Bug 463633 | |
12 | * Marc-Andre Laperle <marc-andre.laperle@ericsson.com> - Copied to Trace Compass to work around bug 501379 | |
13 | *******************************************************************************/ | |
14 | ||
15 | package org.eclipse.tracecompass.internal.tmf.ui.project.wizards.importtrace; | |
16 | ||
17 | import java.io.File; | |
18 | import java.io.FileInputStream; | |
19 | import java.io.IOException; | |
20 | import java.io.InputStream; | |
21 | import java.util.Enumeration; | |
6120dc63 MAL |
22 | |
23 | import org.apache.commons.compress.archivers.tar.TarArchiveEntry; | |
24 | import org.apache.commons.compress.archivers.tar.TarArchiveInputStream; | |
25 | import org.apache.commons.compress.compressors.gzip.GzipCompressorInputStream; | |
5d5f933e MAL |
26 | |
27 | ||
28 | /** | |
29 | * Reads a .tar or .tar.gz archive file, providing an index enumeration | |
30 | * and allows for accessing an InputStream for arbitrary files in the | |
31 | * archive. | |
32 | */ | |
33 | public class TarFile { | |
6120dc63 MAL |
34 | private File file; |
35 | private TarArchiveInputStream entryEnumerationStream; | |
36 | private TarArchiveEntry curEntry; | |
37 | private TarArchiveInputStream entryStream; | |
5d5f933e | 38 | |
6120dc63 | 39 | private InputStream internalEntryStream; |
5d5f933e MAL |
40 | // This field is just to prevent try with resources error and keep the code |
41 | // similar to the original | |
42 | private InputStream fInputStream; | |
43 | ||
6120dc63 MAL |
44 | /** |
45 | * Create a new TarFile for the given file. | |
46 | * | |
47 | * @param file the file | |
48 | * @throws IOException on i/o error (bad format, etc) | |
49 | */ | |
50 | public TarFile(File file) throws IOException { | |
51 | this.file = file; | |
52 | ||
53 | fInputStream = new FileInputStream(file); | |
54 | // First, check if it's a GZIPInputStream. | |
55 | try { | |
56 | fInputStream = new GzipCompressorInputStream(fInputStream); | |
57 | } catch (IOException e) { | |
58 | //If it is not compressed we close | |
59 | //the old one and recreate | |
60 | fInputStream.close(); | |
61 | fInputStream = new FileInputStream(file); | |
62 | } | |
63 | entryEnumerationStream = new TarArchiveInputStream(fInputStream); | |
64 | try { | |
65 | curEntry = (TarArchiveEntry) entryEnumerationStream.getNextEntry(); | |
c4d84203 MAL |
66 | if (!curEntry.isCheckSumOK()) { |
67 | throw new IOException("Error detected parsing initial entry header"); //$NON-NLS-1$ | |
68 | } | |
6120dc63 MAL |
69 | } catch (IOException e) { |
70 | fInputStream.close(); | |
71 | throw e; | |
72 | } | |
73 | } | |
74 | ||
75 | /** | |
76 | * Close the tar file input stream. | |
77 | * | |
78 | * @throws IOException if the file cannot be successfully closed | |
79 | */ | |
80 | public void close() throws IOException { | |
81 | if (entryEnumerationStream != null) { | |
5d5f933e MAL |
82 | entryEnumerationStream.close(); |
83 | } | |
6120dc63 | 84 | if (internalEntryStream != null) { |
5d5f933e MAL |
85 | internalEntryStream.close(); |
86 | } | |
6120dc63 MAL |
87 | } |
88 | ||
89 | /** | |
90 | * Create a new TarFile for the given path name. | |
91 | * | |
92 | * @param filename the file name to create the TarFile from | |
93 | * @throws IOException on i/o error (bad format, etc) | |
94 | */ | |
95 | public TarFile(String filename) throws IOException { | |
96 | this(new File(filename)); | |
97 | } | |
98 | ||
99 | /** | |
100 | * Returns an enumeration cataloguing the tar archive. | |
101 | * | |
102 | * @return enumeration of all files in the archive | |
103 | */ | |
104 | public Enumeration<TarArchiveEntry> entries() { | |
105 | return new Enumeration<TarArchiveEntry>() { | |
106 | @Override | |
107 | public boolean hasMoreElements() { | |
108 | return (curEntry != null); | |
109 | } | |
110 | ||
111 | @Override | |
112 | public TarArchiveEntry nextElement() { | |
113 | TarArchiveEntry oldEntry = curEntry; | |
114 | try { | |
115 | curEntry = (TarArchiveEntry) entryEnumerationStream.getNextEntry(); | |
116 | } catch(IOException e) { | |
117 | curEntry = null; | |
118 | } | |
119 | return oldEntry; | |
120 | } | |
121 | }; | |
122 | } | |
123 | ||
124 | /** | |
125 | * Returns a new InputStream for the given file in the tar archive. | |
126 | * | |
127 | * @param entry the entry to get the InputStream from | |
128 | * @return an input stream for the given file | |
129 | * @throws IOException on i/o error (bad format, etc) | |
130 | */ | |
131 | public InputStream getInputStream(TarArchiveEntry entry) throws IOException { | |
132 | if(entryStream == null || !skipToEntry(entryStream, entry)) { | |
133 | if (internalEntryStream != null) { | |
134 | internalEntryStream.close(); | |
135 | } | |
136 | internalEntryStream = new FileInputStream(file); | |
137 | // First, check if it's a GzipCompressorInputStream. | |
138 | try { | |
139 | internalEntryStream = new GzipCompressorInputStream(internalEntryStream); | |
140 | } catch(IOException e) { | |
141 | //If it is not compressed we close | |
142 | //the old one and recreate | |
143 | internalEntryStream.close(); | |
144 | internalEntryStream = new FileInputStream(file); | |
145 | } | |
146 | entryStream = new TarArchiveInputStream(internalEntryStream) { | |
147 | @Override | |
148 | public void close() { | |
149 | // Ignore close() since we want to reuse the stream. | |
150 | } | |
151 | }; | |
152 | skipToEntry(entryStream, entry); | |
153 | } | |
154 | return entryStream; | |
155 | } | |
156 | ||
157 | private static boolean skipToEntry(TarArchiveInputStream entryStream, TarArchiveEntry entry) throws IOException { | |
158 | TarArchiveEntry e = entryStream.getNextTarEntry(); | |
159 | while (e != null) { | |
160 | if (e.equals(entry)) { | |
161 | return true; | |
162 | } | |
163 | ||
164 | e = entryStream.getNextTarEntry(); | |
165 | } | |
166 | ||
167 | return false; | |
168 | } | |
169 | ||
170 | /** | |
171 | * Returns the path name of the file this archive represents. | |
172 | * | |
173 | * @return path | |
174 | */ | |
175 | public String getName() { | |
176 | return file.getPath(); | |
177 | } | |
178 | ||
179 | @Override | |
180 | protected void finalize() throws Throwable { | |
181 | close(); | |
182 | } | |
5d5f933e | 183 | } |