blob: f7486eb9cd541393320695e804b72a8be43300e5 [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.attrib.RawAttribute;
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.rop.cst.ConstantPool;
import com.android.dx.rop.cst.CstString;
import com.android.dx.util.ByteArray;
import com.android.dx.util.Hex;
/**
* Factory capable of instantiating various {@link Attribute} subclasses
* depending on the context and name.
*/
public class AttributeFactory {
/** context for attributes on class files */
public static final int CTX_CLASS = 0;
/** context for attributes on fields */
public static final int CTX_FIELD = 1;
/** context for attributes on methods */
public static final int CTX_METHOD = 2;
/** context for attributes on code attributes */
public static final int CTX_CODE = 3;
/** number of contexts */
public static final int CTX_COUNT = 4;
/**
* Constructs an instance.
*/
public AttributeFactory() {
// This space intentionally left blank.
}
/**
* Parses and makes an attribute based on the bytes at the
* indicated position in the given array. This method figures out
* the name, and then does all the setup to call on to {@link #parse0},
* which does the actual construction.
*
* @param cf {@code non-null;} class file to parse from
* @param context context to parse in; one of the {@code CTX_*}
* constants
* @param offset offset into {@code dcf}'s {@code bytes}
* to start parsing at
* @param observer {@code null-ok;} parse observer to report to, if any
* @return {@code non-null;} an appropriately-constructed {@link Attribute}
*/
public final Attribute parse(DirectClassFile cf, int context, int offset,
ParseObserver observer) {
if (cf == null) {
throw new NullPointerException("cf == null");
}
if ((context < 0) || (context >= CTX_COUNT)) {
throw new IllegalArgumentException("bad context");
}
CstString name = null;
try {
ByteArray bytes = cf.getBytes();
ConstantPool pool = cf.getConstantPool();
int nameIdx = bytes.getUnsignedShort(offset);
int length = bytes.getInt(offset + 2);
name = (CstString) pool.get(nameIdx);
if (observer != null) {
observer.parsed(bytes, offset, 2,
"name: " + name.toHuman());
observer.parsed(bytes, offset + 2, 4,
"length: " + Hex.u4(length));
}
return parse0(cf, context, name.getString(), offset + 6, length,
observer);
} catch (ParseException ex) {
ex.addContext("...while parsing " +
((name != null) ? (name.toHuman() + " ") : "") +
"attribute at offset " + Hex.u4(offset));
throw ex;
}
}
/**
* Parses attribute content. The base class implements this by constructing
* an instance of {@link RawAttribute}. Subclasses are expected to
* override this to do something better in most cases.
*
* @param cf {@code non-null;} class file to parse from
* @param context context to parse in; one of the {@code CTX_*}
* constants
* @param name {@code non-null;} the attribute name
* @param offset offset into {@code bytes} to start parsing at; this
* is the offset to the start of attribute data, not to the header
* @param length the length of the attribute data
* @param observer {@code null-ok;} parse observer to report to, if any
* @return {@code non-null;} an appropriately-constructed {@link Attribute}
*/
protected Attribute parse0(DirectClassFile cf, int context, String name,
int offset, int length,
ParseObserver observer) {
ByteArray bytes = cf.getBytes();
ConstantPool pool = cf.getConstantPool();
Attribute result = new RawAttribute(name, bytes, offset, length, pool);
if (observer != null) {
observer.parsed(bytes, offset, length, "attribute data");
}
return result;
}
}