1use std::ffi::CStr;
2use std::marker::PhantomData;
3
4use bitflags::bitflags;
5
6use crate::ffi::BADADDR;
7use crate::ffi::name::{
8 get_nlist_ea, get_nlist_idx, get_nlist_name, get_nlist_size, is_in_nlist, is_public_name,
9 is_weak_name,
10};
11
12use crate::Address;
13use crate::idb::IDB;
14
15pub type NameIndex = usize;
16
17pub struct NameList<'a> {
18 _marker: PhantomData<&'a IDB>,
19}
20
21bitflags! {
22 #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
23 pub struct NameProperties: u8 {
24 const PUBLIC = 0x01;
25 const WEAK = 0x02;
26 }
27}
28
29#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
30pub struct Name {
31 address: Address,
32 name: String,
33 index: NameIndex,
34 properties: NameProperties,
35}
36
37impl Name {
38 pub fn address(&self) -> Address {
39 self.address
40 }
41
42 pub fn name(&self) -> &str {
43 &self.name
44 }
45
46 pub fn is_public(&self) -> bool {
47 self.properties.contains(NameProperties::PUBLIC)
48 }
49
50 pub fn is_weak(&self) -> bool {
51 self.properties.contains(NameProperties::WEAK)
52 }
53}
54
55impl<'a> NameList<'a> {
56 pub(crate) fn new(_: &'a IDB) -> Self {
57 Self {
58 _marker: PhantomData,
59 }
60 }
61
62 pub fn get_by_index(&self, index: NameIndex) -> Option<Name> {
63 let addr = self.get_address_by_index(index)?;
64 let name = unsafe { get_nlist_name(index) };
65 if name.is_null() {
66 return None;
67 }
68
69 let name = unsafe { CStr::from_ptr(name) }.to_string_lossy().into_owned();
70
71 let mut properties = NameProperties::empty();
72
73 if unsafe { is_public_name(addr.into()) } {
74 properties.insert(NameProperties::PUBLIC);
75 }
76
77 if unsafe { is_weak_name(addr.into()) } {
78 properties.insert(NameProperties::WEAK);
79 }
80
81 Some(Name {
82 address: addr,
83 name,
84 index,
85 properties,
86 })
87 }
88
89 pub fn get_closest_by_address(&self, address: Address) -> Option<Name> {
90 let index = unsafe { get_nlist_idx(address.into()) };
91 self.get_by_index(index)
92 }
93
94 pub fn get_address_by_index(&self, index: NameIndex) -> Option<Address> {
95 let addr = unsafe { get_nlist_ea(index) };
96 if addr == BADADDR {
97 None
98 } else {
99 Some(addr.into())
100 }
101 }
102
103 pub fn has_name(&self, address: Address) -> bool {
104 unsafe { is_in_nlist(address.into()) }
105 }
106
107 pub fn len(&self) -> usize {
108 unsafe { get_nlist_size() }
109 }
110
111 pub fn is_empty(&self) -> bool {
112 self.len() == 0
113 }
114
115 pub fn iter(&self) -> NameListIter<'_, 'a> {
116 NameListIter {
117 name_list: self,
118 current_index: 0,
119 }
120 }
121}
122
123pub struct NameListIter<'s, 'a> {
124 name_list: &'s NameList<'a>,
125 current_index: NameIndex,
126}
127
128impl<'s, 'a> Iterator for NameListIter<'s, 'a> {
129 type Item = Name;
130
131 fn next(&mut self) -> Option<Self::Item> {
132 while self.current_index < self.name_list.len() {
133 let name = self.name_list.get_by_index(self.current_index);
134
135 self.current_index += 1;
136
137 if name.is_some() {
138 return name;
139 }
140 }
141 None
142 }
143}