1use std::marker::PhantomData;
2
3use crate::ffi::bytes::idalib_get_bytes;
4use crate::ffi::strings::{
5 build_strlist, clear_strlist, get_strlist_qty, idalib_get_strlist_item_addr,
6 idalib_get_strlist_item_length,
7};
8use crate::ffi::BADADDR;
9
10use crate::idb::IDB;
11use crate::Address;
12
13pub type StringIndex = usize;
14
15pub struct StringList<'a> {
16 _marker: PhantomData<&'a IDB>,
17}
18
19impl<'a> StringList<'a> {
20 pub(crate) fn new(_: &'a IDB) -> Self {
21 Self {
22 _marker: PhantomData,
23 }
24 }
25
26 pub fn rebuild(&self) {
27 unsafe { build_strlist() }
28 }
29
30 pub fn clear(&self) {
31 unsafe { clear_strlist() }
32 }
33
34 pub fn get_by_index(&self, index: StringIndex) -> Option<String> {
35 let addr = self.get_address_by_index(index)?;
36 let size = self.get_length_by_index(index);
37
38 let mut buf = Vec::with_capacity(size);
40 let Ok(new_len) = (unsafe { idalib_get_bytes(addr.into(), &mut buf) }) else {
41 return None;
42 };
43 unsafe {
44 buf.set_len(new_len);
45 }
46
47 Some(String::from_utf8_lossy(&buf).into_owned())
49 }
50
51 pub fn get_address_by_index(&self, index: StringIndex) -> Option<Address> {
52 let addr = unsafe { idalib_get_strlist_item_addr(index) };
53 if addr == BADADDR {
54 None
55 } else {
56 Some(addr.into())
57 }
58 }
59
60 fn get_length_by_index(&self, index: StringIndex) -> usize {
61 unsafe { idalib_get_strlist_item_length(index) }
62 }
63
64 pub fn len(&self) -> usize {
65 unsafe { get_strlist_qty() }
66 }
67
68 pub fn is_empty(&self) -> bool {
69 self.len() == 0
70 }
71
72 pub fn iter(&self) -> StringListIter<'_, 'a> {
73 StringListIter {
74 string_list: self,
75 current_index: 0,
76 }
77 }
78}
79
80pub struct StringListIter<'s, 'a> {
81 string_list: &'s StringList<'a>,
82 current_index: StringIndex,
83}
84
85impl<'s, 'a> Iterator for StringListIter<'s, 'a> {
86 type Item = (Address, String);
87
88 fn next(&mut self) -> Option<Self::Item> {
89 while self.current_index < self.string_list.len() {
90 let addr = self.string_list.get_address_by_index(self.current_index);
91 let string = self.string_list.get_by_index(self.current_index);
92
93 self.current_index += 1;
94
95 if let (Some(addr), Some(string)) = (addr, string) {
96 return Some((addr, string));
97 };
98 }
102 None
103 }
104}