r10721: Handle allocations and primitive / deferred data correctly. In theory,
authorJelmer Vernooij <jelmer@samba.org>
Wed, 5 Oct 2005 00:29:47 +0000 (00:29 +0000)
committerGerald (Jerry) Carter <jerry@samba.org>
Wed, 10 Oct 2007 18:39:24 +0000 (13:39 -0500)
the generated output for DFS should work now (it compiles cleanly, but
I haven't tested it yet).

Not supported:
 - subcontexts()
 - relative pointers
 - unions of pointers
 - DATA_BLOB
 - several other things

Also still need to do:
 - Remove some spurious spaces in the output
 - Do range() checking

Example output is still available at http://samba.org/~jelmer/pidl_samba3/
(This used to be commit e2d7e382bb645f1bddd2047669bed10f121b59d2)

source4/pidl/lib/Parse/Pidl/Samba3/Header.pm
source4/pidl/lib/Parse/Pidl/Samba3/Parser.pm
source4/pidl/lib/Parse/Pidl/Samba3/Types.pm

index 21a56e4c2d1c7bddb2e77b2635c7ff85adce1e05..5b7fddc14fd8dc120d609a7087dfe2b8f51e7398 100644 (file)
@@ -37,6 +37,7 @@ sub ParseElement($)
                        }
                        if ($l->{IS_VARYING}) {
                                pidl "\tuint32 length_$e->{NAME};";
+                               pidl "\tuint32 offset_$e->{NAME};";
                        }
                }
        }
index 166d98bfb1b8bbb3fb6f4ec04895403077c026a5..702835c3782cf1f9c07bfa8e428d4a2478e202b1 100644 (file)
@@ -14,6 +14,9 @@ use Parse::Pidl::Samba3::Types qw(DeclShort DeclLong InitType DissectType);
 use vars qw($VERSION);
 $VERSION = '0.01';
 
+use constant PRIMITIVES => 1;
+use constant DEFERRED => 2;
+
 my $res = "";
 my $tabs = "";
 sub indent() { $tabs.="\t"; }
@@ -22,17 +25,22 @@ sub pidl($) { $res .= $tabs.(shift)."\n"; }
 sub fatal($$) { my ($e,$s) = @_; die("$e->{FILE}:$e->{LINE}: $s\n"); }
 
 #TODO:
-# - Different scalars / buffers functions for arrays + unions
-# - Memory allocation for arrays
+# - Add some security checks (array sizes, memory alloc == NULL, etc)
+# - Don't add seperate _p and _d functions if there is no deferred data
 
