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