• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.iface.Attribute;
20 import com.android.dx.cf.iface.ParseException;
21 import com.android.dx.cf.iface.ParseObserver;
22 import com.android.dx.cf.iface.StdAttributeList;
23 import com.android.dx.util.ByteArray;
24 import com.android.dx.util.Hex;
25 
26 /**
27  * Parser for lists of attributes.
28  */
29 final /*package*/ class AttributeListParser {
30     /** {@code non-null;} the class file to parse from */
31     private final DirectClassFile cf;
32 
33     /** attribute parsing context */
34     private final int context;
35 
36     /** offset in the byte array of the classfile to the start of the list */
37     private final int offset;
38 
39     /** {@code non-null;} attribute factory to use */
40     private final AttributeFactory attributeFactory;
41 
42     /** {@code non-null;} list of parsed attributes */
43     private final StdAttributeList list;
44 
45     /** {@code >= -1;} the end offset of this list in the byte array of the
46      * classfile, or {@code -1} if not yet parsed */
47     private int endOffset;
48 
49     /** {@code null-ok;} parse observer, if any */
50     private ParseObserver observer;
51 
52     /**
53      * Constructs an instance.
54      *
55      * @param cf {@code non-null;} class file to parse from
56      * @param context attribute parsing context (see {@link AttributeFactory})
57      * @param offset offset in {@code bytes} to the start of the list
58      * @param attributeFactory {@code non-null;} attribute factory to use
59      */
AttributeListParser(DirectClassFile cf, int context, int offset, AttributeFactory attributeFactory)60     public AttributeListParser(DirectClassFile cf, int context, int offset,
61                                AttributeFactory attributeFactory) {
62         if (cf == null) {
63             throw new NullPointerException("cf == null");
64         }
65 
66         if (attributeFactory == null) {
67             throw new NullPointerException("attributeFactory == null");
68         }
69 
70         int size = cf.getBytes().getUnsignedShort(offset);
71 
72         this.cf = cf;
73         this.context = context;
74         this.offset = offset;
75         this.attributeFactory = attributeFactory;
76         this.list = new StdAttributeList(size);
77         this.endOffset = -1;
78     }
79 
80     /**
81      * Sets the parse observer for this instance.
82      *
83      * @param observer {@code null-ok;} the observer
84      */
setObserver(ParseObserver observer)85     public void setObserver(ParseObserver observer) {
86         this.observer = observer;
87     }
88 
89     /**
90      * Gets the end offset of this constant pool in the {@code byte[]}
91      * which it came from.
92      *
93      * @return {@code >= 0;} the end offset
94      */
getEndOffset()95     public int getEndOffset() {
96         parseIfNecessary();
97         return endOffset;
98     }
99 
100     /**
101      * Gets the parsed list.
102      *
103      * @return {@code non-null;} the list
104      */
getList()105     public StdAttributeList getList() {
106         parseIfNecessary();
107         return list;
108     }
109 
110     /**
111      * Runs {@link #parse} if it has not yet been run successfully.
112      */
parseIfNecessary()113     private void parseIfNecessary() {
114         if (endOffset < 0) {
115             parse();
116         }
117     }
118 
119     /**
120      * Does the actual parsing.
121      */
parse()122     private void parse() {
123         int sz = list.size();
124         int at = offset + 2; // Skip the count.
125 
126         ByteArray bytes = cf.getBytes();
127 
128         if (observer != null) {
129             observer.parsed(bytes, offset, 2,
130                             "attributes_count: " + Hex.u2(sz));
131         }
132 
133         for (int i = 0; i < sz; i++) {
134             try {
135                 if (observer != null) {
136                     observer.parsed(bytes, at, 0,
137                                     "\nattributes[" + i + "]:\n");
138                     observer.changeIndent(1);
139                 }
140 
141                 Attribute attrib =
142                     attributeFactory.parse(cf, context, at, observer);
143 
144                 at += attrib.byteLength();
145                 list.set(i, attrib);
146 
147                 if (observer != null) {
148                     observer.changeIndent(-1);
149                     observer.parsed(bytes, at, 0,
150                                     "end attributes[" + i + "]\n");
151                 }
152             } catch (ParseException ex) {
153                 ex.addContext("...while parsing attributes[" + i + "]");
154                 throw ex;
155             } catch (RuntimeException ex) {
156                 ParseException pe = new ParseException(ex);
157                 pe.addContext("...while parsing attributes[" + i + "]");
158                 throw pe;
159             }
160         }
161 
162         endOffset = at;
163     }
164 }
165