diff options
-rw-r--r-- | source4/build/pidl/TODO | 30 | ||||
-rw-r--r-- | source4/build/pidl/ndr.pm | 35 | ||||
-rw-r--r-- | source4/build/pidl/ndr_parser.pm | 68 | ||||
-rw-r--r-- | source4/build/pidl/validator.pm | 1 | ||||
-rw-r--r-- | source4/librpc/ndr/ndr_string.c | 27 |
5 files changed, 104 insertions, 57 deletions
diff --git a/source4/build/pidl/TODO b/source4/build/pidl/TODO index 4969bf78b4..d51bd83b04 100644 --- a/source4/build/pidl/TODO +++ b/source4/build/pidl/TODO @@ -1,38 +1,10 @@ -- Fix string support. - This would make strings a special kind of arrays flagged by the - [string] attribute. Pidl itself would support a couple of extra - attributes for it's own use while being compatible with other IDL - compilers. - Proposed extensions for pidl (to arrays): - [convert(t)] attribute for forcing conversions from CH_UCS2, etc to UTF8 - [noheader] attribute -> Indicating the string is not preceded - Implement: - ndr.pm: - - represent a string as an array with length set to "STRING" - - [string] implies is_varying unless noheader is specified. ndr_parser.pm: - if [charset()] specified, use instead of the for loops (call ndr_pu{ll,sh}_charset() - - calculate length using helper function if [string] is specified - -The various flags for strings would change as follows: - -LIBNDR_FLAG_STR_ASCII -> [convert(CH_ASCII)] -LIBNDR_FLAG_STR_LEN4 -> [string] -LIBNDR_FLAG_STR_SIZE4 -> [size_is()] or if needed [conformant] -LIBNDR_FLAG_STR_NOTERM -> array -LIBNDR_FLAG_STR_NULLTERM -> [noheader] -LIBNDR_FLAG_STR_SIZE2 -> uint16 length; [string] char data[length] -LIBNDR_FLAG_STR_BYTESIZE -> uint16 length; [string] char data[length] -LIBNDR_FLAG_STR_FIXLEN32 -> [32] -LIBNDR_FLAG_STR_CONFORMANT -> no longer needed -LIBNDR_FLAG_STR_CHARLEN -> ??? -LIBNDR_FLAG_STR_UTF8 -> Nothing (but UCS2 has [convert(CH_UCS2)] -LIBNDR_FLAG_STR_FIXLEN15 -> [15] - True multiple dimension array / strings in arrays support (closely related to things specified above) - compatibility mode for generating MIDL-readable data: - strip out pidl-specific properties - - convert subcontext() to an array of chars. + - convert subcontext() to an array of uint8. diff --git a/source4/build/pidl/ndr.pm b/source4/build/pidl/ndr.pm index 09e1d2efc1..f866a0ea8e 100644 --- a/source4/build/pidl/ndr.pm +++ b/source4/build/pidl/ndr.pm @@ -48,15 +48,20 @@ sub GetElementLevelTable($) my $is_surrounding = 0; my $is_varying = 0; my $is_conformant = 0; + my $is_string = 0; if ($d eq "*") { $is_conformant = 1; - unless ($size = shift @size_is) { + if ($size = shift @size_is) { + } elsif ((scalar(@size_is) == 0) and util::has_property($e, "string")) { + $is_string = 1; + delete($e->{PROPERTIES}->{string}); + } else { print "$e->{FILE}:$e->{LINE}: Must specify size_is() for conformant array!\n"; exit 1; } - if ($length = shift @length_is) { + if (($length = shift @length_is) or $is_string) { $is_varying = 1; } else { $length = $size; @@ -73,9 +78,8 @@ sub GetElementLevelTable($) SIZE_IS => $size, LENGTH_IS => $length, IS_DEFERRED => "$is_deferred", - # Inline arrays (which are a pidl extension) are never encoded - # as surrounding the struct they're part of IS_SURROUNDING => "$is_surrounding", + IS_ZERO_TERMINATED => "$is_string", IS_VARYING => "$is_varying", IS_CONFORMANT => "$is_conformant", IS_FIXED => (not $is_conformant and util::is_constant($size)), @@ -104,30 +108,43 @@ sub GetElementLevelTable($) # everything that follows will be deferred $is_deferred = 1 if ($e->{PARENT}->{TYPE} ne "FUNCTION"); - my $array_size; + my $array_size = shift @size_is; my $array_length; - if ($array_size = shift @size_is) { - my $is_varying = 0; + my $is_varying; + my $is_conformant; + my $is_string = 0; + if ($array_size) { + $is_conformant = 1; if ($array_length = shift @length_is) { $is_varying = 1; } else { $array_length = $array_size; + $is_varying =0; } + } + + if (scalar(@size_is) == 0 and util::has_property($e, "string")) { + $is_string = 1; + $is_varying = $is_conformant = util::has_property($e, "noheader")?0:1; + delete($e->{PROPERTIES}->{string}); + } + if ($array_size or $is_string) { push (@$order, { TYPE => "ARRAY", + IS_ZERO_TERMINATED => "$is_string", SIZE_IS => $array_size, LENGTH_IS => $array_length, IS_DEFERRED => "$is_deferred", IS_SURROUNDING => 0, IS_VARYING => "$is_varying", - IS_CONFORMANT => 1, + IS_CONFORMANT => "$is_conformant", IS_FIXED => 0, IS_INLINE => 0, }); $is_deferred = 0; - } + } } if (defined(util::has_property($e, "subcontext"))) { diff --git a/source4/build/pidl/ndr_parser.pm b/source4/build/pidl/ndr_parser.pm index 0af3cde311..4eab424c75 100644 --- a/source4/build/pidl/ndr_parser.pm +++ b/source4/build/pidl/ndr_parser.pm @@ -237,8 +237,15 @@ sub ParseArrayPushHeader($$$$$) $var_name = get_pointer_to($var_name); } - my $size = ParseExpr($l->{SIZE_IS}, $env); - my $length = ParseExpr($l->{LENGTH_IS}, $env); + my $size; + my $length; + + if ($l->{IS_ZERO_TERMINATED}) { + $size = $length = "ndr_string_length($var_name, sizeof(*$var_name))"; + } else { + $size = ParseExpr($l->{SIZE_IS}, $env); + $length = ParseExpr($l->{LENGTH_IS}, $env); + } if ((!$l->{IS_SURROUNDING}) and $l->{IS_CONFORMANT}) { pidl "NDR_CHECK(ndr_push_uint32($ndr, NDR_SCALARS, $size));"; @@ -262,17 +269,17 @@ sub ParseArrayPullHeader($$$$$) $var_name = get_pointer_to($var_name); } - # $var_name contains the name of the first argument here - - my $length = ParseExpr($l->{SIZE_IS}, $env); - my $size = $length; + my $length; + my $size; if ($l->{IS_CONFORMANT}) { $length = $size = "ndr_get_array_size($ndr, " . get_pointer_to($var_name) . ")"; + } elsif ($l->{IS_ZERO_TERMINATED}) { # Noheader arrays + $length = $size = "ndr_get_string_size($ndr, sizeof(*$var_name))"; + } else { + $length = $size = ParseExpr($l->{SIZE_IS}, $env); } - # if this is a conformant array then we use that size to allocate, and make sure - # we allocate enough to pull the elements if ((!$l->{IS_SURROUNDING}) and $l->{IS_CONFORMANT}) { pidl "NDR_CHECK(ndr_pull_array_size(ndr, " . get_pointer_to($var_name) . "));"; } @@ -293,13 +300,13 @@ sub ParseArrayPullHeader($$$$$) pidl "}"; } - if ($l->{IS_CONFORMANT}) { + if ($l->{IS_CONFORMANT} and not $l->{IS_ZERO_TERMINATED}) { my $size = ParseExpr($l->{SIZE_IS}, $env); check_null_pointer($size); pidl "NDR_CHECK(ndr_check_array_size(ndr, (void*)" . get_pointer_to($var_name) . ", $size));"; } - if ($l->{IS_VARYING}) { + if ($l->{IS_VARYING} and not $l->{IS_ZERO_TERMINATED}) { my $length = ParseExpr($l->{LENGTH_IS}, $env); check_null_pointer($length); pidl "NDR_CHECK(ndr_check_array_length(ndr, (void*)" . get_pointer_to($var_name) . ", $length));"; @@ -541,7 +548,9 @@ sub ParseElementPushLevel $var_name = get_pointer_to($var_name); } - pidl "NDR_CHECK(ndr_push_array_$e->{TYPE}($ndr, $ndr_flags, $var_name, $length));"; + my $nl = Ndr::GetNextLevel($e, $l); + + pidl "NDR_CHECK(ndr_push_array_$nl->{DATA_TYPE}($ndr, $ndr_flags, $var_name, $length));"; return; } } elsif ($l->{TYPE} eq "SWITCH") { @@ -666,13 +675,21 @@ sub ParseElementPrint($$$) } $var_name = get_value_of($var_name); } elsif ($l->{TYPE} eq "ARRAY") { - my $length = ParseExpr($l->{LENGTH_IS}, $env); + my $length; + + if (is_scalar_array($e, $l) and ($l->{IS_CONFORMANT} or $l->{IS_VARYING})){ + $var_name = get_pointer_to($var_name); + } + + if ($l->{IS_ZERO_TERMINATED}) { + $length = "ndr_string_length($var_name, sizeof(*$var_name))"; + } else { + $length = ParseExpr($l->{LENGTH_IS}, $env); + } if (is_scalar_array($e, $l)) { - if ($l->{IS_CONFORMANT} or $l->{IS_VARYING}){ - $var_name = get_pointer_to($var_name); - } - pidl "ndr_print_array_$e->{TYPE}(ndr, \"$e->{NAME}\", $var_name, $length);"; + my $nl = Ndr::GetNextLevel($e, $l); + pidl "ndr_print_array_$nl->{DATA_TYPE}(ndr, \"$e->{NAME}\", $var_name, $length);"; last; } @@ -825,8 +842,13 @@ sub ParseElementPullLevel if ($l->{IS_VARYING} or $l->{IS_CONFORMANT}) { $var_name = get_pointer_to($var_name); } + my $nl = Ndr::GetNextLevel($e, $l); - pidl "NDR_CHECK(ndr_pull_array_$e->{TYPE}($ndr, $ndr_flags, $var_name, $length));"; + pidl "NDR_CHECK(ndr_pull_array_$nl->{DATA_TYPE}($ndr, $ndr_flags, $var_name, $length));"; + if ($l->{IS_ZERO_TERMINATED}) { + # Make sure last element is zero! + pidl "NDR_CHECK(ndr_check_string_terminator($ndr, $var_name, ndr_get_array_length(ndr, " . get_pointer_to($var_name) . "), sizeof(*$var_name)));"; + } return; } } elsif ($l->{TYPE} eq "POINTER") { @@ -876,6 +898,11 @@ sub ParseElementPullLevel ParseElementPullLevel($e,Ndr::GetNextLevel($e,$l), $ndr, $var_name, $env, 1, 0); deindent; pidl "}"; + + if ($l->{IS_ZERO_TERMINATED}) { + # Make sure last element is zero! + pidl "NDR_CHECK(ndr_check_string_terminator($ndr, $var_name, ndr_get_array_length(ndr, " . get_pointer_to($var_name) . "), sizeof(*$var_name)));"; + } } if ($deferred and Ndr::ContainsDeferred($e, $l)) { @@ -1846,14 +1873,15 @@ sub AllocateArrayLevel($$$$$) my $pl = Ndr::GetPrevLevel($e, $l); if (defined($pl) and $pl->{TYPE} eq "POINTER" and - $pl->{POINTER_TYPE} eq "ref") { + $pl->{POINTER_TYPE} eq "ref" + and not $l->{IS_ZERO_TERMINATED}) { pidl "if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {"; pidl "\tNDR_ALLOC_N($ndr, $var, $size);"; pidl "}"; } else { pidl "NDR_ALLOC_N($ndr, $var, $size);"; } - #pidl "memset($var, 0, $size * sizeof(" . $var . "[0]));"; + if (grep(/in/,@{$e->{DIRECTION}}) and grep(/out/,@{$e->{DIRECTION}})) { pidl "memcpy(r->out.$e->{NAME},r->in.$e->{NAME},$size * sizeof(*r->in.$e->{NAME}));"; @@ -1909,6 +1937,8 @@ sub ParseFunctionPull($) $e->{LEVELS}[0]->{POINTER_TYPE} eq "ref"); next if (($e->{LEVELS}[1]->{TYPE} eq "DATA") and ($e->{LEVELS}[1]->{DATA_TYPE} eq "string")); + next if (($e->{LEVELS}[1]->{TYPE} eq "ARRAY") + and $e->{LEVELS}[1]->{IS_ZERO_TERMINATED}); if ($e->{LEVELS}[1]->{TYPE} eq "ARRAY") { my $size = ParseExpr($e->{LEVELS}[1]->{SIZE_IS}, $env); diff --git a/source4/build/pidl/validator.pm b/source4/build/pidl/validator.pm index c4c74753b4..82f1f3dd81 100644 --- a/source4/build/pidl/validator.pm +++ b/source4/build/pidl/validator.pm @@ -131,6 +131,7 @@ my %property_list = ( "range" => ["ELEMENT"], "size_is" => ["ELEMENT"], "string" => ["ELEMENT"], + "noheader" => ["ELEMENT"], "charset" => ["ELEMENT"], "length_is" => ["ELEMENT"], ); diff --git a/source4/librpc/ndr/ndr_string.c b/source4/librpc/ndr/ndr_string.c index aa612eca38..af9783ed95 100644 --- a/source4/librpc/ndr/ndr_string.c +++ b/source4/librpc/ndr/ndr_string.c @@ -569,3 +569,30 @@ void ndr_print_string_array(struct ndr_print *ndr, const char *name, const char } ndr->depth--; } + +/* Return number of elements in a string including the last (zeroed) element */ +uint32_t ndr_string_length(void *_var, uint32_t element_size) +{ + uint32_t i; + uint8_t zero[4] = {0,0,0,0}; + char *var = _var; + + for (i = 0; memcmp(var+i*element_size,zero,element_size) != 0; i++); + + return i+1; +} + +NTSTATUS ndr_check_string_terminator(struct ndr_pull *ndr, const void *_var, uint32_t count, uint32_t element_size) +{ + const char *var = _var; + uint32_t i; + + for (i = 0; i < element_size; i++) { + if (var+element_size*(count-1)+i != 0) { + return NT_STATUS_UNSUCCESSFUL; + } + } + + return NT_STATUS_OK; + +} |