You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@harmony.apache.org by te...@apache.org on 2008/01/04 12:14:27 UTC

svn commit: r608801 - in /harmony/enhanced/classlib/trunk/modules/pack200/src: main/java/org/apache/harmony/pack200/ main/java/org/apache/harmony/pack200/bytecode/ test/java/org/apache/harmony/pack200/tests/

Author: tellison
Date: Fri Jan  4 03:14:19 2008
New Revision: 608801

URL: http://svn.apache.org/viewvc?rev=608801&view=rev
Log:
Apply patch HARMONY-5370 ([classlib] [pack200] Support for compressor-defined class file attributes)

Added:
    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/bytecode/NewAttribute.java   (with props)
Modified:
    harmony/enhanced/classlib/trunk/modules/pack200/src/main/java/org/apache/harmony/pack200/AttrDefinitionBands.java
    harmony/enhanced/classlib/trunk/modules/pack200/src/main/java/org/apache/harmony/pack200/AttributeLayout.java
    harmony/enhanced/classlib/trunk/modules/pack200/src/main/java/org/apache/harmony/pack200/AttributeLayoutMap.java
    harmony/enhanced/classlib/trunk/modules/pack200/src/main/java/org/apache/harmony/pack200/BandSet.java
    harmony/enhanced/classlib/trunk/modules/pack200/src/main/java/org/apache/harmony/pack200/BcBands.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/CpBands.java
    harmony/enhanced/classlib/trunk/modules/pack200/src/main/java/org/apache/harmony/pack200/FileBands.java
    harmony/enhanced/classlib/trunk/modules/pack200/src/main/java/org/apache/harmony/pack200/IcBands.java
    harmony/enhanced/classlib/trunk/modules/pack200/src/main/java/org/apache/harmony/pack200/bytecode/EnclosingMethodAttribute.java
    harmony/enhanced/classlib/trunk/modules/pack200/src/test/java/org/apache/harmony/pack200/tests/BandSetTest.java

Modified: harmony/enhanced/classlib/trunk/modules/pack200/src/main/java/org/apache/harmony/pack200/AttrDefinitionBands.java
URL: http://svn.apache.org/viewvc/harmony/enhanced/classlib/trunk/modules/pack200/src/main/java/org/apache/harmony/pack200/AttrDefinitionBands.java?rev=608801&r1=608800&r2=608801&view=diff
==============================================================================
--- harmony/enhanced/classlib/trunk/modules/pack200/src/main/java/org/apache/harmony/pack200/AttrDefinitionBands.java (original)
+++ harmony/enhanced/classlib/trunk/modules/pack200/src/main/java/org/apache/harmony/pack200/AttrDefinitionBands.java Fri Jan  4 03:14:19 2008
@@ -18,7 +18,6 @@
 
 import java.io.IOException;
 import java.io.InputStream;
-import java.io.OutputStream;
 
 /**
  *
@@ -41,14 +40,6 @@
     }
 
     /* (non-Javadoc)
-     * @see org.apache.harmony.pack200.BandSet#pack(java.io.OutputStream)
-     */
-    public void pack(OutputStream outputStream) {
-        // TODO Auto-generated method stub
-
-    }
-
-    /* (non-Javadoc)
      * @see org.apache.harmony.pack200.BandSet#unpack(java.io.InputStream)
      */
     public void unpack(InputStream in) throws IOException,
@@ -73,9 +64,11 @@
             if(index == -1) {
                 index = overflowIndex++;
             }
-            attributeDefinitionMap.add(new AttributeLayout(
+            AttributeLayout layout = new AttributeLayout(
                     attributeDefinitionName[i], context,
-                    attributeDefinitionLayout[i], index));
+                    attributeDefinitionLayout[i], index, false);
+            NewAttributeBands newBands = new NewAttributeBands(segment, layout);
+            attributeDefinitionMap.add(layout, newBands);
         }
         attributeDefinitionMap.checkMap();
     }

Modified: harmony/enhanced/classlib/trunk/modules/pack200/src/main/java/org/apache/harmony/pack200/AttributeLayout.java
URL: http://svn.apache.org/viewvc/harmony/enhanced/classlib/trunk/modules/pack200/src/main/java/org/apache/harmony/pack200/AttributeLayout.java?rev=608801&r1=608800&r2=608801&view=diff
==============================================================================
--- harmony/enhanced/classlib/trunk/modules/pack200/src/main/java/org/apache/harmony/pack200/AttributeLayout.java (original)
+++ harmony/enhanced/classlib/trunk/modules/pack200/src/main/java/org/apache/harmony/pack200/AttributeLayout.java Fri Jan  4 03:14:19 2008
@@ -98,28 +98,46 @@
 	private long mask;
     
     private String name;
+    private boolean isDefault;
+    private int backwardsCallCount;
+    
 
+    /**
+     * Construct a default AttributeLayout
+     *  (equivalent to <code>new AttributeLayout(name, context, layout, index, true);</code>)
+     * @param name
+     * @param context
+     * @param layout
+     * @param index
+     * @throws Pack200Exception
+     */
 	public AttributeLayout(String name, int context, String layout, int index)
 			throws Pack200Exception {
-		super();
+		this(name, context, layout, index, true);
+	}
+    
+    public AttributeLayout(String name, int context, String layout, int index,
+            boolean isDefault) throws Pack200Exception {
+        super();
         this.index = index;
         this.context = context;
-		if (index >= 0) {
-			this.mask = 1L << index;
-		} else {
-			this.mask = 0;
-		}
+        if (index >= 0) {
+            this.mask = 1L << index;
+        } else {
+            this.mask = 0;
+        }
         if (context != CONTEXT_CLASS && context != CONTEXT_CODE
                 && context != CONTEXT_FIELD && context != CONTEXT_METHOD)
             throw new Pack200Exception("Attribute context out of range: "
                     + context);
-		if (layout == null) // || layout.length() == 0)
-			throw new Pack200Exception("Cannot have a null layout");
+        if (layout == null) // || layout.length() == 0)
+            throw new Pack200Exception("Cannot have a null layout");
         if (name == null || name.length() == 0)
-                throw new Pack200Exception("Cannot have an unnamed layout");
+            throw new Pack200Exception("Cannot have an unnamed layout");
         this.name = name;
-		this.layout = layout;
-	}
+        this.layout = layout;
+        this.isDefault = isDefault;
+    }
     
     
 	public boolean equals(Object obj) {
@@ -243,18 +261,19 @@
     
     public int numBackwardsCallables() {
         if(layout == "*") {
-            return 1; // TODO: complicated attributes (shouldn't be *'s at all...)
-        }
-        int num = 0;
-        String[] split = layout.split("\\(");
-        if(split.length > 0) {
-            for (int i = 1; i < split.length; i++) {
-                if(split[i].startsWith("-") || split[i].startsWith("0")) {
-                    num++;
-                }
-            }
+            return 1;
+        } else {
+            return backwardsCallCount;
         }
-        return num;
+    }
+
+
+    public boolean isDefaultLayout() {
+        return isDefault;
+    }
+
+    public void setBackwardsCallCount(int backwardsCallCount) {
+        this.backwardsCallCount = backwardsCallCount;
     }
 
 }

Modified: harmony/enhanced/classlib/trunk/modules/pack200/src/main/java/org/apache/harmony/pack200/AttributeLayoutMap.java
URL: http://svn.apache.org/viewvc/harmony/enhanced/classlib/trunk/modules/pack200/src/main/java/org/apache/harmony/pack200/AttributeLayoutMap.java?rev=608801&r1=608800&r2=608801&view=diff
==============================================================================
--- harmony/enhanced/classlib/trunk/modules/pack200/src/main/java/org/apache/harmony/pack200/AttributeLayoutMap.java (original)
+++ harmony/enhanced/classlib/trunk/modules/pack200/src/main/java/org/apache/harmony/pack200/AttributeLayoutMap.java Fri Jan  4 03:14:19 2008
@@ -198,6 +198,8 @@
     // the value of their context constants (AttributeLayout.CONTEXT_CLASS etc.)
     private final Map[] layouts = new Map[] {classLayouts, fieldLayouts, methodLayouts, codeLayouts};
 
+    private final Map layoutsToBands = new HashMap();
+    
 	public AttributeLayoutMap() throws Pack200Exception {
 		AttributeLayout[] defaultAttributeLayouts = getDefaultAttributeLayouts();
 		for (int i = 0; i < defaultAttributeLayouts.length; i++) {
@@ -208,6 +210,13 @@
 	public void add(AttributeLayout layout) {
         layouts[layout.getContext()].put(new Integer(layout.getIndex()), layout);
 	}
+    
+
+
+    public void add(AttributeLayout layout, NewAttributeBands newBands) {
+        add(layout);
+        layoutsToBands.put(layout, newBands);
+    }
 
 	public AttributeLayout getAttributeLayout(String name, int context)
 			throws Pack200Exception {
@@ -257,6 +266,10 @@
                 }
             }
         }
+    }
+
+    public NewAttributeBands getAttributeBands(AttributeLayout layout) {
+        return (NewAttributeBands) layoutsToBands.get(layout);
     }
     
 }

