You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@harmony.apache.org by sj...@apache.org on 2009/06/12 11:32:54 UTC

svn commit: r784048 [1/2] - in /harmony/enhanced/classlib/trunk/modules/pack200/src: main/java/org/apache/harmony/pack200/ main/java5/org/apache/harmony/pack200/ test/java/org/apache/harmony/pack200/tests/

Author: sjanuary
Date: Fri Jun 12 09:32:53 2009
New Revision: 784048

URL: http://svn.apache.org/viewvc?rev=784048&view=rev
Log:
Pack200 - support for non-standard class file attributes (-U,-C,-F,-M and -D command line options) and better framework for passing in other command line options.

Added:
    harmony/enhanced/classlib/trunk/modules/pack200/src/main/java/org/apache/harmony/pack200/NewAttribute.java   (with props)
    harmony/enhanced/classlib/trunk/modules/pack200/src/main/java/org/apache/harmony/pack200/NewAttributeBands.java   (with props)
    harmony/enhanced/classlib/trunk/modules/pack200/src/main/java/org/apache/harmony/pack200/PackingOptions.java   (with props)
Modified:
    harmony/enhanced/classlib/trunk/modules/pack200/src/main/java/org/apache/harmony/pack200/Archive.java
    harmony/enhanced/classlib/trunk/modules/pack200/src/main/java/org/apache/harmony/pack200/AttributeDefinitionBands.java
    harmony/enhanced/classlib/trunk/modules/pack200/src/main/java/org/apache/harmony/pack200/ClassBands.java
    harmony/enhanced/classlib/trunk/modules/pack200/src/main/java/org/apache/harmony/pack200/MetadataBandGroup.java
    harmony/enhanced/classlib/trunk/modules/pack200/src/main/java/org/apache/harmony/pack200/Pack200ClassReader.java
    harmony/enhanced/classlib/trunk/modules/pack200/src/main/java/org/apache/harmony/pack200/Segment.java
    harmony/enhanced/classlib/trunk/modules/pack200/src/main/java5/org/apache/harmony/pack200/Pack200PackerAdapter.java
    harmony/enhanced/classlib/trunk/modules/pack200/src/test/java/org/apache/harmony/pack200/tests/ArchiveTest.java

Modified: harmony/enhanced/classlib/trunk/modules/pack200/src/main/java/org/apache/harmony/pack200/Archive.java
URL: http://svn.apache.org/viewvc/harmony/enhanced/classlib/trunk/modules/pack200/src/main/java/org/apache/harmony/pack200/Archive.java?rev=784048&r1=784047&r2=784048&view=diff
==============================================================================
--- harmony/enhanced/classlib/trunk/modules/pack200/src/main/java/org/apache/harmony/pack200/Archive.java (original)
+++ harmony/enhanced/classlib/trunk/modules/pack200/src/main/java/org/apache/harmony/pack200/Archive.java Fri Jun 12 09:32:53 2009
@@ -32,34 +32,56 @@
 import java.util.jar.Manifest;
 import java.util.zip.GZIPOutputStream;
 
