idalib/
strings.rs

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        // See also `IDB::get_bytes`
39        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        // TODO: switch to `String::from_utf8_lossy_owned` once it's stable
48        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) -> StringIndex {
65        unsafe { get_strlist_qty() }
66    }
67
68    pub fn is_empty(&self) -> bool {
69        self.len() == 0
70    }
71}