1 /*
2  * Copyright (C) 2007 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.dx.cf.direct;
18 
19 import com.android.dx.cf.attrib.RawAttribute;
20 import com.android.dx.cf.iface.Attribute;
21 import com.android.dx.cf.iface.ParseException;
22 import com.android.dx.cf.iface.ParseObserver;
23 import com.android.dx.rop.cst.ConstantPool;
24 import com.android.dx.rop.cst.CstString;
25 import com.android.dx.util.ByteArray;
26 import com.android.dx.util.Hex;
27 
28 /**
29  * Factory capable of instantiating various {@link Attribute} subclasses
30  * depending on the context and name.
31  */
32 public class AttributeFactory {
33     /** context for attributes on class files */
34     public static final int CTX_CLASS = 0;
35 
36     /** context for attributes on fields */
37     public static final int CTX_FIELD = 1;
38 
39     /** context for attributes on methods */
40     public static final int CTX_METHOD = 2;
41 
42     /** context for attributes on code attributes */
43     public static final int CTX_CODE = 3;
44 
45     /** number of contexts */
46     public static final int CTX_COUNT = 4;
47 
48     /**
49      * Constructs an instance.
50      */
AttributeFactory()51     public AttributeFactory() {
52         // This space intentionally left blank.
53     }
54 
55     /**
56      * Parses and makes an attribute based on the bytes at the
57      * indicated position in the given array. This method figures out
58      * the name, and then does all the setup to call on to {@link #parse0},
59      * which does the actual construction.
60      *
61      * @param cf {@code non-null;} class file to parse from
62      * @param context context to parse in; one of the {@code CTX_*}
63      * constants
64      * @param offset offset into {@code dcf}'s {@code bytes}
65      * to start parsing at
66      * @param observer {@code null-ok;} parse observer to report to, if any
67      * @return {@code non-null;} an appropriately-constructed {@link Attribute}
68      */
parse(DirectClassFile cf, int context, int offset, ParseObserver observer)69     public final Attribute parse(DirectClassFile cf, int context, int offset,
70                                  ParseObserver observer) {
71         if (cf == null) {
72             throw new NullPointerException("cf == null");
73         }
74 
75         if ((context < 0) || (context >= CTX_COUNT)) {
76             throw new IllegalArgumentException("bad context");
77         }
78 
79         CstString name = null;
80 
81         try {
82             ByteArray bytes = cf.getBytes();
83             ConstantPool pool = cf.getConstantPool();
84             int nameIdx = bytes.getUnsignedShort(offset);
85             int length = bytes.getInt(offset + 2);
86 
87             name = (CstString) pool.get(nameIdx);
88 
89             if (observer != null) {
90                 observer.parsed(bytes, offset, 2,
91                                 "name: " + name.toHuman());
92                 observer.parsed(bytes, offset + 2, 4,
93                                 "length: " + Hex.u4(length));
94             }
95 
96             return parse0(cf, context, name.getString(), offset + 6, length,
97                           observer);
98         } catch (ParseException ex) {
99             ex.addContext("...while parsing " +
100                     ((name != null) ? (name.toHuman() + " ") : "") +
101                     "attribute at offset " + Hex.u4(offset));
102             throw ex;
103         }
104     }
105 
106     /**
107      * Parses attribute content. The base class implements this by constructing
108      * an instance of {@link RawAttribute}. Subclasses are expected to
109      * override this to do something better in most cases.
110      *
111      * @param cf {@code non-null;} class file to parse from
112      * @param context context to parse in; one of the {@code CTX_*}
113      * constants
114      * @param name {@code non-null;} the attribute name
115      * @param offset offset into {@code bytes} to start parsing at; this
116      * is the offset to the start of attribute data, not to the header
117      * @param length the length of the attribute data
118      * @param observer {@code null-ok;} parse observer to report to, if any
119      * @return {@code non-null;} an appropriately-constructed {@link Attribute}
120      */
parse0(DirectClassFile cf, int context, String name, int offset, int length, ParseObserver observer)121     protected Attribute parse0(DirectClassFile cf, int context, String name,
122                                int offset, int length,
123                                ParseObserver observer) {
124         ByteArray bytes = cf.getBytes();
125         ConstantPool pool = cf.getConstantPool();
126         Attribute result = new RawAttribute(name, bytes, offset, length, pool);
127 
128         if (observer != null) {
129             observer.parsed(bytes, offset, length, "attribute data");
130         }
131 
132         return result;
133     }
134 }
135