I found two bugs in the standard version of bam.exe which provided by Ja.Net, the symptoms is:
- When merging any assemblies as “bam cvf a.dll *****”, if there is no folder information for the target assemble name (“a.dll”), the bam.exe will throw a null-pointer exception
- The name of resources embedded by bam.exe are error:
- The resource names are not separated by “.”, there are separated by “/”
- The resource names are start from the root folder, it should be start with current folder.
Following the steps to do the fixing.
- Download source code from Ja.Net SVN server
- Go to “\janetse\trunk\janet_jdktools\modules\jdktools”
- Go to “src\main\java\org\janet\tools\bam”
- Open file ResourceName.java and edit it.
- Do modification action on Bam.java and AssemblyMerger.java
I have copy the source code out there, you can replace them directly.
janet bam src20090930.rar (35.61 kb)
Compile the new Bam.exe as:
Ja.Net\jdk\bin\javac -bam:newbam.dll -nowarn -d classes -cp Mono.Cecil.Merge.dll;Mono.Cecil.dll;Mono.Cecil.Pdb.dll;janet.ecj.dll;janet.tools.dll;System.dll;System.XML.dll src
ResourceName.java
package org.janet.tools.bam;
public class ResourceName
{
public ResourceName(String folderName,String fileName)
{
this.FolderName = folderName;
this.FileName = fileName;
}
public String FolderName;
public String FileName;
}
Bam.java
public synchronized int run(String args[])
{
……
if(outputAssemblyExists)
{
outputAssemblyLastModified = getAssemblyLastModified(outputAssemblyFileName);
}
else
{
// Make sure the directory for the assembly is present
File f = new File(outputAssemblyFileName);
File parent = f.getParentFile();
if(null != parent)
{
if(!parent.exists())
if(!parent.mkdirs())
{
error("unable to create directory for output");
return 1;
}
}
}
……
}//end of run
private int parseInputFiles(String[] aryArguments,int nStart)
{
inputNames = new ArrayList<Path>();
File f = null;
try
{
for(int nIndex = nStart;nIndex < aryArguments.length;nIndex++)
{
if(aryArguments[nIndex].charAt(0) == '@')
{
return processInputFile(aryArguments[nIndex].substring(1));
}
if(aryArguments[nIndex].equals("-C"))
{
String strFolder = aryArguments[++nIndex];
f = new File(strFolder);
if(!f.exists() || !f.isDirectory())
{
error("Invalid directory " + strFolder);
return 1;
}
String strFileName = aryArguments[++nIndex];
inputNames.add(new Path(strFolder,strFileName));
}
else
{
inputNames.add(new Path(null,aryArguments[nIndex]));
}
}
}
catch(ArrayIndexOutOfBoundsException e)
{
error("Input filename's are malformed");
usageError();
return 1;
}
if(inputNames.size() == 0)
{
error("No input files specified");
usageError();
return 1;
}
return 0;
}
private boolean getItemsFromInputFiles(ArrayList<File> assemMergeList,ArrayList<ResourceName> resMergeList)
{
// The inputFiles ArrayList contains the names provided as input arguments
for(int nIdx = 0;nIdx < inputNames.size();nIdx++)
{
Path inputPath = inputNames.get(nIdx);
String parentDir = System.IO.Path.GetFullPath(inputPath.directory != null ? inputPath.directory : inputPath.name);
if(!parentDir.endsWith(File.separator))
{
parentDir = parentDir + File.separator;
}
File fullName = new File(inputPath.directory,inputPath.name);
String searchPattern = "*";
if(fullName.isDirectory())
{
String searchDir = System.IO.Path.GetFullPath(fullName.getAbsolutePath());
debug("Searching directory " + searchDir + " with pattern " + searchPattern);
String[] files = System.IO.Directory.GetFiles(searchDir,searchPattern,System.IO.SearchOption.AllDirectories);
for(int nfile = 0;nfile < files.length;nfile++)
{
addFile2Merge(assemMergeList,resMergeList,parentDir,files[nfile]);
}
}
else
{
addFile2Merge(assemMergeList,resMergeList,parentDir,fullName.getAbsolutePath());
}
}
return true;
}
private void addFile2Merge(ArrayList<File> assemMergeList,ArrayList<ResourceName> resMergeList,String strBaseDir,String strFileName)
{
if(null == strFileName)
{
return;
}
File f = new File(strFileName);
if(f.isFile() == false || f.exists() == false)
{
return;
}
strFileName = System.IO.Path.GetFullPath(strFileName);
if(strFileName.toLowerCase().endsWith(".class"))
{
assemMergeList.add(f);
//debug("Adding assembly: " + strFileName);
}
else
{
if(!strFileName.toLowerCase().endsWith(".pdb")
&& !strFileName.toLowerCase().endsWith(".class")
&& !strFileName.toLowerCase().endsWith(".dll")
&& !strFileName.toLowerCase().endsWith(".exe")
)
{
String strFName = strFileName;
if(null != strBaseDir && strBaseDir.length() > 0)
{
strFName = strFileName.substring(strBaseDir.length());
if(strFName.charAt(0) == '/' || strFName.charAt(0) == '\\')
{
strFName = strFName.substring(1);
}
}
resMergeList.add(new ResourceName(strBaseDir,strFName));
debug("Adding resource: " + strFileName + "=" + strFName);
}
}
}
AssemblyMerger.java
private void addResources(AssemblyDefinition assembly,ArrayList<ResourceName> resources)
throws IOException
{
if(resources == null)
return;
int num = resources.size();
if(num == 0)
return;
ResourceCollection assemResources = assembly.get_MainModule().get_Resources();
if(verbose)
output("[merging resources ...]");
for(int i = 0;i < num;i++)
{
ResourceName rName = resources.get(i);
File f = new File(rName.FolderName,rName.FileName);
String fileName = f.getAbsolutePath();
String resourceName = rName.FileName.replace('\\','/');
if(resourceName.charAt(0) == '/')
{
resourceName = resourceName.substring(1);
}
resourceName = resourceName.replaceAll("\\\\",".");
resourceName = resourceName.replaceAll("\\/",".");
if(verbose)
{
output("[merging resource " + fileName + " as resource " + resourceName + "]");
}
try
{
System.Byte[] res = System.IO.File.ReadAllBytes(fileName);
EmbeddedResource eres = new EmbeddedResource(resourceName,ManifestResourceAttributes.Public,res);
assemResources.Add(eres);
}
catch(Throwable t)
{
throw new IOException("Error while merging resource: " + fileName + " " + t.getMessage());
}
}
}