Modified: harmony/enhanced/classlib/trunk/modules/pack200/src/main/java/org/apache/harmony/pack200/BandSet.java
URL: http://svn.apache.org/viewvc/harmony/enhanced/classlib/trunk/modules/pack200/src/main/java/org/apache/harmony/pack200/BandSet.java?rev=608801&r1=608800&r2=608801&view=diff
==============================================================================
--- harmony/enhanced/classlib/trunk/modules/pack200/src/main/java/org/apache/harmony/pack200/BandSet.java (original)
+++ harmony/enhanced/classlib/trunk/modules/pack200/src/main/java/org/apache/harmony/pack200/BandSet.java Fri Jan  4 03:14:19 2008
@@ -19,12 +19,17 @@
 import java.io.ByteArrayOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
-import java.io.OutputStream;
 
+import org.apache.harmony.pack200.bytecode.CPClass;
 import org.apache.harmony.pack200.bytecode.CPDouble;
+import org.apache.harmony.pack200.bytecode.CPFieldRef;
 import org.apache.harmony.pack200.bytecode.CPFloat;
 import org.apache.harmony.pack200.bytecode.CPInteger;
+import org.apache.harmony.pack200.bytecode.CPInterfaceMethodRef;
 import org.apache.harmony.pack200.bytecode.CPLong;
+import org.apache.harmony.pack200.bytecode.CPMethodRef;
+import org.apache.harmony.pack200.bytecode.CPNameAndType;
+import org.apache.harmony.pack200.bytecode.CPString;
 import org.apache.harmony.pack200.bytecode.CPUTF8;
 import org.apache.harmony.pack200.bytecode.ClassConstantPool;
 
@@ -32,8 +37,6 @@
     
     public abstract void unpack(InputStream inputStream) throws IOException, Pack200Exception;
     
-    public abstract void pack(OutputStream outputStream);
-    
     protected Segment segment;
     
     protected SegmentHeader header;
@@ -482,6 +485,107 @@
             result[i] = new CPUTF8[num];
             System.arraycopy(refs, pos, result[i], 0, num);
             pos += num;
+        }
+        return result;
+    }
+
+    public CPString[] parseCPStringReferences(String name, InputStream in, BHSDCodec codec, int count) throws IOException, Pack200Exception {
+        String[] reference = segment.getCpBands().getCpString();        
+        int[] indices = decodeBandInt(name, in, codec, count, reference.length - 1);
+        CPString[] result = new CPString[indices.length];
+        for (int i1 = 0; i1 < count; i1++) {
+            int index = indices[i1];
+            if (index < 0 || index >= reference.length)
+                throw new Pack200Exception(
+                        "Something has gone wrong during parsing references, index = " + index + ", array size = " + reference.length);
+            result[i1] = new CPString(reference[index]);
+        }
+        return result;
+    }
+
+    public CPInterfaceMethodRef[] parseCPInterfaceMethodRefReferences(String name, InputStream in, BHSDCodec codec, int count) throws IOException, Pack200Exception {
+        String[] reference = segment.getCpBands().getCpIMethodClass();
+        String[] descriptors = segment.getCpBands().getCpIMethodDescriptor();
+        int[] indices = decodeBandInt(name, in, codec, count, reference.length - 1);
+        CPInterfaceMethodRef[] result = new CPInterfaceMethodRef[indices.length];
+        for (int i1 = 0; i1 < count; i1++) {
+            int index = indices[i1];
+            if (index < 0 || index >= reference.length)
+                throw new Pack200Exception(
+                        "Something has gone wrong during parsing references, index = " + index + ", array size = " + reference.length);
+            result[i1] = new CPInterfaceMethodRef(reference[index], descriptors[index]);
+        }
+        return result;
+    }
+
+    public CPMethodRef[] parseCPMethodRefReferences(String name, InputStream in, BHSDCodec codec, int count) throws IOException, Pack200Exception {
+        String[] reference = segment.getCpBands().getCpMethodClass();        
+        String[] descriptors = segment.getCpBands().getCpMethodDescriptor();
+        int[] indices = decodeBandInt(name, in, codec, count, reference.length - 1);
+        CPMethodRef[] result = new CPMethodRef[indices.length];
+        for (int i1 = 0; i1 < count; i1++) {
+            int index = indices[i1];
+            if (index < 0 || index >= reference.length)
+                throw new Pack200Exception(
+                        "Something has gone wrong during parsing references, index = " + index + ", array size = " + reference.length);
+            result[i1] = new CPMethodRef(reference[index], descriptors[index]);
+        }
+        return result;
+    }
+
+    public CPFieldRef[] parseCPFieldRefReferences(String name, InputStream in, BHSDCodec codec, int count) throws IOException, Pack200Exception {
+        String[] reference = segment.getCpBands().getCpFieldClass();        
+        String[] descriptors = segment.getCpBands().getCpFieldDescriptor();
+        int[] indices = decodeBandInt(name, in, codec, count, reference.length - 1);
+        CPFieldRef[] result = new CPFieldRef[indices.length];
+        for (int i1 = 0; i1 < count; i1++) {
+            int index = indices[i1];
+            if (index < 0 || index >= reference.length)
+                throw new Pack200Exception(
+                        "Something has gone wrong during parsing references, index = " + index + ", array size = " + reference.length);
+            result[i1] = new CPFieldRef(reference[index], descriptors[index]);
+        }
+        return result;
+    }
+
+    public CPNameAndType[] parseCPDescriptorReferences(String name, InputStream in, BHSDCodec codec, int count) throws IOException, Pack200Exception {
+        String[] reference = segment.getCpBands().getCpDescriptor();        
+        int[] indices = decodeBandInt(name, in, codec, count, reference.length - 1);
+        CPNameAndType[] result = new CPNameAndType[indices.length];
+        for (int i1 = 0; i1 < count; i1++) {
+            int index = indices[i1];
+            if (index < 0 || index >= reference.length)
+                throw new Pack200Exception(
+                        "Something has gone wrong during parsing references, index = " + index + ", array size = " + reference.length);
+            result[i1] = new CPNameAndType(reference[index]);
+        }
+        return result;
+    }
+
+    public CPUTF8[] parseCPSignatureReferences(String name, InputStream in, BHSDCodec codec, int count) throws IOException, Pack200Exception {
+        String[] reference = segment.getCpBands().getCpSignature();        
+        int[] indices = decodeBandInt(name, in, codec, count, reference.length - 1);
+        CPUTF8[] result = new CPUTF8[indices.length];
+        for (int i1 = 0; i1 < count; i1++) {
+            int index = indices[i1];
+            if (index < 0 || index >= reference.length)
+                throw new Pack200Exception(
+                        "Something has gone wrong during parsing references, index = " + index + ", array size = " + reference.length);
+            result[i1] = new CPUTF8(reference[index], ClassConstantPool.DOMAIN_UNDEFINED);
+        }
+        return result;
+    }
+
+    public CPClass[] parseCPClassReferences(String name, InputStream in, BHSDCodec codec, int count) throws IOException, Pack200Exception {
+        String[] reference = segment.getCpBands().getCpClass();        
+        int[] indices = decodeBandInt(name, in, codec, count, reference.length - 1);
+        CPClass[] result = new CPClass[indices.length];
+        for (int i1 = 0; i1 < count; i1++) {
+            int index = indices[i1];
+            if (index < 0 || index >= reference.length)
+                throw new Pack200Exception(
+                        "Something has gone wrong during parsing references, index = " + index + ", array size = " + reference.length);
+            result[i1] = new CPClass(reference[index]);
         }
         return result;
     }

Modified: harmony/enhanced/classlib/trunk/modules/pack200/src/main/java/org/apache/harmony/pack200/BcBands.java
URL: http://svn.apache.org/viewvc/harmony/enhanced/classlib/trunk/modules/pack200/src/main/java/org/apache/harmony/pack200/BcBands.java?rev=608801&r1=608800&r2=608801&view=diff
==============================================================================
--- harmony/enhanced/classlib/trunk/modules/pack200/src/main/java/org/apache/harmony/pack200/BcBands.java (original)
+++ harmony/enhanced/classlib/trunk/modules/pack200/src/main/java/org/apache/harmony/pack200/BcBands.java Fri Jan  4 03:14:19 2008
@@ -19,7 +19,6 @@
 import java.io.ByteArrayOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
-import java.io.OutputStream;
 import java.util.ArrayList;
 import java.util.List;
 
@@ -27,7 +26,6 @@
 import org.apache.harmony.pack200.bytecode.BCIRenumberedAttribute;
 import org.apache.harmony.pack200.bytecode.ByteCode;
 import org.apache.harmony.pack200.bytecode.CodeAttribute;
