]> git.ipfire.org Git - people/ms/suricata.git/blame - scripts/dnp3-gen/dnp3-gen.py
script/dnp3-gen: update generator to reflect in tree changes
[people/ms/suricata.git] / scripts / dnp3-gen / dnp3-gen.py
CommitLineData
240d789c
JI
1#! /usr/bin/env python
2#
3# Copyright (C) 2015 Open Information Security Foundation
4#
5# You can copy, redistribute or modify this Program under the terms of
6# the GNU General Public License version 2 as published by the Free
7# Software Foundation.
8#
9# This program is distributed in the hope that it will be useful,
10# but WITHOUT ANY WARRANTY; without even the implied warranty of
11# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12# GNU General Public License for more details.
13#
14# You should have received a copy of the GNU General Public License
15# version 2 along with this program; if not, write to the Free Software
16# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17# 02110-1301, USA.
18
19# This script generates DNP3 related source code based on definitions
20# of DNP3 objects (currently the object structs).
21
22from __future__ import print_function
23
24import sys
25import re
240d789c 26import yaml
240d789c
JI
27
28import jinja2
29
30IN_PLACE_START = "/* START GENERATED CODE */"
31IN_PLACE_END = "/* END GENERATED CODE */"
32
33util_lua_dnp3_objects_c_template = """/* Copyright (C) 2015 Open Information Security Foundation
34 *
35 * You can copy, redistribute or modify this Program under the terms of
36 * the GNU General Public License version 2 as published by the Free
37 * Software Foundation.
38 *
39 * This program is distributed in the hope that it will be useful,
40 * but WITHOUT ANY WARRANTY; without even the implied warranty of
41 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
42 * GNU General Public License for more details.
43 *
44 * You should have received a copy of the GNU General Public License
45 * version 2 along with this program; if not, write to the Free Software
46 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
47 * 02110-1301, USA.
48 */
49
50/**
51 * DO NOT EDIT. THIS FILE IS AUTO-GENERATED.
52 *
53 * Generated by command:
54 * {{command_line}}
55 */
56
57#include "suricata-common.h"
58
59#include "app-layer-dnp3.h"
60#include "app-layer-dnp3-objects.h"
61
62#ifdef HAVE_LUA
63
64#include <lua.h>
65#include <lualib.h>
66#include <lauxlib.h>
67
68#include "util-lua.h"
ac7cf48a 69#include "util-lua-dnp3-objects.h"
240d789c
JI
70
71/**
72 * \\brief Push an object point item onto the stack.
73 */
74void DNP3PushPoint(lua_State *luastate, DNP3Object *object,
75 DNP3Point *point)
76{
77 switch (DNP3_OBJECT_CODE(object->group, object->variation)) {
78{% for object in objects %}
79 case DNP3_OBJECT_CODE({{object.group}}, {{object.variation}}): {
80 DNP3ObjectG{{object.group}}V{{object.variation}} *data = point->data;
81{% for field in object.fields %}
82{% if is_integer_type(field.type) %}
83 lua_pushliteral(luastate, "{{field.name}}");
84 lua_pushinteger(luastate, data->{{field.name}});
85 lua_settable(luastate, -3);
86{% elif field["type"] in ["flt32", "flt64"] %}
87 lua_pushliteral(luastate, "{{field.name}}");
88 lua_pushnumber(luastate, data->{{field.name}});
89 lua_settable(luastate, -3);
90{% elif field["type"] == "chararray" %}
91 lua_pushliteral(luastate, "{{field.name}}");
92 LuaPushStringBuffer(luastate, (uint8_t *)data->{{field.name}},
93 strlen(data->{{field.name}}));
94 lua_settable(luastate, -3);
95{% elif field["type"] == "vstr4" %}
96 lua_pushliteral(luastate, "{{field.name}}");
97 LuaPushStringBuffer(luastate, (uint8_t *)data->{{field.name}},
98 strlen(data->{{field.name}}));
99 lua_settable(luastate, -3);
100{% elif field.type == "bytearray" %}
101 lua_pushliteral(luastate, "{{field.name}}");
102 lua_pushlstring(luastate, (const char *)data->{{field.name}},
103 data->{{field.len_field}});
104 lua_settable(luastate, -3);
105{% elif field.type == "bstr8" %}
106{% for field in field.fields %}
107 lua_pushliteral(luastate, "{{field.name}}");
108 lua_pushinteger(luastate, data->{{field.name}});
109 lua_settable(luastate, -3);
110{% endfor %}
111{% else %}
112{{ raise("Unhandled datatype: %s" % (field.type)) }}
113{% endif %}
114{% endfor %}
115 break;
116 }
117{% endfor %}
118 default:
119 break;
120 }
121}
122
123#endif /* HAVE_LUA */
124
125"""
126
127output_json_dnp3_objects_template = """/* Copyright (C) 2015 Open Information Security Foundation
128 *
129 * You can copy, redistribute or modify this Program under the terms of
130 * the GNU General Public License version 2 as published by the Free
131 * Software Foundation.
132 *
133 * This program is distributed in the hope that it will be useful,
134 * but WITHOUT ANY WARRANTY; without even the implied warranty of
135 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
136 * GNU General Public License for more details.
137 *
138 * You should have received a copy of the GNU General Public License
139 * version 2 along with this program; if not, write to the Free Software
140 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
141 * 02110-1301, USA.
142 */
143
144/**
145 * DO NOT EDIT. THIS FILE IS AUTO-GENERATED.
146 *
147 * Generated by command:
148 * {{command_line}}
149 */
150
151#include "suricata-common.h"
152
153#include "util-crypt.h"
154
155#include "app-layer-dnp3.h"
156#include "app-layer-dnp3-objects.h"
ac7cf48a 157#include "output-json-dnp3-objects.h"
4976afd9 158#include "output-json.h"
240d789c 159
240d789c
JI
160void OutputJsonDNP3SetItem(json_t *js, DNP3Object *object,
161 DNP3Point *point)
162{
163
164 switch (DNP3_OBJECT_CODE(object->group, object->variation)) {
165{% for object in objects %}
166 case DNP3_OBJECT_CODE({{object.group}}, {{object.variation}}): {
167 DNP3ObjectG{{object.group}}V{{object.variation}} *data = point->data;
168{% for field in object.fields %}
169{% if is_integer_type(field.type) %}
170 json_object_set_new(js, "{{field.name}}",
171 json_integer(data->{{field.name}}));
172{% elif field.type in ["flt32", "flt64"] %}
173 json_object_set_new(js, "{{field.name}}",
174 json_real(data->{{field.name}}));
175{% elif field.type == "bytearray" %}
176 unsigned long {{field.name}}_b64_len = data->{{field.len_field}} * 2;
177 uint8_t {{field.name}}_b64[{{field.name}}_b64_len];
178 Base64Encode(data->{{field.name}}, data->{{field.len_field}},
179 {{field.name}}_b64, &{{field.name}}_b64_len);
180 json_object_set_new(js, "data->{{field.name}}",
181 json_string((char *){{field.name}}_b64));
182{% elif field.type == "vstr4" %}
4976afd9 183 json_object_set_new(js, "data->{{field.name}}", SCJsonString(data->{{field.name}}));
240d789c
JI
184{% elif field.type == "chararray" %}
185 if (data->{{field.len_field}} > 0) {
186 /* First create a null terminated string as not all versions
187 * of jansson have json_stringn. */
188 char tmpbuf[data->{{field.len_field}} + 1];
189 memcpy(tmpbuf, data->{{field.name}}, data->{{field.len_field}});
190 tmpbuf[data->{{field.len_field}}] = '\\0';
4976afd9 191 json_object_set_new(js, "{{field.name}}", SCJsonString(tmpbuf));
240d789c
JI
192 } else {
193 json_object_set_new(js, "{{field.name}}", json_string(""));
194 }
195{% elif field.type == "bstr8" %}
196{% for field in field.fields %}
197 json_object_set_new(js, "{{field.name}}",
198 json_integer(data->{{field.name}}));
199{% endfor %}
200{% else %}
201{{ raise("Unhandled datatype: %s" % (field.type)) }}
202{% endif %}
203{% endfor %}
204 break;
205 }
206{% endfor %}
207 default:
208 SCLogDebug("Unknown object: %d:%d", object->group,
209 object->variation);
210 break;
211 }
212
213}
214
240d789c
JI
215"""
216
217def has_freeable_types(fields):
218 freeable_types = [
219 "bytearray",
220 ]
221 for field in fields:
222 if field["type"] in freeable_types:
223 return True
224 return False
225
226def is_integer_type(datatype):
227 integer_types = [
228 "uint64",
229 "uint32",
230 "uint24",
231 "uint16",
232 "uint8",
233 "int64",
234 "int32",
235 "int16",
236 "int8",
237 "dnp3time",
238 ]
239 return datatype in integer_types
240
241def to_type(datatype):
242 type_map = {
243 "uint8": "uint8_t",
244 }
245 if datatype in type_map:
246 return type_map[datatype]
247 else:
248 raise Exception("Unknown datatype: %s" % (datatype))
249
250def generate(template, filename, context):
251 print("Generating %s." % (filename))
252 try:
253 env = jinja2.Environment(trim_blocks=True)
254 output = env.from_string(template).render(context)
255 with open(filename, "w") as fileobj:
256 fileobj.write(output)
257 except Exception as err:
258 print("Failed to generate %s: %s" % (filename, err))
259 sys.exit(1)
260
261def raise_helper(msg):
262 raise Exception(msg)
263
264def gen_object_structs(context):
265 """ Generate structs for all the define DNP3 objects. """
266
267 template = """
268
269/* Code generated by:
270 * {{command_line}}
271 */
272
273{% for object in objects %}
274typedef struct DNP3ObjectG{{object.group}}V{{object.variation}}_ {
275{% for field in object.fields %}
276{% if field.type == "bstr8" %}
277{% for field in field.fields %}
278 uint8_t {{field.name}}:{{field.width}};
279{% endfor %}
280{% else %}
281{% if field.type == "int16" %}
282 int16_t {{field.name}};
283{% elif field.type == "int32" %}
284 int32_t {{field.name}};
285{% elif field.type == "uint8" %}
286 uint8_t {{field.name}};
287{% elif field.type == "uint16" %}
288 uint16_t {{field.name}};
289{% elif field.type == "uint24" %}
290 uint32_t {{field.name}};
291{% elif field.type == "uint32" %}
292 uint32_t {{field.name}};
293{% elif field.type == "uint64" %}
294 uint64_t {{field.name}};
295{% elif field.type == "flt32" %}
296 float {{field.name}};
297{% elif field.type == "flt64" %}
298 double {{field.name}};
299{% elif field.type == "dnp3time" %}
300 uint64_t {{field.name}};
301{% elif field.type == "bytearray" %}
302 uint8_t *{{field.name}};
303{% elif field.type == "vstr4" %}
304 char {{field.name}}[5];
305{% elif field.type == "chararray" %}
306 char {{field.name}}[{{field.size}}];
307{% else %}
308 {{ raise("Unknown datatype type '%s' for object %d:%d" % (
309 field.type, object.group, object.variation)) }}
310{% endif %}
311{% endif %}
312{% endfor %}
313{% if object.extra_fields %}
314{% for field in object.extra_fields %}
315{% if field.type == "uint8" %}
316 uint8_t {{field.name}};
317{% elif field.type == "uint16" %}
318 uint16_t {{field.name}};
319{% elif field.type == "uint32" %}
320 uint32_t {{field.name}};
321{% else %}
322 {{ raise("Unknown datatype: %s" % (field.type)) }}
323{% endif %}
324{% endfor %}
325{% endif %}
326} DNP3ObjectG{{object.group}}V{{object.variation}};
327
328{% endfor %}
329"""
330
331 filename = "src/app-layer-dnp3-objects.h"
332 try:
333 env = jinja2.Environment(trim_blocks=True)
334 code = env.from_string(template).render(context)
335 content = open(filename).read()
336 content = re.sub(
337 "(%s).*(%s)" % (re.escape(IN_PLACE_START), re.escape(IN_PLACE_END)),
338 r"\1%s\2" % (code), content, 1, re.M | re.DOTALL)
339 open(filename, "w").write(content)
340 print("Updated %s." % (filename))
341 except Exception as err:
342 print("Failed to update %s: %s" % (filename, err), file=sys.stderr)
343 sys.exit(1)
344
345def gen_object_decoders(context):
346 """ Generate decoders for all defined DNP3 objects. """
347
348 template = """
349
350/* Code generated by:
351 * {{command_line}}
352 */
353
354{% for object in objects %}
355{% if object.packed %}
356static int DNP3DecodeObjectG{{object.group}}V{{object.variation}}(const uint8_t **buf, uint32_t *len,
357 uint8_t prefix_code, uint32_t start, uint32_t count,
358 DNP3PointList *points)
359{
360 DNP3ObjectG{{object.group}}V{{object.variation}} *object = NULL;
361 int bytes = (count / 8) + 1;
362 uint32_t prefix = 0;
2a0bb108 363 int point_index = start;
240d789c
JI
364
365 if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) {
366 goto error;
367 }
368
369 for (int i = 0; i < bytes; i++) {
370
371 uint8_t octet;
372
373 if (!DNP3ReadUint8(buf, len, &octet)) {
374 goto error;
375 }
376
377 for (int j = 0; j < 8 && count; j = j + {{object.fields[0].width}}) {
378
379 object = SCCalloc(1, sizeof(*object));
380 if (unlikely(object == NULL)) {
381 goto error;
382 }
383
384{% if object.fields[0].width == 1 %}
385 object->{{object.fields[0].name}} = (octet >> j) & 0x1;
386{% elif object.fields[0].width == 2 %}
387 object->{{object.fields[0].name}} = (octet >> j) & 0x3;
388{% else %}
389#error "Unhandled field width: {{object.fields[0].width}}"
390{% endif %}
391
2a0bb108 392 if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) {
240d789c
JI
393 goto error;
394 }
395
396 object = NULL;
397 count--;
2a0bb108 398 point_index++;
240d789c
JI
399 }
400
401 }
402
403 return 1;
404error:
405 if (object != NULL) {
406 SCFree(object);
407 }
408 return 0;
409}
410
411{% else %}
412static int DNP3DecodeObjectG{{object.group}}V{{object.variation}}(const uint8_t **buf, uint32_t *len,
413 uint8_t prefix_code, uint32_t start, uint32_t count,
414 DNP3PointList *points)
415{
416 DNP3ObjectG{{object.group}}V{{object.variation}} *object = NULL;
417 uint32_t prefix = 0;
2a0bb108 418 uint32_t point_index = start;
240d789c
JI
419{% if object._track_offset %}
420 uint32_t offset;
421{% endif %}
422{% if object.constraints %}
423
424{% for (key, val) in object.constraints.items() %}
425{% if key == "require_size_prefix" %}
426 if (!DNP3PrefixIsSize(prefix_code)) {
427 goto error;
428 }
429{% elif key == "require_prefix_code" %}
430 if (prefix_code != {{val}}) {
431 goto error;
432 }
433{% else %}
434{{ raise("Unhandled constraint: %s" % (key)) }}
435{% endif %}
436{% endfor %}
437{% endif %}
438
439 while (count--) {
440
441 object = SCCalloc(1, sizeof(*object));
442 if (unlikely(object == NULL)) {
443 goto error;
444 }
445
446 if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) {
447 goto error;
448 }
449{% if object._track_offset %}
450
451 offset = *len;
452{% endif %}
453
454{% for field in object.fields %}
455{% if field.type == "int16" %}
456 if (!DNP3ReadUint16(buf, len, (uint16_t *)&object->{{field.name}})) {
457 goto error;
458 }
459{% elif field.type == "int32" %}
460 if (!DNP3ReadUint32(buf, len, (uint32_t *)&object->{{field.name}})) {
461 goto error;
462 }
463{% elif field.type == "uint8" %}
464 if (!DNP3ReadUint8(buf, len, &object->{{field.name}})) {
465 goto error;
466 }
467{% elif field.type == "uint16" %}
468 if (!DNP3ReadUint16(buf, len, &object->{{field.name}})) {
469 goto error;
470 }
471{% elif field.type == "uint24" %}
472 if (!DNP3ReadUint24(buf, len, &object->{{field.name}})) {
473 goto error;
474 }
475{% elif field.type == "uint32" %}
476 if (!DNP3ReadUint32(buf, len, &object->{{field.name}})) {
477 goto error;
478 }
479{% elif field.type == "uint64" %}
480 if (!DNP3ReadUint64(buf, len, &object->{{field.name}})) {
481 goto error;
482 }
483{% elif field.type == "flt32" %}
484 if (!DNP3ReadFloat32(buf, len, &object->{{field.name}})) {
485 goto error;
486 }
487{% elif field.type == "flt64" %}
488 if (!DNP3ReadFloat64(buf, len, &object->{{field.name}})) {
489 goto error;
490 }
491{% elif field.type == "dnp3time" %}
492 if (!DNP3ReadUint48(buf, len, &object->{{field.name}})) {
493 goto error;
494 }
495{% elif field.type == "vstr4" %}
496 if (*len < 4) {
497 goto error;
498 }
499 memcpy(object->{{field.name}}, *buf, 4);
500 object->{{field.name}}[4] = '\\\\0';
501 *buf += 4;
502 *len -= 4;
503{% elif field.type == "bytearray" %}
504{% if field.len_from_prefix %}
505 object->{{field.len_field}} = prefix - (offset - *len);
506{% endif %}
507 if (object->{{field.len_field}} > 0) {
508 if (*len < object->{{field.len_field}}) {
509 /* Not enough data. */
510 goto error;
511 }
512 object->{{field.name}} = SCCalloc(1, object->{{field.len_field}});
513 if (unlikely(object->{{field.name}} == NULL)) {
514 goto error;
515 }
516 memcpy(object->{{field.name}}, *buf, object->{{field.len_field}});
517 *buf += object->{{field.len_field}};
518 *len -= object->{{field.len_field}};
519 }
520{% elif field.type == "chararray" %}
521{% if field.len_from_prefix %}
522 object->{{field.len_field}} = prefix - (offset - *len);
523{% endif %}
524 if (object->{{field.len_field}} > 0) {
6a6aa04f
PA
525 if (*len < object->{{field.len_field}}) {
526 /* Not enough data. */
527 goto error;
528 }
240d789c
JI
529 memcpy(object->{{field.name}}, *buf, object->{{field.len_field}});
530 *buf += object->{{field.len_field}};
531 *len -= object->{{field.len_field}};
532 }
533 object->{{field.name}}[object->{{field.len_field}}] = '\\\\0';
534{% elif field.type == "bstr8" %}
535 {
536 uint8_t octet;
537 if (!DNP3ReadUint8(buf, len, &octet)) {
538 goto error;
539 }
6a6aa04f 540{% set ns = namespace(shift=0) %}
240d789c
JI
541{% for field in field.fields %}
542{% if field.width == 1 %}
6a6aa04f 543 object->{{field.name}} = (octet >> {{ns.shift}}) & 0x1;
240d789c 544{% elif field.width == 2 %}
6a6aa04f 545 object->{{field.name}} = (octet >> {{ns.shift}}) & 0x3;
240d789c 546{% elif field.width == 4 %}
6a6aa04f 547 object->{{field.name}} = (octet >> {{ns.shift}}) & 0xf;
240d789c 548{% elif field.width == 7 %}
6a6aa04f 549 object->{{field.name}} = (octet >> {{ns.shift}}) & 0x7f;
240d789c
JI
550{% else %}
551{{ raise("Unhandled width of %d." % (field.width)) }}
552{% endif %}
6a6aa04f 553{% set ns.shift = ns.shift + field.width %}
240d789c
JI
554{% endfor %}
555 }
556{% else %}
557{{ raise("Unhandled datatype '%s' for object %d:%d." % (field.type,
558 object.group, object.variation)) }}
559{% endif %}
560{% endfor %}
561
2a0bb108 562 if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) {
240d789c
JI
563 goto error;
564 }
565
566 object = NULL;
2a0bb108 567 point_index++;
240d789c
JI
568 }
569
570 return 1;
571error:
572 if (object != NULL) {
573 SCFree(object);
574 }
575
576 return 0;
577}
578
579{% endif %}
580{% endfor %}
581
582void DNP3FreeObjectPoint(int group, int variation, void *point)
583{
584 switch(DNP3_OBJECT_CODE(group, variation)) {
585{% for object in objects %}
586{% if f_has_freeable_types(object.fields) %}
587 case DNP3_OBJECT_CODE({{object.group}}, {{object.variation}}): {
588 DNP3ObjectG{{object.group}}V{{object.variation}} *object = (DNP3ObjectG{{object.group}}V{{object.variation}} *) point;
589{% for field in object.fields %}
590{% if field.type == "bytearray" %}
591 if (object->{{field.name}} != NULL) {
592 SCFree(object->{{field.name}});
593 }
594{% endif %}
595{% endfor %}
596 break;
597 }
598{% endif %}
599{% endfor %}
600 default:
601 break;
602 }
603 SCFree(point);
604}
605
606/**
607 * \\\\brief Decode a DNP3 object.
608 *
609 * \\\\retval 0 on success. On failure a positive integer corresponding
610 * to a DNP3 application layer event will be returned.
611 */
612int DNP3DecodeObject(int group, int variation, const uint8_t **buf,
613 uint32_t *len, uint8_t prefix_code, uint32_t start,
614 uint32_t count, DNP3PointList *points)
615{
616 int rc = 0;
617
618 switch (DNP3_OBJECT_CODE(group, variation)) {
619{% for object in objects %}
620 case DNP3_OBJECT_CODE({{object.group}}, {{object.variation}}):
621 rc = DNP3DecodeObjectG{{object.group}}V{{object.variation}}(buf, len, prefix_code, start, count,
622 points);
623 break;
624{% endfor %}
625 default:
626 return DNP3_DECODER_EVENT_UNKNOWN_OBJECT;
627 }
628
629 return rc ? 0 : DNP3_DECODER_EVENT_MALFORMED;
630}
631
632"""
633
634 try:
635 filename = "src/app-layer-dnp3-objects.c"
636 env = jinja2.Environment(trim_blocks=True, lstrip_blocks=True)
637 code = env.from_string(template).render(context)
638 content = open(filename).read()
639 content = re.sub(
640 "(%s).*(%s)" % (re.escape(IN_PLACE_START), re.escape(IN_PLACE_END)),
641 r"\1%s\n\2" % (code), content, 1, re.M | re.DOTALL)
642 open(filename, "w").write(content)
643 print("Updated %s." % (filename))
644 except Exception as err:
645 print("Failed to update %s: %s" % (filename, err), file=sys.stderr)
646 sys.exit(1)
647
648def preprocess_object(obj):
649
650 valid_keys = [
651 "group",
652 "variation",
653 "constraints",
654 "extra_fields",
655 "fields",
656 "packed",
657 ]
658
659 valid_field_keys = [
660 "type",
661 "name",
662 "width",
663 "len_from_prefix",
664 "len_field",
665 "fields",
666 "size",
667 ]
668
669 if "unimplemented" in obj:
670 print("Object not implemented: %s:%s: %s" % (
671 str(obj["group"]), str(obj["variation"]), obj["unimplemented"]))
672 return None
673
674 for key, val in obj.items():
675
676 if key not in valid_keys:
677 print("Invalid key '%s' in object %d:%d" % (
678 key, obj["group"], obj["variation"]), file=sys.stderr)
679 sys.exit(1)
680
681 for field in obj["fields"]:
682
683 for key in field.keys():
684 if key not in valid_field_keys:
685 print("Invalid key '%s' in object %d:%d" % (
686 key, obj["group"], obj["variation"]), file=sys.stderr)
687 sys.exit(1)
688
689 if "len_from_prefix" in field and field["len_from_prefix"]:
690 obj["_track_offset"] = True
691 break
692
693 if field["type"] == "bstr8":
694 width = 0
695 for subfield in field["fields"]:
696 width += int(subfield["width"])
697 assert(width == 8)
698
699 return obj
700
701def main():
702
f70e8d00
JI
703 # Require Jinja2 2.10 or greater.
704 jv = jinja2.__version__.split(".")
705 if int(jv[0]) < 2 or (int(jv[0]) == 2 and int(jv[1]) < 10):
706 print("error: jinja2 v2.10 or great required")
707 return 1
708
240d789c
JI
709 definitions = yaml.load(open("scripts/dnp3-gen/dnp3-objects.yaml"))
710 print("Loaded %s objects." % (len(definitions["objects"])))
711 definitions["objects"] = map(preprocess_object, definitions["objects"])
712
713 # Filter out unimplemented objects.
714 definitions["objects"] = [
715 obj for obj in definitions["objects"] if obj != None]
716
717 context = {
718 "raise": raise_helper,
719 "objects": definitions["objects"],
720 "is_integer_type": is_integer_type,
721 "f_to_type": to_type,
722 "f_has_freeable_types": has_freeable_types,
723 "command_line": " ".join(sys.argv),
724 }
725
726 gen_object_structs(context)
727 gen_object_decoders(context)
728 generate(util_lua_dnp3_objects_c_template,
729 "src/util-lua-dnp3-objects.c",
730 context)
731 generate(output_json_dnp3_objects_template,
732 "src/output-json-dnp3-objects.c",
733 context)
734
735if __name__ == "__main__":
736 sys.exit(main())