/* * 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.CstUtf8; 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"); } CstUtf8 name = null; try { ByteArray bytes = cf.getBytes(); ConstantPool pool = cf.getConstantPool(); int nameIdx = bytes.getUnsignedShort(offset); int length = bytes.getInt(offset + 2); name = (CstUtf8) 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; } }