com.android.dx.cf.direct.MemberListParser Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of builder Show documentation
Show all versions of builder Show documentation
Library to build Android applications.
/*
* 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.AttributeList;
import com.android.dx.cf.iface.Member;
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.rop.cst.ConstantPool;
import com.android.dx.rop.cst.CstNat;
import com.android.dx.rop.cst.CstString;
import com.android.dx.rop.cst.CstType;
import com.android.dx.util.ByteArray;
import com.android.dx.util.Hex;
/**
* Parser for lists of class file members (that is, fields and methods).
*/
abstract /*package*/ class MemberListParser {
/** {@code non-null;} the class file to parse from */
private final DirectClassFile cf;
/** {@code non-null;} class being defined */
private final CstType definer;
/** 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 >= -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;} the class file to parse from
* @param definer {@code non-null;} class being defined
* @param offset offset in {@code bytes} to the start of the list
* @param attributeFactory {@code non-null;} attribute factory to use
*/
public MemberListParser(DirectClassFile cf, CstType definer,
int offset, AttributeFactory attributeFactory) {
if (cf == null) {
throw new NullPointerException("cf == null");
}
if (offset < 0) {
throw new IllegalArgumentException("offset < 0");
}
if (attributeFactory == null) {
throw new NullPointerException("attributeFactory == null");
}
this.cf = cf;
this.definer = definer;
this.offset = offset;
this.attributeFactory = attributeFactory;
this.endOffset = -1;
}
/**
* 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;
}
/**
* Sets the parse observer for this instance.
*
* @param observer {@code null-ok;} the observer
*/
public final void setObserver(ParseObserver observer) {
this.observer = observer;
}
/**
* Runs {@link #parse} if it has not yet been run successfully.
*/
protected final void parseIfNecessary() {
if (endOffset < 0) {
parse();
}
}
/**
* Gets the count of elements in the list.
*
* @return the count
*/
protected final int getCount() {
ByteArray bytes = cf.getBytes();
return bytes.getUnsignedShort(offset);
}
/**
* Gets the class file being defined.
*
* @return {@code non-null;} the class
*/
protected final CstType getDefiner() {
return definer;
}
/**
* Gets the human-oriented name for what this instance is parsing.
* Subclasses must override this method.
*
* @return {@code non-null;} the human oriented name
*/
protected abstract String humanName();
/**
* Gets the human-oriented string for the given access flags.
* Subclasses must override this method.
*
* @param accessFlags the flags
* @return {@code non-null;} the string form
*/
protected abstract String humanAccessFlags(int accessFlags);
/**
* Gets the {@code CTX_*} constant to use when parsing attributes.
* Subclasses must override this method.
*
* @return {@code non-null;} the human oriented name
*/
protected abstract int getAttributeContext();
/**
* Sets an element in the list. Subclasses must override this method.
*
* @param n which element
* @param accessFlags the {@code access_flags}
* @param nat the interpreted name and type (based on the two
* {@code *_index} fields)
* @param attributes list of parsed attributes
* @return {@code non-null;} the constructed member
*/
protected abstract Member set(int n, int accessFlags, CstNat nat,
AttributeList attributes);
/**
* Does the actual parsing.
*/
private void parse() {
int attributeContext = getAttributeContext();
int count = getCount();
int at = offset + 2; // Skip the count.
ByteArray bytes = cf.getBytes();
ConstantPool pool = cf.getConstantPool();
if (observer != null) {
observer.parsed(bytes, offset, 2,
humanName() + "s_count: " + Hex.u2(count));
}
for (int i = 0; i < count; i++) {
try {
int accessFlags = bytes.getUnsignedShort(at);
int nameIdx = bytes.getUnsignedShort(at + 2);
int descIdx = bytes.getUnsignedShort(at + 4);
CstString name = (CstString) pool.get(nameIdx);
CstString desc = (CstString) pool.get(descIdx);
if (observer != null) {
observer.startParsingMember(bytes, at, name.getString(),
desc.getString());
observer.parsed(bytes, at, 0, "\n" + humanName() +
"s[" + i + "]:\n");
observer.changeIndent(1);
observer.parsed(bytes, at, 2,
"access_flags: " +
humanAccessFlags(accessFlags));
observer.parsed(bytes, at + 2, 2,
"name: " + name.toHuman());
observer.parsed(bytes, at + 4, 2,
"descriptor: " + desc.toHuman());
}
at += 6;
AttributeListParser parser =
new AttributeListParser(cf, attributeContext, at,
attributeFactory);
parser.setObserver(observer);
at = parser.getEndOffset();
StdAttributeList attributes = parser.getList();
attributes.setImmutable();
CstNat nat = new CstNat(name, desc);
Member member = set(i, accessFlags, nat, attributes);
if (observer != null) {
observer.changeIndent(-1);
observer.parsed(bytes, at, 0, "end " + humanName() +
"s[" + i + "]\n");
observer.endParsingMember(bytes, at, name.getString(),
desc.getString(), member);
}
} catch (ParseException ex) {
ex.addContext("...while parsing " + humanName() + "s[" + i +
"]");
throw ex;
} catch (RuntimeException ex) {
ParseException pe = new ParseException(ex);
pe.addContext("...while parsing " + humanName() + "s[" + i +
"]");
throw pe;
}
}
endOffset = at;
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy