1 ###################################################
2 # Samba3 NDR parser generator for IDL structures
3 # Copyright jelmer@samba.org 2005
4 # released under the GNU GPL
6 package Parse::Pidl::Samba3::Parser;
9 use Parse::Pidl::Typelist qw(hasType getType mapType);
10 use Parse::Pidl::Util qw(has_property ParseExpr);
11 use Parse::Pidl::NDR qw(GetPrevLevel GetNextLevel ContainsDeferred);
12 use Parse::Pidl::Samba3::Types qw(DeclShort DeclLong InitType DissectType);
14 use vars qw($VERSION);
17 use constant PRIMITIVES => 1;
18 use constant DEFERRED => 2;
22 sub indent() { $tabs.="\t"; }
23 sub deindent() { $tabs = substr($tabs, 1); }
24 sub pidl($) { $res .= $tabs.(shift)."\n"; }
25 sub fatal($$) { my ($e,$s) = @_; die("$e->{FILE}:$e->{LINE}: $s\n"); }
28 # - Add some security checks (array sizes, memory alloc == NULL, etc)
29 # - Don't add seperate _p and _d functions if there is no deferred data
31 sub DeclareArrayVariables
38 foreach my $e (@$es) {
39 foreach my $l (@{$e->{LEVELS}}) {
41 next if ($l->{IS_DEFERRED} and $what == PRIMITIVES);
42 next if (not $l->{IS_DEFERRED} and $what == DEFERRED);
44 if ($l->{TYPE} eq "ARRAY") {
45 pidl "uint32 i_$e->{NAME}_$l->{LEVEL_INDEX};";
53 sub ParseElementLevelData($$$$$$)
55 my ($e,$l,$nl,$env,$varname,$what) = @_;
57 my @args = ($e,$l,$varname,$what);
59 # See if we need to add a level argument because we're parsing a union
60 foreach (@{$e->{LEVELS}}) {
61 push (@args, ParseExpr("level_$e->{NAME}", $env))
62 if ($_->{TYPE} eq "SWITCH");
65 my $c = DissectType(@args);
69 pidl "\treturn False;";
72 sub ParseElementLevelArray($$$$$$)
74 my ($e,$l,$nl,$env,$varname,$what) = @_;
76 if ($l->{IS_ZERO_TERMINATED}) {
77 fatal($e, "[string] attribute not supported for Samba3 yet");
82 my $len = ParseExpr($l->{LENGTH_IS}, $env);
83 my $size = ParseExpr($l->{SIZE_IS}, $env);
85 if ($what == PRIMITIVES) {
87 if ($l->{IS_CONFORMANT} and not $l->{IS_SURROUNDING}) {
88 pidl "if (!prs_uint32(\"size_$e->{NAME}\", ps, depth, &" . ParseExpr("size_$e->{NAME}", $env) . "))";
89 pidl "\treturn False;";
93 if ($l->{IS_VARYING}) {
94 pidl "if (!prs_uint32(\"offset_$e->{NAME}\", ps, depth, &" . ParseExpr("offset_$e->{NAME}", $env) . "))";
95 pidl "\treturn False;";
98 pidl "if (!prs_uint32(\"length_$e->{NAME}\", ps, depth, &" . ParseExpr("length_$e->{NAME}", $env) . "))";
99 pidl "\treturn False;";
104 # Everything but fixed arrays have to be allocated
105 if (!$l->{IS_FIXED} and $what == PRIMITIVES) {
106 pidl "if (UNMARSHALLING(ps)) {";
108 pidl "$varname = (void *)PRS_ALLOC_MEM_VOID(ps,sizeof(*$varname)*$size);";
113 return if ($what == DEFERRED and not ContainsDeferred($e,$l));
115 my $i = "i_$e->{NAME}_$l->{LEVEL_INDEX}";
116 pidl "for ($i=0; $i<$len;$i++) {";
118 ParseElementLevel($e,$nl,$env,$varname."[$i]",$what);
123 sub ParseElementLevelSwitch($$$$$$)
125 my ($e,$l,$nl,$env,$varname,$what) = @_;
127 ParseElementLevel($e,$nl,$env,$varname,$what);
130 sub ParseElementLevelPtr($$$$$$)
132 my ($e,$l,$nl,$env,$varname,$what) = @_;
134 if ($what == PRIMITIVES) {
135 pidl "if (!prs_uint32(\"ptr_$e->{NAME}\", ps, depth, &" . ParseExpr("ptr_$e->{NAME}", $env) . "))";
136 pidl "\treturn False;";
140 if ($l->{POINTER_TYPE} eq "relative") {
141 fatal($e, "relative pointers not supported for Samba 3");
145 if ($what == DEFERRED) {
146 pidl "if (" . ParseExpr("ptr_$e->{NAME}", $env) . ") {";
148 ParseElementLevel($e,$nl,$env,$varname,PRIMITIVES);
149 ParseElementLevel($e,$nl,$env,$varname,DEFERRED);
155 sub ParseElementLevelSubcontext($$$$$$)
157 my ($e,$l,$nl,$env,$varname,$what) = @_;
159 fatal($e, "subcontext() not supported for Samba 3");
163 sub ParseElementLevel($$$$$)
165 my ($e,$l,$env,$varname,$what) = @_;
168 DATA => \&ParseElementLevelData,
169 SUBCONTEXT => \&ParseElementLevelSubcontext,
170 POINTER => \&ParseElementLevelPtr,
171 SWITCH => \&ParseElementLevelSwitch,
172 ARRAY => \&ParseElementLevelArray
173 }->{$l->{TYPE}}->($e,$l,GetNextLevel($e,$l),$env,$varname,$what);
176 sub ParseElement($$$)
178 my ($e,$env,$what) = @_;
180 ParseElementLevel($e, $e->{LEVELS}[0], $env, ParseExpr($e->{NAME}, $env), $what);
186 my ($e,$l,$varname,$env) = @_;
188 if ($l->{TYPE} eq "POINTER") {
189 pidl "if ($varname) {";
191 pidl ParseExpr("ptr_$e->{NAME}", $env) . " = 1;";
192 InitLevel($e, GetNextLevel($e,$l), "*$varname", $env);
195 pidl "\t" . ParseExpr("ptr_$e->{NAME}", $env) . " = 0;";
197 } elsif ($l->{TYPE} eq "ARRAY") {
198 pidl ParseExpr($e->{NAME}, $env) . " = $varname;";
199 } elsif ($l->{TYPE} eq "DATA") {
200 pidl InitType($e, $l, ParseExpr($e->{NAME}, $env), $varname);
201 } elsif ($l->{TYPE} eq "SWITCH") {
202 InitLevel($e, GetNextLevel($e,$l), $varname, $env);
206 sub GenerateEnvElement($$)
209 foreach my $l (@{$e->{LEVELS}}) {
210 if ($l->{TYPE} eq "DATA") {
211 $env->{$e->{NAME}} = "v->$e->{NAME}";
212 } elsif ($l->{TYPE} eq "POINTER") {
213 $env->{"ptr_$e->{NAME}"} = "v->ptr_$e->{NAME}";
214 } elsif ($l->{TYPE} eq "SWITCH") {
215 $env->{"level_$e->{NAME}"} = "v->level_$e->{NAME}";
216 } elsif ($l->{TYPE} eq "ARRAY") {
217 $env->{"length_$e->{NAME}"} = "v->length_$e->{NAME}";
218 $env->{"size_$e->{NAME}"} = "v->size_$e->{NAME}";
219 $env->{"offset_$e->{NAME}"} = "v->offset_$e->{NAME}";
228 my $fn = "$if->{NAME}_io_$n";
229 my $sn = uc("$if->{NAME}_$n");
230 my $ifn = "init_$if->{NAME}_$n";
233 foreach (@{$s->{ELEMENTS}}) {
234 $args .= ", " . DeclLong($_);
237 my $env = { "this" => "v" };
238 GenerateEnvElement($_, $env) foreach (@{$s->{ELEMENTS}});
240 pidl "BOOL $ifn($sn *v$args)";
243 pidl "DEBUG(5,(\"$ifn\\n\"));";
245 # Call init for all arguments
246 foreach (@{$s->{ELEMENTS}}) {
247 InitLevel($_, $_->{LEVELS}[0], $_->{NAME}, $env);
258 pidl "BOOL $pfn(const char *desc, $sn *v, prs_struct *ps, int depth)";
261 DeclareArrayVariables($s->{ELEMENTS}, PRIMITIVES);
262 pidl "if (v == NULL)";
263 pidl "\treturn False;";
265 pidl "prs_debug(ps, depth, desc, \"$pfn\");";
267 pidl "if (!prs_align_custom(ps, $s->{ALIGN}))";
268 pidl "\treturn False;";
271 if ($s->{SURROUNDING_ELEMENT}) {
272 pidl "if (!prs_uint32(\"size_$s->{SURROUNDING_ELEMENT}->{NAME}\", ps, depth, &" . ParseExpr("size_$s->{SURROUNDING_ELEMENT}->{NAME}", $env) . "))";
273 pidl "\treturn False;";
277 foreach (@{$s->{ELEMENTS}}) {
278 ParseElement($_, $env, PRIMITIVES);
287 pidl "BOOL $dfn(const char *desc, $sn *v, prs_struct *ps, int depth)";
290 DeclareArrayVariables($s->{ELEMENTS}, DEFERRED);
291 pidl "if (v == NULL)";
292 pidl "\treturn False;";
294 pidl "prs_debug(ps, depth, desc, \"$dfn\");";
296 pidl "if (!prs_align_custom(ps, $s->{ALIGN}))";
297 pidl "\treturn False;";
300 foreach (@{$s->{ELEMENTS}}) {
301 ParseElement($_, $env, DEFERRED);
311 sub UnionGenerateEnvElement($)
316 foreach my $l (@{$e->{LEVELS}}) {
317 if ($l->{TYPE} eq "DATA") {
318 $env->{$e->{NAME}} = "v->u.$e->{NAME}";
319 } elsif ($l->{TYPE} eq "POINTER") {
320 $env->{"ptr_$e->{NAME}"} = "v->ptr";
321 } elsif ($l->{TYPE} eq "SWITCH") {
322 $env->{"level_$e->{NAME}"} = "v->level";
323 } elsif ($l->{TYPE} eq "ARRAY") {
324 $env->{"length_$e->{NAME}"} = "v->length";
325 $env->{"size_$e->{NAME}"} = "v->size";
326 $env->{"offset_$e->{NAME}"} = "v->offset";
337 my $fn = "$if->{NAME}_io_$n";
338 my $sn = uc("$if->{NAME}_$n\_ctr");
343 pidl "BOOL $pfn(const char *desc, $sn* v, uint32 level, prs_struct *ps, int depth)";
346 DeclareArrayVariables($u->{ELEMENTS});
347 pidl "if (!prs_align_custom(ps, $u->{ALIGN}))";
348 pidl "\treturn False;";
351 if (has_property($u, "nodiscriminant")) {
352 pidl "if (!prs_uint32(\"switch_value\", ps, depth, &v->switch_value))";
353 pidl "\treturn False;";
357 # Maybe check here that level and v->switch_value are equal?
359 pidl "switch (level) {";
362 foreach (@{$u->{ELEMENTS}}) {
365 if ($_->{TYPE} ne "EMPTY") {
367 my $env = UnionGenerateEnvElement($_);
368 ParseElement($_, $env, PRIMITIVES);
369 ParseElement($_, $env, DEFERRED);
384 pidl "BOOL $dfn(const char *desc, $sn* v, uint32 level, prs_struct *ps, int depth)";
387 DeclareArrayVariables($u->{ELEMENTS});
388 pidl "if (!prs_align_custom(ps, $u->{ALIGN}))";
389 pidl "\treturn False;";
392 pidl "switch (level) {";
395 foreach (@{$u->{ELEMENTS}}) {
398 if ($_->{TYPE} ne "EMPTY") {
400 my $env = UnionGenerateEnvElement($_);
401 ParseElement($_, $env, DEFERRED);
418 sub CreateFnDirection($$$$)
420 my ($fn,$ifn, $s,$es) = @_;
424 $args .= ", " . DeclLong($_);
427 my $env = { "this" => "v" };
428 GenerateEnvElement($_, $env) foreach (@$es);
430 pidl "BOOL $ifn($s *v$args)";
433 pidl "DEBUG(5,(\"$ifn\\n\"));";
435 # Call init for all arguments
437 InitLevel($_, $_->{LEVELS}[0], $_->{NAME}, $env);
445 pidl "BOOL $fn(const char *desc, $s *v, prs_struct *ps, int depth)";
448 DeclareArrayVariables($es);
449 pidl "if (v == NULL)";
450 pidl "\treturn False;";
452 pidl "prs_debug(ps, depth, desc, \"$fn\");";
456 ParseElement($_, $env, PRIMITIVES);
457 ParseElement($_, $env, DEFERRED);
467 sub ParseFunction($$)
474 foreach (@{$fn->{ELEMENTS}}) {
475 push (@in, $_) if (grep(/in/, @{$_->{DIRECTION}}));
476 push (@out, $_) if (grep(/out/, @{$_->{DIRECTION}}));
479 if (defined($fn->{RETURN_TYPE})) {
482 TYPE => $fn->{RETURN_TYPE},
486 DATA_TYPE => $fn->{RETURN_TYPE}
492 CreateFnDirection("$if->{NAME}_io_q_$fn->{NAME}",
493 "init_$if->{NAME}_q_$fn->{NAME}",
494 uc("$if->{NAME}_q_$fn->{NAME}"),
496 CreateFnDirection("$if->{NAME}_io_r_$fn->{NAME}",
497 "init_$if->{NAME}_r_$fn->{NAME}",
498 uc("$if->{NAME}_r_$fn->{NAME}"),
502 sub ParseInterface($)
507 pidl "/* $if->{NAME} structures */";
508 foreach (@{$if->{TYPEDEFS}}) {
509 ParseStruct($if, $_->{DATA}, $_->{NAME}) if ($_->{DATA}->{TYPE} eq "STRUCT");
510 ParseUnion($if, $_->{DATA}, $_->{NAME}) if ($_->{DATA}->{TYPE} eq "UNION");
513 pidl "/* $if->{NAME} functions */";
514 ParseFunction($if, $_) foreach (@{$if->{FUNCTIONS}});
519 my($ndr,$filename) = @_;
525 pidl " * Unix SMB/CIFS implementation.";
526 pidl " * parser auto-generated by pidl. DO NOT MODIFY!";
529 pidl "#include \"includes.h\"";
531 pidl "#undef DBGC_CLASS";
532 pidl "#define DBGC_CLASS DBGC_RPC_PARSE";
536 ParseInterface($_) if ($_->{TYPE} eq "INTERFACE");