-sub DeclareArrayVariables($)
+sub DeclareArrayVariables
 {
        my $es = shift;
+       my $what = shift;
 
        my $output = 0;
 
        foreach my $e (@$es) {
                foreach my $l (@{$e->{LEVELS}}) {
+                       if ($what) {
+                               next if ($l->{IS_DEFERRED} and $what == PRIMITIVES);
+                               next if (not $l->{IS_DEFERRED} and $what == DEFERRED);
+                       }
                        if ($l->{TYPE} eq "ARRAY") {
                                pidl "uint32 i_$e->{NAME}_$l->{LEVEL_INDEX};";
                                $output = 1;
@@ -42,11 +50,11 @@ sub DeclareArrayVariables($)
        pidl "" if $output;
 }
 
-sub ParseElementLevelData($$$$$)
+sub ParseElementLevelData($$$$$$)
 {
-       my ($e,$l,$nl,$env,$varname) = @_;
+       my ($e,$l,$nl,$env,$varname,$what) = @_;
 
-       my @args = ($e,$l,$varname);
+       my @args = ($e,$l,$varname,$what);
 
        # See if we need to add a level argument because we're parsing a union
        foreach (@{$e->{LEVELS}}) {
@@ -54,64 +62,107 @@ sub ParseElementLevelData($$$$$)
                        if ($_->{TYPE} eq "SWITCH");
        }
 
-       pidl "if (!".DissectType(@args).")";
+       my $c = DissectType(@args);
+       return if not $c;
+
+       pidl "if (!$c)";
        pidl "\treturn False;";
 }
 
-sub ParseElementLevelArray($$$$$)
+sub ParseElementLevelArray($$$$$$)
 {
-       my ($e,$l,$nl,$env,$varname) = @_;
+       my ($e,$l,$nl,$env,$varname,$what) = @_;
 
        my $len = ParseExpr($l->{LENGTH_IS}, $env);
+       my $size = ParseExpr($l->{SIZE_IS}, $env);
+
+       if ($what == PRIMITIVES) {
+               # Fetch headers
+               if ($l->{IS_CONFORMANT} and not $l->{IS_SURROUNDING}) {
+                       pidl "if (!prs_uint32(\"size_$e->{NAME}\", ps, depth, &" . ParseExpr("size_$e->{NAME}", $env) . "))";
+                       pidl "\treturn False;";
+                       pidl "";
+               }
+       
+               if ($l->{IS_VARYING}) {
+                       pidl "if (!prs_uint32(\"offset_$e->{NAME}\", ps, depth, &" . ParseExpr("offset_$e->{NAME}", $env) . "))";
+                       pidl "\treturn False;";
+                       pidl "";
+
+                       pidl "if (!prs_uint32(\"length_$e->{NAME}\", ps, depth, &" . ParseExpr("length_$e->{NAME}", $env) . "))";
+                       pidl "\treturn False;";
+                       pidl "";
+               }
+       }
+
+       # Everything but fixed arrays have to be allocated
+       if (!$l->{IS_FIXED} and $what == PRIMITIVES) {
+               pidl "if (UNMARSHALLING(ps)) {";
+               indent;
+               pidl "$varname = (void *)PRS_ALLOC_MEM_VOID(ps,sizeof(*$varname)*$size);";
+               deindent;
+               pidl "}";
+       }
+
+       return if ($what == DEFERRED and not ContainsDeferred($e,$l));
 
        my $i = "i_$e->{NAME}_$l->{LEVEL_INDEX}";
        pidl "for ($i=0; $i<$len;$i++) {";
        indent;
-       ParseElementLevel($e,$nl,$env,$varname."[$i]");
+       ParseElementLevel($e,$nl,$env,$varname."[$i]",$what);
        deindent;
        pidl "}";
 }
 
-sub ParseElementLevelSwitch($$$$$)
+sub ParseElementLevelSwitch($$$$$$)
 {
-       my ($e,$l,$nl,$env,$varname) = @_;
+       my ($e,$l,$nl,$env,$varname,$what) = @_;
 
-       pidl "if (!prs_uint32(\"level\", ps, depth, &" . ParseExpr("level_$e->{NAME}", $env) . "))";
-       pidl "\treturn False;";
-       pidl "";
+       if ($what == PRIMITIVES) {
+               pidl "if (!prs_uint32(\"level\", ps, depth, &" . ParseExpr("level_$e->{NAME}", $env) . "))";
+               pidl "\treturn False;";
+               pidl "";
+       }
 
-       ParseElementLevel($e,$nl,$env,$varname);
+       ParseElementLevel($e,$nl,$env,$varname,$what);
 }
 
-sub ParseElementLevelPtr($$$$$)
+sub ParseElementLevelPtr($$$$$$)
 {
-       my ($e,$l,$nl,$env,$varname) = @_;
+       my ($e,$l,$nl,$env,$varname,$what) = @_;
+
+       if ($what == PRIMITIVES) {
+               pidl "if (!prs_uint32(\"ptr_$e->{NAME}\", ps, depth, &" . ParseExpr("ptr_$e->{NAME}", $env) . "))";
+               pidl "\treturn False;";
+               pidl "";
+       }
 
        if ($l->{POINTER_TYPE} eq "relative") {
                fatal($e, "relative pointers not supported for Samba 3");
+               #FIXME
        }
-
-       pidl "if (!prs_uint32(\"ptr_$e->{NAME}\", ps, depth, &" . ParseExpr("ptr_$e->{NAME}", $env) . "))";
-       pidl "\treturn False;";
-       pidl "";
        
-       pidl "if (" . ParseExpr("ptr_$e->{NAME}", $env) . ") {";
-       indent;
-       ParseElementLevel($e,$nl,$env,$varname);
-       deindent;
-       pidl "}";
+       if ($what == DEFERRED) {
+               pidl "if (" . ParseExpr("ptr_$e->{NAME}", $env) . ") {";
+               indent;
+               ParseElementLevel($e,$nl,$env,$varname,PRIMITIVES);
+               ParseElementLevel($e,$nl,$env,$varname,DEFERRED);
+               deindent;
+               pidl "}";
+       }
 }
 
-sub ParseElementLevelSubcontext($$$$$)
+sub ParseElementLevelSubcontext($$$$$$)
 {
-       my ($e,$l,$nl,$env,$varname) = @_;
+       my ($e,$l,$nl,$env,$varname,$what) = @_;
 
        fatal($e, "subcontext() not supported for Samba 3");
+       #FIXME
 }
 
-sub ParseElementLevel($$$$)
+sub ParseElementLevel($$$$$)
 {
-       my ($e,$l,$env,$varname) = @_;
+       my ($e,$l,$env,$varname,$what) = @_;
 
        {
                DATA => \&ParseElementLevelData,
@@ -119,14 +170,14 @@ sub ParseElementLevel($$$$)
                POINTER => \&ParseElementLevelPtr,
                SWITCH => \&ParseElementLevelSwitch,
                ARRAY => \&ParseElementLevelArray
-       }->{$l->{TYPE}}->($e,$l,GetNextLevel($e,$l),$env,$varname);
+       }->{$l->{TYPE}}->($e,$l,GetNextLevel($e,$l),$env,$varname,$what);
 }
 
-sub ParseElement($$)
+sub ParseElement($$$)
 {
-       my ($e,$env) = @_;
+       my ($e,$env,$what) = @_;
 
-       ParseElementLevel($e, $e->{LEVELS}[0], $env, ParseExpr($e->{NAME}, $env));
+       ParseElementLevel($e, $e->{LEVELS}[0], $env, ParseExpr($e->{NAME}, $env), $what);
 }
 
 sub InitLevel($$$$)
@@ -164,29 +215,35 @@ sub GenerateEnvElement($$)
                        $env->{"level_$e->{NAME}"} = "v->level_$e->{NAME}";
                } elsif ($l->{TYPE} eq "ARRAY") {
                        $env->{"length_$e->{NAME}"} = "v->length_$e->{NAME}";
+                       $env->{"size_$e->{NAME}"} = "v->size_$e->{NAME}";
+                       $env->{"offset_$e->{NAME}"} = "v->offset_$e->{NAME}";
                }
        }
 }
 
