blob: 2715e6a94b55e6bf2fef962c1bb98f875f474ab6 [file] [log] [blame]
/*
* Copyright (C) 2007 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.dx.cf.direct;
import com.android.dx.cf.iface.Attribute;
import com.android.dx.cf.iface.ParseException;
import com.android.dx.cf.iface.ParseObserver;
import com.android.dx.cf.iface.StdAttributeList;
import com.android.dx.util.ByteArray;
import com.android.dx.util.Hex;
/**
* Parser for lists of attributes.
*/
final /*package*/ class AttributeListParser {
/** {@code non-null;} the class file to parse from */
private final DirectClassFile cf;
/** attribute parsing context */
private final int context;
/** offset in the byte array of the classfile to the start of the list */
private final int offset;
/** {@code non-null;} attribute factory to use */
private final AttributeFactory attributeFactory;
/** {@code non-null;} list of parsed attributes */
private final StdAttributeList list;
/** {@code >= -1;} the end offset of this list in the byte array of the
* classfile, or {@code -1} if not yet parsed */
private int endOffset;
/** {@code null-ok;} parse observer, if any */
private ParseObserver observer;
/**
* Constructs an instance.
*
* @param cf {@code non-null;} class file to parse from
* @param context attribute parsing context (see {@link AttributeFactory})
* @param offset offset in {@code bytes} to the start of the list
* @param attributeFactory {@code non-null;} attribute factory to use
*/
public AttributeListParser(DirectClassFile cf, int context, int offset,
AttributeFactory attributeFactory) {
if (cf == null) {
throw new NullPointerException("cf == null");
}
if (attributeFactory == null) {
throw new NullPointerException("attributeFactory == null");
}
int size = cf.getBytes().getUnsignedShort(offset);
this.cf = cf;
this.context = context;
this.offset = offset;
this.attributeFactory = attributeFactory;
this.list = new StdAttributeList(size);
this.endOffset = -1;
}
/**
* Sets the parse observer for this instance.
*
* @param observer {@code null-ok;} the observer
*/
public void setObserver(ParseObserver observer) {
this.observer = observer;
}
/**
* Gets the end offset of this constant pool in the {@code byte[]}
* which it came from.
*
* @return {@code >= 0;} the end offset
*/
public int getEndOffset() {
parseIfNecessary();
return endOffset;
}
/**
* Gets the parsed list.
*
* @return {@code non-null;} the list
*/
public StdAttributeList getList() {
parseIfNecessary();
return list;
}
/**
* Runs {@link #parse} if it has not yet been run successfully.
*/
private void parseIfNecessary() {
if (endOffset < 0) {
parse();
}
}
/**
* Does the actual parsing.
*/
private void parse() {
int sz = list.size();
int at = offset + 2; // Skip the count.
ByteArray bytes = cf.getBytes();
if (observer != null) {
observer.parsed(bytes, offset, 2,
"attributes_count: " + Hex.u2(sz));
}
for (int i = 0; i < sz; i++) {
try {
if (observer != null) {
observer.parsed(bytes, at, 0,
"\nattributes[" + i + "]:\n");
observer.changeIndent(1);
}
Attribute attrib =
attributeFactory.parse(cf, context, at, observer);
at += attrib.byteLength();
list.set(i, attrib);
if (observer != null) {
observer.changeIndent(-1);
observer.parsed(bytes, at, 0,
"end attributes[" + i + "]\n");
}
} catch (ParseException ex) {
ex.addContext("...while parsing attributes[" + i + "]");
throw ex;
} catch (RuntimeException ex) {
ParseException pe = new ParseException(ex);
pe.addContext("...while parsing attributes[" + i + "]");
throw pe;
}
}
endOffset = at;
}
}