binaryninja/high_level_il/
token_emitter.rs1use std::ptr::NonNull;
2
3use binaryninjacore_sys::*;
4
5use crate::disassembly::{
6 DisassemblySettings, DisassemblyTextLine, InstructionTextToken, InstructionTextTokenContext,
7 InstructionTextTokenType,
8};
9use crate::high_level_il::HighLevelILFunction;
10use crate::language_representation::{OperatorPrecedence, SymbolDisplayResult, SymbolDisplayType};
11use crate::rc::{Array, Ref, RefCountable};
12use crate::variable::Variable;
13
14pub type ScopeType = BNScopeType;
15pub type TokenEmitterExpr = BNTokenEmitterExpr;
16pub type BraceRequirement = BNBraceRequirement;
17
18#[derive(PartialEq, Eq, Hash)]
19pub struct HighLevelILTokenEmitter {
20 handle: NonNull<BNHighLevelILTokenEmitter>,
21}
22
23impl HighLevelILTokenEmitter {
24 pub(crate) unsafe fn from_raw(handle: NonNull<BNHighLevelILTokenEmitter>) -> Self {
25 Self { handle }
26 }
27
28 pub fn current_tokens(&self) -> Array<InstructionTextToken> {
30 let mut count = 0;
31 let array =
32 unsafe { BNHighLevelILTokenEmitterGetCurrentTokens(self.handle.as_ptr(), &mut count) };
33 unsafe { Array::new(array, count, ()) }
34 }
35
36 pub fn lines(&self) -> Array<DisassemblyTextLine> {
38 let mut count = 0;
39 let array = unsafe { BNHighLevelILTokenEmitterGetLines(self.handle.as_ptr(), &mut count) };
40 unsafe { Array::new(array, count, ()) }
41 }
42
43 pub fn prepend_collapse_blank_indicator(&self) {
44 unsafe { BNHighLevelILTokenPrependCollapseBlankIndicator(self.handle.as_ptr()) };
45 }
46
47 pub fn prepend_collapse_indicator(&self, context: InstructionTextTokenContext, hash: u64) {
48 unsafe {
49 BNHighLevelILTokenPrependCollapseIndicator(self.handle.as_ptr(), context.into(), hash)
50 };
51 }
52
53 pub fn has_collapsible_regions(&self) -> bool {
54 unsafe { BNHighLevelILTokenEmitterHasCollapsableRegions(self.handle.as_ptr()) }
55 }
56
57 pub fn set_has_collapsible_regions(&self, state: bool) {
58 unsafe { BNHighLevelILTokenEmitterSetHasCollapsableRegions(self.handle.as_ptr(), state) };
59 }
60
61 pub fn append(&self, token: InstructionTextToken) {
62 let mut raw_token = InstructionTextToken::into_raw(token);
63 unsafe { BNHighLevelILTokenEmitterAppend(self.handle.as_ptr(), &mut raw_token) };
64 InstructionTextToken::free_raw(raw_token);
65 }
66
67 pub fn init_line(&self) {
69 unsafe { BNHighLevelILTokenEmitterInitLine(self.handle.as_ptr()) };
70 }
71
72 pub fn new_line(&self) {
75 unsafe { BNHighLevelILTokenEmitterNewLine(self.handle.as_ptr()) };
76 }
77
78 pub fn increase_indent(&self) {
80 unsafe { BNHighLevelILTokenEmitterIncreaseIndent(self.handle.as_ptr()) };
81 }
82
83 pub fn decrease_indent(&self) {
85 unsafe { BNHighLevelILTokenEmitterDecreaseIndent(self.handle.as_ptr()) };
86 }
87
88 pub fn scope_separator(&self) {
92 unsafe { BNHighLevelILTokenEmitterScopeSeparator(self.handle.as_ptr()) };
93 }
94
95 pub fn begin_scope(&self, ty: ScopeType) {
97 unsafe { BNHighLevelILTokenEmitterBeginScope(self.handle.as_ptr(), ty) };
98 }
99
100 pub fn end_scope(&self, ty: ScopeType) {
104 unsafe { BNHighLevelILTokenEmitterEndScope(self.handle.as_ptr(), ty) };
105 }
106
107 pub fn scope_continuation(&self, force_same_line: bool) {
111 unsafe {
112 BNHighLevelILTokenEmitterScopeContinuation(self.handle.as_ptr(), force_same_line)
113 };
114 }
115
116 pub fn finalize_scope(&self) {
118 unsafe { BNHighLevelILTokenEmitterFinalizeScope(self.handle.as_ptr()) };
119 }
120
121 pub fn no_indent_for_this_line(&self) {
123 unsafe { BNHighLevelILTokenEmitterNoIndentForThisLine(self.handle.as_ptr()) };
124 }
125
126 pub fn begin_force_zero_confidence(&self) {
128 unsafe { BNHighLevelILTokenEmitterBeginForceZeroConfidence(self.handle.as_ptr()) };
129 }
130
131 pub fn end_force_zero_confidence(&self) {
133 unsafe { BNHighLevelILTokenEmitterEndForceZeroConfidence(self.handle.as_ptr()) };
134 }
135
136 pub fn set_current_expr(&self, expr: TokenEmitterExpr) -> CurrentTokenEmitterExpr {
139 let previous_expr =
140 unsafe { BNHighLevelILTokenEmitterSetCurrentExpr(self.handle.as_ptr(), expr) };
141 CurrentTokenEmitterExpr::new(self.to_owned(), expr, previous_expr)
142 }
143
144 fn restore_current_expr(&self, expr: TokenEmitterExpr) {
145 unsafe { BNHighLevelILTokenEmitterRestoreCurrentExpr(self.handle.as_ptr(), expr) };
146 }
147
148 pub fn finalize(&self) {
150 unsafe { BNHighLevelILTokenEmitterFinalize(self.handle.as_ptr()) };
151 }
152
153 pub fn append_open_paren(&self) {
155 unsafe { BNHighLevelILTokenEmitterAppendOpenParen(self.handle.as_ptr()) };
156 }
157
158 pub fn append_close_paren(&self) {
160 unsafe { BNHighLevelILTokenEmitterAppendCloseParen(self.handle.as_ptr()) };
161 }
162
163 pub fn append_open_bracket(&self) {
165 unsafe { BNHighLevelILTokenEmitterAppendOpenBracket(self.handle.as_ptr()) };
166 }
167
168 pub fn append_close_bracket(&self) {
170 unsafe { BNHighLevelILTokenEmitterAppendCloseBracket(self.handle.as_ptr()) };
171 }
172
173 pub fn append_open_brace(&self) {
175 unsafe { BNHighLevelILTokenEmitterAppendOpenBrace(self.handle.as_ptr()) };
176 }
177
178 pub fn append_close_brace(&self) {
180 unsafe { BNHighLevelILTokenEmitterAppendCloseBrace(self.handle.as_ptr()) };
181 }
182
183 pub fn append_semicolon(&self) {
185 unsafe { BNHighLevelILTokenEmitterAppendSemicolon(self.handle.as_ptr()) };
186 }
187
188 pub fn set_brace_requirement(&self, required: BraceRequirement) {
190 unsafe { BNHighLevelILTokenEmitterSetBraceRequirement(self.handle.as_ptr(), required) };
191 }
192
193 pub fn set_braces_around_switch_cases(&self, braces: bool) {
195 unsafe {
196 BNHighLevelILTokenEmitterSetBracesAroundSwitchCases(self.handle.as_ptr(), braces)
197 };
198 }
199
200 pub fn set_default_braces_on_same_line(&self, same_line: bool) {
204 unsafe {
205 BNHighLevelILTokenEmitterSetDefaultBracesOnSameLine(self.handle.as_ptr(), same_line)
206 };
207 }
208
209 pub fn set_simple_scope_allowed(&self, allowed: bool) {
211 unsafe { BNHighLevelILTokenEmitterSetSimpleScopeAllowed(self.handle.as_ptr(), allowed) };
212 }
213
214 pub fn brace_requirement(&self) -> BraceRequirement {
215 unsafe { BNHighLevelILTokenEmitterGetBraceRequirement(self.handle.as_ptr()) }
216 }
217
218 pub fn has_braces_around_switch_cases(&self) -> bool {
219 unsafe { BNHighLevelILTokenEmitterHasBracesAroundSwitchCases(self.handle.as_ptr()) }
220 }
221
222 pub fn default_braces_on_same_line(&self) -> bool {
223 unsafe { BNHighLevelILTokenEmitterGetDefaultBracesOnSameLine(self.handle.as_ptr()) }
224 }
225
226 pub fn is_simple_scope_allowed(&self) -> bool {
227 unsafe { BNHighLevelILTokenEmitterIsSimpleScopeAllowed(self.handle.as_ptr()) }
228 }
229
230 pub fn append_size_token(&self, size: usize, ty: InstructionTextTokenType) {
232 unsafe { BNAddHighLevelILSizeToken(size, ty, self.handle.as_ptr()) }
233 }
234
235 pub fn append_float_size_token(&self, size: usize, ty: InstructionTextTokenType) {
237 unsafe { BNAddHighLevelILFloatSizeToken(size, ty, self.handle.as_ptr()) }
238 }
239
240 pub fn append_var_text_token(
242 &self,
243 func: &HighLevelILFunction,
244 var: Variable,
245 expr_index: usize,
246 size: usize,
247 ) {
248 unsafe {
249 BNAddHighLevelILVarTextToken(
250 func.handle,
251 &BNVariable::from(var),
252 self.handle.as_ptr(),
253 expr_index,
254 size,
255 )
256 }
257 }
258
259 pub fn append_integer_text_token(
261 &self,
262 func: &HighLevelILFunction,
263 expr_index: usize,
264 val: i64,
265 size: usize,
266 ) {
267 unsafe {
268 BNAddHighLevelILIntegerTextToken(
269 func.handle,
270 expr_index,
271 val,
272 size,
273 self.handle.as_ptr(),
274 )
275 }
276 }
277
278 pub fn append_array_index_token(
280 &self,
281 func: &HighLevelILFunction,
282 expr_index: usize,
283 val: i64,
284 size: usize,
285 address: Option<u64>,
286 ) {
287 unsafe {
288 BNAddHighLevelILArrayIndexToken(
289 func.handle,
290 expr_index,
291 val,
292 size,
293 self.handle.as_ptr(),
294 address.unwrap_or(0),
295 )
296 }
297 }
298
299 pub fn append_pointer_text_token(
303 &self,
304 func: &HighLevelILFunction,
305 expr_index: usize,
306 val: i64,
307 settings: &DisassemblySettings,
308 symbol_display: SymbolDisplayType,
309 precedence: OperatorPrecedence,
310 allow_short_string: bool,
311 ) -> SymbolDisplayResult {
312 unsafe {
313 BNAddHighLevelILPointerTextToken(
314 func.handle,
315 expr_index,
316 val,
317 self.handle.as_ptr(),
318 settings.handle,
319 symbol_display,
320 precedence,
321 allow_short_string,
322 )
323 }
324 }
325
326 pub fn append_constant_text_token(
328 &self,
329 func: &HighLevelILFunction,
330 expr_index: usize,
331 val: i64,
332 size: usize,
333 settings: &DisassemblySettings,
334 precedence: OperatorPrecedence,
335 ) {
336 unsafe {
337 BNAddHighLevelILConstantTextToken(
338 func.handle,
339 expr_index,
340 val,
341 size,
342 self.handle.as_ptr(),
343 settings.handle,
344 precedence,
345 )
346 }
347 }
348}
349
350unsafe impl Send for HighLevelILTokenEmitter {}
351unsafe impl Sync for HighLevelILTokenEmitter {}
352
353unsafe impl RefCountable for HighLevelILTokenEmitter {
354 unsafe fn inc_ref(handle: &Self) -> Ref<Self> {
355 let handle = BNNewHighLevelILTokenEmitterReference(handle.handle.as_ptr());
356 let handle = NonNull::new(handle).unwrap();
357 Ref::new(HighLevelILTokenEmitter { handle })
358 }
359
360 unsafe fn dec_ref(handle: &Self) {
361 BNFreeHighLevelILTokenEmitter(handle.handle.as_ptr())
362 }
363}
364
365impl ToOwned for HighLevelILTokenEmitter {
366 type Owned = Ref<Self>;
367
368 fn to_owned(&self) -> Self::Owned {
369 unsafe { RefCountable::inc_ref(self) }
370 }
371}
372
373pub struct CurrentTokenEmitterExpr {
377 pub emitter: Ref<HighLevelILTokenEmitter>,
378 pub expr: TokenEmitterExpr,
379 pub previous_expr: TokenEmitterExpr,
380}
381
382impl CurrentTokenEmitterExpr {
383 pub fn new(
384 emitter: Ref<HighLevelILTokenEmitter>,
385 expr: TokenEmitterExpr,
386 previous_expr: TokenEmitterExpr,
387 ) -> Self {
388 Self {
389 emitter,
390 expr,
391 previous_expr,
392 }
393 }
394}
395
396impl Drop for CurrentTokenEmitterExpr {
397 fn drop(&mut self) {
398 self.emitter.restore_current_expr(self.previous_expr);
399 }
400}