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
38 # Only align if previous element was smaller then current one
40 pidl "if (!prs_align_custom(ps, $b))";
41 pidl "\treturn False;";
48 sub DeclareArrayVariables
55 foreach my $e (@$es) {
56 foreach my $l (@{$e->{LEVELS}}) {
58 next if ($l->{IS_DEFERRED} and $what == PRIMITIVES);
59 next if (not $l->{IS_DEFERRED} and $what == DEFERRED);
61 if ($l->{TYPE} eq "ARRAY") {
62 pidl "uint32 i_$e->{NAME}_$l->{LEVEL_INDEX};";
70 sub ParseElementLevelData($$$$$$$)
72 my ($e,$l,$nl,$env,$varname,$what,$align) = @_;
74 my @args = ($e,$l,$varname,$what);
76 if (defined($e->{ALIGN})) {
77 Align($align, $e->{ALIGN});
83 # See if we need to add a level argument because we're parsing a union
84 foreach (@{$e->{LEVELS}}) {
85 push (@args, ParseExpr("level_$e->{NAME}", $env))
86 if ($_->{TYPE} eq "SWITCH");
89 my $c = DissectType(@args);
93 pidl "\treturn False;";
96 sub ParseElementLevelArray($$$$$$$)
98 my ($e,$l,$nl,$env,$varname,$what,$align) = @_;
100 if ($l->{IS_ZERO_TERMINATED}) {
101 fatal($e, "[string] attribute not supported for Samba3 yet");
106 my $len = ParseExpr($l->{LENGTH_IS}, $env);
107 my $size = ParseExpr($l->{SIZE_IS}, $env);
109 if ($what == PRIMITIVES) {
111 if ($l->{IS_CONFORMANT} and not $l->{IS_SURROUNDING}) {
113 pidl "if (!prs_uint32(\"size_$e->{NAME}\", ps, depth, &" . ParseExpr("size_$e->{NAME}", $env) . "))";
114 pidl "\treturn False;";
118 if ($l->{IS_VARYING}) {
120 pidl "if (!prs_uint32(\"offset_$e->{NAME}\", ps, depth, &" . ParseExpr("offset_$e->{NAME}", $env) . "))";
121 pidl "\treturn False;";
124 pidl "if (!prs_uint32(\"length_$e->{NAME}\", ps, depth, &" . ParseExpr("length_$e->{NAME}", $env) . "))";
125 pidl "\treturn False;";
130 # Everything but fixed arrays have to be allocated
131 if (!$l->{IS_FIXED} and $what == PRIMITIVES) {
132 pidl "if (UNMARSHALLING(ps)) {";
134 pidl "$varname = (void *)PRS_ALLOC_MEM_VOID(ps,sizeof(*$varname)*$size);";
139 return if ($what == DEFERRED and not ContainsDeferred($e,$l));
141 my $i = "i_$e->{NAME}_$l->{LEVEL_INDEX}";
142 pidl "for ($i=0; $i<$len;$i++) {";
144 ParseElementLevel($e,$nl,$env,$varname."[$i]",$what,$align);
149 sub ParseElementLevelSwitch($$$$$$$)
151 my ($e,$l,$nl,$env,$varname,$what,$align) = @_;
153 ParseElementLevel($e,$nl,$env,$varname,$what,$align);
156 sub ParseElementLevelPtr($$$$$$$)
158 my ($e,$l,$nl,$env,$varname,$what,$align) = @_;
160 if ($what == PRIMITIVES) {
161 if ($l->{POINTER_TYPE} eq "ref" and
162 $l->{LEVEL} eq "TOP") {
163 pidl "if (!" . ParseExpr("ptr_$e->{NAME}", $env) . ")";
164 pidl "\treturn False;";
168 pidl "if (!prs_uint32(\"ptr_$e->{NAME}\", ps, depth, &" . ParseExpr("ptr_$e->{NAME}", $env) . "))";
169 pidl "\treturn False;";
174 if ($l->{POINTER_TYPE} eq "relative") {
175 fatal($e, "relative pointers not supported for Samba 3");
179 if ($what == DEFERRED) {
180 pidl "if (" . ParseExpr("ptr_$e->{NAME}", $env) . ") {";
182 ParseElementLevel($e,$nl,$env,$varname,PRIMITIVES,$align);
183 ParseElementLevel($e,$nl,$env,$varname,DEFERRED,$align);
190 sub ParseElementLevelSubcontext($$$$$$$)
192 my ($e,$l,$nl,$env,$varname,$what,$align) = @_;
194 fatal($e, "subcontext() not supported for Samba 3");
198 sub ParseElementLevel($$$$$$)
200 my ($e,$l,$env,$varname,$what,$align) = @_;
203 DATA => \&ParseElementLevelData,
204 SUBCONTEXT => \&ParseElementLevelSubcontext,
205 POINTER => \&ParseElementLevelPtr,
206 SWITCH => \&ParseElementLevelSwitch,
207 ARRAY => \&ParseElementLevelArray
208 }->{$l->{TYPE}}->($e,$l,GetNextLevel($e,$l),$env,$varname,$what,$align);
211 sub ParseElement($$$$)
213 my ($e,$env,$what,$align) = @_;
215 ParseElementLevel($e, $e->{LEVELS}[0], $env, ParseExpr($e->{NAME}, $env), $what, $align);
221 my ($e,$l,$varname,$env) = @_;
223 if ($l->{TYPE} eq "POINTER") {
224 pidl "if ($varname) {";
226 pidl ParseExpr("ptr_$e->{NAME}", $env) . " = 1;";
227 InitLevel($e, GetNextLevel($e,$l), "*$varname", $env);
230 pidl "\t" . ParseExpr("ptr_$e->{NAME}", $env) . " = 0;";
232 } elsif ($l->{TYPE} eq "ARRAY") {
233 pidl ParseExpr($e->{NAME}, $env) . " = $varname;";
234 } elsif ($l->{TYPE} eq "DATA") {
235 pidl InitType($e, $l, ParseExpr($e->{NAME}, $env), $varname);
236 } elsif ($l->{TYPE} eq "SWITCH") {
237 InitLevel($e, GetNextLevel($e,$l), $varname, $env);
241 sub GenerateEnvElement($$)
244 foreach my $l (@{$e->{LEVELS}}) {
245 if ($l->{TYPE} eq "DATA") {
246 $env->{$e->{NAME}} = "v->$e->{NAME}";
247 } elsif ($l->{TYPE} eq "POINTER") {
248 $env->{"ptr_$e->{NAME}"} = "v->ptr_$e->{NAME}";
249 } elsif ($l->{TYPE} eq "SWITCH") {
250 $env->{"level_$e->{NAME}"} = "v->level_$e->{NAME}";
251 } elsif ($l->{TYPE} eq "ARRAY") {
252 $env->{"length_$e->{NAME}"} = "v->length_$e->{NAME}";
253 $env->{"size_$e->{NAME}"} = "v->size_$e->{NAME}";
254 $env->{"offset_$e->{NAME}"} = "v->offset_$e->{NAME}";
263 my $fn = "$if->{NAME}_io_$n";
264 my $sn = uc("$if->{NAME}_$n");
265 my $ifn = "init_$if->{NAME}_$n";
268 foreach (@{$s->{ELEMENTS}}) {
269 $args .= ", " . DeclLong($_);
272 my $env = { "this" => "v" };
273 GenerateEnvElement($_, $env) foreach (@{$s->{ELEMENTS}});
275 pidl "BOOL $ifn($sn *v$args)";
278 pidl "DEBUG(5,(\"$ifn\\n\"));";
280 # Call init for all arguments
281 foreach (@{$s->{ELEMENTS}}) {
282 InitLevel($_, $_->{LEVELS}[0], $_->{NAME}, $env);
293 pidl "BOOL $pfn(const char *desc, $sn *v, prs_struct *ps, int depth)";
296 DeclareArrayVariables($s->{ELEMENTS}, PRIMITIVES);
297 pidl "if (v == NULL)";
298 pidl "\treturn False;";
300 pidl "prs_debug(ps, depth, desc, \"$pfn\");";
303 if ($s->{SURROUNDING_ELEMENT}) {
304 pidl "if (!prs_uint32(\"size_$s->{SURROUNDING_ELEMENT}->{NAME}\", ps, depth, &" . ParseExpr("size_$s->{SURROUNDING_ELEMENT}->{NAME}", $env) . "))";
305 pidl "\treturn False;";
310 foreach (@{$s->{ELEMENTS}}) {
311 ParseElement($_, $env, PRIMITIVES, \$align);
320 pidl "BOOL $dfn(const char *desc, $sn *v, prs_struct *ps, int depth)";
323 DeclareArrayVariables($s->{ELEMENTS}, DEFERRED);
324 pidl "if (v == NULL)";
325 pidl "\treturn False;";
327 pidl "prs_debug(ps, depth, desc, \"$dfn\");";
331 foreach (@{$s->{ELEMENTS}}) {
332 ParseElement($_, $env, DEFERRED, \$align);
342 sub UnionGenerateEnvElement($)
347 foreach my $l (@{$e->{LEVELS}}) {
348 if ($l->{TYPE} eq "DATA") {
349 $env->{$e->{NAME}} = "v->u.$e->{NAME}";
350 } elsif ($l->{TYPE} eq "POINTER") {
351 $env->{"ptr_$e->{NAME}"} = "v->ptr";
352 } elsif ($l->{TYPE} eq "SWITCH") {
353 $env->{"level_$e->{NAME}"} = "v->level";
354 } elsif ($l->{TYPE} eq "ARRAY") {
355 $env->{"length_$e->{NAME}"} = "v->length";
356 $env->{"size_$e->{NAME}"} = "v->size";
357 $env->{"offset_$e->{NAME}"} = "v->offset";
368 my $fn = "$if->{NAME}_io_$n";
369 my $sn = uc("$if->{NAME}_$n\_ctr");
374 pidl "BOOL $pfn(const char *desc, $sn* v, uint32 level, prs_struct *ps, int depth)";
377 DeclareArrayVariables($u->{ELEMENTS});
379 if (has_property($u, "nodiscriminant")) {
380 pidl "if (!prs_uint32(\"switch_value\", ps, depth, &v->switch_value))";
381 pidl "\treturn False;";
385 # Maybe check here that level and v->switch_value are equal?
387 pidl "switch (level) {";
390 foreach (@{$u->{ELEMENTS}}) {
393 if ($_->{TYPE} ne "EMPTY") {
395 my $env = UnionGenerateEnvElement($_);
397 ParseElement($_, $env, PRIMITIVES, \$align);
412 pidl "BOOL $dfn(const char *desc, $sn* v, uint32 level, prs_struct *ps, int depth)";
415 DeclareArrayVariables($u->{ELEMENTS});
417 pidl "switch (level) {";
420 foreach (@{$u->{ELEMENTS}}) {
423 if ($_->{TYPE} ne "EMPTY") {
425 my $env = UnionGenerateEnvElement($_);
427 ParseElement($_, $env, DEFERRED, \$align);
444 sub CreateFnDirection($$$$)
446 my ($fn,$ifn, $s,$es) = @_;
450 $args .= ", " . DeclLong($_);
453 my $env = { "this" => "v" };
454 GenerateEnvElement($_, $env) foreach (@$es);
456 pidl "BOOL $ifn($s *v$args)";
459 pidl "DEBUG(5,(\"$ifn\\n\"));";
461 # Call init for all arguments
463 InitLevel($_, $_->{LEVELS}[0], $_->{NAME}, $env);
471 pidl "BOOL $fn(const char *desc, $s *v, prs_struct *ps, int depth)";
474 DeclareArrayVariables($es);
475 pidl "if (v == NULL)";
476 pidl "\treturn False;";
478 pidl "prs_debug(ps, depth, desc, \"$fn\");";
483 ParseElement($_, $env, PRIMITIVES, \$align);
484 ParseElement($_, $env, DEFERRED, \$align);
494 sub ParseFunction($$)
501 foreach (@{$fn->{ELEMENTS}}) {
502 push (@in, $_) if (grep(/in/, @{$_->{DIRECTION}}));
503 push (@out, $_) if (grep(/out/, @{$_->{DIRECTION}}));
506 if (defined($fn->{RETURN_TYPE})) {
509 TYPE => $fn->{RETURN_TYPE},
513 DATA_TYPE => $fn->{RETURN_TYPE}
519 CreateFnDirection("$if->{NAME}_io_q_$fn->{NAME}",
520 "init_$if->{NAME}_q_$fn->{NAME}",
521 uc("$if->{NAME}_q_$fn->{NAME}"),
523 CreateFnDirection("$if->{NAME}_io_r_$fn->{NAME}",
524 "init_$if->{NAME}_r_$fn->{NAME}",
525 uc("$if->{NAME}_r_$fn->{NAME}"),
529 sub ParseInterface($)
534 pidl "/* $if->{NAME} structures */";
535 foreach (@{$if->{TYPEDEFS}}) {
536 ParseStruct($if, $_->{DATA}, $_->{NAME}) if ($_->{DATA}->{TYPE} eq "STRUCT");
537 ParseUnion($if, $_->{DATA}, $_->{NAME}) if ($_->{DATA}->{TYPE} eq "UNION");
540 pidl "/* $if->{NAME} functions */";
541 ParseFunction($if, $_) foreach (@{$if->{FUNCTIONS}});
546 my($ndr,$filename) = @_;
552 pidl " * Unix SMB/CIFS implementation.";
553 pidl " * parser auto-generated by pidl. DO NOT MODIFY!";
556 pidl "#include \"includes.h\"";
558 pidl "#undef DBGC_CLASS";
559 pidl "#define DBGC_CLASS DBGC_RPC_PARSE";
563 ParseInterface($_) if ($_->{TYPE} eq "INTERFACE");