summaryrefslogtreecommitdiff
path: root/src/fjbg/ch/epfl/lamp/fjbg/JInnerClassesAttribute.java
blob: ac69d249478f0b2243bcfb0b54f437a22dd51fab (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
package ch.epfl.lamp.fjbg;

import java.io.DataOutputStream;
import java.io.IOException;
import java.util.*;

/**
 * InnerClasses attribute. See section 4.7.5 of the JVM
 * Specification.
 *
 * @author Iulian Dragos
 */
public class JInnerClassesAttribute extends JAttribute {
	/** InnerClass entries */
	private Map/*<InnerClassEntry>*/ entries = new LinkedHashMap();

	/** Constant pool of the current classfile. */
	private JConstantPool pool;

    public JInnerClassesAttribute(FJBGContext context,
            JClass clazz) {
    	super(context, clazz);
    	this.pool = clazz.pool;
    }

    public void addEntry(String inner, String outer, String name, int flags) {
        int inIdx = pool.addClass(inner);
        int ouIdx = 0;
        if (outer != null) ouIdx = pool.addClass(outer);
        int nIdx = 0;
        if (name != null) nIdx = pool.addUtf8(name);

    	Entry e = new Entry(inIdx, ouIdx, nIdx, flags);

    	if (entries.containsKey(inner)) {
    		Entry other = (Entry) entries.get(inner);
    		assert other.outerInfo == e.outerInfo && other.originalName == e.originalName && other.innerFlags == e.innerFlags
    			: inner + "already declared as " + other;
    	} else
    		entries.put(inner, e);
    }

    public String getName() { return "InnerClasses"; }

	protected int getSize() {
		return 2 + entries.size() * 8;
	}

	protected void writeContentsTo(DataOutputStream stream) throws IOException {
		stream.writeShort(entries.size());
		for (Iterator it = entries.values().iterator(); it.hasNext(); ) {
			Entry e = (Entry)it.next();
			stream.writeShort(e.innerInfo);
			stream.writeShort(e.outerInfo);
			stream.writeShort(e.originalName);
			stream.writeShort(e.innerFlags);
		}
	}

	/** An entry in the InnerClasses attribute, as defined by the JVM Spec. */
	private class Entry {
		/** CONSTANT_Class_info index in the pool for the inner class (mangled). */
		int innerInfo;

		/** CONSTANT_Class_info index in the pool for the outer class (mangled). */
		int outerInfo;

		/** CONSTANT_Utf8_info index in the pool for the original name of the inner class. */
		int originalName;

		/** Short int for modifier flags. */
		int innerFlags;

		public Entry(int iI, int oI, int oN, int f) {
			this.innerInfo = iI;
			this.outerInfo = oI;
			this.originalName = oN;
			this.innerFlags = f;
		}

		public Entry(String innerClass, String outerClass, String name, int flags) {
			this(pool.addClass(innerClass),pool.addClass(outerClass), pool.addUtf8(name), flags);
		}

		/** Two entries are equal if they refer to the same inner class.
		 *  innerInfo represents a unique name (mangled).
		 */
		public boolean equals(Object other) {
			if (other instanceof Entry) {
				Entry otherEntry = (Entry) other;
				return otherEntry.innerInfo == this.innerInfo;
			}
			return false;
		}
	}
}