1/*
2 * Copyright (C) 2009 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
17package com.android.mkstubs.sourcer;
18
19import org.objectweb.asm.Opcodes;
20
21/**
22 * Source generator for the access fields of methods, fields and classes.
23 * <p/>
24 * Given an integer access field and a type ({@link #IS_CLASS}, {@link #IS_FIELD} or
25 * {@link #IS_METHOD}), the {@link #write(int, int)} method can generate a string
26 * desribing the access modifiers for a Java source.
27 */
28class AccessSourcer {
29
30    private final Output mOutput;
31
32    public static int IS_CLASS  = 1;
33    public static int IS_FIELD  = 2;
34    public static int IS_METHOD = 4;
35
36    private enum Flag {
37        ACC_PUBLIC(Opcodes.ACC_PUBLIC               , IS_CLASS | IS_FIELD | IS_METHOD),
38        ACC_PRIVATE(Opcodes.ACC_PRIVATE             , IS_CLASS | IS_FIELD | IS_METHOD),
39        ACC_PROTECTED(Opcodes.ACC_PROTECTED         , IS_CLASS | IS_FIELD | IS_METHOD),
40        ACC_STATIC(Opcodes.ACC_STATIC               , IS_FIELD | IS_METHOD),
41        ACC_FINAL(Opcodes.ACC_FINAL                 , IS_CLASS | IS_FIELD | IS_METHOD),
42        ACC_SUPER(Opcodes.ACC_SUPER                 , IS_CLASS),
43        ACC_SYNCHRONIZED(Opcodes.ACC_SYNCHRONIZED   , IS_METHOD),
44        ACC_VOLATILE(Opcodes.ACC_VOLATILE           , IS_FIELD),
45        ACC_BRIDGE(Opcodes.ACC_BRIDGE               , IS_METHOD),
46        ACC_VARARGS(Opcodes.ACC_VARARGS             , IS_METHOD),
47        ACC_TRANSIENT(Opcodes.ACC_TRANSIENT         , IS_FIELD),
48        ACC_NATIVE(Opcodes.ACC_NATIVE               , IS_METHOD),
49        ACC_INTERFACE(Opcodes.ACC_INTERFACE         , IS_CLASS),
50        ACC_ABSTRACT(Opcodes.ACC_ABSTRACT           , IS_CLASS | IS_METHOD),
51        ACC_STRICT(Opcodes.ACC_STRICT               , IS_METHOD),
52        ACC_SYNTHETIC(Opcodes.ACC_SYNTHETIC         , IS_CLASS | IS_FIELD | IS_METHOD),
53        ACC_ANNOTATION(Opcodes.ACC_ANNOTATION       , IS_CLASS),
54        ACC_ENUM(Opcodes.ACC_ENUM                   , IS_CLASS),
55        ACC_DEPRECATED(Opcodes.ACC_DEPRECATED       , IS_CLASS | IS_FIELD | IS_METHOD)
56        ;
57
58        private final int mValue;
59        private final int mFilter;
60
61        private Flag(int value, int filter) {
62            mValue = value;
63            mFilter = filter;
64        }
65
66        public int getValue() {
67            return mValue;
68        }
69
70        public int getFilter() {
71            return mFilter;
72        }
73
74        /** Transforms "ACC_PUBLIC" into "public" */
75        @Override
76        public String toString() {
77            return super.toString().substring(4).toLowerCase();
78        }
79    }
80
81
82    public AccessSourcer(Output output) {
83        mOutput = output;
84    }
85
86    /**
87     * Generates a list of access keywords, e.g. "public final".
88     * <p/>
89     * It is up to the caller to filter extra keywords that should not be generated,
90     * e.g. {@link Flag#ACC_SYNTHETIC}.
91     *
92     * @param access The access mode, e.g. 33 or 18
93     * @param filter One of {@link #IS_CLASS}, {@link #IS_FIELD} or {@link #IS_METHOD}, which
94     *        indicates the validity context.
95     */
96    public void write(int access, int filter) {
97
98        boolean need_sep = false;
99
100        for (Flag f : Flag.values()) {
101            if ((f.getFilter() & filter) != 0 && (access & f.getValue()) != 0) {
102                if (need_sep) {
103                    mOutput.write(" ");
104                }
105                mOutput.write(f.toString());
106                need_sep = true;
107            }
108        }
109
110    }
111}
112