-import org.apache.harmony.pack200.bytecode.LineNumberTableAttribute;
 import org.apache.harmony.pack200.bytecode.OperandManager;
 
 /**
@@ -70,14 +68,6 @@
      */
     public BcBands(Segment segment) {
         super(segment);
-    }
-
-    /* (non-Javadoc)
-     * @see org.apache.harmony.pack200.BandSet#pack(java.io.OutputStream)
-     */
-    public void pack(OutputStream outputStream) {
-        // TODO Auto-generated method stub
-
     }
 
     /* (non-Javadoc)

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=608801&r1=608800&r2=608801&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 Jan  4 03:14:19 2008
@@ -18,16 +18,18 @@
 
 import java.io.IOException;
 import java.io.InputStream;
-import java.io.OutputStream;
 import java.util.ArrayList;
 import java.util.Iterator;
+import java.util.List;
 
 import org.apache.harmony.pack200.IcBands.ICTuple;
 import org.apache.harmony.pack200.bytecode.Attribute;
 import org.apache.harmony.pack200.bytecode.CPClass;
+import org.apache.harmony.pack200.bytecode.CPNameAndType;
 import org.apache.harmony.pack200.bytecode.CPUTF8;
 import org.apache.harmony.pack200.bytecode.ClassConstantPool;
 import org.apache.harmony.pack200.bytecode.ConstantValueAttribute;
+import org.apache.harmony.pack200.bytecode.EnclosingMethodAttribute;
 import org.apache.harmony.pack200.bytecode.ExceptionsAttribute;
 import org.apache.harmony.pack200.bytecode.LineNumberTableAttribute;
 import org.apache.harmony.pack200.bytecode.LocalVariableTableAttribute;
@@ -36,7 +38,7 @@
 import org.apache.harmony.pack200.bytecode.SourceFileAttribute;
 
 /**
- * 
+ * Pack200 Class Bands
  */
 public class ClassBands extends BandSet {
 
@@ -106,16 +108,6 @@
     /*
      * (non-Javadoc)
      * 
-     * @see org.apache.harmony.pack200.BandSet#pack(java.io.OutputStream)
-     */
-    public void pack(OutputStream outputStream) {
-        // TODO Auto-generated method stub
-
-    }
-
-    /*
-     * (non-Javadoc)
-     * 
      * @see org.apache.harmony.pack200.BandSet#unpack(java.io.InputStream)
      */
     public void unpack(InputStream in) throws IOException, Pack200Exception {
@@ -143,6 +135,10 @@
             Pack200Exception {
         fieldDescr = parseReferences("field_descr", in, Codec.DELTA5,
                 classFieldCount, cpBands.getCpDescriptor());
+        parseFieldAttrBands(in);
+    }
+
+    private void parseFieldAttrBands(InputStream in) throws IOException, Pack200Exception {
         fieldFlags = parseFlags("field_flags", in, classFieldCount,
                 Codec.UNSIGNED5, options.hasFieldFlagsHi());
         int fieldAttrCount = SegmentUtils.countBit16(fieldFlags);
@@ -154,6 +150,15 @@
                 AttributeLayout.CONTEXT_FIELD);
         int[] fieldAttrCalls = decodeBandInt("field_attr_calls", in,
                 Codec.UNSIGNED5, callCount);
+        
+        // Assign empty field attributes
+        fieldAttributes = new ArrayList[classCount][];
+        for (int i = 0; i < classCount; i++) {
+            fieldAttributes[i] = new ArrayList[fieldFlags[i].length];
+            for (int j = 0; j < fieldFlags[i].length; j++) {
+                fieldAttributes[i][j] = new ArrayList();
+            }
+        }
 
         AttributeLayout constantValueLayout = attrMap.getAttributeLayout(
                 "ConstantValue", AttributeLayout.CONTEXT_FIELD);
@@ -172,11 +177,38 @@
                 Codec.UNSIGNED5, signatureCount);
         int signatureIndex = 0;
 
-        fieldAttributes = new ArrayList[classCount][];
+        int backwardsCallsUsed = parseFieldMetadataBands(in, fieldAttrCalls);
+        
+        // Parse non-predefined attribute bands
+        int backwardsCallIndex = backwardsCallsUsed;
+        int limit = options.hasFieldFlagsHi() ? 62 : 31;
+        AttributeLayout[] otherLayouts = new AttributeLayout[limit + 1];
+        int[] counts = new int[limit + 1];
+        List[] otherAttributes = new List[limit + 1];
+        for (int i = 0; i < limit; i++) {
+            AttributeLayout layout = attrMap.getAttributeLayout(i, AttributeLayout.CONTEXT_FIELD);
+            if(layout != null && !(layout.isDefaultLayout())) {
+                otherLayouts[i] = layout;
+                counts[i] = SegmentUtils.countMatches(fieldFlags,
+                        layout);
+            }
+        }
+        for (int i = 0; i < counts.length; i++) {
+            if(counts[i] > 0) {
+                NewAttributeBands bands = attrMap.getAttributeBands(otherLayouts[i]);                
+                otherAttributes[i] = bands.parseAttributes(in, counts[i]);
+                int numBackwardsCallables = otherLayouts[i].numBackwardsCallables();
+                if(numBackwardsCallables > 0) {
+                    int[] backwardsCalls = new int[numBackwardsCallables];
+                    System.arraycopy(fieldAttrCalls, backwardsCallIndex, backwardsCalls, 0, numBackwardsCallables);
+                    bands.setBackwardsCalls(backwardsCalls);
+                    backwardsCallIndex+= numBackwardsCallables;
+                }
+            }
+        }
+
         for (int i = 0; i < classCount; i++) {
-            fieldAttributes[i] = new ArrayList[fieldFlags[i].length];
             for (int j = 0; j < fieldFlags[i].length; j++) {
-                fieldAttributes[i][j] = new ArrayList();
                 long flag = fieldFlags[i][j];
                 if (constantValueLayout.matches(flag)) {
                     // we've got a value to read
@@ -205,20 +237,28 @@
                             .add(new SignatureAttribute(value));
                     signatureIndex++;
                 }
+                // Non-predefined attributes
+                for (int k = 0; k < otherLayouts.length; k++) {
+                    if(otherLayouts[k] != null && otherLayouts[k].matches(flag)) {
+                        // Add the next attribute
+                        fieldAttributes[i][j].add(otherAttributes[k].get(0));
+                        otherAttributes[k].remove(0);
+                    }
+                }
             }
         }
-        parseFieldMetadataBands(in, fieldAttrCalls);
-
-        // TODO: Parse other attribute bands
     }
 
     private void parseMethodBands(InputStream in) throws IOException,
             Pack200Exception {
         methodDescr = parseReferences("method_descr", in, Codec.MDELTA5,
-                classMethodCount, cpBands.getCpDescriptor());
+                classMethodCount, cpBands.getCpDescriptor());        
+        parseMethodAttrBands(in);
+    }
+
+    private void parseMethodAttrBands(InputStream in) throws IOException, Pack200Exception {
         methodFlags = parseFlags("method_flags", in, classMethodCount,
                 Codec.UNSIGNED5, options.hasMethodFlagsHi());
-
         int methodAttrCount = SegmentUtils.countBit16(methodFlags);
         int[] methodAttrCounts = decodeBandInt("method_attr_count", in,
                 Codec.UNSIGNED5, methodAttrCount);
@@ -228,7 +268,7 @@
                 AttributeLayout.CONTEXT_METHOD);
         methodAttrCalls = decodeBandInt("code_attr_calls", in, Codec.UNSIGNED5,
                 callCount);
-
+        
         // assign empty method attributes
         methodAttributes = new ArrayList[classCount][];
         for (int i = 0; i < classCount; i++) {
@@ -237,11 +277,98 @@
                 methodAttributes[i][j] = new ArrayList();
             }
         }
-        parseAttributeMethodExceptions(in);
-        parseAttributeMethodSigntaure(in);
-        parseMethodMetadataBands(in, methodAttrCalls);
 
-        // TODO: Parse other attribute bands
+        // Parse method exceptions attributes
+        AttributeLayout methodExceptionsLayout = attrMap.getAttributeLayout(AttributeLayout.ATTRIBUTE_EXCEPTIONS,
+                AttributeLayout.CONTEXT_METHOD);
+        int count = SegmentUtils.countMatches(methodFlags, methodExceptionsLayout);
+        int[] numExceptions = decodeBandInt("method_Exceptions_n", in,
+                Codec.UNSIGNED5, count);
+        String[][] methodExceptionsRS = parseReferences("method_Exceptions_RC",
+                in, Codec.UNSIGNED5, numExceptions, cpBands.getCpClass());
+        
+        // Parse method signature attributes
+        AttributeLayout methodSignatureLayout = attrMap.getAttributeLayout(
+                AttributeLayout.ATTRIBUTE_SIGNATURE,
+                AttributeLayout.CONTEXT_METHOD);
+        int count1 = SegmentUtils.countMatches(methodFlags, methodSignatureLayout);
+        long[] methodSignatureRS = decodeBandLong("method_signature_RS", in,
+                Codec.UNSIGNED5, count1);
+        
+        // Parse method metadata bands
+        int backwardsCallsUsed = parseMethodMetadataBands(in, methodAttrCalls);        
+        
+        // Parse non-predefined attribute bands
+        int backwardsCallIndex = backwardsCallsUsed;
+        int limit = options.hasMethodFlagsHi() ? 62 : 31;
+        AttributeLayout[] otherLayouts = new AttributeLayout[limit + 1];
+        int[] counts = new int[limit + 1];
+        List[] otherAttributes = new List[limit + 1];
+        for (int i = 0; i < limit; i++) {
+            AttributeLayout layout = attrMap.getAttributeLayout(i, AttributeLayout.CONTEXT_METHOD);
+            if(layout != null && !(layout.isDefaultLayout())) {
+                otherLayouts[i] = layout;
+                counts[i] = SegmentUtils.countMatches(methodFlags,
+                        layout);
+            }
+        }
+        for (int i = 0; i < counts.length; i++) {
+            if(counts[i] > 0) {
+                NewAttributeBands bands = attrMap.getAttributeBands(otherLayouts[i]);                
+                otherAttributes[i] = bands.parseAttributes(in, counts[i]);
+                int numBackwardsCallables = otherLayouts[i].numBackwardsCallables();
+                if(numBackwardsCallables > 0) {
+                    int[] backwardsCalls = new int[numBackwardsCallables];
+                    System.arraycopy(methodAttrCalls, backwardsCallIndex, backwardsCalls, 0, numBackwardsCallables);
+                    bands.setBackwardsCalls(backwardsCalls);
+                    backwardsCallIndex+= numBackwardsCallables;
+                }
+            }
+        }
+
+        // Add attributes to the attribute arrays
+        int methodExceptionsIndex = 0;
+        int methodSignatureIndex = 0;
+        for (int i = 0; i < methodAttributes.length; i++) {
+            for (int j = 0; j < methodAttributes[i].length; j++) {
+                long flag = methodFlags[i][j];
+                if (methodExceptionsLayout.matches(flag)) {
+                    int n = numExceptions[methodExceptionsIndex];
+                    String[] exceptions = methodExceptionsRS[methodExceptionsIndex];
+                    CPClass[] exceptionClasses = new CPClass[n];
+                    for (int k = 0; k < n; k++) {
+                        exceptionClasses[k] = new CPClass(exceptions[k]);
+                    }
+                    methodAttributes[i][j].add(new ExceptionsAttribute(
+                            exceptionClasses));
+                    methodExceptionsIndex++;
+                }
+                if (methodSignatureLayout.matches(flag)) {
+                    // We've got a signature attribute
+                    long result = methodSignatureRS[methodSignatureIndex];
+                    String desc = methodDescr[i][j];
+                    int colon = desc.indexOf(':');
+                    String type = desc.substring(colon + 1);
+                    // TODO Got to get better at this ... in any case, it should
+                    // be e.g. KIB or KIH
+                    if (type.equals("B") || type.equals("H"))
+                        type = "I";
+                    Object value = methodSignatureLayout.getValue(result, type, cpBands
+                            .getConstantPool());
+                    methodAttributes[i][j]
+                            .add(new ConstantValueAttribute(value));
+                    methodSignatureIndex++;
+                }
+                // Non-predefined attributes
+                for (int k = 0; k < otherLayouts.length; k++) {
+                    if(otherLayouts[k] != null && otherLayouts[k].matches(flag)) {
+                        // Add the next attribute
+                        methodAttributes[i][j].add(otherAttributes[k].get(0));
+                        otherAttributes[k].remove(0);
+                    }
+                }
+            }
+        }
     }
 
     private int getCallCount(int[][] methodAttrIndexes, long[][] flags,
@@ -270,71 +397,6 @@
         return callCount;
     }
 
