yara-ffi 3.1.0 → 4.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,161 @@
1
+ module Yara
2
+ # Public: Wrapper around the YARA-X YRX_COMPILER API.
3
+ #
4
+ # This class allows adding multiple sources, defining globals before
5
+ # compilation, and building a YRX_RULES object that can be used by
6
+ # {Yara::Scanner}.
7
+ class Compiler
8
+ class CompileError < StandardError; end
9
+
10
+ def initialize(flags = 0)
11
+ @compiler_ptr_holder = ::FFI::MemoryPointer.new(:pointer)
12
+ result = Yara::FFI.yrx_compiler_create(flags, @compiler_ptr_holder)
13
+ if result != Yara::FFI.yrx_last_error && result != Yara::FFI::YRX_SUCCESS
14
+ # Defensive: use yrx_last_error for message but prefer success check
15
+ end
16
+
17
+ if result != Yara::FFI::YRX_SUCCESS
18
+ raise CompileError, "Failed to create compiler: #{Yara::FFI.yrx_last_error}"
19
+ end
20
+ @compiler = @compiler_ptr_holder.get_pointer(0)
21
+ end
22
+
23
+ def add_source(src, origin = nil)
24
+ if origin
25
+ result = Yara::FFI.yrx_compiler_add_source_with_origin(@compiler, src, origin)
26
+ else
27
+ result = Yara::FFI.yrx_compiler_add_source(@compiler, src)
28
+ end
29
+
30
+ if result != Yara::FFI::YRX_SUCCESS
31
+ raise CompileError, "Failed to add source: #{Yara::FFI.yrx_last_error}"
32
+ end
33
+ nil
34
+ end
35
+
36
+ def define_global_str(ident, value)
37
+ result = Yara::FFI.yrx_compiler_define_global_str(@compiler, ident, value)
38
+ if result != Yara::FFI::YRX_SUCCESS
39
+ raise CompileError, "Failed to define global str #{ident}: #{Yara::FFI.yrx_last_error}"
40
+ end
41
+ nil
42
+ end
43
+
44
+ def define_global_bool(ident, value)
45
+ result = Yara::FFI.yrx_compiler_define_global_bool(@compiler, ident, !!value)
46
+ if result != Yara::FFI::YRX_SUCCESS
47
+ raise CompileError, "Failed to define global bool #{ident}: #{Yara::FFI.yrx_last_error}"
48
+ end
49
+ nil
50
+ end
51
+
52
+ def define_global_int(ident, value)
53
+ result = Yara::FFI.yrx_compiler_define_global_int(@compiler, ident, value)
54
+ if result != Yara::FFI::YRX_SUCCESS
55
+ raise CompileError, "Failed to define global int #{ident}: #{Yara::FFI.yrx_last_error}"
56
+ end
57
+ nil
58
+ end
59
+
60
+ def define_global_float(ident, value)
61
+ result = Yara::FFI.yrx_compiler_define_global_float(@compiler, ident, value)
62
+ if result != Yara::FFI::YRX_SUCCESS
63
+ raise CompileError, "Failed to define global float #{ident}: #{Yara::FFI.yrx_last_error}"
64
+ end
65
+ nil
66
+ end
67
+
68
+ # Build and return a pointer to YRX_RULES. The caller is responsible for
69
+ # calling yrx_rules_destroy on the returned pointer when finished.
70
+ def build
71
+ rules_ptr = Yara::FFI.yrx_compiler_build(@compiler)
72
+ if rules_ptr.nil? || rules_ptr.null?
73
+ raise CompileError, "Failed to build rules: #{Yara::FFI.yrx_last_error}"
74
+ end
75
+ rules_ptr
76
+ end
77
+
78
+ # Public: Build and return a serialized representation of compiled rules.
79
+ #
80
+ # Compiles the currently added sources (via add_source) into a YRX_RULES
81
+ # object and serializes it into a binary blob suitable for persistence or
82
+ # transport. The returned String contains the serialized rules and can be
83
+ # deserialized later with Yara::Scanner.from_serialized or the underlying
84
+ # yrx_rules_deserialize FFI call.
85
+ #
86
+ # Returns a String containing binary serialized rules (raw bytes).
87
+ # Raises CompileError if compilation or serialization fails.
88
+ def build_serialized
89
+ rules_ptr = build
90
+
91
+ buf_ptr_holder = ::FFI::MemoryPointer.new(:pointer)
92
+ result = Yara::FFI.yrx_rules_serialize(rules_ptr, buf_ptr_holder)
93
+
94
+ # Destroy the rules pointer after serialization (we own it from build)
95
+ Yara::FFI.yrx_rules_destroy(rules_ptr)
96
+
97
+ if result != Yara::FFI::YRX_SUCCESS
98
+ raise CompileError, "Failed to serialize rules: #{Yara::FFI.yrx_last_error}"
99
+ end
100
+
101
+ buf_ptr = buf_ptr_holder.get_pointer(0)
102
+ buffer = Yara::FFI::YRX_BUFFER.new(buf_ptr)
103
+ begin
104
+ data_ptr = buffer[:data]
105
+ length = buffer[:length]
106
+ str = data_ptr.get_bytes(0, length)
107
+ return str
108
+ ensure
109
+ Yara::FFI.yrx_buffer_destroy(buf_ptr)
110
+ end
111
+ end
112
+
113
+ # Return compilation errors as a parsed JSON object (Array of error objects).
114
+ # This uses yrx_compiler_errors_json which returns a YRX_BUFFER containing
115
+ # the JSON serialization. The buffer is destroyed after being converted.
116
+ def errors_json
117
+ buf_ptr_holder = ::FFI::MemoryPointer.new(:pointer)
118
+ result = Yara::FFI.yrx_compiler_errors_json(@compiler, buf_ptr_holder)
119
+ if result != Yara::FFI::YRX_SUCCESS
120
+ raise CompileError, "Failed to get errors JSON: #{Yara::FFI.yrx_last_error}"
121
+ end
122
+
123
+ buf_ptr = buf_ptr_holder.get_pointer(0)
124
+ buffer = Yara::FFI::YRX_BUFFER.new(buf_ptr)
125
+ data_ptr = buffer[:data]
126
+ length = buffer[:length]
127
+ json_str = data_ptr.read_string_length(length)
128
+ Yara::FFI.yrx_buffer_destroy(buf_ptr)
129
+
130
+ JSON.parse(json_str)
131
+ end
132
+
133
+ # Return compilation warnings as parsed JSON (Array of warning objects).
134
+ def warnings_json
135
+ buf_ptr_holder = ::FFI::MemoryPointer.new(:pointer)
136
+ result = Yara::FFI.yrx_compiler_warnings_json(@compiler, buf_ptr_holder)
137
+ if result != Yara::FFI::YRX_SUCCESS
138
+ raise CompileError, "Failed to get warnings JSON: #{Yara::FFI.yrx_last_error}"
139
+ end
140
+
141
+ buf_ptr = buf_ptr_holder.get_pointer(0)
142
+ buffer = Yara::FFI::YRX_BUFFER.new(buf_ptr)
143
+ data_ptr = buffer[:data]
144
+ length = buffer[:length]
145
+ json_str = data_ptr.read_string_length(length)
146
+ Yara::FFI.yrx_buffer_destroy(buf_ptr)
147
+
148
+ JSON.parse(json_str)
149
+ end
150
+
151
+ def destroy
152
+ Yara::FFI.yrx_compiler_destroy(@compiler) if @compiler
153
+ @compiler = nil
154
+ end
155
+
156
+ # Ensure resources are cleaned up.
157
+ def finalize
158
+ destroy
159
+ end
160
+ end
161
+ end