|
2 | 2 | package org.jetbrains.java.decompiler.struct; |
3 | 3 |
|
4 | 4 | import org.jetbrains.java.decompiler.main.DecompilerContext; |
5 | | -import org.jetbrains.java.decompiler.main.extern.IResultSaver; |
6 | 5 | import org.jetbrains.java.decompiler.main.extern.IBytecodeProvider; |
7 | 6 | import org.jetbrains.java.decompiler.main.extern.IContextSource; |
8 | 7 | import org.jetbrains.java.decompiler.main.extern.IFernflowerLogger; |
| 8 | +import org.jetbrains.java.decompiler.main.extern.IResultSaver; |
9 | 9 | import org.jetbrains.java.decompiler.struct.gen.generics.GenericMain; |
10 | 10 | import org.jetbrains.java.decompiler.struct.gen.generics.GenericMethodDescriptor; |
11 | 11 | import org.jetbrains.java.decompiler.util.DataInputFullStream; |
|
14 | 14 | import java.io.IOException; |
15 | 15 | import java.io.InputStream; |
16 | 16 | import java.io.UncheckedIOException; |
17 | | -import java.util.ArrayList; |
18 | | -import java.util.HashMap; |
19 | | -import java.util.List; |
20 | | -import java.util.Map; |
21 | | -import java.util.Objects; |
| 17 | +import java.nio.ByteBuffer; |
| 18 | +import java.nio.ByteOrder; |
| 19 | +import java.nio.channels.SeekableByteChannel; |
| 20 | +import java.nio.file.Files; |
| 21 | +import java.util.*; |
22 | 22 | import java.util.concurrent.ConcurrentHashMap; |
23 | 23 | import java.util.stream.Collectors; |
24 | 24 |
|
@@ -129,30 +129,53 @@ public void saveContext() { |
129 | 129 | } |
130 | 130 | } |
131 | 131 |
|
| 132 | + private static boolean isJarFile(File file) { |
| 133 | + if (!file.isFile()) return false; |
| 134 | + String name = file.getName(); |
| 135 | + if (name.endsWith(".jar") || name.endsWith(".zip")) return true; |
| 136 | + if (name.endsWith(".class")) return false; |
| 137 | + try (SeekableByteChannel channel = Files.newByteChannel(file.toPath())) { |
| 138 | + long size = channel.size(); |
| 139 | + // The EOCD ZIP record has 22+n bytes depending on the length of the comment. |
| 140 | + if (size < 22) return false; |
| 141 | + int bufferSize = (int) Math.min(size & ~3, 1024); |
| 142 | + channel.position(size - bufferSize); |
| 143 | + ByteBuffer buffer = ByteBuffer.allocate(bufferSize).order(ByteOrder.LITTLE_ENDIAN); |
| 144 | + int read = 0; |
| 145 | + while (read < bufferSize) { |
| 146 | + read += channel.read(buffer); |
| 147 | + } |
| 148 | + buffer.flip(); |
| 149 | + for (int pos = buffer.limit() - 22; pos >= 0; pos--) { |
| 150 | + if (buffer.getInt(pos) == 0x06054b50) { |
| 151 | + return true; |
| 152 | + } |
| 153 | + } |
| 154 | + } catch (IOException e) { |
| 155 | + DecompilerContext.getLogger().writeMessage("Could not determine if " + file + " contains a JAR file", IFernflowerLogger.Severity.WARN, e); |
| 156 | + } |
| 157 | + return false; |
| 158 | + } |
| 159 | + |
132 | 160 | public void addSpace(File file, boolean isOwn) { |
133 | 161 | if (file.isDirectory()) { |
134 | 162 | addSpace(new DirectoryContextSource(this.legacyProvider, file), isOwn); |
135 | | - } else { |
136 | | - final String name = file.getName(); |
137 | | - if (name.endsWith(".jar") || name.endsWith(".zip")) { |
138 | | - if (file.isFile()) { |
139 | | - // archive |
140 | | - try { |
141 | | - addSpace(new JarContextSource(this.legacyProvider, file), isOwn); |
142 | | - } catch (final IOException ex) { |
143 | | - final String message = "Invalid archive " + file; |
144 | | - DecompilerContext.getLogger().writeMessage(message, IFernflowerLogger.Severity.ERROR, ex); |
145 | | - throw new UncheckedIOException(message, ex); |
146 | | - } |
147 | | - } |
148 | | - } else { |
149 | | - try { |
150 | | - addSpace(new SingleFileContextSource(this.legacyProvider, file), isOwn); |
151 | | - } catch (final IOException ex) { |
152 | | - final String message = "Invalid file " + file; |
153 | | - DecompilerContext.getLogger().writeMessage(message, IFernflowerLogger.Severity.ERROR, ex); |
154 | | - throw new UncheckedIOException(message, ex); |
155 | | - } |
| 163 | + } else if (isJarFile(file)) { |
| 164 | + // archive |
| 165 | + try { |
| 166 | + addSpace(new JarContextSource(this.legacyProvider, file), isOwn); |
| 167 | + } catch (final IOException ex) { |
| 168 | + final String message = "Invalid archive " + file; |
| 169 | + DecompilerContext.getLogger().writeMessage(message, IFernflowerLogger.Severity.ERROR, ex); |
| 170 | + throw new UncheckedIOException(message, ex); |
| 171 | + } |
| 172 | + } else if (file.isFile()) { |
| 173 | + try { |
| 174 | + addSpace(new SingleFileContextSource(this.legacyProvider, file), isOwn); |
| 175 | + } catch (final IOException ex) { |
| 176 | + final String message = "Invalid file " + file; |
| 177 | + DecompilerContext.getLogger().writeMessage(message, IFernflowerLogger.Severity.ERROR, ex); |
| 178 | + throw new UncheckedIOException(message, ex); |
156 | 179 | } |
157 | 180 | } |
158 | 181 | } |
|
0 commit comments