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.

  1. Download source code from Ja.Net SVN server
  2. Go to “\janetse\trunk\janet_jdktools\modules\jdktools”
  3. Go to “src\main\java\org\janet\tools\bam”
  4. Open file ResourceName.java and edit it.
  5. 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());
           }
       }

   }


Jeason Zhao (沈胜衣,斛律光) ------雪饮再现,一个人的江湖
我知道我是谁,我是沈胜衣,默默的活着,就像空气。