-sub CreateStruct($$$$$)
+sub ParseStruct($$$)
 {
-       my ($fn,$ifn, $s,$es,$a) = @_;
+       my ($if,$s,$n) = @_;
+
+       my $fn = "$if->{NAME}_io_$n";
+       my $sn = uc("$if->{NAME}_$n");
+       my $ifn = "init_$if->{NAME}_$n";
 
        my $args = "";
-       foreach (@$es) {
+       foreach (@{$s->{ELEMENTS}}) {
                $args .= ", " . DeclLong($_);
        }
 
        my $env = { "this" => "v" };
-       GenerateEnvElement($_, $env) foreach (@$es);
+       GenerateEnvElement($_, $env) foreach (@{$s->{ELEMENTS}});
 
-       pidl "BOOL $ifn($s *v$args)";
+       pidl "BOOL $ifn($sn *v$args)";
        pidl "{";
        indent;
        pidl "DEBUG(5,(\"$ifn\\n\"));";
        pidl "";
        # Call init for all arguments
-       foreach (@$es) {
+       foreach (@{$s->{ELEMENTS}}) {
                InitLevel($_, $_->{LEVELS}[0], $_->{NAME}, $env);
                pidl "";
        }
@@ -194,24 +251,31 @@ sub CreateStruct($$$$$)
        deindent;
        pidl "}";
        pidl "";
+
+       my $pfn = "$fn\_p";
+       my $dfn = "$fn\_d";
        
-       pidl "BOOL $fn(const char *desc, $s *v, prs_struct *ps, int depth)";
+       pidl "BOOL $pfn(const char *desc, $sn *v, prs_struct *ps, int depth)";
        pidl "{";
        indent;
-       DeclareArrayVariables($es);
+       DeclareArrayVariables($s->{ELEMENTS}, PRIMITIVES);
        pidl "if (v == NULL)";
        pidl "\treturn False;";
        pidl "";
-       pidl "prs_debug(ps, depth, desc, \"$fn\");";
+       pidl "prs_debug(ps, depth, desc, \"$pfn\");";
        pidl "depth++;";
-       if ($a > 0) {
-               pidl "if (!prs_align_custom(ps, $a))";
+       pidl "if (!prs_align_custom(ps, $s->{ALIGN}))";
+       pidl "\treturn False;";
+       pidl "";
+
+       if ($s->{SURROUNDING_ELEMENT}) {
+               pidl "if (!prs_uint32(\"size_$s->{SURROUNDING_ELEMENT}->{NAME}\", ps, depth, &" . ParseExpr("size_$s->{SURROUNDING_ELEMENT}->{NAME}", $env) . "))";
                pidl "\treturn False;";
                pidl "";
        }
 
-       foreach (@$es) {
-               ParseElement($_, $env);
+       foreach (@{$s->{ELEMENTS}}) {
+               ParseElement($_, $env, PRIMITIVES); 
                pidl "";
        }
 
@@ -219,16 +283,29 @@ sub CreateStruct($$$$$)
        deindent;
        pidl "}";
        pidl "";
-}
 
-sub ParseStruct($$$)
-{
-       my ($if,$s,$n) = @_;
+       pidl "BOOL $dfn(const char *desc, $sn *v, prs_struct *ps, int depth)";
+       pidl "{";
+       indent;
+       DeclareArrayVariables($s->{ELEMENTS}, DEFERRED);
+       pidl "if (v == NULL)";
+       pidl "\treturn False;";
+       pidl "";
+       pidl "prs_debug(ps, depth, desc, \"$dfn\");";
+       pidl "depth++;";
+       pidl "if (!prs_align_custom(ps, $s->{ALIGN}))";
+       pidl "\treturn False;";
+       pidl "";
 
-       my $fn = "$if->{NAME}_io_$n";
-       my $sn = uc("$if->{NAME}_$n");
+       foreach (@{$s->{ELEMENTS}}) {
+               ParseElement($_, $env, DEFERRED); 
+               pidl "";
+       }
 
-       CreateStruct($fn, "init_$if->{NAME}_$n", $sn, $s->{ELEMENTS}, $s->{ALIGN});
+       pidl "return True;";
+       deindent;
+       pidl "}";
+       pidl "";
 }
 
 sub ParseUnion($$$)
@@ -238,7 +315,44 @@ sub ParseUnion($$$)
        my $fn = "$if->{NAME}_io_$n";
        my $sn = uc("$if->{NAME}_$n");
 
-       pidl "BOOL $fn(const char *desc, $sn* v, uint32 level, prs_struct *ps, int depth)";
+       my $pfn = "$fn\_p";
+       my $dfn = "$fn\_d";
+       
+       pidl "BOOL $pfn(const char *desc, $sn* v, uint32 level, prs_struct *ps, int depth)";
+       pidl "{";
+       indent;
+       DeclareArrayVariables($u->{ELEMENTS});
+       pidl "if (!prs_align_custom(ps, $u->{ALIGN}))";
+       pidl "\treturn False;";
+       pidl "";
+
+       pidl "switch (level) {";
+       indent;
+
+       foreach (@{$u->{ELEMENTS}}) {
+               pidl "$_->{CASE}:";
+               indent;
+               if ($_->{TYPE} ne "EMPTY") {
+                       pidl "depth++;";
+                       my $env = {};
+                       GenerateEnvElement($_, $env);
+                       ParseElement($_, $env, PRIMITIVES); 
+                       ParseElement($_, $env, DEFERRED); 
+                       pidl "depth--;";
+               }
+               pidl "break;";
+               deindent;
+               pidl "";
+       }
+
+       deindent;
+       pidl "}";
+       pidl "";
+       pidl "return True;";
+       deindent;
+       pidl "}";
+
+       pidl "BOOL $dfn(const char *desc, $sn* v, uint32 level, prs_struct *ps, int depth)";
        pidl "{";
        indent;
        DeclareArrayVariables($u->{ELEMENTS});
@@ -256,7 +370,7 @@ sub ParseUnion($$$)
                        pidl "depth++;";
                        my $env = {};
                        GenerateEnvElement($_, $env);
-                       ParseElement($_, $env);
+                       ParseElement($_, $env, DEFERRED); 
                        pidl "depth--;";
                }
                pidl "break;";
@@ -270,6 +384,56 @@ sub ParseUnion($$$)
        pidl "return True;";
        deindent;
        pidl "}";
+
+}
+
+sub CreateFnDirection($$$$)
+{
+       my ($fn,$ifn, $s,$es) = @_;
+
+       my $args = "";
+       foreach (@$es) {
+               $args .= ", " . DeclLong($_);
+       }
+
+       my $env = { "this" => "v" };
+       GenerateEnvElement($_, $env) foreach (@$es);
+
+       pidl "BOOL $ifn($s *v$args)";
+       pidl "{";
+       indent;
+       pidl "DEBUG(5,(\"$ifn\\n\"));";
+       pidl "";
+       # Call init for all arguments
+       foreach (@$es) {
+               InitLevel($_, $_->{LEVELS}[0], $_->{NAME}, $env);
+               pidl "";
+       }
+       pidl "return True;";
+       deindent;
+       pidl "}";
+       pidl "";
+       
+       pidl "BOOL $fn(const char *desc, $s *v, prs_struct *ps, int depth)";
+       pidl "{";
+       indent;
+       DeclareArrayVariables($es);
+       pidl "if (v == NULL)";
+       pidl "\treturn False;";
+       pidl "";
+       pidl "prs_debug(ps, depth, desc, \"$fn\");";
+       pidl "depth++;";
+
+       foreach (@$es) {
+               ParseElement($_, $env, PRIMITIVES); 
+               ParseElement($_, $env, DEFERRED); 
+               pidl "";
+       }
+
+       pidl "return True;";
+       deindent;
+       pidl "}";
+       pidl "";
 }
 
 sub ParseFunction($$)
@@ -297,14 +461,14 @@ sub ParseFunction($$)
                } );
        }
 
