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 17package com.android.dx.cf.direct; 18 19import com.android.dx.cf.iface.Attribute; 20import com.android.dx.cf.iface.ParseException; 21import com.android.dx.cf.iface.ParseObserver; 22import com.android.dx.cf.iface.StdAttributeList; 23import com.android.dx.util.ByteArray; 24import com.android.dx.util.Hex; 25 26/** 27 * Parser for lists of attributes. 28 */ 29final /*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 */ 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 */ 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 */ 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 */ 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 */ 113 private void parseIfNecessary() { 114 if (endOffset < 0) { 115 parse(); 116 } 117 } 118 119 /** 120 * Does the actual parsing. 121 */ 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