/src/suricata/rust/htp/src/c_api/bstr.rs
Line | Count | Source |
1 | | use crate::bstr::Bstr; |
2 | | use core::cmp::Ordering; |
3 | | use std::{boxed::Box, ffi::CStr}; |
4 | | |
5 | | /// Allocate a zero-length bstring, reserving space for at least size bytes. |
6 | 0 | fn bstr_alloc(len: libc::size_t) -> *mut Bstr { |
7 | 0 | let b = Bstr::with_capacity(len); |
8 | 0 | let boxed = Box::new(b); |
9 | 0 | Box::into_raw(boxed) |
10 | 0 | } |
11 | | |
12 | | /// Deallocate the supplied bstring instance. Allows NULL on input. |
13 | | /// # Safety |
14 | | /// This function is unsafe because improper use may lead to memory problems. For example, a double-free may occur if the function is called twice on the same raw pointer. |
15 | | #[no_mangle] |
16 | 0 | pub unsafe extern "C" fn bstr_free(b: *mut Bstr) { |
17 | 0 | if !b.is_null() { |
18 | 0 | drop(Box::from_raw(b)); |
19 | 0 | } |
20 | 0 | } |
21 | | |
22 | | /// Return the length of the string |
23 | | /// # Safety |
24 | | /// x must be properly intialized: not NULL, dangling, or misaligned |
25 | | #[no_mangle] |
26 | 1.16M | pub unsafe extern "C" fn bstr_len(x: *const Bstr) -> libc::size_t { |
27 | 1.16M | (*x).len() |
28 | 1.16M | } |
29 | | |
30 | | /// Return a pointer to the bstr payload |
31 | | /// # Safety |
32 | | /// x must be properly intialized: not NULL, dangling, or misaligned |
33 | | #[no_mangle] |
34 | 2.39M | pub unsafe extern "C" fn bstr_ptr(x: *const Bstr) -> *mut libc::c_uchar { |
35 | 2.39M | (*x).as_ptr() as *mut u8 |
36 | 2.39M | } |
37 | | |
38 | | /// Return the capacity of the string |
39 | | /// # Safety |
40 | | /// x must be properly intialized: not NULL, dangling, or misaligned |
41 | | #[no_mangle] |
42 | 2.53k | pub unsafe extern "C" fn bstr_size(x: *const Bstr) -> libc::size_t { |
43 | 2.53k | (*x).capacity() |
44 | 2.53k | } |
45 | | |
46 | | /// Case-sensitive comparison of a bstring and a NUL-terminated string. |
47 | | /// returns -1 if b is less than c |
48 | | /// 0 if b is equal to c |
49 | | /// 1 if b is greater than c |
50 | | /// # Safety |
51 | | /// b and c must be properly intialized: not NULL, dangling, or misaligned. |
52 | | /// c must point to memory that contains a valid nul terminator byte at the end of the string |
53 | | #[no_mangle] |
54 | 3.72k | pub unsafe extern "C" fn bstr_cmp_c(b: *const Bstr, c: *const libc::c_char) -> libc::c_int { |
55 | 3.72k | let cs = CStr::from_ptr(c); |
56 | 3.72k | match (*b).cmp_slice(cs.to_bytes()) { |
57 | 1.63k | Ordering::Less => -1, |
58 | 1.51k | Ordering::Equal => 0, |
59 | 581 | Ordering::Greater => 1, |
60 | | } |
61 | 3.72k | } |
62 | | |
63 | | /// Case-indensitive comparison of a bstring and a NUL-terminated string. |
64 | | /// returns -1 if b is less than c |
65 | | /// 0 if b is equal to c |
66 | | /// 1 if b is greater than c |
67 | | /// # Safety |
68 | | /// b and c must be properly intialized: not NULL, dangling, or misaligned. |
69 | | /// c must point to memory that contains a valid nul terminator byte at the end of the string |
70 | | #[no_mangle] |
71 | 2.21k | pub unsafe extern "C" fn bstr_cmp_c_nocase(b: *const Bstr, c: *const libc::c_char) -> bool { |
72 | 2.21k | let cs = CStr::from_ptr(c); |
73 | 2.21k | (*b).cmp_nocase(cs.to_bytes()) |
74 | 2.21k | } |
75 | | |
76 | | /// Create a new bstring by copying the provided NUL-terminated string |
77 | | /// # Safety |
78 | | /// cstr must be properly intialized: not NULL, dangling, or misaligned. |
79 | | /// cstr must point to memory that contains a valid nul terminator byte at the end of the string |
80 | | #[no_mangle] |
81 | 0 | pub unsafe extern "C" fn bstr_dup_c(cstr: *const libc::c_char) -> *mut Bstr { |
82 | 0 | let cs = CStr::from_ptr(cstr).to_bytes(); |
83 | 0 | let new = bstr_alloc(cs.len()); |
84 | 0 | (*new).add(cs); |
85 | 0 | new |
86 | 0 | } |
87 | | |
88 | | /// Create a new NUL-terminated string out of the provided bstring. If NUL bytes |
89 | | /// are contained in the bstring, each will be replaced with "\0" (two characters). |
90 | | /// The caller is responsible to keep track of the allocated memory area and free |
91 | | /// it once it is no longer needed. |
92 | | /// returns The newly created NUL-terminated string, or NULL in case of memory |
93 | | /// allocation failure. |
94 | | /// # Safety |
95 | | /// b must be properly intialized and not dangling nor misaligned. |
96 | | #[no_mangle] |
97 | 0 | pub unsafe extern "C" fn bstr_util_strdup_to_c(b: *const Bstr) -> *mut libc::c_char { |
98 | 0 | if b.is_null() { |
99 | 0 | return std::ptr::null_mut(); |
100 | 0 | } |
101 | 0 | let src = std::slice::from_raw_parts(bstr_ptr(b), bstr_len(b)); |
102 | | |
103 | | // Since the memory returned here is just a char* and the caller will |
104 | | // free() it we have to use malloc() here. |
105 | | // So we allocate enough space for doubled NULL bytes plus the trailing NULL. |
106 | 0 | let mut null_count = 1; |
107 | 0 | for byte in src { |
108 | 0 | if *byte == 0 { |
109 | 0 | null_count += 1; |
110 | 0 | } |
111 | | } |
112 | 0 | let newlen = bstr_len(b) + null_count; |
113 | 0 | let mem = libc::malloc(newlen) as *mut libc::c_char; |
114 | 0 | if mem.is_null() { |
115 | 0 | return std::ptr::null_mut(); |
116 | 0 | } |
117 | 0 | let dst: &mut [libc::c_char] = std::slice::from_raw_parts_mut(mem, newlen); |
118 | 0 | let mut dst_idx = 0; |
119 | 0 | for byte in src { |
120 | 0 | if *byte == 0 { |
121 | 0 | dst[dst_idx] = '\\' as libc::c_char; |
122 | 0 | dst_idx += 1; |
123 | 0 | dst[dst_idx] = '0' as libc::c_char; |
124 | 0 | } else { |
125 | 0 | dst[dst_idx] = *byte as libc::c_char; |
126 | 0 | } |
127 | 0 | dst_idx += 1; |
128 | | } |
129 | 0 | dst[dst_idx] = 0; |
130 | | |
131 | 0 | mem |
132 | 0 | } |
133 | | |
134 | | #[cfg(test)] |
135 | | mod test { |
136 | | use super::*; |
137 | | use std::ffi::CString; |
138 | | |
139 | | macro_rules! cstr { |
140 | | ( $x:expr ) => {{ |
141 | | CString::new($x).unwrap() |
142 | | }}; |
143 | | } |
144 | | |
145 | | #[test] |
146 | | fn Bstr_Alloc() { |
147 | | unsafe { |
148 | | let p1 = bstr_alloc(10); |
149 | | assert_eq!(10, bstr_size(p1)); |
150 | | assert_eq!(0, bstr_len(p1)); |
151 | | bstr_free(p1); |
152 | | } |
153 | | } |
154 | | |
155 | | #[test] |
156 | | fn Bstr_DupC() { |
157 | | unsafe { |
158 | | let p1 = bstr_dup_c(cstr!("arfarf").as_ptr()); |
159 | | |
160 | | assert_eq!(6, bstr_size(p1)); |
161 | | assert_eq!(6, bstr_len(p1)); |
162 | | assert_eq!( |
163 | | 0, |
164 | | libc::memcmp( |
165 | | cstr!("arfarf").as_ptr() as *const core::ffi::c_void, |
166 | | bstr_ptr(p1) as *const core::ffi::c_void, |
167 | | 6 |
168 | | ) |
169 | | ); |
170 | | bstr_free(p1); |
171 | | } |
172 | | } |
173 | | |
174 | | #[test] |
175 | | fn Bstr_UtilDupToC() { |
176 | | unsafe { |
177 | | let s = Bstr::from(b"ABCDEFGHIJKL\x00NOPQRST" as &[u8]); |
178 | | let c = bstr_util_strdup_to_c(&s); |
179 | | let e = CString::new("ABCDEFGHIJKL\\0NOPQRST").unwrap(); |
180 | | assert_eq!(0, libc::strcmp(e.as_ptr(), c)); |
181 | | |
182 | | libc::free(c as *mut core::ffi::c_void); |
183 | | } |
184 | | } |
185 | | |
186 | | #[test] |
187 | | fn Bstr_CmpC() { |
188 | | unsafe { |
189 | | let p1 = Bstr::from("arfarf"); |
190 | | assert_eq!(0, bstr_cmp_c(&p1, cstr!("arfarf").as_ptr())); |
191 | | assert_eq!(-1, bstr_cmp_c(&p1, cstr!("arfarf2").as_ptr())); |
192 | | assert_eq!(1, bstr_cmp_c(&p1, cstr!("arf").as_ptr())); |
193 | | assert_eq!(-1, bstr_cmp_c(&p1, cstr!("not equal").as_ptr())); |
194 | | } |
195 | | } |
196 | | } |