-       CreateStruct("$if->{NAME}_io_q_$fn->{NAME}", 
+       CreateFnDirection("$if->{NAME}_io_q_$fn->{NAME}", 
                                 "init_$if->{NAME}_q_$fn->{NAME}", 
                                 uc("$if->{NAME}_q_$fn->{NAME}"), 
-                                \@in, 0);
-       CreateStruct("$if->{NAME}_io_r_$fn->{NAME}", 
+                                \@in);
+       CreateFnDirection("$if->{NAME}_io_r_$fn->{NAME}", 
                                 "init_$if->{NAME}_r_$fn->{NAME}",
                                 uc("$if->{NAME}_r_$fn->{NAME}"), 
-                                \@out, 0);
+                                \@out);
 }
 
 sub ParseInterface($)
index a3bf91d54f386dd18685c3c0d981272bf6a618af..9a7a31a6bb483e3767cf68693e65218614757b14 100644 (file)
@@ -109,50 +109,50 @@ my $known_types =
        {
                DECL => "uint8",
                INIT => \&init_scalar,
-               DISSECT => \&dissect_scalar,
+               DISSECT_P => \&dissect_scalar,
        },
        uint16 => 
        {
                DECL => "uint16",
                INIT => \&init_scalar,
-               DISSECT => \&dissect_scalar,
+               DISSECT_P => \&dissect_scalar,
        },
        uint32 => 
        {
                DECL => "uint32",
                INIT => \&init_scalar,
-               DISSECT => \&dissect_scalar,
+               DISSECT_P => \&dissect_scalar,
        },
        uint64 => 
        {
                DECL => "uint64",
                INIT => \&init_scalar,
-               DISSECT => \&dissect_scalar,
+               DISSECT_P => \&dissect_scalar,
        },
        string => 
        {
                DECL => \&decl_string,
                EXT_DECL => \&ext_decl_string,
                INIT => \&init_string,
-               DISSECT => \&dissect_string,
+               DISSECT_P => \&dissect_string,
        },
        NTSTATUS => 
        {
                DECL => "NTSTATUS",
                INIT => \&init_scalar,
-               DISSECT => \&dissect_scalar,
+               DISSECT_P => \&dissect_scalar,
        },
        WERROR => 
        {
                DECL => "WERROR",
                INIT => \&init_scalar,
-               DISSECT => \&dissect_scalar,
+               DISSECT_P => \&dissect_scalar,
        },
        GUID => 
        {
                DECL => "struct uuid",
                INIT => "",
-               DISSECT => sub { 
+               DISSECT_P => sub { 
                        my ($e,$l,$n) = @_; 
                        return "smb_io_uuid(\"$e->{NAME}\", &$n, ps, depth)";
                }
@@ -161,7 +161,7 @@ my $known_types =
        {
                DECL => "NTTIME",
                INIT => "",
-               DISSECT => sub { 
+               DISSECT_P => sub { 
                        my ($e,$l,$n) = @_; 
                        return "smb_io_nttime(\"$e->{NAME}\", &n, ps, depth)"; 
                }
@@ -170,7 +170,7 @@ my $known_types =
        {
                DECL => "DOM_SID",
                INIT => "",
-               DISSECT => sub {
+               DISSECT_P => sub {
                        my ($e,$l,$n) = @_;
                        return "smb_io_dom_sid(\"$e->{NAME}\", &n, ps, depth)";
                }
@@ -179,7 +179,7 @@ my $known_types =
        {
                DECL => "POLICY_HND",
                INIT => "",
-               DISSECT => sub {
+               DISSECT_P => sub {
                        my ($e,$l,$n) = @_;
                        return "smb_io_pol_hnd(\"$e->{NAME}\", &n, ps, depth)";
                }
@@ -301,6 +301,7 @@ sub DissectType
        my $e = shift @_;
        my $l = shift @_;
        my $varname = shift @_;
+       my $what = shift @_;
 
        my $t = $known_types->{$l->{DATA_TYPE}};
 
@@ -309,11 +310,20 @@ sub DissectType
                return undef;
        }
 
+       my $dissect;
+       if ($what == 1) { #primitives
+               $dissect = $t->{DISSECT_P};
+       } elsif ($what == 2) {
+               $dissect = $t->{DISSECT_D};
+       }
+
+       return "" if not defined($dissect);
+
        # DISSECT can be a function
-       if (ref($t->{DISSECT}) eq "CODE") {
-               return $t->{DISSECT}->(@args);
+       if (ref($dissect) eq "CODE") {
+               return $dissect->(@args);
        } else {
-               return $t->{DISSECT};
+               return $dissect;
        }
 }
 
@@ -330,25 +340,40 @@ sub LoadTypes($)
                                        return "$n = $v;";
                        };
                        
-                       my $dissect;
+                       my $dissect_d;
+                       my $dissect_p;
                        if ($td->{DATA}->{TYPE} eq "UNION") {
-                                $dissect = sub {
-                                       my ($e,$l,$n,$s) = @_;
+                                $dissect_p = sub {
+                                       my ($e,$l,$n,$w,$s) = @_;
+
+                                       return "$if->{NAME}_io_$td->{NAME}_p(\"$e->{NAME}\", &$n, $s, ps, depth)";
+                               };
 
-                                       return "$if->{NAME}_io_$td->{NAME}(\"$e->{NAME}\", &$n, $s, ps, depth)";
+                                $dissect_d = sub {
+                                       my ($e,$l,$n,$w,$s) = @_;
+
+                                       return "$if->{NAME}_io_$td->{NAME}_d(\"$e->{NAME}\", &$n, $s, ps, depth)";
                                };
+
                        } else {
-                                $dissect = sub {
-                                       my ($e,$l,$n) = @_;
+                                $dissect_p = sub {
+                                       my ($e,$l,$n,$w) = @_;
 
-                                       return "$if->{NAME}_io_$td->{NAME}(\"$e->{NAME}\", &$n, ps, depth)";
+                                       return "$if->{NAME}_io_$td->{NAME}_p(\"$e->{NAME}\", &$n, ps, depth)";
                                };
+                               $dissect_d = sub {
+                                       my ($e,$l,$n,$w) = @_;
+
+                                       return "$if->{NAME}_io_$td->{NAME}_d(\"$e->{NAME}\", &$n, ps, depth)";
+                               };
+
                        }
 
                        AddType($td->{NAME}, {
                                DECL => $decl,
                                INIT => $init,
-                               DISSECT => $dissect                     
+                               DISSECT_D => $dissect_d,
+                               DISSECT_P => $dissect_p
                        });
                }
        }