-import org.objectweb.asm.ClassReader;
-
 /**
- *
+ * Archive is the main entry point to pack200 and represents a packed archive.
+ * An archive is constructed with either a JarInputStream and an output stream
+ * or a JarFile as input and an OutputStream. Options can be set, then
+ * <code>pack()</code> is called, to pack the Jar file into a pack200 archive.
  */
 public class Archive {
 
     private final JarInputStream inputStream;
     private final OutputStream outputStream;
     private JarFile jarFile;
-    private long segmentLimit = 1000000;
     private long currentSegmentSize;
-    private boolean stripDebug;
-    private int effort = 5;
+    private final PackingOptions options;
 
+    /**
+     * Creates an Archive with streams for the input and output.
+     *
+     * @param inputStream
+     * @param outputStream
+     * @param options - packing options (if null then defaults are used)
+     * @throws IOException
+     */
     public Archive(JarInputStream inputStream, OutputStream outputStream,
-            boolean gzip) throws IOException {
+            PackingOptions options) throws IOException {
         this.inputStream = inputStream;
-        if (gzip) {
+        if(options == null) { // use all defaults
+            options = new PackingOptions();
+        }
+        this.options = options;
+        if (options.isGzip()) {
             outputStream = new GZIPOutputStream(outputStream);
         }
         this.outputStream = new BufferedOutputStream(outputStream);
     }
 
+    /**
+     * Creates an Archive with the given input file and a stream for the output
+     *
+     * @param jarFile - the input file
+     * @param outputStream
+     * @param options - packing options (if null then defaults are used)
+     * @throws IOException
+     */
     public Archive(JarFile jarFile, OutputStream outputStream,
-            boolean gzip) throws IOException {
-
-        if (gzip) {
+            PackingOptions options) throws IOException {
+        if(options == null) { // use all defaults
+            options = new PackingOptions();
+        }
+        this.options = options;
+        if (options.isGzip()) {
             outputStream = new GZIPOutputStream(outputStream);
         }
         this.outputStream = new BufferedOutputStream(outputStream);
@@ -67,26 +89,21 @@
         inputStream = null;
     }
 
-    public void setSegmentLimit(int limit) {
-        segmentLimit = limit;
-    }
-
-    public void setEffort(int effort) {
-        this.effort = effort;
-    }
-
-    public void stripDebugAttributes() {
-        stripDebug = true;
-    }
-
+    /**
+     * Pack the archive
+     * @throws Pack200Exception
+     * @throws IOException
+     */
     public void pack() throws Pack200Exception, IOException {
         List classes = new ArrayList();
         List files = new ArrayList();
 
+        int effort = options.getEffort();
+        long segmentLimit = options.getSegmentLimit();
+
         if(effort == 0) {
             doZeroEffortPack();
         } else {
-
             if (inputStream != null) {
                 Manifest manifest = jarFile != null ? jarFile.getManifest()
                         : inputStream.getManifest();
@@ -109,7 +126,7 @@
                     if (!added) { // not added because segment has reached
                         // maximum size
                         if(classes.size() > 0 || files.size() > 0) {
-                            new Segment().pack(classes, files, outputStream, stripDebug, effort);
+                            new Segment().pack(classes, files, outputStream, options);
                             classes = new ArrayList();
                             files = new ArrayList();
                             currentSegmentSize = 0;
@@ -118,7 +135,7 @@
                         }
                     } else if (segmentLimit == 0 && estimateSize(jarEntry) > 0) {
                         // create a new segment for each class unless size = 0
-                        new Segment().pack(classes, files, outputStream, stripDebug, effort);
+                        new Segment().pack(classes, files, outputStream, options);
                         classes = new ArrayList();
                         files = new ArrayList();
                     }
@@ -132,7 +149,7 @@
                             jarFile.getInputStream(jarEntry)), classes, files);
                     if (!added) { // not added because segment has reached maximum
                         // size
-                        new Segment().pack(classes, files, outputStream, stripDebug, effort);
+                        new Segment().pack(classes, files, outputStream, options);
                         classes = new ArrayList();
                         files = new ArrayList();
                         currentSegmentSize = 0;
@@ -141,14 +158,14 @@
                         currentSegmentSize = 0; // ignore the size of the first entry for compatibility with the RI
                     } else if (segmentLimit == 0 && estimateSize(jarEntry) > 0) {
                         // create a new segment for each class unless size = 0
-                        new Segment().pack(classes, files, outputStream, stripDebug, effort);
+                        new Segment().pack(classes, files, outputStream, options);
                         classes = new ArrayList();
                         files = new ArrayList();
                     }
                 }
             }
             if(classes.size() > 0 || files.size() > 0) {
-                new Segment().pack(classes, files, outputStream, stripDebug, effort);
+                new Segment().pack(classes, files, outputStream, options);
             }
             outputStream.close();
         }
@@ -207,6 +224,7 @@
 
     private boolean addJarEntry(JarEntry jarEntry, InputStream stream,
             List javaClasses, List files) throws IOException, Pack200Exception {
+        long segmentLimit = options.getSegmentLimit();
         String name = jarEntry.getName();
         long size = jarEntry.getSize();
         if (size > Integer.MAX_VALUE) {
@@ -232,7 +250,8 @@
             throw new RuntimeException("Error reading from stream");
         }
         if (name.endsWith(".class")) {
-            ClassReader classParser = new Pack200ClassReader(bytes);
+            Pack200ClassReader classParser = new Pack200ClassReader(bytes);
+            classParser.setFileName(name);
             javaClasses.add(classParser);
             bytes = new byte[0];
         }
@@ -257,7 +276,7 @@
     static class File {
 
         private final String name;
-        private final byte[] contents;
+        private byte[] contents;
         private final long modtime;
 
         public File(String name, byte[] contents, long modtime) {
@@ -281,6 +300,10 @@
         public String toString() {
             return name;
         }
+
+        public void setContents(byte[] contents) {
+            this.contents = contents;
+        }
     }
 
 }

Modified: harmony/enhanced/classlib/trunk/modules/pack200/src/main/java/org/apache/harmony/pack200/AttributeDefinitionBands.java
URL: http://svn.apache.org/viewvc/harmony/enhanced/classlib/trunk/modules/pack200/src/main/java/org/apache/harmony/pack200/AttributeDefinitionBands.java?rev=784048&r1=784047&r2=784048&view=diff
==============================================================================
--- harmony/enhanced/classlib/trunk/modules/pack200/src/main/java/org/apache/harmony/pack200/AttributeDefinitionBands.java (original)
+++ harmony/enhanced/classlib/trunk/modules/pack200/src/main/java/org/apache/harmony/pack200/AttributeDefinitionBands.java Fri Jun 12 09:32:53 2009
@@ -24,9 +24,11 @@
 import java.util.List;
 import java.util.Map;
 
+import org.objectweb.asm.Attribute;
+
 /**
- * Attribute Definition bands define how any unknown attributes should be
- * read by the decompressor.
+ * Attribute Definition bands define how any unknown attributes should be read
+ * by the decompressor.
  */
 public class AttributeDefinitionBands extends BandSet {
 
@@ -35,98 +37,132 @@
     public static final int CONTEXT_FIELD = 1;
     public static final int CONTEXT_METHOD = 2;
 
-    private final Map layouts = new HashMap();
-
-    private final Map classAttributes = new HashMap();
-    private final Map methodAttributes = new HashMap();
-    private final Map fieldAttributes = new HashMap();
-    private final Map codeAttributes = new HashMap();
+    private final List classAttributeLayouts = new ArrayList();
+    private final List methodAttributeLayouts = new ArrayList();
+    private final List fieldAttributeLayouts = new ArrayList();
+    private final List codeAttributeLayouts = new ArrayList();
 
     private final List attributeDefinitions = new ArrayList();
 
     private final CpBands cpBands;
     private final Segment segment;
 
-    public AttributeDefinitionBands(Segment segment, int effort) {
+    public AttributeDefinitionBands(Segment segment, int effort,
+            Attribute[] attributePrototypes) {
         super(effort, segment.getSegmentHeader());
         this.cpBands = segment.getCpBands();
         this.segment = segment;
-    }
-
-    public void finaliseBands() {
-        addSyntheticDefinitions();
-        segmentHeader.setAttribute_definition_count(classAttributes.keySet()
-                .size()
-                + methodAttributes.keySet().size()
-                + fieldAttributes.keySet().size()
-                + codeAttributes.keySet().size()
-                + attributeDefinitions.size());
-        if (classAttributes.keySet().size() > 7) {
+        Map classLayouts = new HashMap();
+        Map methodLayouts = new HashMap();
+        Map fieldLayouts = new HashMap();
+        Map codeLayouts = new HashMap();
+
+        for (int i = 0; i < attributePrototypes.length; i++) {
+            NewAttribute newAttribute = (NewAttribute) attributePrototypes[i];
+            if (newAttribute.isContextClass()) {
+                classLayouts.put(newAttribute.type, newAttribute.getLayout());
+            }
+            if (newAttribute.isContextMethod()) {
+                methodLayouts.put(newAttribute.type, newAttribute.getLayout());
+            }
+            if (newAttribute.isContextField()) {
+                fieldLayouts.put(newAttribute.type, newAttribute.getLayout());
+            }
+            if (newAttribute.isContextCode()) {
+                codeLayouts.put(newAttribute.type, newAttribute.getLayout());
+            }
+        }
+        if (classLayouts.keySet().size() > 7) {
             segmentHeader.setHave_class_flags_hi(true);
         }
-        if(methodAttributes.keySet().size() > 6) {
+        if (methodLayouts.keySet().size() > 6) {
             segmentHeader.setHave_method_flags_hi(true);
         }
-        if(fieldAttributes.keySet().size() > 10) {
+        if (fieldLayouts.keySet().size() > 10) {
             segmentHeader.setHave_field_flags_hi(true);
         }
-        if(codeAttributes.keySet().size() > 15) {
+        if (codeLayouts.keySet().size() > 15) {
             segmentHeader.setHave_code_flags_hi(true);
         }
-    }
-
-    public void pack(OutputStream out) throws IOException, Pack200Exception {
-        int[] availableClassIndices = new int[] {25, 26, 27, 28, 29, 30, 31};
-        if(classAttributes.size() > 7) {
+        int[] availableClassIndices = new int[] { 25, 26, 27, 28, 29, 30, 31 };
+        if (classLayouts.size() > 7) {
             availableClassIndices = addHighIndices(availableClassIndices);
         }
-        addAttributeDefinitions(classAttributes, availableClassIndices, CONTEXT_CLASS);
-        int[] availableMethodIndices = new int[] {26, 27, 28, 29, 30, 31};
-        if(methodAttributes.size() > 6) {
+        addAttributeDefinitions(classLayouts, availableClassIndices,
+                CONTEXT_CLASS);
+        int[] availableMethodIndices = new int[] { 26, 27, 28, 29, 30, 31 };
+        if (methodAttributeLayouts.size() > 6) {
             availableMethodIndices = addHighIndices(availableMethodIndices);
         }
-        addAttributeDefinitions(methodAttributes, availableMethodIndices, CONTEXT_METHOD);
-        int[] availableFieldIndices = new int[] {18, 23, 24, 25, 26, 27, 28, 29, 30, 31};
-        if(fieldAttributes.size() > 10) {
+        addAttributeDefinitions(methodLayouts, availableMethodIndices,
+                CONTEXT_METHOD);
+        int[] availableFieldIndices = new int[] { 18, 23, 24, 25, 26, 27, 28,
+                29, 30, 31 };
+        if (fieldAttributeLayouts.size() > 10) {
             availableFieldIndices = addHighIndices(availableFieldIndices);
         }
-        addAttributeDefinitions(fieldAttributes, availableFieldIndices, CONTEXT_FIELD);
-        int[] availableCodeIndices = new int[] {17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31};
-        if(codeAttributes.size() > 15) {
+        addAttributeDefinitions(fieldLayouts, availableFieldIndices,
+                CONTEXT_FIELD);
+        int[] availableCodeIndices = new int[] { 17, 18, 19, 20, 21, 22, 23,
+                24, 25, 26, 27, 28, 29, 30, 31 };
+        if (codeAttributeLayouts.size() > 15) {
             availableCodeIndices = addHighIndices(availableCodeIndices);
         }
-        addAttributeDefinitions(codeAttributes, availableCodeIndices, CONTEXT_CODE);
+        addAttributeDefinitions(codeLayouts, availableCodeIndices, CONTEXT_CODE);
+    }
 
+    /**
+     * All input classes for the segment have now been read in, so this method
+     * is called so that this class can calculate/complete anything it could not
+     * do while classes were being read.
+     */
+    public void finaliseBands() {
+        addSyntheticDefinitions();
+        segmentHeader.setAttribute_definition_count(attributeDefinitions.size());
+    }
+
+    public void pack(OutputStream out) throws IOException, Pack200Exception {
         int[] attributeDefinitionHeader = new int[attributeDefinitions.size()];
         int[] attributeDefinitionName = new int[attributeDefinitions.size()];
         int[] attributeDefinitionLayout = new int[attributeDefinitions.size()];
         for (int i = 0; i < attributeDefinitionLayout.length; i++) {
-            AttributeDefinition def = (AttributeDefinition) attributeDefinitions.get(i);
-            attributeDefinitionHeader[i] = def.contextType | (def.index + 1 << 2);
+            AttributeDefinition def = (AttributeDefinition) attributeDefinitions
+                    .get(i);
+            attributeDefinitionHeader[i] = def.contextType
+                    | (def.index + 1 << 2);
             attributeDefinitionName[i] = def.name.getIndex();
             attributeDefinitionLayout[i] = def.layout.getIndex();
         }
 
-        out.write(encodeBandInt("attributeDefinitionHeader", attributeDefinitionHeader, Codec.BYTE1));
-        out.write(encodeBandInt("attributeDefinitionName", attributeDefinitionName, Codec.UNSIGNED5));
-        out.write(encodeBandInt("attributeDefinitionLayout", attributeDefinitionLayout, Codec.UNSIGNED5));
+        out.write(encodeBandInt("attributeDefinitionHeader",
+                attributeDefinitionHeader, Codec.BYTE1));
+        out.write(encodeBandInt("attributeDefinitionName",
+                attributeDefinitionName, Codec.UNSIGNED5));
+        out.write(encodeBandInt("attributeDefinitionLayout",
+                attributeDefinitionLayout, Codec.UNSIGNED5));
     }
 
     private void addSyntheticDefinitions() {
-        boolean anySytheticClasses = segment.getClassBands().isAnySyntheticClasses();
-        boolean anySyntheticMethods = segment.getClassBands().isAnySyntheticMethods();
-        boolean anySyntheticFields = segment.getClassBands().isAnySyntheticFields();
-        if(anySytheticClasses || anySyntheticMethods || anySyntheticFields) {
+        boolean anySytheticClasses = segment.getClassBands()
+                .isAnySyntheticClasses();
+        boolean anySyntheticMethods = segment.getClassBands()
+                .isAnySyntheticMethods();
+        boolean anySyntheticFields = segment.getClassBands()
+                .isAnySyntheticFields();
+        if (anySytheticClasses || anySyntheticMethods || anySyntheticFields) {
             CPUTF8 syntheticUTF = cpBands.getCPUtf8("Synthetic");
             CPUTF8 emptyUTF = cpBands.getCPUtf8("");
-            if(anySytheticClasses) {
-                attributeDefinitions.add(new AttributeDefinition(12, CONTEXT_CLASS, syntheticUTF, emptyUTF));
+            if (anySytheticClasses) {
+                attributeDefinitions.add(new AttributeDefinition(12,
+                        CONTEXT_CLASS, syntheticUTF, emptyUTF));
             }
-            if(anySyntheticMethods) {
-                attributeDefinitions.add(new AttributeDefinition(12, CONTEXT_METHOD, syntheticUTF, emptyUTF));
+            if (anySyntheticMethods) {
+                attributeDefinitions.add(new AttributeDefinition(12,
+                        CONTEXT_METHOD, syntheticUTF, emptyUTF));
             }
-            if(anySyntheticFields) {
-                attributeDefinitions.add(new AttributeDefinition(12, CONTEXT_FIELD, syntheticUTF, emptyUTF));
+            if (anySyntheticFields) {
+                attributeDefinitions.add(new AttributeDefinition(12,
+                        CONTEXT_FIELD, syntheticUTF, emptyUTF));
             }
         }
     }
@@ -137,29 +173,58 @@
             temp[i] = availableIndices[i];
         }
         int j = 32;
-        for (int i = availableIndices.length; i < temp.length ; i++) {
+        for (int i = availableIndices.length; i < temp.length; i++) {
             temp[i] = j;
             j++;
         }
         return temp;
     }
 
-    private void addAttributeDefinitions(Map attributes,
-            int[] availableIndices, int contextType) {
+    private void addAttributeDefinitions(Map layouts, int[] availableIndices,
+            int contextType) {
         int i = 0;
-        for (Iterator iterator = attributes.keySet().iterator(); iterator.hasNext();) {
+        for (Iterator iterator = layouts.keySet().iterator(); iterator
+                .hasNext();) {
             String name = (String) iterator.next();
             String layout = (String) layouts.get(name);
             int index = availableIndices[i];
-            attributeDefinitions.add(new AttributeDefinition(index, contextType, cpBands.getCPUtf8(name), cpBands.getCPUtf8(layout)));
+            AttributeDefinition definition = new AttributeDefinition(index,
+                    contextType, cpBands.getCPUtf8(name), cpBands
+                            .getCPUtf8(layout));
+            attributeDefinitions.add(definition);
+            switch (contextType) {
+            case CONTEXT_CLASS:
+                classAttributeLayouts.add(definition);
+                break;
+            case CONTEXT_METHOD:
+                methodAttributeLayouts.add(definition);
+                break;
+            case CONTEXT_FIELD:
+                fieldAttributeLayouts.add(definition);
+                break;
+            case CONTEXT_CODE:
+                codeAttributeLayouts.add(definition);
+            }
         }
     }
 
-    public void addLayout(String name, String layout) {
-        layouts.put(name, layout);
+    public List getClassAttributeLayouts() {
+        return classAttributeLayouts;
+    }
+
+    public List getMethodAttributeLayouts() {
+        return methodAttributeLayouts;
+    }
+
+    public List getFieldAttributeLayouts() {
+        return fieldAttributeLayouts;
+    }
+
+    public List getCodeAttributeLayouts() {
+        return codeAttributeLayouts;
     }
 
-    private static class AttributeDefinition {
+    public static class AttributeDefinition {
 
         public int index;
         public int contextType;

Modified: harmony/enhanced/classlib/trunk/modules/pack200/src/main/java/org/apache/harmony/pack200/ClassBands.java
URL: http://svn.apache.org/viewvc/harmony/enhanced/classlib/trunk/modules/pack200/src/main/java/org/apache/harmony/pack200/ClassBands.java?rev=784048&r1=784047&r2=784048&view=diff
==============================================================================
--- harmony/enhanced/classlib/trunk/modules/pack200/src/main/java/org/apache/harmony/pack200/ClassBands.java (original)
+++ harmony/enhanced/classlib/trunk/modules/pack200/src/main/java/org/apache/harmony/pack200/ClassBands.java Fri Jun 12 09:32:53 2009
@@ -19,6 +19,8 @@
 import java.io.IOException;
 import java.io.OutputStream;
 import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Iterator;
@@ -26,11 +28,15 @@
 import java.util.Map;
 import java.util.Set;
 
+import org.apache.harmony.pack200.AttributeDefinitionBands.AttributeDefinition;
 import org.apache.harmony.pack200.IcBands.IcTuple;
-import org.objectweb.asm.Attribute;
 import org.objectweb.asm.Label;
 import org.objectweb.asm.Opcodes;
 
+/**
+ * Class bands (corresponds to the <code>class_bands</code> set of bands in the
+ * pack200 specification)
+ */
 public class ClassBands extends BandSet {
 
     private final CpBands cpBands;
@@ -77,6 +83,7 @@
     private final List codeHandlerCatchPO = new ArrayList();
     private final List codeHandlerClass = new ArrayList();
     private final List codeFlags = new ArrayList();
+    private int[] code_attr_calls;
     private final IntList codeLineNumberTableN = new IntList();
     private final List codeLineNumberTableBciP = new ArrayList();
     private final IntList codeLineNumberTableLine = new IntList();
@@ -103,6 +110,11 @@
     private final MetadataBandGroup method_RIPA_bands;
     private final MetadataBandGroup method_AD_bands;
 
+    private final List classAttributeBands = new ArrayList();
+    private final List methodAttributeBands = new ArrayList();
+    private final List fieldAttributeBands = new ArrayList();
+    private final List codeAttributeBands = new ArrayList();
+
     private final List tempFieldFlags = new ArrayList();
     private final List tempFieldDesc = new ArrayList();
     private final List tempMethodFlags = new ArrayList();
@@ -114,9 +126,20 @@
     private final Segment segment;
 
     private final Map classReferencesInnerClass = new HashMap();
+    private final boolean stripDebug;
+
+    private int index = 0;
+
+    private int numMethodArgs = 0;
+    private int[] class_InnerClasses_N;
+    private CPClass[] class_InnerClasses_RC;
+    private int[] class_InnerClasses_F;
+    private List classInnerClassesOuterRCN;
+    private List classInnerClassesNameRUN;
 
-    public ClassBands(Segment segment, int numClasses, int effort) {
+    public ClassBands(Segment segment, int numClasses, int effort, boolean stripDebug) throws IOException {
         super(effort, segment.getSegmentHeader());
+        this.stripDebug = stripDebug;
         this.segment = segment;
         this.cpBands = segment.getCpBands();
         this.attrBands = segment.getAttrBands();
@@ -143,16 +166,32 @@
         method_RVPA_bands = new MetadataBandGroup("RVPA", MetadataBandGroup.CONTEXT_METHOD, cpBands, segmentHeader, effort);
         method_RIPA_bands = new MetadataBandGroup("RIPA", MetadataBandGroup.CONTEXT_METHOD, cpBands, segmentHeader, effort);
         method_AD_bands = new MetadataBandGroup("AD", MetadataBandGroup.CONTEXT_METHOD, cpBands, segmentHeader, effort);
-    }
 
-    private int index = 0;
+        createNewAttributeBands();
+    }
 
-    private int numMethodArgs = 0;
-    private int[] class_InnerClasses_N;
-    private CPClass[] class_InnerClasses_RC;
-    private int[] class_InnerClasses_F;
-    private List classInnerClassesOuterRCN;
-    private List classInnerClassesNameRUN;
+    private void createNewAttributeBands() throws IOException {
+        List classAttributeLayouts = attrBands.getClassAttributeLayouts();
+        for (Iterator iterator = classAttributeLayouts.iterator(); iterator.hasNext();) {
+            AttributeDefinition def = (AttributeDefinition) iterator.next();
+            classAttributeBands.add(new NewAttributeBands(effort, cpBands, segment.getSegmentHeader(), def));
+        }
+        List methodAttributeLayouts = attrBands.getMethodAttributeLayouts();
+        for (Iterator iterator = methodAttributeLayouts.iterator(); iterator.hasNext();) {
+            AttributeDefinition def = (AttributeDefinition) iterator.next();
+            methodAttributeBands.add(new NewAttributeBands(effort, cpBands, segment.getSegmentHeader(), def));
+        }
+        List fieldAttributeLayouts = attrBands.getFieldAttributeLayouts();
+        for (Iterator iterator = fieldAttributeLayouts.iterator(); iterator.hasNext();) {
+            AttributeDefinition def = (AttributeDefinition) iterator.next();
+            fieldAttributeBands.add(new NewAttributeBands(effort, cpBands, segment.getSegmentHeader(), def));
+        }
+        List codeAttributeLayouts = attrBands.getCodeAttributeLayouts();
+        for (Iterator iterator = codeAttributeLayouts.iterator(); iterator.hasNext();) {
+            AttributeDefinition def = (AttributeDefinition) iterator.next();
+            codeAttributeBands.add(new NewAttributeBands(effort, cpBands, segment.getSegmentHeader(), def));
+        }
+    }
 
     public void addClass(int major, int flags, String className,
             String signature, String superName, String[] interfaces) {
@@ -232,6 +271,11 @@
         tempFieldFlags.add(new Long(flags));
     }
 
+    /**
+     * All input classes for the segment have now been read in, so this method
+     * is called so that this class can calculate/complete anything it could not
+     * do while classes were being read.
+     */
     public void finaliseBands() {
         int defaultMajorVersion = segmentHeader.getDefaultMajorVersion();
         for (int i = 0; i < class_flags.length; i++) {
@@ -332,6 +376,8 @@
         IntList classAttrCalls = new IntList();
         IntList fieldAttrCalls = new IntList();
         IntList methodAttrCalls = new IntList();
+        IntList codeAttrCalls = new IntList();
+
         if(class_RVA_bands.hasContent()) {
             classAttrCalls.add(class_RVA_bands.numBackwardsCalls());
         }
@@ -359,9 +405,61 @@
         if(method_AD_bands.hasContent()) {
             methodAttrCalls.add(method_AD_bands.numBackwardsCalls());
         }
+
+        // Sort non-predefined attribute bands
+        Comparator comparator = new Comparator() {
+            public int compare(Object arg0, Object arg1) {
+                NewAttributeBands bands0 = (NewAttributeBands)arg0;
+                NewAttributeBands bands1 = (NewAttributeBands)arg1;
+                return bands0.getFlagIndex() - bands1.getFlagIndex();
+            }
+        };
+        Collections.sort(classAttributeBands, comparator);
+        Collections.sort(methodAttributeBands, comparator);
+        Collections.sort(fieldAttributeBands, comparator);
+        Collections.sort(codeAttributeBands, comparator);
+
+        for (Iterator iterator = classAttributeBands.iterator(); iterator.hasNext();) {
+            NewAttributeBands bands = (NewAttributeBands) iterator.next();
+            if(bands.isUsedAtLeastOnce()) {
+                int[] backwardsCallCounts = bands.numBackwardsCalls();
+                for (int i = 0; i < backwardsCallCounts.length; i++) {
+                    classAttrCalls.add(backwardsCallCounts[i]);
+                }
+            }
+        }
+        for (Iterator iterator = methodAttributeBands.iterator(); iterator.hasNext();) {
+            NewAttributeBands bands = (NewAttributeBands) iterator.next();
+            if(bands.isUsedAtLeastOnce()) {
+                int[] backwardsCallCounts = bands.numBackwardsCalls();
+                for (int i = 0; i < backwardsCallCounts.length; i++) {
+                    methodAttrCalls.add(backwardsCallCounts[i]);
+                }
+            }
+        }
+        for (Iterator iterator = fieldAttributeBands.iterator(); iterator.hasNext();) {
+            NewAttributeBands bands = (NewAttributeBands) iterator.next();
+            if(bands.isUsedAtLeastOnce()) {
+                int[] backwardsCallCounts = bands.numBackwardsCalls();
+                for (int i = 0; i < backwardsCallCounts.length; i++) {
+                    fieldAttrCalls.add(backwardsCallCounts[i]);
+                }
+            }
+        }
+        for (Iterator iterator = codeAttributeBands.iterator(); iterator.hasNext();) {
+            NewAttributeBands bands = (NewAttributeBands) iterator.next();
+            if(bands.isUsedAtLeastOnce()) {
+                int[] backwardsCallCounts = bands.numBackwardsCalls();
+                for (int i = 0; i < backwardsCallCounts.length; i++) {
+                    codeAttrCalls.add(backwardsCallCounts[i]);
+                }
+            }
+        }
+
         class_attr_calls = classAttrCalls.toArray();
         field_attr_calls = fieldAttrCalls.toArray();
         method_attr_calls = methodAttrCalls.toArray();
+        code_attr_calls = codeAttrCalls.toArray();
     }
 
     public void pack(OutputStream out) throws IOException, Pack200Exception {
@@ -440,6 +538,10 @@
                 cpEntryListToArray(fieldSignature), Codec.UNSIGNED5));
         field_RVA_bands.pack(out);
         field_RIA_bands.pack(out);
+        for (Iterator iterator = fieldAttributeBands.iterator(); iterator.hasNext();) {
+            NewAttributeBands bands = (NewAttributeBands) iterator.next();
+            bands.pack(out);
+        }
     }
 
     private void writeMethodAttributeBands(OutputStream out)
@@ -460,14 +562,25 @@
         method_RVPA_bands.pack(out);
         method_RIPA_bands.pack(out);
         method_AD_bands.pack(out);
+        for (Iterator iterator = methodAttributeBands.iterator(); iterator.hasNext();) {
+            NewAttributeBands bands = (NewAttributeBands) iterator.next();
+            bands.pack(out);
+        }
     }
 
     private void writeClassAttributeBands(OutputStream out) throws IOException,
             Pack200Exception {
         out.write(encodeFlags("class_flags", class_flags, Codec.UNSIGNED5,
                 Codec.UNSIGNED5, segmentHeader.have_class_flags_hi()));
+
+        // These bands are not needed, but could be used to reduce the size of
+        // the archive if there are enough different non-standard attributes
+        // defined that segmentHeader.have_class_flags_hi() is true. The same
+        // applies to method_attr_count, field_attr_count, code_attr_count etc.
+
 //        *class_attr_count :UNSIGNED5 [COUNT(1<<16,...)]
 //        *class_attr_indexes :UNSIGNED5 [SUM(*class_attr_count)]
+
         out.write(encodeBandInt("class_attr_calls", class_attr_calls, Codec.UNSIGNED5));
         out.write(encodeBandInt("classSourceFile",
                 cpEntryOrNullListToArray(classSourceFile), Codec.UNSIGNED5));
@@ -490,6 +603,10 @@
                 classFileVersionMinor.toArray(), Codec.UNSIGNED5));
         out.write(encodeBandInt("classFileVersionMajor",
                 classFileVersionMajor.toArray(), Codec.UNSIGNED5));
+        for (Iterator iterator = classAttributeBands.iterator(); iterator.hasNext();) {
+            NewAttributeBands bands = (NewAttributeBands) iterator.next();
+            bands.pack(out);
+        }
     }
 
     private int[] getInts(CPClass[] cpClasses) {
@@ -527,7 +644,8 @@
 
         // *code_attr_count :UNSIGNED5 [COUNT(1<<16,...)]
         // *code_attr_indexes :UNSIGNED5 [SUM(*code_attr_count)]
-        // *code_attr_calls :UNSIGNED5 [...]
+        out.write(encodeBandInt("code_attr_calls", code_attr_calls,
+                Codec.UNSIGNED5));
         out.write(encodeBandInt("code_LineNumberTable_N",
                 codeLineNumberTableN.toArray(), Codec.UNSIGNED5));
         out.write(encodeBandInt("code_LineNumberTable_bci_P",
@@ -562,7 +680,10 @@
                 Codec.UNSIGNED5));
         out.write(encodeBandInt("code_LocalVariableTypeTable_slot",
                 codeLocalVariableTypeTableSlot.toArray(), Codec.UNSIGNED5));
-
+        for (Iterator iterator = codeAttributeBands.iterator(); iterator.hasNext();) {
+            NewAttributeBands bands = (NewAttributeBands) iterator.next();
+            bands.pack(out);
+        }
     }
 
     public void addMethod(int flags, String name, String desc,
@@ -690,14 +811,64 @@
                 .getCPNameAndType(name, desc));
     }
 
-    public void addUnknownFieldAttribute(Attribute arg0) {
-        // TODO Auto-generated method stub
-
-    }
-
-    public void addUnknownMethodAttribute(Attribute arg0) {
-        // TODO Auto-generated method stub
-
+    public void addClassAttribute(NewAttribute attribute) {
+        // TODO: backwards calls
+        String attributeName = attribute.type;
+        for (Iterator iterator = classAttributeBands.iterator(); iterator.hasNext();) {
+            NewAttributeBands bands = (NewAttributeBands) iterator.next();
+            if(bands.getAttributeName().equals(attributeName)) {
+                bands.addAttribute(attribute);
+                int flagIndex = bands.getFlagIndex();
+                class_flags[index] |= (1 << flagIndex);
+                return;
+            }
+        }
+        throw new RuntimeException("No suitable definition for " + attributeName);
+    }
+
+    public void addFieldAttribute(NewAttribute attribute) {
+        String attributeName = attribute.type;
+        for (Iterator iterator = fieldAttributeBands.iterator(); iterator.hasNext();) {
+            NewAttributeBands bands = (NewAttributeBands) iterator.next();
+            if(bands.getAttributeName().equals(attributeName)) {
+                bands.addAttribute(attribute);
+                int flagIndex = bands.getFlagIndex();
+                Long flags = (Long)tempFieldFlags.remove(tempFieldFlags.size() - 1);
+                tempFieldFlags.add(new Long(flags.longValue() | (1 << flagIndex)));
+                return;
+            }
+        }
+        throw new RuntimeException("No suitable definition for " + attributeName);
+    }
+
+    public void addMethodAttribute(NewAttribute attribute) {
+        String attributeName = attribute.type;
+        for (Iterator iterator = methodAttributeBands.iterator(); iterator.hasNext();) {
+            NewAttributeBands bands = (NewAttributeBands) iterator.next();
+            if(bands.getAttributeName().equals(attributeName)) {
+                bands.addAttribute(attribute);
+                int flagIndex = bands.getFlagIndex();
+                Long flags = (Long)tempMethodFlags.remove(tempMethodFlags.size() - 1);
+                tempMethodFlags.add(new Long(flags.longValue() | (1 << flagIndex)));
+                return;
+            }
+        }
+        throw new RuntimeException("No suitable definition for " + attributeName);
+    }
+
+    public void addCodeAttribute(NewAttribute attribute) {
+        String attributeName = attribute.type;
+        for (Iterator iterator = codeAttributeBands.iterator(); iterator.hasNext();) {
+            NewAttributeBands bands = (NewAttributeBands) iterator.next();
+            if(bands.getAttributeName().equals(attributeName)) {
+                bands.addAttribute(attribute);
+                int flagIndex = bands.getFlagIndex();
+                Long flags = (Long)codeFlags.remove(codeFlags.size() - 1);
+                codeFlags.add(new Long(flags.longValue() | (1 << flagIndex)));
+                return;
+            }
+        }
+        throw new RuntimeException("No suitable definition for " + attributeName);
     }
 
     public void addMaxStack(int maxStack, int maxLocals) {
@@ -713,10 +884,10 @@
         codeMaxLocals.add(maxLocals);
     }
 
-    public void addCode(boolean stripDebug) {
+    public void addCode() {
         codeHandlerCount.add(0);
         if(!stripDebug) {
-            codeFlags.add(new Long((1 << 2))); // TODO: What if there's no debug information?
+            codeFlags.add(new Long((1 << 2)));
             codeLocalVariableTableN.add(0);
         }
     }
@@ -743,7 +914,6 @@
         }
         codeLineNumberTableLine.add(line);
         codeLineNumberTableBciP.add(start);
-        // TODO: bci renumbering
     }
 
     public void addLocalVariable(String name, String desc, String signature,
@@ -946,4 +1116,136 @@
         Long flag = (Long) tempMethodFlags.remove(tempMethodFlags.size() - 1);
         tempMethodFlags.add(new Long(flag.longValue() | (1<<25)));
     }
+
+    /**
+     * Remove all entries for the current class
+     */
+    public void removeCurrentClass() {
+        // Note - this doesn't remove any entries added to the constant pool but
+        // that shouldn't be a problem
+        if ((class_flags[index] & (1 << 17)) != 0) {
+            classSourceFile.remove(classSourceFile.size() - 1);
+        }
+        if ((class_flags[index] & (1 << 18)) != 0) {
+            classEnclosingMethodClass
+                    .remove(classEnclosingMethodClass.size() - 1);
+            classEnclosingMethodDesc
+                    .remove(classEnclosingMethodDesc.size() - 1);
+        }
+        if ((class_flags[index] & (1 << 19)) != 0) {
+            classSignature.remove(classSignature.size() - 1);
+        }
+        if ((class_flags[index] & (1 << 21)) != 0) {
+            class_RVA_bands.removeLatest();
+        }
+        if ((class_flags[index] & (1 << 22)) != 0) {
+            class_RIA_bands.removeLatest();
+        }
+        for (Iterator iterator = tempFieldFlags.iterator(); iterator.hasNext();) {
+            Long flagsL = (Long) iterator.next();
+            long flags = flagsL.longValue();
+            if ((flags & (1 << 19)) != 0) {
+                fieldSignature.remove(fieldSignature.size() - 1);
+            }
+            if ((flags & (1 << 17)) != 0) {
+                fieldConstantValueKQ.remove(fieldConstantValueKQ.size() - 1);
+            }
+            if ((flags & (1 << 21)) != 0) {
+                field_RVA_bands.removeLatest();
+            }
+            if ((flags & (1 << 22)) != 0) {
+                field_RIA_bands.removeLatest();
+            }
+        }
+        for (Iterator iterator = tempMethodFlags.iterator(); iterator.hasNext();) {
+            Long flagsL = (Long) iterator.next();
+            long flags = flagsL.longValue();
+            if ((flags & (1 << 19)) != 0) {
+                methodSignature.remove(methodSignature.size() - 1);
+            }
+            if ((flags & (1 << 18)) != 0) {
+                int exceptions = methodExceptionNumber
+                        .remove(methodExceptionNumber.size() - 1);
+                for (int i = 0; i < exceptions; i++) {
+                    methodExceptionClasses
+                            .remove(methodExceptionClasses.size() - 1);
+                }
+            }
+            if ((flags & (1 << 17)) != 0) { // has code attribute
+                codeMaxLocals.remove(codeMaxLocals.size() - 1);
+                codeMaxStack.remove(codeMaxStack.size() - 1);
+                int handlers = codeHandlerCount
+                        .remove(codeHandlerCount.size() - 1);
+                for (int i = 0; i < handlers; i++) {
+                    int index = codeHandlerStartP.size() - 1;
+                    codeHandlerStartP.remove(index);
+                    codeHandlerEndPO.remove(index);
+                    codeHandlerCatchPO.remove(index);
+                    codeHandlerClass.remove(index);
+                }
+                if (!stripDebug) {
+                    long cdeFlags = ((Long) codeFlags
+                            .remove(codeFlags.size() - 1)).longValue();
+                    int numLocalVariables = codeLocalVariableTableN
+                            .remove(codeLocalVariableTableN.size() - 1);
+                    for (int i = 0; i < numLocalVariables; i++) {
+                        int location = codeLocalVariableTableBciP.size() - 1;
+                        codeLocalVariableTableBciP.remove(location);
+                        codeLocalVariableTableSpanO.remove(location);
+                        codeLocalVariableTableNameRU.remove(location);
+                        codeLocalVariableTableTypeRS.remove(location);
+                        codeLocalVariableTableSlot.remove(location);
+                    }
+                    if ((cdeFlags & (1 << 3)) != 0) {
+                        int numLocalVariablesInTypeTable = codeLocalVariableTypeTableN
+                                .remove(codeLocalVariableTypeTableN.size() - 1);
+                        for (int i = 0; i < numLocalVariablesInTypeTable; i++) {
+                            int location = codeLocalVariableTypeTableBciP
+                                    .size() - 1;
+                            codeLocalVariableTypeTableBciP.remove(location);
+                            codeLocalVariableTypeTableSpanO.remove(location);
+                            codeLocalVariableTypeTableNameRU.remove(location);
+                            codeLocalVariableTypeTableTypeRS.remove(location);
+                            codeLocalVariableTypeTableSlot.remove(location);
+                        }
+                    }
+                    if ((cdeFlags & (1 << 1)) != 0) {
+                        int numLineNumbers = codeLineNumberTableN
+                                .remove(codeLineNumberTableN.size() - 1);
+                        for (int i = 0; i < numLineNumbers; i++) {
+                            int location = codeLineNumberTableBciP.size() - 1;
+                            codeLineNumberTableBciP.remove(location);
+                            codeLineNumberTableLine.remove(location);
+                        }
+                    }
+                }
+            }
+            if ((flags & (1 << 21)) != 0) {
+                method_RVA_bands.removeLatest();
+            }
+            if ((flags & (1 << 22)) != 0) {
+                method_RIA_bands.removeLatest();
+            }
+            if ((flags & (1 << 23)) != 0) {
+                method_RVPA_bands.removeLatest();
+            }
+            if ((flags & (1 << 24)) != 0) {
+                method_RIPA_bands.removeLatest();
+            }
+            if ((flags & (1 << 25)) != 0) {
+                method_AD_bands.removeLatest();
+            }
+        }
+        class_this[index] = null;
+        class_super[index] = null;
+        class_interface_count[index] = 0;
+        class_interface[index] = null;
+        major_versions[index] = 0;
+        class_flags[index] = 0;
+        tempFieldDesc.clear();
+        tempFieldFlags.clear();
+        tempMethodDesc.clear();
+        tempMethodFlags.clear();
+        index--;
+    }
 }

Modified: harmony/enhanced/classlib/trunk/modules/pack200/src/main/java/org/apache/harmony/pack200/MetadataBandGroup.java
URL: http://svn.apache.org/viewvc/harmony/enhanced/classlib/trunk/modules/pack200/src/main/java/org/apache/harmony/pack200/MetadataBandGroup.java?rev=784048&r1=784047&r2=784048&view=diff
==============================================================================
--- harmony/enhanced/classlib/trunk/modules/pack200/src/main/java/org/apache/harmony/pack200/MetadataBandGroup.java (original)
+++ harmony/enhanced/classlib/trunk/modules/pack200/src/main/java/org/apache/harmony/pack200/MetadataBandGroup.java Fri Jun 12 09:32:53 2009
@@ -36,9 +36,9 @@
     private int numBackwardsCalls = 0;
 
     public List param_NB = new ArrayList(); // TODO: Lazy instantiation?
-    public List anno_N = new ArrayList();
+    public IntList anno_N = new IntList();
     public List type_RS = new ArrayList();
-    public List pair_N = new ArrayList();
+    public IntList pair_N = new IntList();
     public List name_RU = new ArrayList();
     public List T = new ArrayList();
     public List caseI_KI = new ArrayList();
@@ -49,9 +49,9 @@
     public List caseet_RS = new ArrayList();
     public List caseec_RU = new ArrayList();
     public List cases_RU = new ArrayList();
-    public List casearray_N = new ArrayList();
+    public IntList casearray_N = new IntList();
     public List nesttype_RS = new ArrayList();
-    public List nestpair_N = new ArrayList();
+    public IntList nestpair_N = new IntList();
     public List nestname_RU = new ArrayList();
 
     private final CpBands cpBands;
@@ -59,7 +59,18 @@
 
     /**
      * Constructs a new MetadataBandGroup
-     * @param type - must be either AD, RVA, RIA, RVPA or RIPA.
+     *
+     * @param type
+     *            must be either AD, RVA, RIA, RVPA or RIPA.
+     * @param context
+     *            <code>CONTEXT_CLASS</code>, <code>CONTEXT_METHOD</code> or
+     *            <code>CONTEXT_FIELD</code>
+     * @param cpBands
+     *            constant pool bands
+     * @param segmentHeader
+     *            segment header
+     * @param effort
+     *            packing effort
      */
     public MetadataBandGroup(String type, int context, CpBands cpBands, SegmentHeader segmentHeader, int effort) {
         super(effort, segmentHeader);
@@ -82,9 +93,9 @@
                 contextStr = "Method";
             }
             if(!type.equals("AD")) {
-                out.write(encodeBandInt(contextStr + "_" + type + " anno_N",  listToArray(anno_N), Codec.UNSIGNED5));
+                out.write(encodeBandInt(contextStr + "_" + type + " anno_N",  anno_N.toArray(), Codec.UNSIGNED5));
                 out.write(encodeBandInt(contextStr + "_" + type + " type_RS",  cpEntryListToArray(type_RS), Codec.UNSIGNED5));
-                out.write(encodeBandInt(contextStr + "_" + type + " pair_N",  listToArray(pair_N), Codec.UNSIGNED5));
+                out.write(encodeBandInt(contextStr + "_" + type + " pair_N",  pair_N.toArray(), Codec.UNSIGNED5));
                 out.write(encodeBandInt(contextStr + "_" + type + " name_RU",  cpEntryListToArray(name_RU), Codec.UNSIGNED5));
             }
             out.write(encodeBandInt(contextStr + "_" + type + " T",  tagListToArray(T), Codec.BYTE1));
@@ -96,9 +107,9 @@
             out.write(encodeBandInt(contextStr + "_" + type + " caseet_RS",  cpEntryListToArray(caseet_RS), Codec.UNSIGNED5));
             out.write(encodeBandInt(contextStr + "_" + type + " caseec_RU",  cpEntryListToArray(caseec_RU), Codec.UNSIGNED5));
             out.write(encodeBandInt(contextStr + "_" + type + " cases_RU",  cpEntryListToArray(cases_RU), Codec.UNSIGNED5));
-            out.write(encodeBandInt(contextStr + "_" + type + " casearray_N",  listToArray(casearray_N), Codec.UNSIGNED5));
+            out.write(encodeBandInt(contextStr + "_" + type + " casearray_N",  casearray_N.toArray(), Codec.UNSIGNED5));
             out.write(encodeBandInt(contextStr + "_" + type + " nesttype_RS",  cpEntryListToArray(nesttype_RS), Codec.UNSIGNED5));
-            out.write(encodeBandInt(contextStr + "_" + type + " nestpair_N",  listToArray(nestpair_N), Codec.UNSIGNED5));
+            out.write(encodeBandInt(contextStr + "_" + type + " nestpair_N",  nestpair_N.toArray(), Codec.UNSIGNED5));
             out.write(encodeBandInt(contextStr + "_" + type + " nestname_RU",  cpEntryListToArray(nestname_RU), Codec.UNSIGNED5));
         }
     }
@@ -111,9 +122,21 @@
         return ints;
     }
 
+    /**
+     * Add an annotation to this set of bands
+     *
+     * @param desc
+     * @param nameRU
+     * @param t
+     * @param values
+     * @param caseArrayN
+     * @param nestTypeRS
+     * @param nestNameRU
+     * @param nestPairN
+     */
     public void addAnnotation(String desc, List nameRU, List t, List values, List caseArrayN, List nestTypeRS, List nestNameRU, List nestPairN) {
         type_RS.add(cpBands.getCPSignature(desc));
-        pair_N.add(new Integer(t.size()));
+        pair_N.add(t.size());
 
         for (Iterator iterator = nameRU.iterator(); iterator.hasNext();) {
             String name = (String) iterator.next();
@@ -152,9 +175,9 @@
             // do nothing here for [ or @ (handled below)
         }
         for (Iterator iterator = caseArrayN.iterator(); iterator.hasNext();) {
-            Integer arraySize = (Integer) iterator.next();
+            int arraySize = ((Integer)iterator.next()).intValue();
             casearray_N.add(arraySize);
-            numBackwardsCalls += arraySize.intValue();
+            numBackwardsCalls += arraySize;
         }
         for (Iterator iterator = nesttype_RS.iterator(); iterator.hasNext();) {
             String type = (String) iterator.next();
@@ -171,6 +194,9 @@
         }
     }
 
+    /**
+     * Returns true if any annotations have been added to this set of bands
+     */
     public boolean hasContent() {
         return type_RS.size() > 0;
     }
@@ -180,12 +206,62 @@
     }
 
     public void incrementAnnoN() {
-        Integer latest = (Integer)anno_N.remove(anno_N.size() -1);
-        anno_N.add(new Integer(latest.intValue() + 1));
+        anno_N.increment(anno_N.size() - 1);
     }
 
     public void newEntryInAnnoN() {
-        anno_N.add(new Integer(1));
+        anno_N.add(1);
+    }
+
+    /**
+     * Remove the latest annotation that was added to this group
+     */
+    public void removeLatest() {
+        int latest = anno_N.remove(anno_N.size() -1);
+        for (int i = 0; i < latest; i++) {
+            type_RS.remove(type_RS.size() - 1);
+            int pairs = pair_N.remove(pair_N.size() - 1);
+            for (int j = 0; j < pairs; j++) {
+                removeOnePair();
+            }
+        }
+    }
+
+    /*
+     * Convenience method for removeLatest
+     */
+    private void removeOnePair() {
+        String tag = (String) T.remove(T.size() - 1);
+        if (tag.equals("B") || tag.equals("C") || tag.equals("I")
+                || tag.equals("S") || tag.equals("Z")) {
+            caseI_KI.remove(caseI_KI.size() - 1);
+        } else if (tag.equals("D")) {
+            caseD_KD.remove(caseD_KD.size() - 1);
+        } else if (tag.equals("F")) {
+            caseF_KF.remove(caseF_KF.size() - 1);
+        } else if (tag.equals("J")) {
+            caseJ_KJ.remove(caseJ_KJ.size() - 1);
+        } else if (tag.equals("C")) {
+            casec_RS.remove(casec_RS.size() - 1);
+        } else if (tag.equals("e")) {
+            caseet_RS.remove(caseet_RS.size() - 1);
+            caseec_RU.remove(caseet_RS.size() - 1);
+        } else if (tag.equals("s")) {
+            cases_RU.remove(cases_RU.size() - 1);
+        } else if (tag.equals("[")) {
+            int arraySize = casearray_N.remove(casearray_N.size() - 1);
+            numBackwardsCalls -= arraySize;
+            for (int k = 0; k < arraySize; k++) {
+                removeOnePair();
+            }
+        } else if (tag.equals("@")) {
+            nesttype_RS.remove(nesttype_RS.size() - 1);
+            int numPairs = nestpair_N.remove(nestpair_N.size() - 1);
+            numBackwardsCalls -= numPairs;
+            for (int i = 0; i < numPairs; i++) {
+                removeOnePair();
+            }
+        }
     }
 
 }

Added: harmony/enhanced/classlib/trunk/modules/pack200/src/main/java/org/apache/harmony/pack200/NewAttribute.java
URL: http://svn.apache.org/viewvc/harmony/enhanced/classlib/trunk/modules/pack200/src/main/java/org/apache/harmony/pack200/NewAttribute.java?rev=784048&view=auto
==============================================================================
--- harmony/enhanced/classlib/trunk/modules/pack200/src/main/java/org/apache/harmony/pack200/NewAttribute.java (added)
+++ harmony/enhanced/classlib/trunk/modules/pack200/src/main/java/org/apache/harmony/pack200/NewAttribute.java Fri Jun 12 09:32:53 2009
@@ -0,0 +1,140 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+package org.apache.harmony.pack200;
+
+import org.objectweb.asm.Attribute;
+import org.objectweb.asm.ClassReader;
+import org.objectweb.asm.Label;
+
+/**
+ * NewAttribute extends <code>Attribute</code> and manages unknown attributes
+ * encountered by ASM that have had a layout definition given to pack200 (e.g.
+ * via one of the -C, -M, -F or -D command line options)
+ */
+public class NewAttribute extends Attribute {
+
+    private boolean contextClass = false;
+    private boolean contextMethod = false;
+    private boolean contextField = false;
+    private boolean contextCode = false;
+
+    private final String layout;
+    private byte[] contents;
+    private int codeOff;
+    private Label[] labels;
+    private ClassReader classReader;
+    private char[] buf;
+
+    public NewAttribute(String type, String layout, int context) {
+        super(type);
+        this.layout = layout;
+        addContext(context);
+    }
+
+    public NewAttribute(ClassReader classReader, String type, String layout, byte[] contents, char[] buf,
+            int codeOff, Label[] labels) {
+        super(type);
+        this.classReader = classReader;
+        this.contents = contents;
+        this.layout = layout;
+        this.codeOff = codeOff;
+        this.labels = labels;
+        this.buf = buf;
+    }
+
+    public void addContext(int context) {
+        switch(context) {
+        case AttributeDefinitionBands.CONTEXT_CLASS:
+            contextClass = true;
+            break;
+        case AttributeDefinitionBands.CONTEXT_METHOD:
+            contextMethod = true;
+            break;
+        case AttributeDefinitionBands.CONTEXT_FIELD:
+            contextField = true;
+            break;
+        case AttributeDefinitionBands.CONTEXT_CODE:
+            contextCode = true;
+        }
+    }
+
+    public boolean isContextClass() {
+        return contextClass;
+    }
+
+    public boolean isContextMethod() {
+        return contextMethod;
+    }
+
+    public boolean isContextField() {
+        return contextField;
+    }
+
+    public boolean isContextCode() {
+        return contextCode;
+    }
+
+    public String getLayout() {
+        return layout;
+    }
+
+    public boolean isUnknown() {
+        return false;
+    }
+
+    public boolean isCodeAttribute() {
+        return codeOff != -1;
+    }
+
+    protected Attribute read(ClassReader cr, int off, int len, char[] buf,
+            int codeOff, Label[] labels) {
+        byte[] attributeContents = new byte[len];
+        System.arraycopy(cr.b, off, attributeContents, 0, len);
+        return new NewAttribute(cr, type, layout, attributeContents, buf, codeOff,
+                labels);
+    }
+
+    public boolean isUnknown(int context) {
+        switch(context) {
+        case AttributeDefinitionBands.CONTEXT_CLASS:
+            return contextClass;
+        case AttributeDefinitionBands.CONTEXT_METHOD:
+            return contextMethod;
+        case AttributeDefinitionBands.CONTEXT_FIELD:
+            return contextField;
+        case AttributeDefinitionBands.CONTEXT_CODE:
+            return contextCode;
+        }
+        return false;
+    }
+
+    public String readUTF8(int index) {
+        return classReader.readUTF8(index, buf);
+    }
+
+    public String readClass(int index) {
+        return classReader.readClass(index, buf);
+    }
+
+    public Object readConst(int index) {
+        return classReader.readConst(index, buf);
+    }
+
+    public byte[] getBytes() {
+        return contents;
+    }
+}

Propchange: harmony/enhanced/classlib/trunk/modules/pack200/src/main/java/org/apache/harmony/pack200/NewAttribute.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: harmony/enhanced/classlib/trunk/modules/pack200/src/main/java/org/apache/harmony/pack200/NewAttribute.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: harmony/enhanced/classlib/trunk/modules/pack200/src/main/java/org/apache/harmony/pack200/NewAttributeBands.java
URL: http://svn.apache.org/viewvc/harmony/enhanced/classlib/trunk/modules/pack200/src/main/java/org/apache/harmony/pack200/NewAttributeBands.java?rev=784048&view=auto
==============================================================================
--- harmony/enhanced/classlib/trunk/modules/pack200/src/main/java/org/apache/harmony/pack200/NewAttributeBands.java (added)
+++ harmony/enhanced/classlib/trunk/modules/pack200/src/main/java/org/apache/harmony/pack200/NewAttributeBands.java Fri Jun 12 09:32:53 2009
@@ -0,0 +1,780 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+package org.apache.harmony.pack200;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.StringReader;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import org.apache.harmony.pack200.AttributeDefinitionBands.AttributeDefinition;
+
+/**
+ * Set of bands relating to a non-predefined attribute that has had a layout
+ * definition given to pack200 (e.g. via one of the -C, -M, -F or -D command
+ * line options)
+ */
+public class NewAttributeBands extends BandSet {
+
+    private List attributeLayoutElements;
+    private int[] backwardsCallCounts;
+    private final CpBands cpBands;
+    private final AttributeDefinition def;
+    private boolean usedAtLeastOnce;
+
+    public NewAttributeBands(int effort, CpBands cpBands, SegmentHeader header, AttributeDefinition def) throws IOException {
+        super(effort, header);
+        this.def = def;
+        this.cpBands = cpBands;
+        parseLayout();
+    }
+
+    public void addAttribute(NewAttribute attribute) {
+        usedAtLeastOnce = true;
+        InputStream stream = new ByteArrayInputStream(attribute.getBytes());
+        for (Iterator iterator = attributeLayoutElements.iterator(); iterator.hasNext();) {
+            AttributeLayoutElement layoutElement = (AttributeLayoutElement) iterator.next();
+            layoutElement.addAttributeToBand(attribute, stream);
+        }
+    }
+
+    public void pack(OutputStream out) throws IOException, Pack200Exception {
+        for (Iterator iterator = attributeLayoutElements.iterator(); iterator.hasNext();) {
+            AttributeLayoutElement layoutElement = (AttributeLayoutElement) iterator.next();
+            layoutElement.pack(out);
+        }
+    }
+
+    public String getAttributeName() {
+        return def.name.getUnderlyingString();
+    }
+
+    public int getFlagIndex() {
+        return def.index;
+    }
+
+    public int[] numBackwardsCalls() {
+        return backwardsCallCounts;
+    }
+
+    public boolean isUsedAtLeastOnce() {
+        return usedAtLeastOnce;
+    }
+
+    private void parseLayout() throws IOException {
+        String layout = def.layout.getUnderlyingString();
+        if (attributeLayoutElements == null) {
+            attributeLayoutElements = new ArrayList();
+            StringReader stream = new StringReader(layout);
+            AttributeLayoutElement e;
+            while ((e = readNextAttributeElement(stream)) != null) {
+                attributeLayoutElements.add(e);
+            }
+            resolveCalls();
+        }
+    }
+
+    /**
+     * Resolve calls in the attribute layout and returns the number of backwards
+     * callables
+     *
+     * @param tokens -
+     *            the attribute layout as a List of AttributeElements
+     */
+    private void resolveCalls() {
+        for (int i = 0; i < attributeLayoutElements.size(); i++) {
+            AttributeLayoutElement element = (AttributeLayoutElement) attributeLayoutElements
+                    .get(i);
+            if (element instanceof Callable) {
+                Callable callable = (Callable) element;
+                List body = callable.body; // Look for calls in the body
+                for (int iIndex = 0; iIndex < body.size(); iIndex++) {
+                    LayoutElement layoutElement = (LayoutElement) body
+                            .get(iIndex);
+                    // Set the callable for each call
+                    resolveCallsForElement(i, callable, layoutElement);
+                }
+            }
+        }
+        int backwardsCallableIndex = 0;
+        for (int i = 0; i < attributeLayoutElements.size(); i++) {
+            AttributeLayoutElement element = (AttributeLayoutElement) attributeLayoutElements
+                    .get(i);
+            if (element instanceof Callable) {
+                Callable callable = (Callable) element;
+                if(callable.isBackwardsCallable) {
+                    callable.setBackwardsCallableIndex(backwardsCallableIndex);
+                    backwardsCallableIndex++;
+                }
+            }
+        }
+        backwardsCallCounts = new int[backwardsCallableIndex];
+    }
+
+    private void resolveCallsForElement(int i,
+            Callable currentCallable, LayoutElement layoutElement) {
+        if (layoutElement instanceof Call) {
+            Call call = (Call) layoutElement;
+            int index = call.callableIndex;
+            if (index == 0) { // Calls the parent callable
+                call.setCallable(currentCallable);
+            } else if (index > 0) { // Forwards call
+                for (int k = i + 1; k < attributeLayoutElements.size(); k++) {
+                    AttributeLayoutElement el = (AttributeLayoutElement) attributeLayoutElements
+                            .get(k);
+                    if (el instanceof Callable) {
+                        index--;
+                        if (index == 0) {
+                            call.setCallable((Callable) el);
+                            break;
+                        }
+                    }
+                }
+            } else { // Backwards call
+                for (int k = i; k >= 0; k--) {
+                    AttributeLayoutElement el = (AttributeLayoutElement) attributeLayoutElements
+                            .get(k);
+                    if (el instanceof Callable) {
+                        index++;
+                        if (index == 0) {
+                            call.setCallable((Callable) el);
+                            break;
+                        }
+                    }
+                }
+            }
+        } else if (layoutElement instanceof Replication) {
+            List children = ((Replication)layoutElement).layoutElements;
+            for (Iterator iterator = children.iterator(); iterator.hasNext();) {
+                LayoutElement object = (LayoutElement) iterator.next();
+                resolveCallsForElement(i, currentCallable, object);
+            }
+        }
+    }
+
+    private AttributeLayoutElement readNextAttributeElement(StringReader stream)
+            throws IOException {
+        int nextChar = stream.read();
+        if (nextChar == -1) {
+            return null;
+        }
+        if (nextChar == '[') {
+            List body = readBody(getStreamUpToMatchingBracket(stream));
+            return new Callable(body);
+        } else {
+            return readNextLayoutElement(stream);
+        }
+    }
+
+    private LayoutElement readNextLayoutElement(StringReader stream)
+            throws IOException {
+        char nextChar = (char)stream.read();
+        if (nextChar == -1) {
+            return null;
+        }
+        switch (nextChar) {
+        // Integrals
+        case 'B':
+        case 'H':
+        case 'I':
+        case 'V':
+            return new Integral(new String(new char[] { nextChar }));
+        case 'S':
+        case 'F':
+            return new Integral(new String(new char[] { nextChar,
+                    (char) stream.read() }));
+        case 'P':
+            stream.mark(1);
+            if (stream.read() != 'O') {
+                stream.reset();
+                return new Integral("P" + (char) stream.read());
+            } else {
+                return new Integral("PO" + (char) stream.read());
+            }
+        case 'O':
+            stream.mark(1);
+            if (stream.read() != 'S') {
+                stream.reset();
+                return new Integral("O" + (char) stream.read());
+            } else {
+                return new Integral("OS" + (char) stream.read());
+            }
+
+            // Replication
+        case 'N':
+            char uint_type = (char) stream.read();
+            stream.read(); // '['
+            String str = readUpToMatchingBracket(stream);
+            return new Replication("" + uint_type, str);
+
+            // Union
+        case 'T':
+            String int_type = "" + (char) stream.read();
+            if (int_type.equals("S")) {
+                int_type += (char) stream.read();
+            }
+            List unionCases = new ArrayList();
+            UnionCase c;
+            while ((c = readNextUnionCase(stream)) != null) {
+                unionCases.add(c);
+            }
+            stream.read(); // '('
+            stream.read(); // ')'
+            stream.read(); // '['
+            List body = null;
+            stream.mark(1);
+            char next = (char) stream.read();
+            if (next != ']') {
+                stream.reset();
+                body = readBody(getStreamUpToMatchingBracket(stream));
+            }
+            return new Union(int_type, unionCases, body);
+
+            // Call
+        case '(':
+            int number = readNumber(stream).intValue();
+            stream.read(); // ')'
+            return new Call(number);
+            // Reference
+        case 'K':
+        case 'R':
+            String string = "" + nextChar + (char) stream.read();
+            char nxt = (char) stream.read();
+            string += nxt;
+            if (nxt == 'N') {
+                string += (char) stream.read();
+            }
+            return new Reference(string);
+        }
+        return null;
+    }
+
+    /**
+     * Read a UnionCase from the stream
+     *
+     * @param stream
+     * @return
+     * @throws IOException
+     */
+    private UnionCase readNextUnionCase(StringReader stream) throws IOException {
+        stream.mark(2);
+        stream.read(); // '('
+        char next = (char) stream.read();
+        if (next == ')') {
+            stream.reset();
+            return null;
+        } else {
+            stream.reset();
+            stream.read(); // '('
+        }
+        List tags = new ArrayList();
+        Integer nextTag;
+        do {
+            nextTag = readNumber(stream);
+            if(nextTag != null) {
+                tags.add(nextTag);
+                stream.read(); // ',' or ')'
+            }
+        } while (nextTag != null);
+        stream.read(); // '['
+        stream.mark(1);
+        next = (char) stream.read();
+        if (next == ']') {
+            return new UnionCase(tags);
+        } else {
+            stream.reset();
+            return new UnionCase(tags,
+                    readBody(getStreamUpToMatchingBracket(stream)));
+        }
+    }
+
+    /**
+     * An AttributeLayoutElement is a part of an attribute layout and has one or
+     * more bands associated with it, which transmit the AttributeElement data
+     * for successive Attributes of this type.
+     */
+    private interface AttributeLayoutElement {
+
+        public void addAttributeToBand(NewAttribute attribute, InputStream stream);
+
+        public void pack(OutputStream out) throws IOException, Pack200Exception;
+
+        // TODO: bci renumbering
+
+    }
+
+    private abstract class LayoutElement implements AttributeLayoutElement {
+
+        protected int getLength(char uint_type) {
+            int length = 0;
+            switch (uint_type) {
+            case 'B':
+                length = 1;
+                break;
+            case 'H':
+                length = 2;
+                break;
+            case 'I':
+                length = 4;
+                break;
+            case 'V':
+                length = 0;
+                break;
+            }
+            return length;
+        }
+    }
+
+    private class Integral extends LayoutElement {
+
+        private final String tag;
+        private final IntList band = new IntList();
+        private final BHSDCodec defaultCodec;
+
+        public Integral(String tag) {
+            this.tag = tag;
+            this.defaultCodec = getCodec(tag);
+        }
+
+        public void addAttributeToBand(NewAttribute attribute,
+                InputStream stream) {
+            int value = 0;
+            if (tag.equals("B") || tag.equals("FB")) {
+                value = readInteger(1, stream) & 0xFF; // unsigned byte
+            } else if (tag.equals("SB")) {
+                value = readInteger(1, stream);
+            } else if (tag.equals("H") || tag.equals("FH")) {
+                value = readInteger(2, stream) & 0xFFFF; // unsigned short
+            } else if (tag.equals("SH")) {
+                value = readInteger(2, stream);
+            } else if (tag.equals("I") || tag.equals("FI")) {
+                value = readInteger(4, stream);
+            } else if (tag.equals("SI")) {
+                value = readInteger(4, stream);
+            } else if (tag.equals("V") || tag.equals("FV") || tag.equals("SV")) {
+                // TODO
+            } else if (tag.startsWith("PO") || tag.startsWith("OS")) {
+                // TODO: bci renumbering
+                char uint_type = tag.substring(2).toCharArray()[0];
+                int length = getLength(uint_type);
+                value = readInteger(length, stream);
+            } else if (tag.startsWith("P") || tag.startsWith("O")) {
+                char uint_type = tag.substring(1).toCharArray()[0];
+                int length = getLength(uint_type);
+                value = readInteger(length, stream);
+            }
+            band.add(value);
+        }
+
+        public void pack(OutputStream out) throws IOException, Pack200Exception {
+            out.write(encodeBandInt(tag, band.toArray(), defaultCodec));
+        }
+
+        public int latestValue() {
+            return band.get(band.size() - 1);
+        }
+
+    }
+
+    /**
+     * A replication is an array of layout elements, with an associated count
+     */
+    private class Replication extends LayoutElement {
+
+        private final Integral countElement;
+
+        private final List layoutElements = new ArrayList();
+
+        public Replication(String tag, String contents) throws IOException {
+            this.countElement = new Integral(tag);
+            StringReader stream = new StringReader(contents);
+            LayoutElement e;
+            while ((e = readNextLayoutElement(stream)) != null) {
+                layoutElements.add(e);
+            }
+        }
+
+        public void addAttributeToBand(NewAttribute attribute,
+                InputStream stream) {
+            countElement.addAttributeToBand(attribute, stream);
+            for (Iterator iterator = layoutElements.iterator(); iterator.hasNext();) {
+                AttributeLayoutElement layoutElement = (AttributeLayoutElement) iterator.next();
+                layoutElement.addAttributeToBand(attribute, stream);
+            }
+        }
+
+        public void pack(OutputStream out) throws IOException, Pack200Exception {
+            countElement.pack(out);
+            for (Iterator iterator = layoutElements.iterator(); iterator.hasNext();) {
+                AttributeLayoutElement layoutElement = (AttributeLayoutElement) iterator.next();
+                layoutElement.pack(out);
+            }
+        }
+    }
+
+    /**
+     * A Union is a type of layout element where the tag value acts as a
+     * selector for one of the union cases
+     */
+    private class Union extends LayoutElement {
+
+        private final Integral unionTag;
+        private final List unionCases;
+        private final List defaultCaseBody;
+
+        public Union(String tag, List unionCases, List body) {
+            this.unionTag = new Integral(tag);
+            this.unionCases = unionCases;
+            this.defaultCaseBody = body;
+        }
+
+        public void addAttributeToBand(NewAttribute attribute,
+                InputStream stream) {
+            unionTag.addAttributeToBand(attribute, stream);
+            long tag = unionTag.latestValue();
+            boolean defaultCase = true;
+            for (int i = 0; i < unionCases.size(); i++) {
+                UnionCase element = (UnionCase) unionCases.get(i);
+                if (element.hasTag(tag)) {
+                    defaultCase = false;
+                    element.addAttributeToBand(attribute, stream);
+                }
+            }
+            if (defaultCase) {
+                for (int i = 0; i < defaultCaseBody.size(); i++) {
+                    LayoutElement element = (LayoutElement) defaultCaseBody
+                            .get(i);
+                    element.addAttributeToBand(attribute, stream);
+                }
+            }
+        }
+
+        public void pack(OutputStream out) throws IOException, Pack200Exception {
+            unionTag.pack(out);
+            for (Iterator iterator = unionCases.iterator(); iterator.hasNext();) {
+                UnionCase unionCase = (UnionCase) iterator.next();
+                unionCase.pack(out);
+            }
+            for (Iterator iterator = defaultCaseBody.iterator(); iterator
+                    .hasNext();) {
+                AttributeLayoutElement layoutElement = (AttributeLayoutElement) iterator
+                        .next();
+                layoutElement.pack(out);
+            }
+        }
+    }
+
+    private class Call extends LayoutElement {
+
+        private final int callableIndex;
+        private Callable callable;
+
+        public Call(int callableIndex) {
+            this.callableIndex = callableIndex;
+        }
+
+        public void setCallable(Callable callable) {
+            this.callable = callable;
+            if (callableIndex < 1) {
+                callable.setBackwardsCallable();
+            }
+        }
+
+        public void addAttributeToBand(NewAttribute attribute,
+                InputStream stream) {
+            callable.addAttributeToBand(attribute, stream);
+            if(callableIndex < 1) {
+                callable.addBackwardsCall();
+            }
+        }
+
+        public void pack(OutputStream out) {
+            // do nothing here - as pack will be called on the callable at another time
+        }
+    }
+
+    /**
+     * Constant Pool Reference
+     */
+    private class Reference extends LayoutElement {
+
+        private final String tag;
+
+        private List band;
+
+        private final int length;
+
+        private boolean nullsAllowed = false;
+
+        public Reference(String tag) {
+            this.tag = tag;
+            length = getLength(tag.charAt(tag.length() - 1));
+            nullsAllowed = tag.indexOf('N') != -1;
+        }
+
+        public void addAttributeToBand(NewAttribute attribute,
+                InputStream stream) {
+            int index = readInteger(4, stream);
+            if(tag.startsWith("RC")) { // Class
+                band.add(cpBands.getCPClass(attribute.readClass(index)));
+            } else if (tag.startsWith("RU")) { // UTF8 String
+                band.add(cpBands.getCPUtf8(attribute.readUTF8(index)));
+            } else if (tag.startsWith("RS")) { // Signature
+                band.add(cpBands.getCPSignature(attribute.readUTF8(index)));
+            } else { // Constant
+                band.add(cpBands.getConstant(attribute.readConst(index)));
+            }
+            // TODO method and field references
+        }
+
+        public void pack(OutputStream out) throws IOException, Pack200Exception {
+            int[] ints;
+            if(nullsAllowed) {
+                ints = cpEntryOrNullListToArray(band);
+            } else {
+                ints = cpEntryListToArray(band);
+            }
+            out.write(encodeBandInt(tag, ints, Codec.UNSIGNED5));
+        }
+
+    }
+
+    private class Callable implements AttributeLayoutElement {
+
+        private final List body;
+
+        private boolean isBackwardsCallable;
+
+        private int backwardsCallableIndex;
+
+        public Callable(List body) throws IOException {
+            this.body = body;
+        }
+
+        public void setBackwardsCallableIndex(int backwardsCallableIndex) {
+            this.backwardsCallableIndex = backwardsCallableIndex;
+        }
+
+        public void addBackwardsCall() {
+            backwardsCallCounts[backwardsCallableIndex]++;
+        }
+
+        public boolean isBackwardsCallable() {
+            return isBackwardsCallable;
+        }
+
+        /**
+         * Tells this Callable that it is a backwards callable
+         */
+        public void setBackwardsCallable() {
+            this.isBackwardsCallable = true;
+        }
+
+        public void addAttributeToBand(NewAttribute attribute,
+                InputStream stream) {
+            for (Iterator iterator = body.iterator(); iterator.hasNext();) {
+                AttributeLayoutElement layoutElement = (AttributeLayoutElement) iterator.next();
+                layoutElement.addAttributeToBand(attribute, stream);
+            }
+        }
+
+        public void pack(OutputStream out) throws IOException, Pack200Exception {
+            for (Iterator iterator = body.iterator(); iterator.hasNext();) {
+                AttributeLayoutElement layoutElement = (AttributeLayoutElement) iterator.next();
+                layoutElement.pack(out);
+            }
+        }
+    }
+
+    /**
+     * A Union case
+     */
+    private class UnionCase extends LayoutElement {
+
+        private List body;
+
+        private final List tags;
+
+        public UnionCase(List tags) {
+            this.tags = tags;
+        }
+
+        public boolean hasTag(long l) {
+            return tags.contains(new Integer((int) l));
+        }
+
+        public UnionCase(List tags, List body) throws IOException {
+            this.tags = tags;
+            this.body = body;
+        }
+
+        public void addAttributeToBand(NewAttribute attribute,
+                InputStream stream) {
+            for (int i = 0; i < body.size(); i++) {
+                LayoutElement element = (LayoutElement) body.get(i);
+                element.addAttributeToBand(attribute, stream);
+            }
+        }
+
+        public void pack(OutputStream out) throws IOException, Pack200Exception {
+            for (int i = 0; i < body.size(); i++) {
+                LayoutElement element = (LayoutElement) body.get(i);
+                element.pack(out);
+            }
+        }
+    }
+
+    /**
+     * Utility method to get the contents of the given stream, up to the next
+     * ']', (ignoring pairs of brackets '[' and ']')
+     *
+     * @param stream
+     * @return
+     * @throws IOException
+     */
+    private StringReader getStreamUpToMatchingBracket(StringReader stream)
+            throws IOException {
+        StringBuffer sb = new StringBuffer();
+        int foundBracket = -1;
+        while (foundBracket != 0) {
+            char c = (char) stream.read();
+            if (c == ']') {
+                foundBracket++;
+            }
+            if (c == '[') {
+                foundBracket--;
+            }
+            if (!(foundBracket == 0)) {
+                sb.append(c);
+            }
+        }
+        return new StringReader(sb.toString());
+    }
+
+    private int readInteger(int i, InputStream stream) {
+        int result = 0;
+        for (int j = 0; j < i; j++) {
+            try {
+                result = result << 8 | stream.read();
+            } catch (IOException e) {
+                throw new RuntimeException("Error reading unknown attribute");
+            }
+        }
+        return result;
+    }
+
+    /**
+     * Returns the {@link BHSDCodec} that should be used for the given layout
+     * element
+     *
+     * @param layoutElement
+     */
+    private BHSDCodec getCodec(String layoutElement) {
+        if (layoutElement.indexOf('O') >= 0) {
+            return Codec.BRANCH5;
+        } else if (layoutElement.indexOf('P') >= 0) {
+            return Codec.BCI5;
+        } else if (layoutElement.indexOf('S') >= 0 && layoutElement.indexOf("KS") < 0 //$NON-NLS-1$
+                && layoutElement.indexOf("RS") < 0) { //$NON-NLS-1$
+            return Codec.SIGNED5;
+        } else if (layoutElement.indexOf('B') >= 0) {
+            return Codec.BYTE1;
+        } else {
+            return Codec.UNSIGNED5;
+        }
+    }
+
+    /**
+     * Utility method to get the contents of the given stream, up to the next
+     * ']', (ignoring pairs of brackets '[' and ']')
+     *
+     * @param stream
+     * @return
+     * @throws IOException
+     */
+    private String readUpToMatchingBracket(StringReader stream)
+            throws IOException {
+        StringBuffer sb = new StringBuffer();
+        int foundBracket = -1;
+        while (foundBracket != 0) {
+            char c = (char) stream.read();
+            if (c == ']') {
+                foundBracket++;
+            }
+            if (c == '[') {
+                foundBracket--;
+            }
+            if (!(foundBracket == 0)) {
+                sb.append(c);
+            }
+        }
+        return sb.toString();
+    }
+
+    /**
+     * Read a number from the stream and return it
+     *
+     * @param stream
+     * @return
+     * @throws IOException
+     */
+    private Integer readNumber(StringReader stream) throws IOException {
+        stream.mark(1);
+        char first = (char) stream.read();
+        boolean negative = first == '-';
+        if (!negative) {
+            stream.reset();
+        }
+        stream.mark(100);
+        int i;
+        int length = 0;
+        while ((i = (stream.read())) != -1 && Character.isDigit((char) i)) {
+            length++;
+        }
+        stream.reset();
+        if(length == 0) {
+            return null;
+        }
+        char[] digits = new char[length];
+        int read = stream.read(digits);
+        if (read != digits.length) {
+            throw new IOException("Error reading from the input stream");
+        }
+        return new Integer(Integer.parseInt((negative ? "-" : "") + new String(digits)));
+    }
+
+    /**
+     * Read a 'body' section of the layout from the given stream
+     *
+     * @param stream
+     * @return List of LayoutElements
+     * @throws IOException
+     */
+    private List readBody(StringReader stream) throws IOException {
+        List layoutElements = new ArrayList();
+        LayoutElement e;
+        while ((e = readNextLayoutElement(stream)) != null) {
+            layoutElements.add(e);
+        }
+        return layoutElements;
+    }
+
+}

Propchange: harmony/enhanced/classlib/trunk/modules/pack200/src/main/java/org/apache/harmony/pack200/NewAttributeBands.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: harmony/enhanced/classlib/trunk/modules/pack200/src/main/java/org/apache/harmony/pack200/NewAttributeBands.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Modified: harmony/enhanced/classlib/trunk/modules/pack200/src/main/java/org/apache/harmony/pack200/Pack200ClassReader.java
URL: http://svn.apache.org/viewvc/harmony/enhanced/classlib/trunk/modules/pack200/src/main/java/org/apache/harmony/pack200/Pack200ClassReader.java?rev=784048&r1=784047&r2=784048&view=diff
==============================================================================
--- harmony/enhanced/classlib/trunk/modules/pack200/src/main/java/org/apache/harmony/pack200/Pack200ClassReader.java (original)
+++ harmony/enhanced/classlib/trunk/modules/pack200/src/main/java/org/apache/harmony/pack200/Pack200ClassReader.java Fri Jun 12 09:32:53 2009
@@ -22,7 +22,7 @@
 import org.objectweb.asm.ClassReader;
 
 /**
- * Wrapper for ClassReader than enables pack200 to obtain extra class file
+ * Wrapper for ClassReader that enables pack200 to obtain extra class file
  * information
  */
 public class Pack200ClassReader extends ClassReader {
@@ -30,6 +30,7 @@
     private boolean lastConstantHadWideIndex;
     private int lastUnsignedShort;
     private boolean anySyntheticAttributes;
+    private String fileName;
 
     /**
      * @param b
@@ -96,4 +97,12 @@
         return anySyntheticAttributes;
     }
 
+    public void setFileName(String name) {
+        this.fileName = name;
+    }
+
+    public String getFileName() {
+        return fileName;
+    }
+
 }