r7695: Add support for the [string] attribute that works in the traditional sense...
authorJelmer Vernooij <jelmer@samba.org>
Fri, 17 Jun 2005 16:29:27 +0000 (16:29 +0000)
committerGerald (Jerry) Carter <jerry@samba.org>
Wed, 10 Oct 2007 18:18:23 +0000 (13:18 -0500)
used anywhere yet.

source/build/pidl/TODO
source/build/pidl/ndr.pm
source/build/pidl/ndr_parser.pm
source/build/pidl/validator.pm
source/librpc/ndr/ndr_string.c

index 4969bf78b4b493888ed72ddcd6d0eb4c4be1d5d9..d51bd83b04c558ec134d2b2b3fa0b4fb8fdb8234 100644 (file)
@@ -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.
index 09e1d2efc1a8f924bce4d3a581548a33f3be9da1..f866a0ea8e1b9df414c0e0859f84c5d85ad657b4 100644 (file)
@@ -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"))) {
index 0af3cde3113f3b1e558b983341e5d8f1fa58f2bb..4eab424c759529d713c9476402a467fb7f756e64 100644 (file)
@@ -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);
index c4c74753b497d7a7bcadc50c3c88e94be699d516..82f1f3dd812af894741f6795727d712d580c8d8a 100644 (file)
@@ -131,6 +131,7 @@ my %property_list = (
        "range"                 => ["ELEMENT"],
        "size_is"               => ["ELEMENT"],
        "string"        => ["ELEMENT"],
+       "noheader"      => ["ELEMENT"],
        "charset"       => ["ELEMENT"],
        "length_is"             => ["ELEMENT"],
 );
index aa612eca38bdda4d017b2a0cf14e98bdefca7314..af9783ed959a6bfdaf83b8842b8017efbfe65da0 100644 (file)
@@ -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;
+
+}