package com.intellij.util.lang;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.util.io.UnsyncByteArrayInputStream;
import com.intellij.util.io.zip.ZipShort;
import gnu.trove.THashMap;
import org.jetbrains.annotations.Nullable;
import sun.misc.Resource;
import java.io.*;
import java.net.URL;
import java.util.Map;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
/**
* @author Dmitry Avdeev
* Date: 7/12/11
*/
public class JarMemoryLoader {
public static final String SIZE_ENTRY = "META-INF/jb/$$size$$";
//private static final Logger LOG = Logger.getInstance(JarMemoryLoader.class);
private final Map<String, Resource> myResources = new THashMap<String, Resource>();
public Resource getResource(String entryName) {
return myResources.remove(entryName);
}
@Nullable
public static JarMemoryLoader load(File file, URL baseUrl) throws IOException {
FileInputStream inputStream = new FileInputStream(file);
try {
// long start = System.currentTimeMillis();
JarMemoryLoader loader = load(inputStream, baseUrl);
// if (loader != null) {
// LOG.info(loader.myResources.size() + " classes from " + file.getName() + " preloaded in " + (System.currentTimeMillis() - start) + " ms");
// }
return loader;
}
finally {
inputStream.close();
}
}
@Nullable
public static JarMemoryLoader load(InputStream inputStream, URL baseUrl) throws IOException {
ZipInputStream zipStream = new ZipInputStream(inputStream);
try {
ZipEntry sizeEntry = zipStream.getNextEntry();
if (sizeEntry == null || !sizeEntry.getName().equals(SIZE_ENTRY)) return null;
byte[] bytes = FileUtil.loadBytes(zipStream, 2);
int size = ZipShort.getValue(bytes);
JarMemoryLoader loader = new JarMemoryLoader();
for (int i = 0; i < size; i++) {
ZipEntry entry = zipStream.getNextEntry();
if (entry == null) return loader;
byte[] content = FileUtil.loadBytes(zipStream, (int)entry.getSize());
MyResource resource = new MyResource(entry.getName(), new URL(baseUrl, entry.getName()), content);
loader.myResources.put(entry.getName(), resource);
}
return loader;
}
finally {
zipStream.close();
}
}
private static class MyResource extends Resource {
private String myName;
private URL myUrl;
private final byte[] myContent;
public MyResource(String name, URL url, byte[] content) {
myName = name;
myUrl = url;
myContent = content;
}
@Override
public String getName() {
return myName;
}
@Override
public URL getURL() {
return myUrl;
}
@Override
public URL getCodeSourceURL() {
return myUrl;
}
@Override
public InputStream getInputStream() throws IOException {
return new UnsyncByteArrayInputStream(myContent);
}
@Override
public int getContentLength() throws IOException {
return myContent.length;
}
}
}