Home | History | Annotate | Download | only in direct
      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 
     17 package com.android.dx.cf.direct;
     18 
     19 import com.android.dx.cf.attrib.RawAttribute;
     20 import com.android.dx.cf.iface.Attribute;
     21 import com.android.dx.cf.iface.ParseException;
     22 import com.android.dx.cf.iface.ParseObserver;
     23 import com.android.dx.rop.cst.ConstantPool;
     24 import com.android.dx.rop.cst.CstString;
     25 import com.android.dx.util.ByteArray;
     26 import com.android.dx.util.Hex;
     27 
     28 /**
     29  * Factory capable of instantiating various {@link Attribute} subclasses
     30  * depending on the context and name.
     31  */
     32 public class AttributeFactory {
     33     /** context for attributes on class files */
     34     public static final int CTX_CLASS = 0;
     35 
     36     /** context for attributes on fields */
     37     public static final int CTX_FIELD = 1;
     38 
     39     /** context for attributes on methods */
     40     public static final int CTX_METHOD = 2;
     41 
     42     /** context for attributes on code attributes */
     43     public static final int CTX_CODE = 3;
     44 
     45     /** number of contexts */
     46     public static final int CTX_COUNT = 4;
     47 
     48     /**
     49      * Constructs an instance.
     50      */
     51     public AttributeFactory() {
     52         // This space intentionally left blank.
     53     }
     54 
     55     /**
     56      * Parses and makes an attribute based on the bytes at the
     57      * indicated position in the given array. This method figures out
     58      * the name, and then does all the setup to call on to {@link #parse0},
     59      * which does the actual construction.
     60      *
     61      * @param cf {@code non-null;} class file to parse from
     62      * @param context context to parse in; one of the {@code CTX_*}
     63      * constants
     64      * @param offset offset into {@code dcf}'s {@code bytes}
     65      * to start parsing at
     66      * @param observer {@code null-ok;} parse observer to report to, if any
     67      * @return {@code non-null;} an appropriately-constructed {@link Attribute}
     68      */
     69     public final Attribute parse(DirectClassFile cf, int context, int offset,
     70                                  ParseObserver observer) {
     71         if (cf == null) {
     72             throw new NullPointerException("cf == null");
     73         }
     74 
     75         if ((context < 0) || (context >= CTX_COUNT)) {
     76             throw new IllegalArgumentException("bad context");
     77         }
     78 
     79         CstString name = null;
     80 
     81         try {
     82             ByteArray bytes = cf.getBytes();
     83             ConstantPool pool = cf.getConstantPool();
     84             int nameIdx = bytes.getUnsignedShort(offset);
     85             int length = bytes.getInt(offset + 2);
     86 
     87             name = (CstString) pool.get(nameIdx);
     88 
     89             if (observer != null) {
     90                 observer.parsed(bytes, offset, 2,
     91                                 "name: " + name.toHuman());
     92                 observer.parsed(bytes, offset + 2, 4,
     93                                 "length: " + Hex.u4(length));
     94             }
     95 
     96             return parse0(cf, context, name.getString(), offset + 6, length,
     97                           observer);
     98         } catch (ParseException ex) {
     99             ex.addContext("...while parsing " +
    100                     ((name != null) ? (name.toHuman() + " ") : "") +
    101                     "attribute at offset " + Hex.u4(offset));
    102             throw ex;
    103         }
    104     }
    105 
    106     /**
    107      * Parses attribute content. The base class implements this by constructing
    108      * an instance of {@link RawAttribute}. Subclasses are expected to
    109      * override this to do something better in most cases.
    110      *
    111      * @param cf {@code non-null;} class file to parse from
    112      * @param context context to parse in; one of the {@code CTX_*}
    113      * constants
    114      * @param name {@code non-null;} the attribute name
    115      * @param offset offset into {@code bytes} to start parsing at; this
    116      * is the offset to the start of attribute data, not to the header
    117      * @param length the length of the attribute data
    118      * @param observer {@code null-ok;} parse observer to report to, if any
    119      * @return {@code non-null;} an appropriately-constructed {@link Attribute}
    120      */
    121     protected Attribute parse0(DirectClassFile cf, int context, String name,
    122                                int offset, int length,
    123                                ParseObserver observer) {
    124         ByteArray bytes = cf.getBytes();
    125         ConstantPool pool = cf.getConstantPool();
    126         Attribute result = new RawAttribute(name, bytes, offset, length, pool);
    127 
    128         if (observer != null) {
    129             observer.parsed(bytes, offset, length, "attribute data");
    130         }
    131 
    132         return result;
    133     }
    134 }
    135