1f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/*
2f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Copyright (C) 2007 The Android Open Source Project
3f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
4f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License");
5f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * you may not use this file except in compliance with the License.
6f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * You may obtain a copy of the License at
7f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
8f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *      http://www.apache.org/licenses/LICENSE-2.0
9f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
10f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Unless required by applicable law or agreed to in writing, software
11f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS,
12f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * See the License for the specific language governing permissions and
14f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * limitations under the License.
15f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */
16f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
17f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectpackage com.android.dx.cf.direct;
18f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
19f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport com.android.dx.cf.iface.Attribute;
20f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport com.android.dx.cf.iface.ParseException;
21f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport com.android.dx.cf.iface.ParseObserver;
22f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport com.android.dx.cf.iface.StdAttributeList;
23f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport com.android.dx.util.ByteArray;
24f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport com.android.dx.util.Hex;
25f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
26f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/**
27f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Parser for lists of attributes.
28f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */
29f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectfinal /*package*/ class AttributeListParser {
3099409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    /** {@code non-null;} the class file to parse from */
31f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private final DirectClassFile cf;
32f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
33f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /** attribute parsing context */
34f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private final int context;
35f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
36f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /** offset in the byte array of the classfile to the start of the list */
37f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private final int offset;
38f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
3999409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    /** {@code non-null;} attribute factory to use */
40f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private final AttributeFactory attributeFactory;
41f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
4299409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    /** {@code non-null;} list of parsed attributes */
43f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private final StdAttributeList list;
44f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
4599409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    /** {@code >= -1;} the end offset of this list in the byte array of the
4699409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * classfile, or {@code -1} if not yet parsed */
47f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private int endOffset;
48f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
4999409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    /** {@code null-ok;} parse observer, if any */
50f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private ParseObserver observer;
51f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
52f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
53f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Constructs an instance.
54f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     *
5599409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * @param cf {@code non-null;} class file to parse from
56f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * @param context attribute parsing context (see {@link AttributeFactory})
5799409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * @param offset offset in {@code bytes} to the start of the list
5899409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * @param attributeFactory {@code non-null;} attribute factory to use
59f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
60f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    public AttributeListParser(DirectClassFile cf, int context, int offset,
61f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                               AttributeFactory attributeFactory) {
62f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (cf == null) {
63f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            throw new NullPointerException("cf == null");
64f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
65f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
66f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (attributeFactory == null) {
67f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            throw new NullPointerException("attributeFactory == null");
68f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
69f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
70f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        int size = cf.getBytes().getUnsignedShort(offset);
71f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
72f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        this.cf = cf;
73f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        this.context = context;
74f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        this.offset = offset;
75f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        this.attributeFactory = attributeFactory;
76f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        this.list = new StdAttributeList(size);
77f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        this.endOffset = -1;
78f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
79f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
80f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
81f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Sets the parse observer for this instance.
82f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     *
8399409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * @param observer {@code null-ok;} the observer
84f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
85f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    public void setObserver(ParseObserver observer) {
86f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        this.observer = observer;
87f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
88f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
89f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
9099409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * Gets the end offset of this constant pool in the {@code byte[]}
91f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * which it came from.
92f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     *
9399409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * @return {@code >= 0;} the end offset
94f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
95f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    public int getEndOffset() {
96f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        parseIfNecessary();
97f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        return endOffset;
98f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
99f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
100f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
101f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Gets the parsed list.
102f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     *
10399409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * @return {@code non-null;} the list
104f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
105f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    public StdAttributeList getList() {
106f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        parseIfNecessary();
107f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        return list;
108f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
109f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
110f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
111f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Runs {@link #parse} if it has not yet been run successfully.
112f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
113f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private void parseIfNecessary() {
114f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (endOffset < 0) {
115f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            parse();
116f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
117f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
118f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
119f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
120f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Does the actual parsing.
121f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
122f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private void parse() {
123f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        int sz = list.size();
124f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        int at = offset + 2; // Skip the count.
125f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
126f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        ByteArray bytes = cf.getBytes();
127f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
128f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (observer != null) {
129f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            observer.parsed(bytes, offset, 2,
130f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                            "attributes_count: " + Hex.u2(sz));
131f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
132f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
133f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        for (int i = 0; i < sz; i++) {
134f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            try {
135f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                if (observer != null) {
136f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    observer.parsed(bytes, at, 0,
137f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                                    "\nattributes[" + i + "]:\n");
138f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    observer.changeIndent(1);
139f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                }
140f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
141f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                Attribute attrib =
142f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    attributeFactory.parse(cf, context, at, observer);
143f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
144f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                at += attrib.byteLength();
145f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                list.set(i, attrib);
146f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
147f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                if (observer != null) {
148f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    observer.changeIndent(-1);
149f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    observer.parsed(bytes, at, 0,
150f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                                    "end attributes[" + i + "]\n");
151f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                }
152f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            } catch (ParseException ex) {
153f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                ex.addContext("...while parsing attributes[" + i + "]");
154f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                throw ex;
155f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            } catch (RuntimeException ex) {
156f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                ParseException pe = new ParseException(ex);
157f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                pe.addContext("...while parsing attributes[" + i + "]");
158f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                throw pe;
159f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
160f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
161f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
162f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        endOffset = at;
163f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
164f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project}
165