-    private void parseAttributeMethodSigntaure(InputStream in)
-            throws IOException, Pack200Exception {
-        AttributeLayout layout = attrMap.getAttributeLayout(
-                AttributeLayout.ATTRIBUTE_SIGNATURE,
-                AttributeLayout.CONTEXT_METHOD);
-        int count = SegmentUtils.countMatches(methodFlags, layout);
-        long[] methodSignatureRS = decodeBandLong("method_signature_RS", in,
-                Codec.UNSIGNED5, count);
-        int index = 0;
-        for (int i = 0; i < methodAttributes.length; i++) {
-            for (int j = 0; j < methodAttributes[i].length; j++) {
-                long flag = methodFlags[i][j];
-                if (layout.matches(flag)) {
-                    // we've got a signature attribute
-                    long result = methodSignatureRS[index];
-                    String desc = methodDescr[i][j];
-                    int colon = desc.indexOf(':');
-                    String type = desc.substring(colon + 1);
-                    // TODO Got to get better at this ... in any case, it should
-                    // be e.g. KIB or KIH
-                    if (type.equals("B") || type.equals("H"))
-                        type = "I";
-                    Object value = layout.getValue(result, type, cpBands
-                            .getConstantPool());
-                    methodAttributes[i][j]
-                            .add(new ConstantValueAttribute(value));
-                    index++;
-                }
-            }
-        }
-    }
-
-    /**
-     * @param in
-     * @throws Pack200Exception
-     * @throws IOException
-     */
-    private void parseAttributeMethodExceptions(InputStream in)
-            throws Pack200Exception, IOException {
-        AttributeLayout layout = attrMap.getAttributeLayout("Exceptions",
-                AttributeLayout.CONTEXT_METHOD);
-        int count = SegmentUtils.countMatches(methodFlags, layout);
-        int[] numExceptions = decodeBandInt("method_Exceptions_n", in,
-                Codec.UNSIGNED5, count);
-        String[][] methodExceptionsRS = parseReferences("method_Exceptions_RC",
-                in, Codec.UNSIGNED5, numExceptions, cpBands.getCpClass());
-        int index = 0;
-        for (int i = 0; i < classCount; i++) {
-            for (int j = 0; j < methodFlags[i].length; j++) {
-                long flag = methodFlags[i][j];
-                if (layout.matches(flag)) {
-                    int n = numExceptions[index];
-                    String[] exceptions = methodExceptionsRS[index];
-                    CPClass[] exceptionClasses = new CPClass[n];
-                    for (int k = 0; k < n; k++) {
-                        exceptionClasses[k] = new CPClass(exceptions[k]);
-                    }
-                    methodAttributes[i][j].add(new ExceptionsAttribute(
-                            exceptionClasses));
-                    index++;
-                }
-            }
-        }
-    }
-
     private void parseClassAttrBands(InputStream in) throws IOException,
             Pack200Exception {
         String[] cpUTF8 = cpBands.getCpUTF8();
@@ -371,10 +433,11 @@
                 AttributeLayout.CONTEXT_CLASS);
         int enclosingMethodCount = SegmentUtils.countMatches(classFlags,
                 enclosingMethodLayout);
-        int[] enclosingMethodRC = decodeBandInt("class_EnclosingMethod_RC", in,
-                Codec.UNSIGNED5, enclosingMethodCount);
-        int[] enclosingMethodRDN = decodeBandInt("class_EnclosingMethod_RDN",
-                in, Codec.UNSIGNED5, enclosingMethodCount);
+        String[] enclosingMethodRC = parseReferences(
+                "class_EnclosingMethod_RC", in, Codec.UNSIGNED5,
+                enclosingMethodCount, cpClass);
+        String[] enclosingMethodRDN = parseReferences(
+                "class_EnclosingMethod_RDN", in, Codec.UNSIGNED5, enclosingMethodCount, cpBands.getCpDescriptor());
 
         AttributeLayout signatureLayout = attrMap.getAttributeLayout(
                 AttributeLayout.ATTRIBUTE_SIGNATURE,
@@ -384,7 +447,7 @@
         int[] classSignature = decodeBandInt("class_Signature_RS", in,
                 Codec.UNSIGNED5, signatureCount);
 
-        parseClassMetadataBands(in, classAttrCalls);
+        int backwardsCallsUsed = parseClassMetadataBands(in, classAttrCalls);
 
         AttributeLayout innerClassLayout = attrMap.getAttributeLayout(
                 AttributeLayout.ATTRIBUTE_INNER_CLASSES,
@@ -425,7 +488,34 @@
         int defaultVersionMajor = header.getDefaultClassMajorVersion();
         int defaultVersionMinor = header.getDefaultClassMinorVersion();
 
-        // TODO: Parse other attribute bands
+
+        // Parse non-predefined attribute bands
+        int backwardsCallIndex = backwardsCallsUsed;
+        int limit = options.hasClassFlagsHi() ? 62 : 31;
+        AttributeLayout[] otherLayouts = new AttributeLayout[limit + 1];
+        int[] counts = new int[limit + 1];
+        List[] otherAttributes = new List[limit + 1];
+        for (int i = 0; i < limit; i++) {
+            AttributeLayout layout = attrMap.getAttributeLayout(i, AttributeLayout.CONTEXT_CLASS);
+            if(layout != null && !(layout.isDefaultLayout())) {
+                otherLayouts[i] = layout;
+                counts[i] = SegmentUtils.countMatches(classFlags,
+                        layout);
+            }
+        }
+        for (int i = 0; i < counts.length; i++) {
+            if(counts[i] > 0) {
+                NewAttributeBands bands = attrMap.getAttributeBands(otherLayouts[i]);                
+                otherAttributes[i] = bands.parseAttributes(in, counts[i]);
+                int numBackwardsCallables = otherLayouts[i].numBackwardsCallables();
+                if(numBackwardsCallables > 0) {
+                    int[] backwardsCalls = new int[numBackwardsCallables];
+                    System.arraycopy(classAttrCalls, backwardsCallIndex, backwardsCalls, 0, numBackwardsCallables);
+                    bands.setBackwardsCalls(backwardsCalls);
+                    backwardsCallIndex+= numBackwardsCallables;
+                }
+            }
+        }
 
         // Now process the attribute bands we have parsed
         int sourceFileIndex = 0;
@@ -468,7 +558,10 @@
                 sourceFileIndex++;
             }
             if (enclosingMethodLayout.matches(flag)) {
-                // long result =
+                CPClass theClass = new CPClass(enclosingMethodRC[enclosingMethodIndex]);
+                CPNameAndType theMethod = new CPNameAndType(enclosingMethodRDN[enclosingMethodIndex]);
+                classAttributes[i].add(new EnclosingMethodAttribute(theClass, theMethod));
+                enclosingMethodIndex++;
             }
             if (signatureLayout.matches(flag)) {
                 long result = classSignature[signatureIndex];
@@ -514,6 +607,14 @@
                 classVersionMajor[i] = defaultVersionMajor;
                 classVersionMinor[i] = defaultVersionMinor;
             }
+            // Non-predefined attributes
+            for (int j = 0; j < otherLayouts.length; j++) {
+                if(otherLayouts[j] != null && otherLayouts[j].matches(flag)) {
+                    // Add the next attribute
+                    classAttributes[i].add(otherAttributes[j].get(0));
+                    otherAttributes[j].remove(0);
+                }
+            }
         }
     }
 
