rusty_dex/dex/
access_flags.rs

1#![allow(non_camel_case_types)]
2
3//! Helper functions to manipulate access flags
4//!
5//! Access flags are stored as an unsigned 32 bits integer and can be used for classes, fields, or
6//! methods. In this module we define structs to represent these flags and help methods to parse
7//! and print them.
8//!
9//! # Example
10//!
11//! ```
12//! use dex_parser::dex::access_flags::{ AccessFlag, AccessFlagType };
13//!
14//! let flags = AccessFlag::parse(0x0001_0009, AccessFlagType::Method);
15//!
16//! assert_eq!(flags, vec![AccessFlag::ACC_PUBLIC,
17//!                        AccessFlag::ACC_STATIC,
18//!                        AccessFlag::ACC_CONSTRUCTOR]);
19//! ```
20
21use std::fmt;
22use log::warn;
23
24/// Representation of the different access flag types: for classes, fields, or methods
25#[derive(Debug)]
26pub enum AccessFlagType {
27    /// Flag for a class
28    Class,
29    /// Flag for a class field
30    Field,
31    /// Flag for a method
32    Method
33}
34
35/// Implementation of the `Display` trait for access flag types
36impl fmt::Display for AccessFlagType {
37    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
38        match *self {
39            AccessFlagType::Class  => { write!(f, "class") },
40            AccessFlagType::Field  => { write!(f, "field") },
41            AccessFlagType::Method => { write!(f, "method") }
42        }
43    }
44}
45
46/// Representation of the different access flag
47///
48/// Bitfields of these flags are used to indicate the accessibility and overall properties of
49/// classes and class members.
50#[derive(Debug, PartialEq)]
51pub enum AccessFlag {
52    /// Public: visible everywhere
53    ACC_PUBLIC,
54    /// Private: only visible to defining class
55    ACC_PRIVATE,
56    /// Protected: visible to package and subclasses
57    ACC_PROTECTED,
58    /// Static: meaning depends of where the flag is used
59    ///   * for classes: is not constructed with an outer `this` reference
60    ///   * for methods: does not take a `this` argument
61    ///   * for fields: global to defining class
62    ACC_STATIC,
63    /// Final: meaning depends of where the flag is used
64    ///   * for classes: not subclassable
65    ///   * for methods: not overridable
66    ///   * for fields: immutable after construction
67    ACC_FINAL,
68    /// Synchronized (only valid for methods): associated lock automatically
69    /// acquired around call to this method.
70    /// Note: only valid to set when `ACC_NATIVE` is also set.
71    ACC_SYNCHRONIZED,
72    /// Volatile (only valid for fields): special access rules to help with
73    /// thread safety
74    ACC_VOLATILE,
75    /// Bridge (only valid for methods): method added automatically by the
76    /// compiler as a type-safe bridge
77    ACC_BRIDGE,
78    /// Transient (only valid for fields): the field must not be saved by
79    /// default serialization
80    ACC_TRANSIENT,
81    /// Varargs (only valid for methods): the last argument to this method
82    /// should be treated as a "rest" argument by the compiler
83    ACC_VARARGS,
84    /// Native (only valid for methods): this method is implemented in
85    /// native code
86    ACC_NATIVE,
87    /// Interface (only valid for classes): multiply-implementable abstract class
88    ACC_INTERFACE,
89    /// Abstract (only valid for classes and methods):
90    ///   * for classes: not directly instantiable
91    ///   * for methods: unimplemented by this class
92    ACC_ABSTRACT,
93    /// Strict floating-point (only valid for methods): strict rules for
94    /// floating-point arithmetic
95    ACC_STRICT,
96    /// Synthetic: not directly defined in source code
97    ACC_SYNTHETIC,
98    /// Annotation (only valid for classes): declared as an annotation class
99    ACC_ANNOTATION,
100    /// Enum (only valid for classes and fields):
101    ///   * for classes: declared as an enumerated type
102    ///   * for fields: declared as an enumerated value
103    ACC_ENUM,
104    /// Constructor (only valid for methods): contructor method
105    ACC_CONSTRUCTOR,
106    /// Declared synchronized (only valid for methods): method declared
107    /// as `synchronized`
108    ACC_DECLARED_SYNCHRONIZED,
109}
110
111impl AccessFlag {
112    /// Converts a raw flag (an unsigned 32 bits integer) into a vector for access flags
113    ///
114    /// The result values will be different depending on where the type is used (for a class, a
115    /// method, or a field)
116    pub fn parse(raw: u32, for_type: AccessFlagType) -> Vec<Self> {
117        let mut flags = Vec::new();
118
119        if raw & 0x01 != 0 { flags.push(AccessFlag::ACC_PUBLIC); }
120        if raw & 0x02 != 0 { flags.push(AccessFlag::ACC_PRIVATE); }
121        if raw & 0x04 != 0 { flags.push(AccessFlag::ACC_PROTECTED); }
122        if raw & 0x08 != 0 { flags.push(AccessFlag::ACC_STATIC); }
123        if raw & 0x10 != 0 { flags.push(AccessFlag::ACC_FINAL); }
124        if raw & 0x20 != 0 {
125            match for_type {
126                AccessFlagType::Method => {
127                    flags.push(AccessFlag::ACC_SYNCHRONIZED);
128                },
129                _ => {
130                    warn!("Ignoring invalid flag for {for_type}: 0x20");
131                }
132            }
133        }
134        if raw & 0x40 != 0 {
135            match for_type {
136                AccessFlagType::Class => {
137                    warn!("Ignoring invalid flag for {for_type}: 0x40");
138                },
139                AccessFlagType::Field => {
140                    flags.push(AccessFlag::ACC_VOLATILE);
141                },
142                AccessFlagType::Method => {
143                    flags.push(AccessFlag::ACC_BRIDGE);
144                }
145            }
146        }
147        if raw & 0x80 != 0 {
148            match for_type {
149                AccessFlagType::Class => {
150                    warn!("Ignoring invalid flag for {for_type}: 0x80");
151                },
152                AccessFlagType::Field => {
153                    flags.push(AccessFlag::ACC_TRANSIENT);
154                },
155                AccessFlagType::Method => {
156                    flags.push(AccessFlag::ACC_VARARGS);
157                }
158            }
159        }
160        if raw & 0x100 != 0 {
161            match for_type {
162                AccessFlagType::Method => {
163                    flags.push(AccessFlag::ACC_NATIVE);
164                },
165                _ => {
166                    warn!("Ignoring invalid flag for {for_type}: 0x100");
167                }
168            }
169        }
170        if raw & 0x200 != 0 {
171            match for_type {
172                AccessFlagType::Class => {
173                    flags.push(AccessFlag::ACC_INTERFACE);
174                },
175                _ => {
176                    warn!("Ignoring invalid flag for {for_type}: 0x200");
177                }
178            }
179        }
180        if raw & 0x400 != 0 {
181            match for_type {
182                AccessFlagType::Field => {
183                    warn!("Ignoring invalid flag for {for_type}: 0x400");
184                },
185                _ => {
186                    flags.push(AccessFlag::ACC_ABSTRACT);
187                }
188            }
189        }
190        if raw & 0x800 != 0 {
191            match for_type {
192                AccessFlagType::Method => {
193                    flags.push(AccessFlag::ACC_STRICT);
194                },
195                _ => {
196                    warn!("Ignoring invalid flag for {for_type}: 0x800");
197                }
198            }
199        }
200        if raw & 0x1000 != 0 { flags.push(AccessFlag::ACC_SYNTHETIC); }
201        if raw & 0x2000 != 0 {
202            match for_type {
203                AccessFlagType::Class => {
204                    flags.push(AccessFlag::ACC_ANNOTATION);
205                },
206                _ => {
207                    warn!("Ignoring invalid flag for {for_type}: 0x2000");
208                }
209            }
210        }
211        if raw & 0x4000 != 0 {
212            match for_type {
213                AccessFlagType::Method => {
214                    warn!("Ignoring invalid flag for {for_type}: 0x4000");
215                },
216                _ => {
217                    flags.push(AccessFlag::ACC_ENUM);
218                }
219            }
220        }
221        if raw & 0x8000 != 0  { warn!("Ignoring invalid (unused) flag: 0x8000"); }
222        if raw & 0x10000 != 0 {
223            match for_type {
224                AccessFlagType::Method => {
225                    flags.push(AccessFlag::ACC_CONSTRUCTOR);
226                },
227                _ => {
228                    warn!("Ignoring invalid flag for {for_type}: 0x10000");
229                }
230            }
231        }
232        if raw & 0x20000 != 0 {
233            match for_type {
234                AccessFlagType::Method => {
235                    flags.push(AccessFlag::ACC_DECLARED_SYNCHRONIZED);
236                },
237                _ => {
238                    warn!("Ignoring invalid flag for {for_type}: 0x20000");
239                }
240            }
241        }
242
243        flags
244    }
245
246    /// Pretty print a vector of access flags
247    pub fn vec_to_string(flags: &[AccessFlag]) -> String {
248        let mut output = String::new();
249        let flags_len = flags.len();
250
251        for (idx, flag) in flags.iter().enumerate() {
252            output.push_str(&flag.to_string());
253            if idx < flags_len - 1{
254                output.push('|');
255            }
256        }
257
258        output
259    }
260}
261
262/// Implementation of the `Display` trait for access flags
263impl fmt::Display for AccessFlag {
264    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
265        match *self {
266            AccessFlag::ACC_PUBLIC => write!(f, "public" ),
267            AccessFlag::ACC_PRIVATE => write!(f, "private" ),
268            AccessFlag::ACC_PROTECTED => write!(f, "protected" ),
269            AccessFlag::ACC_STATIC => write!(f, "static" ),
270            AccessFlag::ACC_FINAL => write!(f, "final" ),
271            AccessFlag::ACC_SYNCHRONIZED => write!(f, "synchronized" ),
272            AccessFlag::ACC_VOLATILE => write!(f, "volatile" ),
273            AccessFlag::ACC_BRIDGE => write!(f, "bridge" ),
274            AccessFlag::ACC_TRANSIENT => write!(f, "transient" ),
275            AccessFlag::ACC_VARARGS => write!(f, "varargs" ),
276            AccessFlag::ACC_NATIVE => write!(f, "native" ),
277            AccessFlag::ACC_INTERFACE => write!(f, "interface" ),
278            AccessFlag::ACC_ABSTRACT => write!(f, "abstract" ),
279            AccessFlag::ACC_STRICT => write!(f, "strict" ),
280            AccessFlag::ACC_SYNTHETIC => write!(f, "synthetic" ),
281            AccessFlag::ACC_ANNOTATION => write!(f, "annotation" ),
282            AccessFlag::ACC_ENUM => write!(f, "enum" ),
283            AccessFlag::ACC_CONSTRUCTOR => write!(f, "constructor" ),
284            AccessFlag::ACC_DECLARED_SYNCHRONIZED => write!(f, "synchronized" ),
285        }
286    }
287}
288
289#[cfg(test)]
290mod tests {
291    use super::*;
292
293    #[test]
294    fn test_access_flag_type_display() {
295        let class_flag = AccessFlagType::Class;
296        let field_flag = AccessFlagType::Field;
297        let method_flag = AccessFlagType::Method;
298
299        assert_eq!(class_flag.to_string(), "class");
300        assert_eq!(field_flag.to_string(), "field");
301        assert_eq!(method_flag.to_string(), "method");
302    }
303
304    #[test]
305    fn test_access_flag_class_parse() {
306        // Test with valid flags
307        // Testing all at once because there is no semantics at play here
308        let flags = AccessFlag::parse(0x3ffff, AccessFlagType::Class);
309        assert_eq!(flags, vec![AccessFlag::ACC_PUBLIC,
310                               AccessFlag::ACC_PRIVATE,
311                               AccessFlag::ACC_PROTECTED,
312                               AccessFlag::ACC_STATIC,
313                               AccessFlag::ACC_FINAL,
314                               AccessFlag::ACC_INTERFACE,
315                               AccessFlag::ACC_ABSTRACT,
316                               AccessFlag::ACC_SYNTHETIC,
317                               AccessFlag::ACC_ANNOTATION,
318                               AccessFlag::ACC_ENUM]);
319    }
320
321    #[test]
322    fn test_access_flag_field_parse() {
323        // Test with valid flags
324        // Testing all at once because there is no semantics at play here
325        let flags = AccessFlag::parse(0x3ffff, AccessFlagType::Field);
326        assert_eq!(flags, vec![AccessFlag::ACC_PUBLIC,
327                               AccessFlag::ACC_PRIVATE,
328                               AccessFlag::ACC_PROTECTED,
329                               AccessFlag::ACC_STATIC,
330                               AccessFlag::ACC_FINAL,
331                               AccessFlag::ACC_VOLATILE,
332                               AccessFlag::ACC_TRANSIENT,
333                               AccessFlag::ACC_SYNTHETIC,
334                               AccessFlag::ACC_ENUM]);
335    }
336
337    #[test]
338    fn test_access_flag_method_parse() {
339        // Test with valid flags
340        // Testing all at once because there is no semantics at play here
341        let flags = AccessFlag::parse(0x3ffff, AccessFlagType::Method);
342        assert_eq!(flags, vec![AccessFlag::ACC_PUBLIC,
343                               AccessFlag::ACC_PRIVATE,
344                               AccessFlag::ACC_PROTECTED,
345                               AccessFlag::ACC_STATIC,
346                               AccessFlag::ACC_FINAL,
347                               AccessFlag::ACC_SYNCHRONIZED,
348                               AccessFlag::ACC_BRIDGE,
349                               AccessFlag::ACC_VARARGS,
350                               AccessFlag::ACC_NATIVE,
351                               AccessFlag::ACC_ABSTRACT,
352                               AccessFlag::ACC_STRICT,
353                               AccessFlag::ACC_SYNTHETIC,
354                               AccessFlag::ACC_CONSTRUCTOR,
355                               AccessFlag::ACC_DECLARED_SYNCHRONIZED]);
356    }
357}