/*
* JarTypeLoader.java
*
* Copyright (c) 2013 Mike Strobel
*
* This source code is based on Mono.Cecil from Jb Evain, Copyright (c) Jb Evain;
* and ILSpy/ICSharpCode from SharpDevelop, Copyright (c) AlphaSierraPapa.
*
* This source code is subject to terms and conditions of the Apache License, Version 2.0.
* A copy of the license can be found in the License.html file at the root of this distribution.
* By using this source code in any fashion, you are agreeing to be bound by the terms of the
* Apache License, Version 2.0.
*
* You must not remove this notice, or any other, from this software.
*/
package org.jboss.windup.decompiler.procyon;
import java.io.IOException;
import java.io.InputStream;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import java.util.logging.Level;
import java.util.logging.Logger;
import com.strobel.assembler.ir.ConstantPool;
import com.strobel.assembler.metadata.Buffer;
import com.strobel.assembler.metadata.ITypeLoader;
import com.strobel.assembler.metadata.JarTypeLoader;
import com.strobel.core.ExceptionUtilities;
import com.strobel.core.VerifyArgument;
public class WindupJarTypeLoader implements ITypeLoader
{
private final static Logger LOG = Logger.getLogger(JarTypeLoader.class.getSimpleName());
private final JarFile _jarFile;
private final Map<String, String> _knownMappings = new ConcurrentHashMap<>(1000);
public WindupJarTypeLoader(final JarFile jarFile)
{
_jarFile = VerifyArgument.notNull(jarFile, "jarFile");
}
@Override
public boolean tryLoadType(final String internalName, final Buffer buffer)
{
try
{
if (LOG.isLoggable(Level.FINE))
{
LOG.fine("Attempting to load type: " + internalName + "...");
}
final JarEntry entry = _jarFile.getJarEntry(internalName + ".class");
if (entry == null)
{
final String mappedName = _knownMappings.get(internalName);
return mappedName != null &&
!mappedName.equals(internalName) && tryLoadType(mappedName, buffer);
}
final InputStream inputStream = _jarFile.getInputStream(entry);
int remainingBytes = inputStream.available();
buffer.reset(remainingBytes);
while (remainingBytes > 0)
{
final int bytesRead = inputStream.read(buffer.array(), buffer.position(), remainingBytes);
if (bytesRead < 0)
{
break;
}
buffer.position(buffer.position() + bytesRead);
remainingBytes -= bytesRead;
}
buffer.position(0);
final String actualName = getInternalNameFromClassFile(buffer);
if (actualName != null && !actualName.equals(internalName))
{
_knownMappings.put(actualName, internalName);
}
if (LOG.isLoggable(Level.FINE))
{
LOG.fine("Type loaded from " + _jarFile.getName() + "!" + entry.getName() + ".");
}
return true;
}
catch (IOException e)
{
throw ExceptionUtilities.asRuntimeException(e);
}
}
private static String getInternalNameFromClassFile(final Buffer b)
{
final long magic = b.readInt() & 0xFFFFFFFFL;
if (magic != 0xCAFEBABEL)
{
return null;
}
b.readUnsignedShort(); // minor version
b.readUnsignedShort(); // major version
final ConstantPool constantPool = ConstantPool.read(b);
b.readUnsignedShort(); // access flags
final ConstantPool.TypeInfoEntry thisClass = constantPool.getEntry(b.readUnsignedShort());
b.position(0);
return thisClass.getName();
}
}