@@ -689,6 +790,34 @@
                 "code_LocalVariableTypeTable_slot", in, Codec.UNSIGNED5,
                 localVariableTypeTableN);
 
+        // Parse non-predefined attribute bands
+        int backwardsCallIndex = 0;
+        int limit = options.hasCodeFlagsHi() ? 62 : 31;
+        AttributeLayout[] otherLayouts = new AttributeLayout[limit + 1];
+        int[] counts = new int[limit + 1];
+        List[] otherAttributes = new List[limit + 1];
+        for (int i = 0; i < limit; i++) {
+            AttributeLayout layout = attrMap.getAttributeLayout(i, AttributeLayout.CONTEXT_CODE);
+            if(layout != null && !(layout.isDefaultLayout())) {
+                otherLayouts[i] = layout;
+                counts[i] = SegmentUtils.countMatches(codeFlags,
+                        layout);
+            }
+        }
+        for (int i = 0; i < counts.length; i++) {
+            if(counts[i] > 0) {
+                NewAttributeBands bands = attrMap.getAttributeBands(otherLayouts[i]);                
+                otherAttributes[i] = bands.parseAttributes(in, counts[i]);
+                int numBackwardsCallables = otherLayouts[i].numBackwardsCallables();
+                if(numBackwardsCallables > 0) {
+                    int[] backwardsCalls = new int[numBackwardsCallables];
+                    System.arraycopy(codeAttrCalls, backwardsCallIndex, backwardsCalls, 0, numBackwardsCallables);
+                    bands.setBackwardsCalls(backwardsCalls);
+                    backwardsCallIndex+= numBackwardsCallables;
+                }
+            }
+        }     
+
         int lineNumberIndex = 0;
         int lvtIndex = 0;
         int lvttIndex = 0;
@@ -723,8 +852,16 @@
                 lvttIndex++;
                 codeAttributes[i].add(lvtta);
             }
+            // Non-predefined attributes
+            for (int j = 0; j < otherLayouts.length; j++) {
+                if(otherLayouts[j] != null && otherLayouts[j].matches(codeFlags[i])) {
+                    // Add the next attribute
+                    codeAttributes[i].add(otherAttributes[j].get(0));
+                    otherAttributes[j].remove(0);
+                }
+            }
         }
-        // TODO: Parse other attribute bands
+        
     }
 
     private CPUTF8[][] stringsToCPUTF8(String[][] strings) {
@@ -748,8 +885,9 @@
         return cpUTF8s;
     }
 
-    private void parseFieldMetadataBands(InputStream in, int[] fieldAttrCalls)
+    private int parseFieldMetadataBands(InputStream in, int[] fieldAttrCalls)
             throws Pack200Exception, IOException {
+        int backwardsCallsUsed = 0;
         String[] RxA = new String[] { "RVA", "RIA" };
 
         AttributeLayout rvaLayout = attrMap.getAttributeLayout(
@@ -765,11 +903,14 @@
         int[] backwardsCalls = new int[] {0, 0};
         if(rvaCount > 0) {
             backwardsCalls[0] = fieldAttrCalls[0];
+            backwardsCallsUsed++;
             if(riaCount > 0) {
                 backwardsCalls[1] = fieldAttrCalls[1];
+                backwardsCallsUsed++;
             }
         } else if (riaCount > 0) {
             backwardsCalls[1] = fieldAttrCalls[0];
+            backwardsCallsUsed++;
         }
         MetadataBandGroup[] mb = parseMetadata(in, RxA, RxACount, backwardsCalls, "field");
         Iterator rvaAttributesIterator = mb[0].getAttributes().iterator();
@@ -784,6 +925,7 @@
                 }
             }
         }
+        return backwardsCallsUsed;
     }
 
     private MetadataBandGroup[] parseMetadata(InputStream in, String[] RxA, int[] RxACount,
@@ -884,14 +1026,16 @@
         return mbg;
     }
 
-    private void parseMethodMetadataBands(InputStream in, int[] methodAttrCalls)
+    private int parseMethodMetadataBands(InputStream in, int[] methodAttrCalls)
             throws Pack200Exception, IOException {
+        int backwardsCallsUsed = 0;
         String[] RxA = new String[] { "RVA", "RIA", "RVPA", "RIPA", "AD" };
         int[] rxaCounts = new int[] { 0, 0, 0, 0, 0 };
         int[] backwardsCalls = new int[5];
         int methodAttrIndex = 0;
         for (int i = 0; i < backwardsCalls.length; i++) {
             if(rxaCounts[i] > 0) {
+                backwardsCallsUsed++;
                 backwardsCalls[i] = methodAttrCalls[methodAttrIndex];
                 methodAttrIndex++;
             } else {
@@ -936,9 +1080,19 @@
                 }
             }
         }
+        return backwardsCallsUsed;
     }
 
