/src/yara/libyara/object.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | Copyright (c) 2014. The YARA Authors. All Rights Reserved. |
3 | | |
4 | | Redistribution and use in source and binary forms, with or without modification, |
5 | | are permitted provided that the following conditions are met: |
6 | | |
7 | | 1. Redistributions of source code must retain the above copyright notice, this |
8 | | list of conditions and the following disclaimer. |
9 | | |
10 | | 2. Redistributions in binary form must reproduce the above copyright notice, |
11 | | this list of conditions and the following disclaimer in the documentation and/or |
12 | | other materials provided with the distribution. |
13 | | |
14 | | 3. Neither the name of the copyright holder nor the names of its contributors |
15 | | may be used to endorse or promote products derived from this software without |
16 | | specific prior written permission. |
17 | | |
18 | | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND |
19 | | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
20 | | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
21 | | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR |
22 | | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
23 | | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
24 | | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON |
25 | | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
26 | | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
27 | | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
28 | | */ |
29 | | |
30 | | #include <assert.h> |
31 | | #include <ctype.h> |
32 | | #include <math.h> |
33 | | #include <stdarg.h> |
34 | | #include <stdio.h> |
35 | | #include <stdlib.h> |
36 | | #include <string.h> |
37 | | #include <yara/error.h> |
38 | | #include <yara/exec.h> |
39 | | #include <yara/globals.h> |
40 | | #include <yara/mem.h> |
41 | | #include <yara/object.h> |
42 | | #include <yara/strutils.h> |
43 | | #include <yara/utils.h> |
44 | | |
45 | | //////////////////////////////////////////////////////////////////////////////// |
46 | | // Creates a new object with the given type and identifier. If a parent is |
47 | | // specified the new object is owned by the parent and it will be destroyed when |
48 | | // the parent is destroyed. You must not call yr_object_destroy on an objected |
49 | | // that has a parent, you should destroy the parent instead. |
50 | | // |
51 | | int yr_object_create( |
52 | | int8_t type, |
53 | | const char* identifier, |
54 | | YR_OBJECT* parent, |
55 | | YR_OBJECT** object) |
56 | 9.34M | { |
57 | 9.34M | YR_OBJECT* obj; |
58 | 9.34M | size_t object_size = 0; |
59 | | |
60 | 9.34M | assert(parent != NULL || object != NULL); |
61 | 9.34M | assert(identifier != NULL); |
62 | | |
63 | 9.34M | switch (type) |
64 | 9.34M | { |
65 | 1.45M | case OBJECT_TYPE_STRUCTURE: |
66 | 1.45M | object_size = sizeof(YR_OBJECT_STRUCTURE); |
67 | 1.45M | break; |
68 | 40.0k | case OBJECT_TYPE_ARRAY: |
69 | 40.0k | object_size = sizeof(YR_OBJECT_ARRAY); |
70 | 40.0k | break; |
71 | 0 | case OBJECT_TYPE_DICTIONARY: |
72 | 0 | object_size = sizeof(YR_OBJECT_DICTIONARY); |
73 | 0 | break; |
74 | 7.28M | case OBJECT_TYPE_INTEGER: |
75 | 7.28M | object_size = sizeof(YR_OBJECT); |
76 | 7.28M | break; |
77 | 0 | case OBJECT_TYPE_FLOAT: |
78 | 0 | object_size = sizeof(YR_OBJECT); |
79 | 0 | break; |
80 | 557k | case OBJECT_TYPE_STRING: |
81 | 557k | object_size = sizeof(YR_OBJECT); |
82 | 557k | break; |
83 | 8.00k | case OBJECT_TYPE_FUNCTION: |
84 | 8.00k | object_size = sizeof(YR_OBJECT_FUNCTION); |
85 | 8.00k | break; |
86 | 0 | default: |
87 | 0 | assert(false); |
88 | 9.34M | } |
89 | | |
90 | 9.34M | obj = (YR_OBJECT*) yr_malloc(object_size); |
91 | | |
92 | 9.34M | if (obj == NULL) |
93 | 0 | return ERROR_INSUFFICIENT_MEMORY; |
94 | | |
95 | 9.34M | obj->type = type; |
96 | 9.34M | obj->identifier = yr_strdup(identifier); |
97 | 9.34M | obj->parent = parent; |
98 | 9.34M | obj->data = NULL; |
99 | | |
100 | 9.34M | switch (type) |
101 | 9.34M | { |
102 | 7.28M | case OBJECT_TYPE_INTEGER: |
103 | 7.28M | obj->value.i = YR_UNDEFINED; |
104 | 7.28M | break; |
105 | 0 | case OBJECT_TYPE_FLOAT: |
106 | 0 | obj->value.d = NAN; |
107 | 0 | break; |
108 | 557k | case OBJECT_TYPE_STRING: |
109 | 557k | obj->value.ss = NULL; |
110 | 557k | break; |
111 | 1.45M | case OBJECT_TYPE_STRUCTURE: |
112 | 1.45M | object_as_structure(obj)->members = NULL; |
113 | 1.45M | break; |
114 | 40.0k | case OBJECT_TYPE_ARRAY: |
115 | 40.0k | object_as_array(obj)->items = NULL; |
116 | 40.0k | object_as_array(obj)->prototype_item = NULL; |
117 | 40.0k | break; |
118 | 0 | case OBJECT_TYPE_DICTIONARY: |
119 | 0 | object_as_dictionary(obj)->items = NULL; |
120 | 0 | object_as_dictionary(obj)->prototype_item = NULL; |
121 | 0 | break; |
122 | 8.00k | case OBJECT_TYPE_FUNCTION: |
123 | 8.00k | object_as_function(obj)->return_obj = NULL; |
124 | 88.0k | for (int i = 0; i < YR_MAX_OVERLOADED_FUNCTIONS; i++) |
125 | 80.0k | { |
126 | 80.0k | object_as_function(obj)->prototypes[i].arguments_fmt = NULL; |
127 | 80.0k | object_as_function(obj)->prototypes[i].code = NULL; |
128 | 80.0k | } |
129 | 8.00k | break; |
130 | 9.34M | } |
131 | | |
132 | 9.34M | if (obj->identifier == NULL) |
133 | 0 | { |
134 | 0 | yr_free(obj); |
135 | 0 | return ERROR_INSUFFICIENT_MEMORY; |
136 | 0 | } |
137 | | |
138 | 9.34M | if (parent != NULL) |
139 | 1.12M | { |
140 | 1.12M | assert( |
141 | 1.12M | parent->type == OBJECT_TYPE_STRUCTURE || |
142 | 1.12M | parent->type == OBJECT_TYPE_ARRAY || |
143 | 1.12M | parent->type == OBJECT_TYPE_DICTIONARY || |
144 | 1.12M | parent->type == OBJECT_TYPE_FUNCTION); |
145 | | |
146 | | // Objects with a parent take the canary from it. |
147 | 1.12M | obj->canary = parent->canary; |
148 | | |
149 | 1.12M | switch (parent->type) |
150 | 1.12M | { |
151 | 1.08M | case OBJECT_TYPE_STRUCTURE: |
152 | 1.08M | FAIL_ON_ERROR_WITH_CLEANUP(yr_object_structure_set_member(parent, obj), { |
153 | 1.08M | yr_free((void*) obj->identifier); |
154 | 1.08M | yr_free(obj); |
155 | 1.08M | }); |
156 | 1.08M | break; |
157 | | |
158 | 40.0k | case OBJECT_TYPE_ARRAY: |
159 | 40.0k | object_as_array(parent)->prototype_item = obj; |
160 | 40.0k | break; |
161 | | |
162 | 0 | case OBJECT_TYPE_DICTIONARY: |
163 | 0 | object_as_dictionary(parent)->prototype_item = obj; |
164 | 0 | break; |
165 | | |
166 | 8.00k | case OBJECT_TYPE_FUNCTION: |
167 | 8.00k | object_as_function(parent)->return_obj = obj; |
168 | 8.00k | break; |
169 | 1.12M | } |
170 | 1.12M | } |
171 | | |
172 | 9.34M | if (object != NULL) |
173 | 8.31M | *object = obj; |
174 | | |
175 | 9.34M | return ERROR_SUCCESS; |
176 | 9.34M | } |
177 | | |
178 | | void yr_object_set_canary(YR_OBJECT* object, int canary) |
179 | 8.00k | { |
180 | 8.00k | object->canary = canary; |
181 | 8.00k | } |
182 | | |
183 | | int yr_object_function_create( |
184 | | const char* identifier, |
185 | | const char* arguments_fmt, |
186 | | const char* return_fmt, |
187 | | YR_MODULE_FUNC code, |
188 | | YR_OBJECT* parent, |
189 | | YR_OBJECT** function) |
190 | 8.00k | { |
191 | 8.00k | YR_OBJECT* return_obj; |
192 | 8.00k | YR_OBJECT* o = NULL; |
193 | 8.00k | YR_OBJECT_FUNCTION* f = NULL; |
194 | | |
195 | 8.00k | int8_t return_type; |
196 | | |
197 | | // The parent of a function must be a structure. |
198 | 8.00k | assert(parent != NULL && parent->type == OBJECT_TYPE_STRUCTURE); |
199 | | |
200 | 8.00k | switch (*return_fmt) |
201 | 8.00k | { |
202 | 0 | case 'i': |
203 | 0 | return_type = OBJECT_TYPE_INTEGER; |
204 | 0 | break; |
205 | 8.00k | case 's': |
206 | 8.00k | return_type = OBJECT_TYPE_STRING; |
207 | 8.00k | break; |
208 | 0 | case 'f': |
209 | 0 | return_type = OBJECT_TYPE_FLOAT; |
210 | 0 | break; |
211 | 0 | default: |
212 | 0 | return ERROR_INVALID_FORMAT; |
213 | 8.00k | } |
214 | | |
215 | | // Try to find if the structure already has a function |
216 | | // with that name. In that case this is a function overload. |
217 | 8.00k | f = object_as_function(yr_object_lookup_field(parent, identifier)); |
218 | | |
219 | | // Overloaded functions must have the same return type. |
220 | 8.00k | if (f != NULL && return_type != f->return_obj->type) |
221 | 0 | return ERROR_WRONG_RETURN_TYPE; |
222 | | |
223 | 8.00k | if (f == NULL) // Function doesn't exist yet |
224 | 8.00k | { |
225 | 8.00k | FAIL_ON_ERROR( |
226 | 8.00k | yr_object_create(OBJECT_TYPE_FUNCTION, identifier, parent, &o)); |
227 | | |
228 | | // In case of failure while creating return_obj we don't need to free the |
229 | | // previously created "o" object, as it is already associated with its |
230 | | // parent and will be destroyed when the parent is destroyed. |
231 | 8.00k | FAIL_ON_ERROR(yr_object_create(return_type, "result", o, &return_obj)); |
232 | | |
233 | 8.00k | f = object_as_function(o); |
234 | 8.00k | } |
235 | | |
236 | 8.00k | for (int i = 0; i < YR_MAX_OVERLOADED_FUNCTIONS; i++) |
237 | 8.00k | { |
238 | 8.00k | if (f->prototypes[i].arguments_fmt == NULL) |
239 | 8.00k | { |
240 | 8.00k | f->prototypes[i].arguments_fmt = arguments_fmt; |
241 | 8.00k | f->prototypes[i].code = code; |
242 | | |
243 | 8.00k | break; |
244 | 8.00k | } |
245 | 8.00k | } |
246 | | |
247 | 8.00k | if (function != NULL) |
248 | 8.00k | *function = (YR_OBJECT*) f; |
249 | | |
250 | 8.00k | return ERROR_SUCCESS; |
251 | 8.00k | } |
252 | | |
253 | | int yr_object_from_external_variable( |
254 | | YR_EXTERNAL_VARIABLE* external, |
255 | | YR_OBJECT** object) |
256 | 0 | { |
257 | 0 | YR_OBJECT* obj; |
258 | 0 | int result; |
259 | 0 | uint8_t obj_type = 0; |
260 | |
|
261 | 0 | switch (external->type) |
262 | 0 | { |
263 | 0 | case EXTERNAL_VARIABLE_TYPE_INTEGER: |
264 | 0 | case EXTERNAL_VARIABLE_TYPE_BOOLEAN: |
265 | 0 | obj_type = OBJECT_TYPE_INTEGER; |
266 | 0 | break; |
267 | | |
268 | 0 | case EXTERNAL_VARIABLE_TYPE_FLOAT: |
269 | 0 | obj_type = OBJECT_TYPE_FLOAT; |
270 | 0 | break; |
271 | | |
272 | 0 | case EXTERNAL_VARIABLE_TYPE_STRING: |
273 | 0 | case EXTERNAL_VARIABLE_TYPE_MALLOC_STRING: |
274 | 0 | obj_type = OBJECT_TYPE_STRING; |
275 | 0 | break; |
276 | | |
277 | 0 | default: |
278 | 0 | assert(false); |
279 | 0 | } |
280 | | |
281 | 0 | result = yr_object_create(obj_type, external->identifier, NULL, &obj); |
282 | |
|
283 | 0 | if (result == ERROR_SUCCESS) |
284 | 0 | { |
285 | 0 | switch (external->type) |
286 | 0 | { |
287 | 0 | case EXTERNAL_VARIABLE_TYPE_INTEGER: |
288 | 0 | case EXTERNAL_VARIABLE_TYPE_BOOLEAN: |
289 | 0 | result = yr_object_set_integer(external->value.i, obj, NULL); |
290 | 0 | break; |
291 | | |
292 | 0 | case EXTERNAL_VARIABLE_TYPE_FLOAT: |
293 | 0 | result = yr_object_set_float(external->value.f, obj, NULL); |
294 | 0 | break; |
295 | | |
296 | 0 | case EXTERNAL_VARIABLE_TYPE_STRING: |
297 | 0 | case EXTERNAL_VARIABLE_TYPE_MALLOC_STRING: |
298 | 0 | result = yr_object_set_string( |
299 | 0 | external->value.s, strlen(external->value.s), obj, NULL); |
300 | 0 | break; |
301 | 0 | } |
302 | | |
303 | 0 | if (result == ERROR_SUCCESS) |
304 | 0 | { |
305 | 0 | *object = obj; |
306 | 0 | } |
307 | 0 | else |
308 | 0 | { |
309 | 0 | yr_object_destroy(obj); |
310 | 0 | } |
311 | 0 | } |
312 | | |
313 | 0 | return result; |
314 | 0 | } |
315 | | |
316 | | //////////////////////////////////////////////////////////////////////////////// |
317 | | // Destroy an objects, and any other object that is a child of it. For example, |
318 | | // destroying a struct will destroy all its members. |
319 | | // |
320 | | void yr_object_destroy(YR_OBJECT* object) |
321 | 9.34M | { |
322 | 9.34M | YR_STRUCTURE_MEMBER* member; |
323 | 9.34M | YR_STRUCTURE_MEMBER* next_member; |
324 | 9.34M | YR_ARRAY_ITEMS* array_items; |
325 | 9.34M | YR_DICTIONARY_ITEMS* dict_items; |
326 | | |
327 | 9.34M | if (object == NULL) |
328 | 0 | return; |
329 | | |
330 | 9.34M | switch (object->type) |
331 | 9.34M | { |
332 | 1.45M | case OBJECT_TYPE_STRUCTURE: |
333 | 1.45M | member = object_as_structure(object)->members; |
334 | | |
335 | 9.34M | while (member != NULL) |
336 | 7.88M | { |
337 | 7.88M | next_member = member->next; |
338 | 7.88M | yr_object_destroy(member->object); |
339 | 7.88M | yr_free(member); |
340 | 7.88M | member = next_member; |
341 | 7.88M | } |
342 | 1.45M | break; |
343 | | |
344 | 557k | case OBJECT_TYPE_STRING: |
345 | 557k | if (object->value.ss != NULL) |
346 | 115k | yr_free(object->value.ss); |
347 | 557k | break; |
348 | | |
349 | 40.0k | case OBJECT_TYPE_ARRAY: |
350 | 40.0k | if (object_as_array(object)->prototype_item != NULL) |
351 | 40.0k | yr_object_destroy(object_as_array(object)->prototype_item); |
352 | | |
353 | 40.0k | array_items = object_as_array(object)->items; |
354 | | |
355 | 40.0k | if (array_items != NULL) |
356 | 6.60k | { |
357 | 1.41M | for (int i = 0; i < array_items->length; i++) |
358 | 1.40M | if (array_items->objects[i] != NULL) |
359 | 1.40M | yr_object_destroy(array_items->objects[i]); |
360 | 6.60k | } |
361 | | |
362 | 40.0k | yr_free(array_items); |
363 | 40.0k | break; |
364 | | |
365 | 0 | case OBJECT_TYPE_DICTIONARY: |
366 | 0 | if (object_as_dictionary(object)->prototype_item != NULL) |
367 | 0 | yr_object_destroy(object_as_dictionary(object)->prototype_item); |
368 | |
|
369 | 0 | dict_items = object_as_dictionary(object)->items; |
370 | |
|
371 | 0 | if (dict_items != NULL) |
372 | 0 | { |
373 | 0 | for (int i = 0; i < dict_items->used; i++) |
374 | 0 | { |
375 | 0 | if (dict_items->objects[i].key != NULL) |
376 | 0 | yr_free(dict_items->objects[i].key); |
377 | |
|
378 | 0 | if (dict_items->objects[i].obj != NULL) |
379 | 0 | yr_object_destroy(dict_items->objects[i].obj); |
380 | 0 | } |
381 | 0 | } |
382 | |
|
383 | 0 | yr_free(dict_items); |
384 | 0 | break; |
385 | | |
386 | 8.00k | case OBJECT_TYPE_FUNCTION: |
387 | 8.00k | yr_object_destroy(object_as_function(object)->return_obj); |
388 | 8.00k | break; |
389 | 9.34M | } |
390 | | |
391 | 9.34M | yr_free((void*) object->identifier); |
392 | 9.34M | yr_free(object); |
393 | 9.34M | } |
394 | | |
395 | | YR_OBJECT* yr_object_lookup_field(YR_OBJECT* object, const char* field_name) |
396 | 24.5M | { |
397 | 24.5M | YR_STRUCTURE_MEMBER* member; |
398 | | |
399 | 24.5M | assert(object != NULL); |
400 | 24.5M | assert(object->type == OBJECT_TYPE_STRUCTURE); |
401 | | |
402 | 24.5M | member = object_as_structure(object)->members; |
403 | | |
404 | 321M | while (member != NULL) |
405 | 313M | { |
406 | 313M | if (strcmp(member->object->identifier, field_name) == 0) |
407 | 16.6M | return member->object; |
408 | | |
409 | 297M | member = member->next; |
410 | 297M | } |
411 | | |
412 | 7.89M | return NULL; |
413 | 24.5M | } |
414 | | |
415 | | static YR_OBJECT* _yr_object_lookup( |
416 | | YR_OBJECT* object, |
417 | | int flags, |
418 | | const char* pattern, |
419 | | va_list args) |
420 | 8.73M | { |
421 | 8.73M | YR_OBJECT* obj = object; |
422 | | |
423 | 8.73M | const char* p = pattern; |
424 | 8.73M | const char* key = NULL; |
425 | | |
426 | 8.73M | char str[256]; |
427 | | |
428 | 8.73M | int i; |
429 | 8.73M | int index = -1; |
430 | | |
431 | 16.6M | while (obj != NULL) |
432 | 16.6M | { |
433 | 16.6M | i = 0; |
434 | | |
435 | 130M | while (*p != '\0' && *p != '.' && *p != '[' && i < sizeof(str) - 1) |
436 | 113M | { |
437 | 113M | str[i++] = *p++; |
438 | 113M | } |
439 | | |
440 | 16.6M | str[i] = '\0'; |
441 | | |
442 | 16.6M | if (obj->type != OBJECT_TYPE_STRUCTURE) |
443 | 0 | return NULL; |
444 | | |
445 | 16.6M | obj = yr_object_lookup_field(obj, str); |
446 | | |
447 | 16.6M | if (obj == NULL) |
448 | 0 | return NULL; |
449 | | |
450 | 16.6M | if (*p == '[') |
451 | 7.95M | { |
452 | 7.95M | p++; |
453 | | |
454 | 7.95M | if (*p == '%') |
455 | 7.95M | { |
456 | 7.95M | p++; |
457 | | |
458 | 7.95M | switch (*p++) |
459 | 7.95M | { |
460 | 7.95M | case 'i': |
461 | 7.95M | index = va_arg(args, int); |
462 | 7.95M | break; |
463 | 0 | case 's': |
464 | 0 | key = va_arg(args, const char*); |
465 | 0 | break; |
466 | | |
467 | 0 | default: |
468 | 0 | return NULL; |
469 | 7.95M | } |
470 | 7.95M | } |
471 | 0 | else if (*p >= '0' && *p <= '9') |
472 | 0 | { |
473 | 0 | index = (int) strtol(p, (char**) &p, 10); |
474 | 0 | } |
475 | 0 | else if (*p == '"') |
476 | 0 | { |
477 | 0 | i = 0; |
478 | 0 | p++; // skip the opening quotation mark |
479 | |
|
480 | 0 | while (*p != '"' && *p != '\0' && i < sizeof(str) - 1) str[i++] = *p++; |
481 | |
|
482 | 0 | str[i] = '\0'; |
483 | 0 | p++; // skip the closing quotation mark |
484 | 0 | key = str; |
485 | 0 | } |
486 | 0 | else |
487 | 0 | { |
488 | 0 | return NULL; |
489 | 0 | } |
490 | | |
491 | 7.95M | assert(*p == ']'); |
492 | 7.95M | p++; |
493 | 7.95M | assert(*p == '.' || *p == '\0'); |
494 | | |
495 | 7.95M | switch (obj->type) |
496 | 7.95M | { |
497 | 7.95M | case OBJECT_TYPE_ARRAY: |
498 | 7.95M | assert(index != -1); |
499 | 7.95M | obj = yr_object_array_get_item(obj, flags, index); |
500 | 7.95M | break; |
501 | | |
502 | 0 | case OBJECT_TYPE_DICTIONARY: |
503 | 0 | assert(key != NULL); |
504 | 0 | obj = yr_object_dict_get_item(obj, flags, key); |
505 | 0 | break; |
506 | 7.95M | } |
507 | 7.95M | } |
508 | | |
509 | 16.6M | if (*p == '\0') |
510 | 8.73M | break; |
511 | | |
512 | 7.95M | p++; |
513 | 7.95M | } |
514 | | |
515 | 8.73M | return obj; |
516 | 8.73M | } |
517 | | |
518 | | YR_OBJECT* yr_object_lookup( |
519 | | YR_OBJECT* object, |
520 | | int flags, |
521 | | const char* pattern, |
522 | | ...) |
523 | 0 | { |
524 | 0 | YR_OBJECT* result; |
525 | |
|
526 | 0 | va_list args; |
527 | 0 | va_start(args, pattern); |
528 | |
|
529 | 0 | result = _yr_object_lookup(object, flags, pattern, args); |
530 | |
|
531 | 0 | va_end(args); |
532 | |
|
533 | 0 | return result; |
534 | 0 | } |
535 | | |
536 | | int yr_object_copy(YR_OBJECT* object, YR_OBJECT** object_copy) |
537 | 8.21M | { |
538 | 8.21M | YR_OBJECT* copy; |
539 | 8.21M | YR_OBJECT* o; |
540 | | |
541 | 8.21M | YR_STRUCTURE_MEMBER* structure_member; |
542 | | |
543 | 8.21M | *object_copy = NULL; |
544 | | |
545 | 8.21M | FAIL_ON_ERROR( |
546 | 8.21M | yr_object_create(object->type, object->identifier, NULL, ©)); |
547 | | |
548 | 8.21M | copy->canary = object->canary; |
549 | | |
550 | 8.21M | switch (object->type) |
551 | 8.21M | { |
552 | 6.27M | case OBJECT_TYPE_INTEGER: |
553 | 6.27M | copy->value.i = object->value.i; |
554 | 6.27M | break; |
555 | | |
556 | 0 | case OBJECT_TYPE_FLOAT: |
557 | 0 | copy->value.d = object->value.d; |
558 | 0 | break; |
559 | | |
560 | 525k | case OBJECT_TYPE_STRING: |
561 | | |
562 | 525k | if (object->value.ss != NULL) |
563 | 0 | copy->value.ss = ss_dup(object->value.ss); |
564 | 525k | else |
565 | 525k | copy->value.ss = NULL; |
566 | | |
567 | 525k | break; |
568 | | |
569 | 0 | case OBJECT_TYPE_FUNCTION: |
570 | |
|
571 | 0 | FAIL_ON_ERROR_WITH_CLEANUP( |
572 | 0 | yr_object_copy( |
573 | 0 | object_as_function(object)->return_obj, |
574 | 0 | &object_as_function(copy)->return_obj), |
575 | | // cleanup |
576 | 0 | yr_object_destroy(copy)); |
577 | |
|
578 | 0 | for (int i = 0; i < YR_MAX_OVERLOADED_FUNCTIONS; i++) |
579 | 0 | object_as_function(copy)->prototypes[i] = |
580 | 0 | object_as_function(object)->prototypes[i]; |
581 | |
|
582 | 0 | break; |
583 | | |
584 | 1.40M | case OBJECT_TYPE_STRUCTURE: |
585 | | |
586 | 1.40M | structure_member = object_as_structure(object)->members; |
587 | | |
588 | 8.21M | while (structure_member != NULL) |
589 | 6.80M | { |
590 | 6.80M | FAIL_ON_ERROR_WITH_CLEANUP( |
591 | 6.80M | yr_object_copy(structure_member->object, &o), |
592 | 6.80M | yr_object_destroy(copy)); |
593 | | |
594 | 6.80M | FAIL_ON_ERROR_WITH_CLEANUP(yr_object_structure_set_member(copy, o), |
595 | | // cleanup |
596 | 6.80M | yr_free(o); |
597 | 6.80M | yr_object_destroy(copy)); |
598 | | |
599 | 6.80M | structure_member = structure_member->next; |
600 | 6.80M | } |
601 | | |
602 | 1.40M | break; |
603 | | |
604 | 1.40M | case OBJECT_TYPE_ARRAY: |
605 | |
|
606 | 0 | FAIL_ON_ERROR_WITH_CLEANUP( |
607 | 0 | yr_object_copy(object_as_array(object)->prototype_item, &o), |
608 | 0 | yr_object_destroy(copy)); |
609 | |
|
610 | 0 | object_as_array(copy)->prototype_item = o; |
611 | |
|
612 | 0 | break; |
613 | | |
614 | 0 | case OBJECT_TYPE_DICTIONARY: |
615 | |
|
616 | 0 | FAIL_ON_ERROR_WITH_CLEANUP( |
617 | 0 | yr_object_copy(object_as_dictionary(object)->prototype_item, &o), |
618 | 0 | yr_object_destroy(copy)); |
619 | |
|
620 | 0 | object_as_dictionary(copy)->prototype_item = o; |
621 | |
|
622 | 0 | break; |
623 | | |
624 | 0 | default: |
625 | 0 | assert(false); |
626 | 8.21M | } |
627 | | |
628 | 8.21M | *object_copy = copy; |
629 | | |
630 | 8.21M | return ERROR_SUCCESS; |
631 | 8.21M | } |
632 | | |
633 | | int yr_object_structure_set_member(YR_OBJECT* object, YR_OBJECT* member) |
634 | 7.88M | { |
635 | 7.88M | YR_STRUCTURE_MEMBER* sm; |
636 | | |
637 | 7.88M | assert(object->type == OBJECT_TYPE_STRUCTURE); |
638 | | |
639 | | // Check if the object already have a member with the same identifier |
640 | | |
641 | 7.88M | if (yr_object_lookup_field(object, member->identifier) != NULL) |
642 | 0 | return ERROR_DUPLICATED_STRUCTURE_MEMBER; |
643 | | |
644 | 7.88M | sm = (YR_STRUCTURE_MEMBER*) yr_malloc(sizeof(YR_STRUCTURE_MEMBER)); |
645 | | |
646 | 7.88M | if (sm == NULL) |
647 | 0 | return ERROR_INSUFFICIENT_MEMORY; |
648 | | |
649 | 7.88M | member->parent = object; |
650 | 7.88M | sm->object = member; |
651 | 7.88M | sm->next = object_as_structure(object)->members; |
652 | | |
653 | 7.88M | object_as_structure(object)->members = sm; |
654 | | |
655 | 7.88M | return ERROR_SUCCESS; |
656 | 7.88M | } |
657 | | |
658 | | int yr_object_array_length(YR_OBJECT* object) |
659 | 0 | { |
660 | 0 | YR_OBJECT_ARRAY* array; |
661 | |
|
662 | 0 | assert(object->type == OBJECT_TYPE_ARRAY); |
663 | 0 | array = object_as_array(object); |
664 | |
|
665 | 0 | if (array->items == NULL) |
666 | 0 | return 0; |
667 | | |
668 | 0 | return array->items->length; |
669 | 0 | } |
670 | | |
671 | | YR_OBJECT* yr_object_array_get_item(YR_OBJECT* object, int flags, int index) |
672 | 7.95M | { |
673 | 7.95M | YR_OBJECT* result = NULL; |
674 | 7.95M | YR_OBJECT_ARRAY* array; |
675 | | |
676 | 7.95M | assert(object->type == OBJECT_TYPE_ARRAY); |
677 | | |
678 | 7.95M | if (index < 0) |
679 | 0 | return NULL; |
680 | | |
681 | 7.95M | array = object_as_array(object); |
682 | | |
683 | 7.95M | if (array->items != NULL && array->items->capacity > index) |
684 | 7.94M | result = array->items->objects[index]; |
685 | | |
686 | 7.95M | if (result == NULL && flags & OBJECT_CREATE) |
687 | 1.40M | { |
688 | 1.40M | yr_object_copy(array->prototype_item, &result); |
689 | | |
690 | 1.40M | if (result != NULL) |
691 | 1.40M | yr_object_array_set_item(object, result, index); |
692 | 1.40M | } |
693 | | |
694 | 7.95M | return result; |
695 | 7.95M | } |
696 | | |
697 | | int yr_object_array_set_item(YR_OBJECT* object, YR_OBJECT* item, int index) |
698 | 1.40M | { |
699 | 1.40M | YR_OBJECT_ARRAY* array; |
700 | | |
701 | 1.40M | int capacity; |
702 | | |
703 | 1.40M | assert(index >= 0); |
704 | 1.40M | assert(object->type == OBJECT_TYPE_ARRAY); |
705 | | |
706 | 1.40M | array = object_as_array(object); |
707 | | |
708 | 1.40M | if (array->items == NULL) |
709 | 6.60k | { |
710 | 6.60k | capacity = 64; |
711 | | |
712 | 6.60k | while (capacity <= index) capacity *= 2; |
713 | | |
714 | 6.60k | array->items = (YR_ARRAY_ITEMS*) yr_malloc( |
715 | 6.60k | sizeof(YR_ARRAY_ITEMS) + capacity * sizeof(YR_OBJECT*)); |
716 | | |
717 | 6.60k | if (array->items == NULL) |
718 | 0 | return ERROR_INSUFFICIENT_MEMORY; |
719 | | |
720 | 6.60k | memset(array->items->objects, 0, capacity * sizeof(YR_OBJECT*)); |
721 | | |
722 | 6.60k | array->items->capacity = capacity; |
723 | 6.60k | array->items->length = 0; |
724 | 6.60k | } |
725 | 1.40M | else if (index >= array->items->capacity) |
726 | 1.65k | { |
727 | 1.65k | capacity = array->items->capacity * 2; |
728 | | |
729 | 1.65k | while (capacity <= index) capacity *= 2; |
730 | | |
731 | 1.65k | array->items = (YR_ARRAY_ITEMS*) yr_realloc( |
732 | 1.65k | array->items, sizeof(YR_ARRAY_ITEMS) + capacity * sizeof(YR_OBJECT*)); |
733 | | |
734 | 1.65k | if (array->items == NULL) |
735 | 0 | return ERROR_INSUFFICIENT_MEMORY; |
736 | | |
737 | 1.71M | for (int i = array->items->capacity; i < capacity; i++) |
738 | 1.70M | array->items->objects[i] = NULL; |
739 | | |
740 | 1.65k | array->items->capacity = capacity; |
741 | 1.65k | } |
742 | | |
743 | 1.40M | item->parent = object; |
744 | 1.40M | array->items->objects[index] = item; |
745 | | |
746 | 1.40M | if (index >= array->items->length) |
747 | 1.40M | array->items->length = index + 1; |
748 | | |
749 | 1.40M | return ERROR_SUCCESS; |
750 | 1.40M | } |
751 | | |
752 | | YR_OBJECT* yr_object_dict_get_item( |
753 | | YR_OBJECT* object, |
754 | | int flags, |
755 | | const char* key) |
756 | 0 | { |
757 | 0 | YR_OBJECT* result = NULL; |
758 | 0 | YR_OBJECT_DICTIONARY* dict; |
759 | |
|
760 | 0 | assert(object->type == OBJECT_TYPE_DICTIONARY); |
761 | | |
762 | 0 | dict = object_as_dictionary(object); |
763 | |
|
764 | 0 | if (dict->items != NULL) |
765 | 0 | { |
766 | 0 | for (int i = 0; i < dict->items->used; i++) |
767 | 0 | { |
768 | 0 | if (strcmp(dict->items->objects[i].key->c_string, key) == 0) |
769 | 0 | result = dict->items->objects[i].obj; |
770 | 0 | } |
771 | 0 | } |
772 | |
|
773 | 0 | if (result == NULL && flags & OBJECT_CREATE) |
774 | 0 | { |
775 | 0 | yr_object_copy(dict->prototype_item, &result); |
776 | |
|
777 | 0 | if (result != NULL) |
778 | 0 | yr_object_dict_set_item(object, result, key); |
779 | 0 | } |
780 | |
|
781 | 0 | return result; |
782 | 0 | } |
783 | | |
784 | | int yr_object_dict_set_item(YR_OBJECT* object, YR_OBJECT* item, const char* key) |
785 | 0 | { |
786 | 0 | YR_OBJECT_DICTIONARY* dict; |
787 | |
|
788 | 0 | int count; |
789 | |
|
790 | 0 | assert(object->type == OBJECT_TYPE_DICTIONARY); |
791 | | |
792 | 0 | dict = object_as_dictionary(object); |
793 | |
|
794 | 0 | if (dict->items == NULL) |
795 | 0 | { |
796 | 0 | count = 64; |
797 | |
|
798 | 0 | dict->items = (YR_DICTIONARY_ITEMS*) yr_malloc( |
799 | 0 | sizeof(YR_DICTIONARY_ITEMS) + count * sizeof(dict->items->objects[0])); |
800 | |
|
801 | 0 | if (dict->items == NULL) |
802 | 0 | return ERROR_INSUFFICIENT_MEMORY; |
803 | | |
804 | 0 | memset(dict->items->objects, 0, count * sizeof(dict->items->objects[0])); |
805 | |
|
806 | 0 | dict->items->free = count; |
807 | 0 | dict->items->used = 0; |
808 | 0 | } |
809 | 0 | else if (dict->items->free == 0) |
810 | 0 | { |
811 | 0 | count = dict->items->used * 2; |
812 | 0 | dict->items = (YR_DICTIONARY_ITEMS*) yr_realloc( |
813 | 0 | dict->items, |
814 | 0 | sizeof(YR_DICTIONARY_ITEMS) + count * sizeof(dict->items->objects[0])); |
815 | |
|
816 | 0 | if (dict->items == NULL) |
817 | 0 | return ERROR_INSUFFICIENT_MEMORY; |
818 | | |
819 | 0 | for (int i = dict->items->used; i < count; i++) |
820 | 0 | { |
821 | 0 | dict->items->objects[i].key = NULL; |
822 | 0 | dict->items->objects[i].obj = NULL; |
823 | 0 | } |
824 | |
|
825 | 0 | dict->items->free = dict->items->used; |
826 | 0 | } |
827 | | |
828 | 0 | item->parent = object; |
829 | |
|
830 | 0 | dict->items->objects[dict->items->used].key = ss_new(key); |
831 | 0 | dict->items->objects[dict->items->used].obj = item; |
832 | |
|
833 | 0 | dict->items->used++; |
834 | 0 | dict->items->free--; |
835 | |
|
836 | 0 | return ERROR_SUCCESS; |
837 | 0 | } |
838 | | |
839 | | bool yr_object_has_undefined_value(YR_OBJECT* object, const char* field, ...) |
840 | 0 | { |
841 | 0 | YR_OBJECT* field_obj; |
842 | |
|
843 | 0 | va_list args; |
844 | 0 | va_start(args, field); |
845 | |
|
846 | 0 | if (field != NULL) |
847 | 0 | field_obj = _yr_object_lookup(object, 0, field, args); |
848 | 0 | else |
849 | 0 | field_obj = object; |
850 | |
|
851 | 0 | va_end(args); |
852 | |
|
853 | 0 | if (field_obj == NULL) |
854 | 0 | return true; |
855 | | |
856 | 0 | switch (field_obj->type) |
857 | 0 | { |
858 | 0 | case OBJECT_TYPE_FLOAT: |
859 | 0 | return yr_isnan(field_obj->value.d); |
860 | 0 | case OBJECT_TYPE_STRING: |
861 | 0 | return field_obj->value.ss == NULL; |
862 | 0 | case OBJECT_TYPE_INTEGER: |
863 | 0 | return field_obj->value.i == YR_UNDEFINED; |
864 | 0 | } |
865 | | |
866 | 0 | return false; |
867 | 0 | } |
868 | | |
869 | | int64_t yr_object_get_integer(YR_OBJECT* object, const char* field, ...) |
870 | 0 | { |
871 | 0 | YR_OBJECT* integer_obj; |
872 | |
|
873 | 0 | va_list args; |
874 | 0 | va_start(args, field); |
875 | |
|
876 | 0 | if (field != NULL) |
877 | 0 | integer_obj = _yr_object_lookup(object, 0, field, args); |
878 | 0 | else |
879 | 0 | integer_obj = object; |
880 | |
|
881 | 0 | va_end(args); |
882 | |
|
883 | 0 | if (integer_obj == NULL) |
884 | 0 | return YR_UNDEFINED; |
885 | | |
886 | 0 | assertf( |
887 | 0 | integer_obj->type == OBJECT_TYPE_INTEGER, |
888 | 0 | "type of \"%s\" is not integer\n", |
889 | 0 | field); |
890 | |
|
891 | 0 | return integer_obj->value.i; |
892 | 0 | } |
893 | | |
894 | | double yr_object_get_float(YR_OBJECT* object, const char* field, ...) |
895 | 0 | { |
896 | 0 | YR_OBJECT* double_obj; |
897 | |
|
898 | 0 | va_list args; |
899 | 0 | va_start(args, field); |
900 | |
|
901 | 0 | if (field != NULL) |
902 | 0 | double_obj = _yr_object_lookup(object, 0, field, args); |
903 | 0 | else |
904 | 0 | double_obj = object; |
905 | |
|
906 | 0 | va_end(args); |
907 | |
|
908 | 0 | if (double_obj == NULL) |
909 | 0 | return NAN; |
910 | | |
911 | 0 | assertf( |
912 | 0 | double_obj->type == OBJECT_TYPE_FLOAT, |
913 | 0 | "type of \"%s\" is not double\n", |
914 | 0 | field); |
915 | |
|
916 | 0 | return double_obj->value.d; |
917 | 0 | } |
918 | | |
919 | | SIZED_STRING* yr_object_get_string(YR_OBJECT* object, const char* field, ...) |
920 | 0 | { |
921 | 0 | YR_OBJECT* string_obj; |
922 | |
|
923 | 0 | va_list args; |
924 | 0 | va_start(args, field); |
925 | |
|
926 | 0 | if (field != NULL) |
927 | 0 | string_obj = _yr_object_lookup(object, 0, field, args); |
928 | 0 | else |
929 | 0 | string_obj = object; |
930 | |
|
931 | 0 | va_end(args); |
932 | |
|
933 | 0 | if (string_obj == NULL) |
934 | 0 | return NULL; |
935 | | |
936 | 0 | assertf( |
937 | 0 | string_obj->type == OBJECT_TYPE_STRING, |
938 | 0 | "type of \"%s\" is not string\n", |
939 | 0 | field); |
940 | |
|
941 | 0 | return string_obj->value.ss; |
942 | 0 | } |
943 | | |
944 | | int yr_object_set_integer( |
945 | | int64_t value, |
946 | | YR_OBJECT* object, |
947 | | const char* field, |
948 | | ...) |
949 | 8.62M | { |
950 | 8.62M | YR_OBJECT* integer_obj; |
951 | | |
952 | 8.62M | va_list args; |
953 | 8.62M | va_start(args, field); |
954 | | |
955 | 8.62M | if (field != NULL) |
956 | 8.62M | integer_obj = _yr_object_lookup(object, OBJECT_CREATE, field, args); |
957 | 0 | else |
958 | 0 | integer_obj = object; |
959 | | |
960 | 8.62M | va_end(args); |
961 | | |
962 | 8.62M | if (integer_obj == NULL) |
963 | 0 | { |
964 | 0 | if (field != NULL) |
965 | 0 | return ERROR_INSUFFICIENT_MEMORY; |
966 | 0 | else |
967 | 0 | return ERROR_INVALID_ARGUMENT; |
968 | 0 | } |
969 | | |
970 | 8.62M | assert(integer_obj->type == OBJECT_TYPE_INTEGER); |
971 | | |
972 | 8.62M | integer_obj->value.i = value; |
973 | | |
974 | 8.62M | return ERROR_SUCCESS; |
975 | 8.62M | } |
976 | | |
977 | | int yr_object_set_float(double value, YR_OBJECT* object, const char* field, ...) |
978 | 0 | { |
979 | 0 | YR_OBJECT* double_obj; |
980 | |
|
981 | 0 | va_list args; |
982 | 0 | va_start(args, field); |
983 | |
|
984 | 0 | if (field != NULL) |
985 | 0 | double_obj = _yr_object_lookup(object, OBJECT_CREATE, field, args); |
986 | 0 | else |
987 | 0 | double_obj = object; |
988 | |
|
989 | 0 | va_end(args); |
990 | |
|
991 | 0 | if (double_obj == NULL) |
992 | 0 | { |
993 | 0 | if (field != NULL) |
994 | 0 | return ERROR_INSUFFICIENT_MEMORY; |
995 | 0 | else |
996 | 0 | return ERROR_INVALID_ARGUMENT; |
997 | 0 | } |
998 | | |
999 | 0 | assert(double_obj->type == OBJECT_TYPE_FLOAT); |
1000 | | |
1001 | 0 | double_obj->value.d = value; |
1002 | |
|
1003 | 0 | return ERROR_SUCCESS; |
1004 | 0 | } |
1005 | | |
1006 | | int yr_object_set_string( |
1007 | | const char* value, |
1008 | | size_t len, |
1009 | | YR_OBJECT* object, |
1010 | | const char* field, |
1011 | | ...) |
1012 | 115k | { |
1013 | 115k | YR_OBJECT* string_obj; |
1014 | | |
1015 | 115k | va_list args; |
1016 | 115k | va_start(args, field); |
1017 | | |
1018 | 115k | if (field != NULL) |
1019 | 115k | string_obj = _yr_object_lookup(object, OBJECT_CREATE, field, args); |
1020 | 0 | else |
1021 | 0 | string_obj = object; |
1022 | | |
1023 | 115k | va_end(args); |
1024 | | |
1025 | 115k | if (string_obj == NULL) |
1026 | 0 | { |
1027 | 0 | if (field != NULL) |
1028 | 0 | return ERROR_INSUFFICIENT_MEMORY; |
1029 | 0 | else |
1030 | 0 | return ERROR_INVALID_ARGUMENT; |
1031 | 0 | } |
1032 | | |
1033 | 115k | assert(string_obj->type == OBJECT_TYPE_STRING); |
1034 | | |
1035 | 115k | if (string_obj->value.ss != NULL) |
1036 | 0 | yr_free(string_obj->value.ss); |
1037 | | |
1038 | 115k | if (value != NULL) |
1039 | 115k | { |
1040 | 115k | string_obj->value.ss = (SIZED_STRING*) yr_malloc( |
1041 | 115k | len + sizeof(SIZED_STRING)); |
1042 | | |
1043 | 115k | if (string_obj->value.ss == NULL) |
1044 | 0 | return ERROR_INSUFFICIENT_MEMORY; |
1045 | | |
1046 | 115k | string_obj->value.ss->length = (uint32_t) len; |
1047 | 115k | string_obj->value.ss->flags = 0; |
1048 | | |
1049 | 115k | memcpy(string_obj->value.ss->c_string, value, len); |
1050 | 115k | string_obj->value.ss->c_string[len] = '\0'; |
1051 | 115k | } |
1052 | 0 | else |
1053 | 0 | { |
1054 | 0 | string_obj->value.ss = NULL; |
1055 | 0 | } |
1056 | | |
1057 | 115k | return ERROR_SUCCESS; |
1058 | 115k | } |
1059 | | |
1060 | | YR_OBJECT* yr_object_get_root(YR_OBJECT* object) |
1061 | 0 | { |
1062 | 0 | YR_OBJECT* o = object; |
1063 | |
|
1064 | 0 | while (o->parent != NULL) o = o->parent; |
1065 | |
|
1066 | 0 | return o; |
1067 | 0 | } |
1068 | | |
1069 | | YR_API void yr_object_print_data( |
1070 | | YR_OBJECT* object, |
1071 | | int indent, |
1072 | | int print_identifier) |
1073 | 0 | { |
1074 | 0 | YR_DICTIONARY_ITEMS* dict_items; |
1075 | 0 | YR_STRUCTURE_MEMBER* member; |
1076 | |
|
1077 | 0 | char indent_spaces[32]; |
1078 | |
|
1079 | 0 | indent = yr_min(indent, sizeof(indent_spaces) - 1); |
1080 | |
|
1081 | 0 | memset(indent_spaces, '\t', indent); |
1082 | 0 | indent_spaces[indent] = '\0'; |
1083 | |
|
1084 | 0 | if (print_identifier && object->type != OBJECT_TYPE_FUNCTION) |
1085 | 0 | printf("%s%s", indent_spaces, object->identifier); |
1086 | |
|
1087 | 0 | switch (object->type) |
1088 | 0 | { |
1089 | 0 | case OBJECT_TYPE_FLOAT: |
1090 | 0 | if (object->value.i != YR_UNDEFINED) |
1091 | 0 | printf(" = %f", object->value.d); |
1092 | 0 | else |
1093 | 0 | printf(" = YR_UNDEFINED"); |
1094 | |
|
1095 | 0 | break; |
1096 | | |
1097 | 0 | case OBJECT_TYPE_INTEGER: |
1098 | |
|
1099 | 0 | if (object->value.i != YR_UNDEFINED) |
1100 | 0 | printf(" = %" PRId64, object->value.i); |
1101 | 0 | else |
1102 | 0 | printf(" = YR_UNDEFINED"); |
1103 | |
|
1104 | 0 | break; |
1105 | | |
1106 | 0 | case OBJECT_TYPE_STRING: |
1107 | |
|
1108 | 0 | if (object->value.ss != NULL) |
1109 | 0 | { |
1110 | 0 | printf(" = \""); |
1111 | |
|
1112 | 0 | for (size_t l = 0; l < object->value.ss->length; l++) |
1113 | 0 | { |
1114 | 0 | char c = object->value.ss->c_string[l]; |
1115 | |
|
1116 | 0 | if (isprint((unsigned char) c)) |
1117 | 0 | printf("%c", c); |
1118 | 0 | else |
1119 | 0 | printf("\\x%02x", (unsigned char) c); |
1120 | 0 | } |
1121 | |
|
1122 | 0 | printf("\""); |
1123 | 0 | } |
1124 | 0 | else |
1125 | 0 | { |
1126 | 0 | printf(" = YR_UNDEFINED"); |
1127 | 0 | } |
1128 | |
|
1129 | 0 | break; |
1130 | | |
1131 | 0 | case OBJECT_TYPE_STRUCTURE: |
1132 | |
|
1133 | 0 | member = object_as_structure(object)->members; |
1134 | |
|
1135 | 0 | while (member != NULL) |
1136 | 0 | { |
1137 | 0 | if (member->object->type != OBJECT_TYPE_FUNCTION) |
1138 | 0 | { |
1139 | 0 | printf("\n"); |
1140 | 0 | yr_object_print_data(member->object, indent + 1, 1); |
1141 | 0 | } |
1142 | 0 | member = member->next; |
1143 | 0 | } |
1144 | |
|
1145 | 0 | break; |
1146 | | |
1147 | 0 | case OBJECT_TYPE_ARRAY: |
1148 | 0 | for (int i = 0; i < yr_object_array_length(object); i++) |
1149 | 0 | { |
1150 | 0 | YR_OBJECT* o = yr_object_array_get_item(object, 0, i); |
1151 | |
|
1152 | 0 | if (o != NULL) |
1153 | 0 | { |
1154 | 0 | printf("\n%s\t[%d]", indent_spaces, i); |
1155 | 0 | yr_object_print_data(o, indent + 1, 0); |
1156 | 0 | } |
1157 | 0 | } |
1158 | 0 | break; |
1159 | | |
1160 | 0 | case OBJECT_TYPE_DICTIONARY: |
1161 | |
|
1162 | 0 | dict_items = object_as_dictionary(object)->items; |
1163 | |
|
1164 | 0 | if (dict_items != NULL) |
1165 | 0 | { |
1166 | 0 | for (int i = 0; i < dict_items->used; i++) |
1167 | 0 | { |
1168 | 0 | printf("\n%s\t%s", indent_spaces, dict_items->objects[i].key->c_string); |
1169 | |
|
1170 | 0 | yr_object_print_data(dict_items->objects[i].obj, indent + 1, 0); |
1171 | 0 | } |
1172 | 0 | } |
1173 | |
|
1174 | 0 | break; |
1175 | 0 | } |
1176 | 0 | } |