r4798: When dissecting structures, name the protocol tree after the field name,
[Samba/gebeck_regimport.git] / source4 / build / pidl / eparser.pm
blob02cc30c0aacefc7a976a28b0d0831be454bffa31
1 ###################################################
2 # Samba4 parser generator for IDL structures
3 # Copyright tridge@samba.org 2000-2003
4 # Copyright tpot@samba.org 2001,2004
5 # released under the GNU GPL
7 package IdlEParser;
9 use strict;
11 # the list of needed functions
12 my %needed;
14 my $module;
15 my $if_uuid;
16 my $if_version;
17 my $if_endpoints;
19 sub pidl($)
21 print OUT shift;
24 #####################################################################
25 # work out is a parse function should be declared static or not
26 sub fn_prefix($)
28 my $fn = shift;
29 if ($fn->{TYPE} eq "TYPEDEF") {
30 if (util::has_property($fn, "public")) {
31 return "";
35 if ($fn->{TYPE} eq "FUNCTION") {
36 if (util::has_property($fn, "public")) {
37 return "";
40 return "static ";
44 #####################################################################
45 # parse a function
46 sub ParseFunctionPull($)
48 my($fn) = shift;
49 my $static = fn_prefix($fn);
51 # request function
52 pidl "int $fn->{NAME}_rqst(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, guint8 *drep)\n{\n";
54 pidl "\tstruct pidl_pull *ndr = pidl_pull_init(tvb, offset, pinfo, drep);\n";
55 pidl "\tstruct $fn->{NAME} *r = talloc_p(NULL, struct $fn->{NAME});\n";
56 pidl "\tpidl_tree ptree;\n\n";
58 pidl "\tptree.proto_tree = tree;\n";
59 pidl "\tptree.subtree_list = NULL;\n\n";
61 pidl "\tndr_pull_$fn->{NAME}(ndr, NDR_IN, &ptree, r);\n";
63 pidl "\n\treturn ndr->offset;\n";
64 pidl "}\n\n";
66 # response function
67 pidl "int $fn->{NAME}_resp(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, guint8 *drep)\n{\n";
69 pidl "\tstruct pidl_pull *ndr = pidl_pull_init(tvb, offset, pinfo, drep);\n";
70 pidl "\tstruct $fn->{NAME} *r = talloc_p(NULL, struct $fn->{NAME});\n";
71 pidl "\tpidl_tree ptree;\n\n";
73 pidl "\tptree.proto_tree = tree;\n";
74 pidl "\tptree.subtree_list = NULL;\n\n";
76 pidl "\tndr_pull_$fn->{NAME}(ndr, NDR_OUT, &ptree, r);\n";
78 pidl "\n\treturn ndr->offset;\n";
79 pidl "}\n\n";
82 #####################################################################
83 # produce a function call table
84 sub FunctionTable($)
86 my($interface) = shift;
87 my($data) = $interface->{DATA};
89 pidl "static dcerpc_sub_dissector dcerpc_dissectors[] = {\n";
90 my $num = 0;
91 foreach my $d (@{$data}) {
92 if ($d->{TYPE} eq "FUNCTION") {
93 # Strip module name from function name, if present
94 my($n) = $d->{NAME};
95 $n = substr($d->{NAME}, length($module) + 1),
96 if $module eq substr($d->{NAME}, 0, length($module));
97 pidl "\t{ $num, \"$n\",\n";
98 pidl "\t\t$d->{NAME}_rqst,\n";
99 pidl "\t\t$d->{NAME}_resp },\n";
100 $num++;
103 pidl "};\n\n";
106 sub type2ft($)
108 my($t) = shift;
110 return "FT_UINT$1" if $t =~ /uint(8|16|32|64)/;
111 return "FT_INT$1" if $t =~ /int(8|16|32|64)/;
112 return "FT_UINT64", if ($t eq "HYPER_T" or $t eq "NTTIME");
114 # Type is an enum
116 return "FT_UINT16";
119 # Determine the display base for an element
121 sub elementbase($)
123 my($e) = shift;
125 if (my $base = util::has_property($e, "display")) {
126 return "BASE_" . uc($base);
129 return "BASE_DEC", if $e->{TYPE} eq "ENUM";
130 return "BASE_DEC", if $e->{TYPE} =~ /u?int(8|16|32|64)/;
131 return "BASE_DEC", if $e->{TYPE} eq "NTTIME" or $e->{TYPE} eq "HYPER_T";
133 # Probably an enum
135 return "BASE_DEC";
138 # Convert a IDL structure field name (e.g access_mask) to a prettier
139 # string like 'Access Mask'.
141 sub field2name($)
143 my($field) = shift;
145 $field =~ s/_/ /g; # Replace underscores with spaces
146 $field =~ s/(\w+)/\u\L$1/g; # Capitalise each word
148 return $field;
151 sub NeededFunction($)
153 my $fn = shift;
155 $needed{"pull_$fn->{NAME}"} = 1;
157 # Add entries for function arguments
159 foreach my $e (@{$fn->{DATA}}) {
161 $e->{PARENT} = $fn;
162 $needed{"pull_$e->{TYPE}"} = 1;
164 if (util::is_scalar_type($e->{TYPE})) {
166 if (defined($e->{ARRAY_LEN}) or
167 util::has_property($e, "size_is")) {
169 # Array of scalar types
171 $needed{"hf_$fn->{NAME}_$e->{NAME}_array"} = {
172 'name' => field2name($e->{NAME}),
173 'type' => $e->{TYPE},
174 'ft' => "FT_BYTES",
175 'base' => elementbase($e)
178 } else {
180 $needed{"hf_$fn->{NAME}_$e->{NAME}"} = {
181 'name' => field2name($e->{NAME}),
182 'type' => $e->{TYPE},
183 'ft' => type2ft($e->{TYPE}),
184 'base' => elementbase($e)
189 $e->{PARENT} = $fn;
191 } else {
192 $needed{"ett_$e->{TYPE}"} = 1;
196 # Add entry for return value
198 $needed{"hf_$fn->{NAME}_result"} = {
199 'name' => field2name('result'),
200 'type' => $fn->{RETURN_TYPE},
201 'ft' => type2ft($fn->{RETURN_TYPE}),
202 'base' => elementbase($fn)
206 sub NeededTypedef($)
208 my $t = shift;
210 if (util::has_property($t, "public")) {
211 $needed{"pull_$t->{NAME}"} = 1;
214 if ($t->{DATA}->{TYPE} eq "STRUCT") {
216 for my $e (@{$t->{DATA}->{ELEMENTS}}) {
218 $e->{PARENT} = $t->{DATA};
220 if ($needed{"pull_$t->{NAME}"}) {
221 $needed{"pull_$e->{TYPE}"} = 1;
224 if (util::is_scalar_type($e->{TYPE})) {
226 if (defined($e->{ARRAY_LEN}) or
227 util::has_property($e, "size_is")) {
229 # Arrays of scalar types are FT_BYTES
231 $needed{"hf_$t->{NAME}_$e->{NAME}_array"} = {
232 'name' => field2name($e->{NAME}),
233 'type' => $e->{TYPE},
234 'ft' => "FT_BYTES",
235 'base' => elementbase($e)
238 } else {
240 $needed{"hf_$t->{NAME}_$e->{NAME}"} = {
241 'name' => field2name($e->{NAME}),
242 'type' => $e->{TYPE},
243 'ft' => type2ft($e->{TYPE}),
244 'base' => elementbase($e)
248 $e->{PARENT} = $t->{DATA};
250 if ($needed{"pull_$t->{NAME}"}) {
251 $needed{"pull_$e->{TYPE}"} = 1;
254 } else {
256 $needed{"ett_$e->{TYPE}"} = 1;
262 if ($t->{DATA}->{TYPE} eq "UNION") {
264 for my $e (@{$t->{DATA}->{DATA}}) {
266 $e->{PARENT} = $t->{DATA};
268 if ($e->{TYPE} eq "UNION_ELEMENT") {
270 if ($needed{"pull_$t->{NAME}"}) {
271 $needed{"pull_$e->{DATA}->{TYPE}"} = 1;
274 $needed{"ett_$e->{DATA}{TYPE}"} = 1;
278 $needed{"ett_$t->{NAME}"} = 1;
281 if ($t->{DATA}->{TYPE} eq "ENUM") {
283 $needed{"hf_$t->{NAME}"} = {
284 'name' => $t->{NAME},
285 'ft' => 'FT_UINT16',
286 'base' => 'BASE_DEC'
291 #####################################################################
292 # work out what parse functions are needed
293 sub BuildNeeded($)
295 my($interface) = shift;
297 my($data) = $interface->{DATA};
299 foreach my $d (@{$data}) {
300 ($d->{TYPE} eq "FUNCTION") &&
301 NeededFunction($d);
304 foreach my $d (reverse @{$data}) {
305 ($d->{TYPE} eq "TYPEDEF") &&
306 NeededTypedef($d);
310 #####################################################################
311 # parse the interface definitions
312 sub ModuleHeader($)
314 my($h) = shift;
316 $if_uuid = $h->{PROPERTIES}->{uuid};
317 $if_version = $h->{PROPERTIES}->{version};
318 $if_endpoints = $h->{PROPERTIES}->{endpoints};
321 #####################################################################
322 # Generate a header file that contains function prototypes for
323 # structs and typedefs.
324 sub ParseHeader($$)
326 my($idl) = shift;
327 my($filename) = shift;
329 open(OUT, ">$filename") || die "can't open $filename";
331 pidl "/* parser auto-generated by pidl */\n\n";
333 foreach my $x (@{$idl}) {
334 if ($x->{TYPE} eq "INTERFACE") {
335 foreach my $d (@{$x->{DATA}}) {
337 # Make prototypes for [public] structures and
338 # unions.
340 if ($d->{TYPE} eq "TYPEDEF" and
341 util::has_property($d, "public")) {
343 if ($d->{DATA}{TYPE} eq "STRUCT") {
344 pidl "void ndr_pull_$d->{NAME}(struct ndr_pull *ndr, int ndr_flags, proto_tree *tree, struct $d->{NAME} *r);\n\n";
347 if ($d->{DATA}{TYPE} eq "UNION") {
348 pidl "void ndr_pull_$d->{NAME}(struct ndr_pull *ndr, int ndr_flags, proto_tree *tree, union $d->{NAME} *r, uint16 level);\n\n";
355 close(OUT);
358 #####################################################################
359 # rewrite autogenerated header file
360 sub RewriteHeader($$$)
362 my($idl) = shift;
363 my($input) = shift;
364 my($output) = shift;
366 %needed = ();
368 # Open files
370 open(IN, "<$input") || die "can't open $input for reading";
371 open(OUT, ">$output") || die "can't open $output for writing";
373 # Read through file
375 while(<IN>) {
377 # Not interested in ndr_push or ndr_print routines as they
378 # define structures we aren't interested in.
380 s/^NTSTATUS ndr_push.*?;\n//smg;
381 s/^void ndr_print.*?;\n//smg;
383 # Get rid of async send and receive function.
385 s/^NTSTATUS dcerpc_.*?;//smg;
386 s/^struct rpc_request.*?;//smg;
388 # Rewrite librpc includes
390 s/^\#include\ \"librpc\/gen_ndr\/ndr_(.*?).h\"$
391 /\#include \"packet-dcerpc-$1.h\"/smgx;
393 # Convert samba fixed width types to stdint types
395 s/((u)?int)([0-9]+)/$1$3_t/smg;
397 # Rename struct ndr_pull to struct pidl_pull
399 s/struct ndr_pull \*ndr/struct pidl_pull \*ndr/smg;
401 # Change prototypes for public functions
403 s/(struct pidl_pull \*ndr, int ndr_flags)/$1, pidl_tree *tree/smg;
405 # Bitmaps
407 s/(uint32_t \*r\);)/pidl_tree *tree, int hf, $1/smg;
409 pidl $_;
412 close(OUT);
415 #####################################################################
416 # rewrite autogenerated C file
417 sub RewriteC($$$)
419 my($idl) = shift;
420 my($input) = shift;
421 my($output) = shift;
423 # Open files
425 open(IN, "<$input") || die "can't open $input for reading";
426 open(OUT, ">$output") || die "can't open $output for writing";
428 # Get name of module
430 foreach my $x (@{$idl}) {
431 if ($x->{TYPE} eq "INTERFACE") {
432 ModuleHeader($x);
433 $module = $x->{NAME};
434 BuildNeeded($x);
438 pidl "#include \"eparser.h\"\n\n";
440 pidl "extern const value_string NT_errors[];\n\n";
442 # Declarations for hf variables
444 pidl "static int hf_opnum = -1;\n";
445 pidl "static int hf_ptr = -1;\n";
446 pidl "static int hf_array_size = -1;\n";
447 pidl "static int hf_result_NTSTATUS = -1;\n";
449 pidl "\n";
451 foreach my $y (keys(%needed)) {
452 pidl "static int $y = -1;\n", if $y =~ /^hf_/;
455 pidl "\n";
457 foreach my $y (keys(%needed)) {
458 pidl "static gint $y = -1;\n", if $y =~ /^ett_/;
461 pidl "\n";
463 # Read through file
465 my $cur_fn;
467 while(<IN>) {
470 # Regexps to do a first pass at removing stuff we aren't
471 # interested in for ehtereal parsers.
474 next, if /^\#include \"includes.h\"/;
476 # Remove the NDR_CHECK() macro calls. Ethereal take care of
477 # this for us as part of the tvbuff_t structure.
479 s/NDR_CHECK\((.*)\)/$1/g;
481 # We're not interested in ndr_{print,push,size} functions so
482 # just delete them.
484 next, if /^(static )?NTSTATUS ndr_push/ .. /^}/;
485 next, if /^void ndr_print/ .. /^}/;
486 next, if /^size_t ndr_size/ .. /^}/;
488 # Get rid of dcerpc interface structures and functions since
489 # they are also not very interesting.
491 next, if /^static const struct dcerpc_interface_call/ .. /^};/;
492 next, if /^static const char \* const [a-z]+_endpoint_strings/ ../^};/;
493 next, if /^static const struct dcerpc_endpoint_list/ .. /^};/;
494 next, if /^const struct dcerpc_interface_table/ .. /^};/;
495 next, if /^static NTSTATUS dcerpc_ndr_[a-z]+_init/ .. /^}/;
496 next, if /^NTSTATUS dcerpc_[a-z]+_init/ .. /^}/;
498 # Rewrite includes to packet-dcerpc-foo.h instead of ndr_foo.h
500 s/^\#include \".*?ndr_(.*?).h\"$/\#include \"packet-dcerpc-$1.h\"/smg;
503 # Remember which structure or function we are processing.
506 $cur_fn = $1, if /NTSTATUS ndr_pull_(.*?)\(struct/;
509 # OK start wrapping the ndr_pull functions that actually
510 # implement the NDR decoding routines. This mainly consists
511 # of adding a couple of parameters to each function call.
514 # Add proto tree and name argument to ndr_pull_ptr() calls.
516 s/(ndr_pull_ptr\(ndr,\ (&_ptr_([^\)]*?))\);)
517 /ndr_pull_ptr(ndr, tree, "$3", $2);/smgx;
519 # Wrap ndr_pull_array_size() and ndr_pull_array_length()
520 # functions. Add leading space in front of first parameter so
521 # we won't get caught by later regexps.
523 s/(ndr_pull_array_(size|length)\(ndr,\ ([^\)]*?)\);)
524 /ndr_pull_array_$2( ndr, tree, $3);/smgx;
526 # Add tree argument to ndr_pull_array() and
527 # ndr_pull_array_foo() calls.
529 s/(ndr_pull_array\(
530 ndr,\
531 ([^,]*?),\ # NDR_SCALARS etc
532 (\(void\ \*\*\)r->(in|out|)\.?([^,]*?)),\ # Pointer to array entries
533 ([^\)].*?)\);) # All other arguments
534 /ndr_pull_array( ndr, $2, tree, $3, $6);/smgx;
536 s/(ndr_pull_array_([^\(]*?)\(
537 ndr,\
538 ([^,]*?),\ # NDR_SCALARS etc
539 (r->((in|out).)?([^,]*?)),\ # Pointer to array elements
540 (.*?)\);) # Number of elements
541 /ndr_pull_array_$2( ndr, $3, tree, hf_${cur_fn}_$7_array, $4, $8);/smgx;
543 # Save ndr_pull_relative{1,2}() calls from being wrapped by the
544 # proceeding regexp by adding a leading space.
546 s/ndr_pull_(relative1|relative2)\((.*?)\);/
547 ndr_pull_$1( $2);/smgx;
549 # Enums
551 s/(^static\ NTSTATUS\ ndr_pull_(.+?),\ (enum\ .+?)\))
552 /static NTSTATUS ndr_pull_$2, pidl_tree *tree, int hf, $3)/smgx;
553 s/uint(8|16|32) v;/uint$1_t v;/smg;
554 s/(ndr_pull_([^\)]*?)\(ndr,\ &v\);)
555 /ndr_pull_$2(ndr, tree, hf, &v);/smgx;
557 s/(ndr_pull_([^\(]+?)\(ndr,\ &_level\);)
558 /ndr_pull_$2(ndr, tree, hf_${cur_fn}_level, &_level);/smgx;
560 # Bitmaps
562 s/(^(static\ )?NTSTATUS\ ndr_pull_(.+?),\ uint32\ \*r\))
563 /NTSTATUS ndr_pull_$3, pidl_tree *tree, int hf, uint32_t *r)/smgx;
565 # Call ethereal wrappers for pull of scalar values in
566 # structures and functions, e.g
568 # ndr_pull_uint32(ndr, &r->in.access_mask);
569 # ndr_pull_uint32(ndr, &r->idx);
571 s/(ndr_pull_([^\)]*?)
572 \(ndr,\
573 (&?r->((in|out)\.)? # Function args contain leading junk
574 ([^\)]*?)) # Element name
575 \);)
576 /ndr_pull_$2(ndr, tree, hf_${cur_fn}_$6, $3);/smgx;
578 # Add tree and hf argument to pulls of "internal" scalars like
579 # array sizes, levels, etc.
581 s/(ndr_pull_(uint32|uint16)\(
582 ndr,\
583 (&_([^\)]*?)) # Internal arg names have leading underscore
584 \);)
585 /ndr_pull_$2(ndr, tree, hf_$4, $3);/smgx;
587 # Add subtree argument to calls dissecting structures, e.g
589 # ndr_pull_string(ndr, NDR_SCALARS|NDR_BUFFERS, &r->command);
590 # ndr_pull_atsvc_enum_ctr(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.ctr);
592 s/(ndr_pull_([^\)]*?)\(
593 ndr,\
594 (NDR_[^,]*?),\
595 (&?r->(in|out|)\.?([^\(].*?))\);)
596 /ndr_pull_$2(ndr, $3, get_subtree(tree, \"$6\", ndr, ett_$2), $4);
597 /smgx;
599 # Add proto_tree parameter to pull function prototypes, e.g
601 # static NTSTATUS ndr_pull_atsvc_JobInfo(struct ndr_pull *ndr,
602 # int ndr_flags, struct atsvc_JobInfo *r)
604 s/^((static\ )?NTSTATUS\ ndr_pull_([^\(]*?)\(
605 struct\ ndr_pull\ \*ndr,\
606 int\ (ndr_)?flags)
607 /$1, proto_tree \*tree/smgx;
609 # Add proto_tree parameter to ndr_pull_subcontext_flags_fn()
611 s/(ndr_pull_subcontext_flags_fn\(ndr)(.*?);/$1, tree$2;/smg;
613 # Get rid of ndr_pull_error() calls for the moment. Ethereal
614 # should take care of buffer overruns and inconsistent array
615 # sizes for us but it would be nice to have some error text in
616 # the dissection.
618 s/(return ndr_pull_error([^;]*?);)/return NT_STATUS_OK; \/\/ $1/smg;
620 # Rename proto_tree args to pidl_tree
622 s/(int (ndr_)?flags), proto_tree \*tree/$1, pidl_tree \*tree/smg;
624 # Rename struct ndr_pull to struct pidl_pull
626 s/struct ndr_pull \*ndr/struct pidl_pull \*ndr/smg;
628 # Fix some internal variable declarations
630 s/uint(16|32) _level;/uint$1_t _level;/smg;
631 s/ndr_pull_([^\(]*)\(ndr,\ tree,\ hf_level,\ &_level\);
632 /ndr_pull_$1(ndr, tree, hf_level_$1, &_level);/smgx;
634 pidl $_;
637 # Function call table
639 foreach my $x (@{$idl}) {
640 if ($x->{TYPE} eq "INTERFACE") {
641 foreach my $y (@{$x->{"INHERITED_DATA"}}) {
642 ($y->{TYPE} eq "FUNCTION") && ParseFunctionPull($y);
645 FunctionTable($x);
649 # Ethereal protocol registration
651 pidl "int proto_dcerpc_pidl_$module = -1;\n\n";
653 pidl "static gint ett_dcerpc_$module = -1;\n\n";
655 if (defined($if_uuid)) {
657 pidl "static e_uuid_t uuid_dcerpc_$module = {\n";
658 pidl "\t0x" . substr($if_uuid, 1, 8);
659 pidl ", 0x" . substr($if_uuid, 10, 4);
660 pidl ", 0x" . substr($if_uuid, 15, 4) . ",\n";
661 pidl "\t{ 0x" . substr($if_uuid, 20, 2);
662 pidl ", 0x" . substr($if_uuid, 22, 2);
663 pidl ", 0x" . substr($if_uuid, 25, 2);
664 pidl ", 0x" . substr($if_uuid, 27, 2);
665 pidl ", 0x" . substr($if_uuid, 29, 2);
666 pidl ", 0x" . substr($if_uuid, 31, 2);
667 pidl ", 0x" . substr($if_uuid, 33, 2);
668 pidl ", 0x" . substr($if_uuid, 35, 2) . " }\n";
669 pidl "};\n\n";
672 if (defined($if_version)) {
673 pidl "static guint16 ver_dcerpc_$module = " . $if_version . ";\n\n";
676 pidl "void proto_register_dcerpc_pidl_$module(void)\n";
677 pidl "{\n";
679 pidl "\tstatic hf_register_info hf[] = {\n";
680 pidl "\t{ &hf_opnum, { \"Operation\", \"$module.opnum\", FT_UINT16, BASE_DEC, NULL, 0x0, \"Operation\", HFILL }},\n";
681 pidl "\t{ &hf_result_NTSTATUS, { \"Return code\", \"$module.rc\", FT_UINT32, BASE_HEX, VALS(NT_errors), 0x0, \"Return status code\", HFILL }},\n";
682 pidl "\t{ &hf_ptr, { \"Pointer\", \"$module.ptr\", FT_UINT32, BASE_HEX, NULL, 0x0, \"Pointer\", HFILL }},\n";
684 foreach my $x (keys(%needed)) {
685 next, if !($x =~ /^hf_/);
686 pidl "\t{ &$x,\n";
687 pidl "\t { \"$needed{$x}{name}\", \"$x\", $needed{$x}{ft}, $needed{$x}{base}, NULL, 0, \"$x\", HFILL }},\n";
690 pidl "\t};\n\n";
692 pidl "\tstatic gint *ett[] = {\n";
693 pidl "\t\t&ett_dcerpc_$module,\n";
694 foreach my $x (keys(%needed)) {
695 pidl "\t\t&$x,\n", if $x =~ /^ett_/;
697 pidl "\t};\n\n";
699 if (defined($if_uuid)) {
701 pidl "\tproto_dcerpc_pidl_$module = proto_register_protocol(\"pidl_$module\", \"pidl_$module\", \"pidl_$module\");\n\n";
703 pidl "\tproto_register_field_array(proto_dcerpc_pidl_$module, hf, array_length (hf));\n";
704 pidl "\tproto_register_subtree_array(ett, array_length(ett));\n";
706 pidl "}\n\n";
708 pidl "void proto_reg_handoff_dcerpc_pidl_$module(void)\n";
709 pidl "{\n";
710 pidl "\tdcerpc_init_uuid(proto_dcerpc_pidl_$module, ett_dcerpc_$module, \n";
711 pidl "\t\t&uuid_dcerpc_$module, ver_dcerpc_$module, \n";
712 pidl "\t\tdcerpc_dissectors, hf_opnum);\n";
713 pidl "}\n";
715 } else {
717 pidl "\tint proto_dcerpc;\n\n";
718 pidl "\tproto_dcerpc = proto_get_id_by_filter_name(\"dcerpc\");\n";
719 pidl "\tproto_register_field_array(proto_dcerpc, hf, array_length(hf));\n";
720 pidl "\tproto_register_subtree_array(ett, array_length(ett));\n";
722 pidl "}\n";
726 close(OUT);