-    private void parseClassMetadataBands(InputStream in, int[] classAttrCalls) throws Pack200Exception, IOException {
+    /**
+     * Parse the class metadata bands and return the number of backwards callables
+     * @param in
+     * @param classAttrCalls
+     * @return
+     * @throws Pack200Exception
+     * @throws IOException
+     */
+    private int parseClassMetadataBands(InputStream in, int[] classAttrCalls) throws Pack200Exception, IOException {
+        int numBackwardsCalls = 0;
         String[] RxA = new String[] { "RVA", "RIA" };
 
         AttributeLayout rvaLayout = attrMap.getAttributeLayout(
@@ -952,11 +1106,14 @@
         int[] RxACount = new int[] { rvaCount, riaCount };
         int[] backwardsCalls = new int[] {0, 0};
         if(rvaCount > 0) {
+            numBackwardsCalls++;
             backwardsCalls[0] = classAttrCalls[0];
             if(riaCount > 0) {
+                numBackwardsCalls++;
                 backwardsCalls[1] = classAttrCalls[1];
             }
         } else if (riaCount > 0) {
+            numBackwardsCalls++;
             backwardsCalls[1] = classAttrCalls[0];
         }
         MetadataBandGroup[] mbgs = parseMetadata(in, RxA, RxACount, backwardsCalls, "class");
@@ -970,6 +1127,7 @@
                 classAttributes[i].add(riaAttributesIterator.next());
             }
         }
+        return numBackwardsCalls;
     }
 
     public int[] getClassFieldCount() {

Modified: harmony/enhanced/classlib/trunk/modules/pack200/src/main/java/org/apache/harmony/pack200/CpBands.java
URL: http://svn.apache.org/viewvc/harmony/enhanced/classlib/trunk/modules/pack200/src/main/java/org/apache/harmony/pack200/CpBands.java?rev=608801&r1=608800&r2=608801&view=diff
==============================================================================
--- harmony/enhanced/classlib/trunk/modules/pack200/src/main/java/org/apache/harmony/pack200/CpBands.java (original)
+++ harmony/enhanced/classlib/trunk/modules/pack200/src/main/java/org/apache/harmony/pack200/CpBands.java Fri Jan  4 03:14:19 2008
@@ -18,7 +18,6 @@
 
 import java.io.IOException;
 import java.io.InputStream;
-import java.io.OutputStream;
 import java.util.ArrayList;
 
 public class CpBands extends BandSet {
@@ -78,10 +77,6 @@
         parseCpField(in);
         parseCpMethod(in);
         parseCpIMethod(in);
-    }
-
-    public void pack(OutputStream outputStream) {
-        
     }
     
     /**

Modified: harmony/enhanced/classlib/trunk/modules/pack200/src/main/java/org/apache/harmony/pack200/FileBands.java
URL: http://svn.apache.org/viewvc/harmony/enhanced/classlib/trunk/modules/pack200/src/main/java/org/apache/harmony/pack200/FileBands.java?rev=608801&r1=608800&r2=608801&view=diff
==============================================================================
--- harmony/enhanced/classlib/trunk/modules/pack200/src/main/java/org/apache/harmony/pack200/FileBands.java (original)
+++ harmony/enhanced/classlib/trunk/modules/pack200/src/main/java/org/apache/harmony/pack200/FileBands.java Fri Jan  4 03:14:19 2008
@@ -18,7 +18,6 @@
 
 import java.io.IOException;
 import java.io.InputStream;
-import java.io.OutputStream;
 
 /**
  * Parses the file band headers (not including the actual bits themselves).
@@ -48,14 +47,6 @@
     public FileBands(Segment segment) {
         super(segment);
         this.cpUTF8 = segment.getCpBands().getCpUTF8();
-    }
-
-    /* (non-Javadoc)
-     * @see org.apache.harmony.pack200.BandSet#pack(java.io.OutputStream)
-     */
-    public void pack(OutputStream outputStream) {
-        // TODO Auto-generated method stub
-
     }
 
     /* (non-Javadoc)

Modified: harmony/enhanced/classlib/trunk/modules/pack200/src/main/java/org/apache/harmony/pack200/IcBands.java
URL: http://svn.apache.org/viewvc/harmony/enhanced/classlib/trunk/modules/pack200/src/main/java/org/apache/harmony/pack200/IcBands.java?rev=608801&r1=608800&r2=608801&view=diff
==============================================================================
--- harmony/enhanced/classlib/trunk/modules/pack200/src/main/java/org/apache/harmony/pack200/IcBands.java (original)
+++ harmony/enhanced/classlib/trunk/modules/pack200/src/main/java/org/apache/harmony/pack200/IcBands.java Fri Jan  4 03:14:19 2008
@@ -18,7 +18,6 @@
 
 import java.io.IOException;
 import java.io.InputStream;
-import java.io.OutputStream;
 
 /**
  * Pack200 Inner Class Bands
@@ -47,14 +46,6 @@
         super(segment);
         this.cpClass = segment.getCpBands().getCpClass();
         this.cpUTF8 = segment.getCpBands().getCpUTF8();
-    }
-
-    /* (non-Javadoc)
-     * @see org.apache.harmony.pack200.BandSet#pack(java.io.OutputStream)
-     */
-    public void pack(OutputStream outputStream) {
-        // TODO Auto-generated method stub
-
     }
 
     /* (non-Javadoc)

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=608801&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 Jan  4 03:14:19 2008
@@ -0,0 +1,920 @@
+/*
+ *  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.IOException;
+import java.io.InputStream;
+import java.io.StringReader;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import org.apache.harmony.pack200.bytecode.Attribute;
+import org.apache.harmony.pack200.bytecode.CPClass;
+import org.apache.harmony.pack200.bytecode.CPDouble;
+import org.apache.harmony.pack200.bytecode.CPFieldRef;
+import org.apache.harmony.pack200.bytecode.CPFloat;
+import org.apache.harmony.pack200.bytecode.CPInteger;
+import org.apache.harmony.pack200.bytecode.CPInterfaceMethodRef;
+import org.apache.harmony.pack200.bytecode.CPLong;
+import org.apache.harmony.pack200.bytecode.CPMethodRef;
+import org.apache.harmony.pack200.bytecode.CPNameAndType;
+import org.apache.harmony.pack200.bytecode.CPString;
+import org.apache.harmony.pack200.bytecode.CPUTF8;
+import org.apache.harmony.pack200.bytecode.NewAttribute;
+
+/**
+ * Set of bands relating to a non-predefined attribute
+ */
+public class NewAttributeBands extends BandSet {
+
+    private AttributeLayout attributeLayout;
+
+    private List attributes;
+
+    private int backwardsCallCount;
+    
+    private List attributeLayoutElements;
+
+    public NewAttributeBands(Segment segment, AttributeLayout attributeLayout) throws IOException {
+        super(segment);
+        this.attributeLayout = attributeLayout;
+        parseLayout();
+        attributeLayout.setBackwardsCallCount(backwardsCallCount);
+    }
+
+    /*
+     * (non-Javadoc)
+     * 
+     * @see org.apache.harmony.pack200.BandSet#unpack(java.io.InputStream)
+     */
+    public void unpack(InputStream in) throws IOException, Pack200Exception {
+        // does nothing - use parseAttributes instead
+    }
+
+    /**
+     * Returns the list of attributes read in by this band set.  This method
+     * should only be called after unpack() or it will return null.
+     * @return List of Attributes
+     */
+    public List getAttributes() {
+        return attributes;
+    }
+
+    /**
+     * Parse the bands relating to this AttributeLayout and return the correct
+     * class file attributes as a List of {@link Attribute}
+     * @throws Pack200Exception 
+     */
+    public List parseAttributes(InputStream in, int occurrenceCount)
+            throws IOException, Pack200Exception {
+        for (Iterator iter = attributeLayoutElements.iterator(); iter.hasNext();) {
+            AttributeLayoutElement element = (AttributeLayoutElement) iter.next();
+            element.readBands(in, occurrenceCount);
+        }
+
+        List attributes = new ArrayList();
+        for (int i = 0; i < occurrenceCount; i++) {
+            attributes.add(getOneAttribute(i, attributeLayoutElements));
+        }
+        return attributes;
+    }
+
+    /**
+     * Get one attribute at the given index from the various bands.
+     * The correct bands must have already been read in.
+     * @param index
+     * @param elements
+     * @return
+     */
+    private Attribute getOneAttribute(int index, List elements) {
+        NewAttribute attribute = new NewAttribute(attributeLayout.getName());
+        for (Iterator iter = elements.iterator(); iter.hasNext();) {
+            AttributeLayoutElement element = (AttributeLayoutElement) iter.next();
+            element.addToAttribute(index, attribute);
+        }
+        return attribute;
+    }
+
+    /**
+     * Tokenise the layout into AttributeElements
+     * @return a List of AttributeElements
+     * @throws IOException
+     */
+    private void parseLayout() throws IOException {
+        if(attributeLayoutElements == null) {
+            attributeLayoutElements = new ArrayList();
+            StringReader stream = new StringReader(attributeLayout.getLayout());
+            AttributeLayoutElement e;
+            while ((e = readNextAttributeElement(stream)) != null) {
+                attributeLayoutElements.add(e);
+            }
+            resolveCalls();
+        }
+    }
+
+    /**
+     * Resolve calls in the attribute layout and returns the number of backwards calls
+     * 
+     * @param tokens -
+     *            the attribute layout as a List of AttributeElements
+     */
+    private void resolveCalls() {
+        int backwardsCalls = 0;
+        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 (Iterator iter = body.iterator(); iter.hasNext();) {
+                    LayoutElement layoutElement = (LayoutElement) iter.next();
+                    if (layoutElement instanceof Call) {
+                        // Set the callable for each call
+                        Call call = (Call) layoutElement;
+                        int index = call.callableIndex; 
+                        if (index == 0) { // Calls the parent callable
+                            backwardsCalls++;
+                            call.setCallable(callable);
+                        } else if (index > 0) { // Forwards call
+                            for (int k = i; 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
+                            backwardsCalls++;
+                            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;
+                                    }
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        }
+        backwardsCallCount = backwardsCalls;
+    }
+
+    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 {
+        int nextChar = 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[] { (char) nextChar }));
+        case 'S':
+        case 'F':
+            return new Integral(new String(new char[] { (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);
+            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;
+        }
+        List tags = new ArrayList();
+        while (next != ')') {
+            tags.add(new Integer(readNumber(stream)));
+            next = (char) stream.read();
+        }
+        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 {
+
+        /**
+         * Read the bands associated with this part of the layout
+         * 
+         * @param in
+         * @param count
+         * @throws Pack200Exception 
+         * @throws IOException 
+         */
+        public void readBands(InputStream in, int count) throws IOException, Pack200Exception;
+
+        /**
+         * Add the band data for this element at the given index to the attribute
+         * 
+         * @param index
+         * @param attribute
+         */
+        public void addToAttribute(int index, NewAttribute attribute);
+
+    }
+
+    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 String tag;
+        private long[] band;
+
+        public Integral(String tag) {
+            this.tag = tag;
+        }
+
+        public void readBands(InputStream in, int count) throws IOException, Pack200Exception {
+            band = decodeBandLong(attributeLayout.getName() + "_" + tag, in, (BHSDCodec) getCodec(tag), count);
+        }
+
+        public void addToAttribute(int n, NewAttribute attribute) {
+            long value = band[n];
+            if(tag.equals("B") || tag.equals("FB")) {
+                attribute.addInteger(1, value);
+            } else if (tag.equals("SB")) {
+                attribute.addInteger(1, (byte)value);
+            } else if(tag.equals("H") || tag.equals("FH")) {
+                attribute.addInteger(2,  value);
+            } else if (tag.equals("SH")) {
+                attribute.addInteger(2, (short)value);
+            } else if (tag.equals("I") || tag.equals("FI")) {
+                attribute.addInteger(4, value);
+            } else if (tag.equals("SI")) {
+                attribute.addInteger(4, (int) value);
+            } else if (tag.equals("V") || tag.equals("FV") || tag.equals("SV")) {
+                // Don't add V's - they shouldn't be written out to the class file
+            } else if (tag.startsWith("PO")) {
+                char uint_type = tag.substring(2).toCharArray()[0];
+                int length = getLength(uint_type);
+                attribute.addBCOffset(length, value);
+            } else if (tag.startsWith("P")) {
+                char uint_type = tag.substring(1).toCharArray()[0];
+                int length = getLength(uint_type);
+                attribute.addBCIndex(length, value);                
+            } else if (tag.startsWith("OS")) {
+                char uint_type = tag.substring(1).toCharArray()[0];
+                int length = getLength(uint_type);
+                if(length == 1) {
+                    value = (byte)value;
+                } else if(length == 2) {
+                    value = (short)value;
+                } else if(length == 4) {
+                    value = (int)value;
+                }
+                attribute.addBCLength(length, value);  
+            } else if (tag.startsWith("O")) {
+                char uint_type = tag.substring(1).toCharArray()[0];
+                int length = getLength(uint_type);
+                attribute.addBCLength(length, value);                
+            }
+        }
+
+        long getValue(int index) {
+            return band[index];
+        }
+
+    }
+
+    /**
+     * A replication is an array of layout elements, with an associated count
+     */
+    private class Replication extends LayoutElement {
+
+        private Integral countElement;
+
+        private 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 readBands(InputStream in, int count) throws IOException, Pack200Exception {
+            countElement.readBands(in, count);
+            int arrayCount = 0;
+            for (int i = 0; i < count; i++) {
+                arrayCount += countElement.getValue(i);                
+            }
+            for (Iterator iter = layoutElements.iterator(); iter.hasNext();) {
+                LayoutElement element = (LayoutElement) iter.next();
+                element.readBands(in, arrayCount);
+            }
+        }
+
+        public void addToAttribute(int index, NewAttribute attribute) {
+            // Add the count value
+            countElement.addToAttribute(index, attribute);
+            
+            // Add the corresponding array values
+            int offset = 0;
+            for (int i = 0; i < index; i++) {
+                offset += countElement.getValue(i);
+            }
+            long numElements = countElement.getValue(index);
+            for (int i = offset; i < offset + numElements; i++) {                
+                for (Iterator iter = layoutElements.iterator(); iter.hasNext();) {
+                    LayoutElement element = (LayoutElement) iter.next();
+                    element.addToAttribute(i, attribute);
+                }
+            }
+        }
+    }
+
+    
+    /**
+     * 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 Integral unionTag;
+        private List unionCases;
+        private List defaultCaseBody;
+        private int[] caseCounts;
+        private int defaultCount;
+
+        public Union(String tag, List unionCases, List body) {
+            this.unionTag = new Integral(tag);
+            this.unionCases = unionCases;
+            this.defaultCaseBody = body;
+        }
+
+        public void readBands(InputStream in, int count) throws IOException, Pack200Exception {
+            unionTag.readBands(in, count);
+            long[] values = unionTag.band;
+            // Count the band size for each union case then read the bands
+            caseCounts = new int[unionCases.size()];
+            for (int i = 0; i < caseCounts.length; i++) {
+                UnionCase unionCase = (UnionCase) unionCases.get(i);
+                for (int j = 0; j < values.length; j++) {
+                    if(unionCase.hasTag(values[j])) {
+                        caseCounts[i]++;
+                    }
+                }
+                unionCase.readBands(in, caseCounts[i]);
+            }
+            // Count number of default cases then read the default bands
+            for (int i = 0; i < values.length; i++) {
+                boolean found = false;
+                for (Iterator iter = unionCases.iterator(); iter.hasNext();) {
+                    UnionCase unionCase = (UnionCase) iter.next();                    
+                    if(unionCase.hasTag(values[i])) {
+                        found = true;
+                    }
+                }
+                if(!found) {
+                    defaultCount++;
+                }
+            }
+            if(defaultCaseBody != null) {
+                for (Iterator iter = defaultCaseBody.iterator(); iter.hasNext();) {
+                    LayoutElement element = (LayoutElement) iter.next();
+                    element.readBands(in, defaultCount);
+                }
+            }
+        }
+
+        public void addToAttribute(int n, NewAttribute attribute) {
+            unionTag.addToAttribute(n, attribute);
+            int offset = 0;
+            long[] tagBand = unionTag.band;
+            long tag = unionTag.getValue(n);
+            boolean defaultCase = true;
+            for (Iterator iter = unionCases.iterator(); iter.hasNext();) {
+                UnionCase element = (UnionCase) iter.next();
+                if(element.hasTag(tag)) {
+                    defaultCase = false;
+                    for (int j = 0; j < n; j++) {
+                        if(element.hasTag(tagBand[j])) {
+                            offset++;
+                        }
+                    }
+                    element.addToAttribute(offset, attribute);
+                }
+            }
+            if(defaultCase) {
+                // default case
+                int defaultOffset = 0;
+                for (int j = 0; j < n; j++) {
+                    boolean found = false;
+                    for (Iterator iter = unionCases.iterator(); iter.hasNext();) {
+                        UnionCase element = (UnionCase) iter.next();
+                        if(element.hasTag(tagBand[j])) {
+                            found = true;
+                        }
+                    }
+                    if(!found) {
+                        defaultOffset++;
+                    }
+                }
+                if(defaultCaseBody != null) {
+                    for (Iterator iter = defaultCaseBody.iterator(); iter.hasNext();) {
+                        LayoutElement element = (LayoutElement) iter.next();
+                        element.addToAttribute(defaultOffset, attribute);
+                    }
+                }
+            }
+        }
+
+    }
+
+    private class Call extends LayoutElement {
+
+        private 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 readBands(InputStream in, int count) {
+            /*
+             * We don't read anything here, but we need to pass the extra count
+             * to the callable if it's a forwards call. For backwards callables
+             * the count is transmitted directly in the attribute bands and
+             * so it is added later.
+             */
+            if(callableIndex > 0) {
+                callable.addCount(count);
+            } 
+        }
+
+        public void addToAttribute(int n, NewAttribute attribute) {
+            callable.addNextToAttribute(attribute);
+        }
+    }
+
+    /**
+     * Constant Pool Reference
+     */
+    private class Reference extends LayoutElement {
+
+        private String tag;
+        
+        private Object band;
+
+        private int length;
+
+        public Reference(String tag) {
+            this.tag = tag;
+            length = getLength(tag.charAt(tag.length()));
+        }
+
+        public void readBands(InputStream in, int count) throws IOException, Pack200Exception {
+            if(tag.startsWith("KI")) { // Integer
+                band = parseCPIntReferences(attributeLayout.getName(), in, Codec.UNSIGNED5, count);
+            } else if(tag.startsWith("KJ")) { // Long
+                band = parseCPLongReferences(attributeLayout.getName(), in, Codec.UNSIGNED5, count);
+            } else if(tag.startsWith("KF")) { // Float
+                band = parseCPFloatReferences(attributeLayout.getName(), in, Codec.UNSIGNED5, count);
+            } else if(tag.startsWith("KD")) { // Double
+                band = parseCPDoubleReferences(attributeLayout.getName(), in, Codec.UNSIGNED5, count);
+            } else if(tag.startsWith("KS")) { // String
+                band = parseCPStringReferences(attributeLayout.getName(), in, Codec.UNSIGNED5, count);
+            } else if(tag.startsWith("RC")) { // Class
+                band = parseCPClassReferences(attributeLayout.getName(), in, Codec.UNSIGNED5, count);
+            } else if(tag.startsWith("RS")) { // Signature
+                band = parseCPSignatureReferences(attributeLayout.getName(), in, Codec.UNSIGNED5, count);
+            } else if(tag.startsWith("RD")) { // Descriptor
+                band = parseCPDescriptorReferences(attributeLayout.getName(), in, Codec.UNSIGNED5, count);
+            } else if(tag.startsWith("RF")) { // Field Reference
+                band = parseCPFieldRefReferences(attributeLayout.getName(), in, Codec.UNSIGNED5, count);
+            } else if(tag.startsWith("RM")) { // Method Reference
+                band = parseCPMethodRefReferences(attributeLayout.getName(), in, Codec.UNSIGNED5, count);
+            } else if(tag.startsWith("RI")) { // Interface Method Reference
+                band = parseCPInterfaceMethodRefReferences(attributeLayout.getName(), in, Codec.UNSIGNED5, count);
+            } else if(tag.startsWith("RU")) { // UTF8 String
+                band = parseCPUTF8References(attributeLayout.getName(), in, Codec.UNSIGNED5, count);
+            }
+        }
+
+        public void addToAttribute(int n, NewAttribute attribute) {
+            if(tag.startsWith("KI")) { // Integer
+                attribute.addCPConstant(length, ((CPInteger[])band)[n]);
+            } else if(tag.startsWith("KJ")) { // Long
+                attribute.addCPConstant(length, ((CPLong[])band)[n]);
+            } else if(tag.startsWith("KF")) { // Float
+                attribute.addCPConstant(length, ((CPFloat[])band)[n]);
+            } else if(tag.startsWith("KD")) { // Double
+                attribute.addCPConstant(length, ((CPDouble[])band)[n]);
+            } else if(tag.startsWith("KS")) { // String
+                attribute.addCPConstant(length, ((CPString[])band)[n]);
+            } else if(tag.startsWith("RC")) { // Class
+                attribute.addCPClass(length, ((CPClass[])band)[n]);
+            } else if(tag.startsWith("RS")) { // Signature
+                attribute.addCPUTF8(length, ((CPUTF8[])band)[n]);
+            } else if(tag.startsWith("RD")) { // Descriptor
+                attribute.addCPNameAndType(length, ((CPNameAndType[])band)[n]);
+            } else if(tag.startsWith("RF")) { // Field Reference
+                attribute.addCPFieldRef(length, ((CPFieldRef[])band)[n]);
+            } else if(tag.startsWith("RM")) { // Method Reference
+                attribute.addCPMethodRef(length, ((CPMethodRef[])band)[n]);
+            } else if(tag.startsWith("RI")) { // Interface Method Reference
+                attribute.addCPIMethodRef(length, ((CPInterfaceMethodRef[])band)[n]);
+            } else if(tag.startsWith("RU")) { // UTF8 String
+                attribute.addCPUTF8(length, ((CPUTF8[])band)[n]);
+            }
+        }
+
+    }
+
+    private class Callable implements AttributeLayoutElement {
+
+        private List body;
+        
+        private boolean isBackwardsCallable;
+
+        public Callable(List body) throws IOException {
+            this.body = body;
+        }
+        
+        private int count;
+        private int index;
+
+        /**
+         * Used by calls when adding band contents to attributes
+         * so they don't have to keep track of the internal index
+         * of the callable
+         * @param attribute
+         */        
+        public void addNextToAttribute(NewAttribute attribute) {
+            for (Iterator iter = body.iterator(); iter.hasNext();) {
+                LayoutElement element = (LayoutElement) iter.next();
+                element.addToAttribute(index, attribute);                
+            }
+            index++;
+        }
+
+        /**
+         * Adds the count of a call to this callable (ie the number of calls)
+         * @param count
+         */
+        public void addCount(int count) {
+            this.count += count;
+        }
+
+        public void readBands(InputStream in, int count) throws IOException, Pack200Exception {
+            count += this.count;
+            for (Iterator iter = body.iterator(); iter.hasNext();) {
+                LayoutElement element = (LayoutElement) iter.next();
+                element.readBands(in, count);
+            }
+        }
+
+        public void addToAttribute(int n, NewAttribute attribute) {
+            // Ignore n because bands also contain element parts from calls
+            for (Iterator iter = body.iterator(); iter.hasNext();) {
+                LayoutElement element = (LayoutElement) iter.next();
+                element.addToAttribute(index, attribute);                
+            }
+            index++;
+        }
+
+        public boolean isBackwardsCallable() {
+            return isBackwardsCallable;
+        }
+        
+        /**
+         * Tells this Callable that it is a backwards callable
+         */
+        public void setBackwardsCallable() {
+            this.isBackwardsCallable = true;
+        }
+    }
+    
+    /**
+     * A Union case
+     */
+    private class UnionCase extends LayoutElement {
+
+        private List body;
+
+        private 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 readBands(InputStream in, int count) throws IOException, Pack200Exception {
+            if(body != null) {
+                for (Iterator iter = body.iterator(); iter.hasNext();) {
+                    LayoutElement element = (LayoutElement) iter.next();
+                    element.readBands(in, count);
+                }
+            }
+        }
+
+        public void addToAttribute(int index, NewAttribute attribute) {
+            if(body != null) {
+                for (Iterator iter = body.iterator(); iter.hasNext();) {
+                    LayoutElement element = (LayoutElement) iter.next();
+                    element.addToAttribute(index, attribute);
+                }
+            }
+        }
+    }
+
+    /**
+     * 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());
+    }
+
+    /**
+     * Returns the codec that should be used for the given layout element
+     * @param layoutElement
+     * @return
+     */
+    public BHSDCodec getCodec(String layoutElement) {
+        if (layoutElement.indexOf("O") >= 0) { //$NON-NLS-1$
+            return Codec.BRANCH5;
+        } else if (layoutElement.indexOf("P") >= 0) { //$NON-NLS-1$
+            return Codec.BCI5;
+        } else if (layoutElement.indexOf("S") >= 0 && layoutElement.indexOf("KS") < 0 //$NON-NLS-1$ //$NON-NLS-2$
+                && layoutElement.indexOf("RS") < 0) { //$NON-NLS-1$
+            return Codec.SIGNED5;
+        } else if (layoutElement.indexOf("B") >= 0) { //$NON-NLS-1$
+            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 int 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();
+        char[] digits = new char[length];
+        stream.read(digits);
+        return 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;
+    }
+
+    public int getBackwardsCallCount() {
+        return backwardsCallCount;
+    }
+
+    /**
+     * Once the attribute bands have been read the callables can be informed
+     * about the number of times each is subject to a backwards call. This
+     * method is used to set this information.
+     * 
+     * @param backwardsCalls
+     *            one int for each backwards callable, which contains the number
+     *            of times that callable is subject to a backwards call.
+     * @throws IOException
+     */
+    public void setBackwardsCalls(int[] backwardsCalls) throws IOException {
+        int index = 0;
+        parseLayout();
+        for (Iterator iter = attributeLayoutElements.iterator(); iter.hasNext();) {
+            AttributeLayoutElement element = (AttributeLayoutElement) iter.next();
+            if(element instanceof Callable && ((Callable)element).isBackwardsCallable()) {
+                ((Callable)element).addCount(backwardsCalls[index]);
+                index++;
+            }
+        }
+    }
+
+}
\ No newline at end of file

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

Modified: harmony/enhanced/classlib/trunk/modules/pack200/src/main/java/org/apache/harmony/pack200/bytecode/EnclosingMethodAttribute.java
URL: http://svn.apache.org/viewvc/harmony/enhanced/classlib/trunk/modules/pack200/src/main/java/org/apache/harmony/pack200/bytecode/EnclosingMethodAttribute.java?rev=608801&r1=608800&r2=608801&view=diff
==============================================================================
--- harmony/enhanced/classlib/trunk/modules/pack200/src/main/java/org/apache/harmony/pack200/bytecode/EnclosingMethodAttribute.java (original)
+++ harmony/enhanced/classlib/trunk/modules/pack200/src/main/java/org/apache/harmony/pack200/bytecode/EnclosingMethodAttribute.java Fri Jan  4 03:14:19 2008
@@ -24,12 +24,12 @@
     private int class_index;
     private int method_index;
     private CPClass cpClass;
-    private CPMethod cpMethod;
+    private CPNameAndType method;
 
-    public EnclosingMethodAttribute(CPClass cpClass, CPMethod cpMethod) {
+    public EnclosingMethodAttribute(CPClass cpClass, CPNameAndType method) {
         super("EnclosingMethod");
         this.cpClass = cpClass;
-        this.cpMethod = cpMethod;
+        this.method = method;
     }
 
     /* (non-Javadoc)
@@ -43,8 +43,8 @@
         super.resolve(pool);
         cpClass.resolve(pool);
         class_index = pool.indexOf(cpClass);
-        cpMethod.resolve(pool);
-        method_index = pool.indexOf(cpMethod);
+        method.resolve(pool);
+        method_index = pool.indexOf(method);
     }
 
     /* (non-Javadoc)

Added: harmony/enhanced/classlib/trunk/modules/pack200/src/main/java/org/apache/harmony/pack200/bytecode/NewAttribute.java
URL: http://svn.apache.org/viewvc/harmony/enhanced/classlib/trunk/modules/pack200/src/main/java/org/apache/harmony/pack200/bytecode/NewAttribute.java?rev=608801&view=auto
==============================================================================
--- harmony/enhanced/classlib/trunk/modules/pack200/src/main/java/org/apache/harmony/pack200/bytecode/NewAttribute.java (added)
+++ harmony/enhanced/classlib/trunk/modules/pack200/src/main/java/org/apache/harmony/pack200/bytecode/NewAttribute.java Fri Jan  4 03:14:19 2008
@@ -0,0 +1,113 @@
+/*
+ *  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.bytecode;
+
+import java.io.DataOutputStream;
+import java.io.IOException;
+
+/**
+ * A New (i.e. non-predefined) Class File attribute
+ */
+public class NewAttribute extends Attribute {
+
+    public NewAttribute(String attributeName) {
+        super(attributeName);
+        // TODO Auto-generated constructor stub
+    }
+
+    /* (non-Javadoc)
+     * @see org.apache.harmony.pack200.bytecode.Attribute#getLength()
+     */
+    protected int getLength() {
+        // TODO Auto-generated method stub
+        return 0;
+    }
+
+    /* (non-Javadoc)
+     * @see org.apache.harmony.pack200.bytecode.Attribute#writeBody(java.io.DataOutputStream)
+     */
+    protected void writeBody(DataOutputStream dos) throws IOException {
+        // TODO Auto-generated method stub
+
+    }
+
+    /* (non-Javadoc)
+     * @see org.apache.harmony.pack200.bytecode.ClassFileEntry#toString()
+     */
+    public String toString() {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    public void addInteger(int length, long value) {
+        
+    }
+
+    public void addBCOffset(int length, long value) {
+        // TODO Auto-generated method stub
+        
+    }
+
+    public void addBCIndex(int length, long value) {
+        // TODO Auto-generated method stub
+        
+    }
+
+    public void addBCLength(int length, long value) {
+        // TODO Auto-generated method stub
+        
+    }
+
+    public void addCPConstant(int length, CPConstant constant) {
+        // TODO Auto-generated method stub
+        
+    }
+
+    public void addCPClass(int length, CPClass class1) {
+        // TODO Auto-generated method stub
+        
+    }
+
+    public void addCPUTF8(int length, CPUTF8 cputf8) {
+        // TODO Auto-generated method stub
+        
+    }
+
+    public void addCPNameAndType(int length, CPNameAndType type) {
+        // TODO Auto-generated method stub
+        
+    }
+
+    public void addCPFieldRef(int length, CPFieldRef ref) {
+        // TODO Auto-generated method stub
+        
+    }
+
+    public void addCPMethodRef(int length, CPMethodRef ref) {
+        // TODO Auto-generated method stub
+        
+    }
+
+    public void addCPIMethodRef(int length, CPInterfaceMethodRef ref) {
+        // TODO Auto-generated method stub
+        
+    }
+    
+    
+    
+
+}

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

Modified: harmony/enhanced/classlib/trunk/modules/pack200/src/test/java/org/apache/harmony/pack200/tests/BandSetTest.java
URL: http://svn.apache.org/viewvc/harmony/enhanced/classlib/trunk/modules/pack200/src/test/java/org/apache/harmony/pack200/tests/BandSetTest.java?rev=608801&r1=608800&r2=608801&view=diff
==============================================================================
--- harmony/enhanced/classlib/trunk/modules/pack200/src/test/java/org/apache/harmony/pack200/tests/BandSetTest.java (original)
+++ harmony/enhanced/classlib/trunk/modules/pack200/src/test/java/org/apache/harmony/pack200/tests/BandSetTest.java Fri Jan  4 03:14:19 2008
@@ -26,7 +26,6 @@
 import org.apache.harmony.pack200.BHSDCodec;
 import org.apache.harmony.pack200.BandSet;
 import org.apache.harmony.pack200.Codec;
-import org.apache.harmony.pack200.CodecEncoding;
 import org.apache.harmony.pack200.Pack200Exception;
 import org.apache.harmony.pack200.Segment;
 import org.apache.harmony.pack200.SegmentHeader;