1/*
2 * Copyright 2012, Google Inc.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
7 * met:
8 *
9 *     * Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 *     * Redistributions in binary form must reproduce the above
12 * copyright notice, this list of conditions and the following disclaimer
13 * in the documentation and/or other materials provided with the
14 * distribution.
15 *     * Neither the name of Google Inc. nor the names of its
16 * contributors may be used to endorse or promote products derived from
17 * this software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 */
31
32package org.jf.dexlib2;
33
34import java.util.HashMap;
35
36public enum AccessFlags
37{
38    PUBLIC(0x1, "public", true, true, true),
39    PRIVATE(0x2, "private", true, true, true),
40    PROTECTED(0x4, "protected", true, true, true),
41    STATIC(0x8, "static", true, true, true),
42    FINAL(0x10, "final", true, true, true),
43    SYNCHRONIZED(0x20, "synchronized", false, true, false),
44    VOLATILE(0x40, "volatile", false, false, true),
45    BRIDGE(0x40, "bridge", false, true, false),
46    TRANSIENT(0x80, "transient", false, false, true),
47    VARARGS(0x80, "varargs", false, true, false),
48    NATIVE(0x100, "native", false, true, false),
49    INTERFACE(0x200, "interface", true, false, false),
50    ABSTRACT(0x400, "abstract", true, true, false),
51    STRICTFP(0x800, "strictfp", false, true, false),
52    SYNTHETIC(0x1000, "synthetic", true, true, true),
53    ANNOTATION(0x2000, "annotation", true, false, false),
54    ENUM(0x4000, "enum", true, false, true),
55    CONSTRUCTOR(0x10000, "constructor", false, true, false),
56    DECLARED_SYNCHRONIZED(0x20000, "declared-synchronized", false, true, false);
57
58    private int value;
59    private String accessFlagName;
60    private boolean validForClass;
61    private boolean validForMethod;
62    private boolean validForField;
63
64    //cache the array of all AccessFlags, because .values() allocates a new array for every call
65    private final static AccessFlags[] allFlags;
66
67    private static HashMap<String, AccessFlags> accessFlagsByName;
68
69    static {
70        allFlags = AccessFlags.values();
71
72        accessFlagsByName = new HashMap<String, AccessFlags>();
73        for (AccessFlags accessFlag: allFlags) {
74            accessFlagsByName.put(accessFlag.accessFlagName, accessFlag);
75        }
76    }
77
78    private AccessFlags(int value, String accessFlagName, boolean validForClass, boolean validForMethod,
79                        boolean validForField) {
80        this.value = value;
81        this.accessFlagName = accessFlagName;
82        this.validForClass = validForClass;
83        this.validForMethod = validForMethod;
84        this.validForField = validForField;
85    }
86
87    public boolean isSet(int accessFlags) {
88        return (this.value & accessFlags) != 0;
89    }
90
91    public static AccessFlags[] getAccessFlagsForClass(int accessFlagValue) {
92        int size = 0;
93        for (AccessFlags accessFlag: allFlags) {
94            if (accessFlag.validForClass && (accessFlagValue & accessFlag.value) != 0) {
95                size++;
96            }
97        }
98
99        AccessFlags[] accessFlags = new AccessFlags[size];
100        int accessFlagsPosition = 0;
101        for (AccessFlags accessFlag: allFlags) {
102            if (accessFlag.validForClass && (accessFlagValue & accessFlag.value) != 0) {
103                accessFlags[accessFlagsPosition++] = accessFlag;
104            }
105        }
106        return accessFlags;
107    }
108
109    private static String formatAccessFlags(AccessFlags[] accessFlags) {
110        int size = 0;
111        for (AccessFlags accessFlag: accessFlags) {
112            size += accessFlag.toString().length() + 1;
113        }
114
115        StringBuilder sb = new StringBuilder(size);
116        for (AccessFlags accessFlag: accessFlags) {
117            sb.append(accessFlag.toString());
118            sb.append(" ");
119        }
120        if (accessFlags.length > 0) {
121            sb.delete(sb.length() - 1, sb.length());
122        }
123        return sb.toString();
124    }
125
126    public static String formatAccessFlagsForClass(int accessFlagValue) {
127        return formatAccessFlags(getAccessFlagsForClass(accessFlagValue));
128    }
129
130    public static AccessFlags[] getAccessFlagsForMethod(int accessFlagValue) {
131        int size = 0;
132        for (AccessFlags accessFlag: allFlags) {
133            if (accessFlag.validForMethod && (accessFlagValue & accessFlag.value) != 0) {
134                size++;
135            }
136        }
137
138        AccessFlags[] accessFlags = new AccessFlags[size];
139        int accessFlagsPosition = 0;
140        for (AccessFlags accessFlag: allFlags) {
141            if (accessFlag.validForMethod && (accessFlagValue & accessFlag.value) != 0) {
142                accessFlags[accessFlagsPosition++] = accessFlag;
143            }
144        }
145        return accessFlags;
146    }
147
148    public static String formatAccessFlagsForMethod(int accessFlagValue) {
149        return formatAccessFlags(getAccessFlagsForMethod(accessFlagValue));
150    }
151
152    public static AccessFlags[] getAccessFlagsForField(int accessFlagValue) {
153        int size = 0;
154        for (AccessFlags accessFlag: allFlags) {
155            if (accessFlag.validForField && (accessFlagValue & accessFlag.value) != 0) {
156                size++;
157            }
158        }
159
160        AccessFlags[] accessFlags = new AccessFlags[size];
161        int accessFlagsPosition = 0;
162        for (AccessFlags accessFlag: allFlags) {
163            if (accessFlag.validForField && (accessFlagValue & accessFlag.value) != 0) {
164                accessFlags[accessFlagsPosition++] = accessFlag;
165            }
166        }
167        return accessFlags;
168    }
169
170    public static String formatAccessFlagsForField(int accessFlagValue) {
171        return formatAccessFlags(getAccessFlagsForField(accessFlagValue));
172    }
173
174    public static AccessFlags getAccessFlag(String accessFlag) {
175        return accessFlagsByName.get(accessFlag);
176    }
177
178    public int getValue() {
179        return value;
180    }
181
182    public String toString() {
183        return accessFlagName;
184    }
185}
186