use Parse::Pidl::Util qw(has_property ParseExpr ParseExprExt print_uuid unmake_str);
use Parse::Pidl::CUtil qw(get_pointer_to get_value_of get_array_element);
use Parse::Pidl::NDR qw(GetPrevLevel GetNextLevel ContainsDeferred is_charset_array);
-use Parse::Pidl::Samba4 qw(is_intree choose_header);
+use Parse::Pidl::Samba4 qw(is_intree choose_header ArrayDynamicallyAllocated);
use Parse::Pidl::Samba4::Header qw(GenerateFunctionInEnv GenerateFunctionOutEnv EnvSubstituteValue GenerateStructEnv);
use Parse::Pidl qw(warning);
if ($l->{IS_CONFORMANT}) {
$length = $size = "ndr_get_array_size($ndr, " . get_pointer_to($var_name) . ")";
- } elsif ($l->{IS_ZERO_TERMINATED}) { # Noheader arrays
+ } elsif ($l->{IS_ZERO_TERMINATED} and $l->{SIZE_IS} == 0 and $l->{LENGTH_IS} == 0) { # Noheader arrays
$length = $size = "ndr_get_string_size($ndr, sizeof(*$var_name))";
} else {
$length = $size = ParseExprExt($l->{SIZE_IS}, $env, $e->{ORIGINAL},
$self->defer("}");
}
- if (not $l->{IS_FIXED} and not is_charset_array($e, $l)) {
+ if (ArrayDynamicallyAllocated($e,$l) and not is_charset_array($e,$l)) {
$self->AllocateArrayLevel($e,$l,$ndr,$var_name,$size);
}
}
if ($l->{TYPE} eq "POINTER" and $deferred) {
+ my $rel_var_name = $var_name;
if ($l->{POINTER_TYPE} ne "ref") {
$self->pidl("if ($var_name) {");
$self->indent;
if ($l->{POINTER_TYPE} eq "relative") {
- $self->pidl("NDR_CHECK(ndr_push_relative_ptr2($ndr, $var_name));");
+ $self->pidl("NDR_CHECK(ndr_push_relative_ptr2_start($ndr, $rel_var_name));");
}
}
$var_name = get_value_of($var_name);
$self->ParseElementPushLevel($e, GetNextLevel($e, $l), $ndr, $var_name, $env, 1, 1);
if ($l->{POINTER_TYPE} ne "ref") {
+ if ($l->{POINTER_TYPE} eq "relative") {
+ $self->pidl("NDR_CHECK(ndr_push_relative_ptr2_end($ndr, $rel_var_name));");
+ }
$self->deindent;
$self->pidl("}");
}
my $length = ParseExpr($l->{LENGTH_IS}, $env, $e->{ORIGINAL});
my $counter = "cntr_$e->{NAME}_$l->{LEVEL_INDEX}";
+ my $array_pointless = ($length eq "0");
+
+ if ($array_pointless) {
+ warning($e->{ORIGINAL}, "pointless array `$e->{NAME}' will always have size 0");
+ }
+
$var_name = get_array_element($var_name, $counter);
- if (($primitives and not $l->{IS_DEFERRED}) or ($deferred and $l->{IS_DEFERRED})) {
+ if ((($primitives and not $l->{IS_DEFERRED}) or ($deferred and $l->{IS_DEFERRED})) and not $array_pointless) {
$self->pidl("for ($counter = 0; $counter < $length; $counter++) {");
$self->indent;
$self->ParseElementPushLevel($e, GetNextLevel($e, $l), $ndr, $var_name, $env, 1, 0);
$self->pidl("}");
}
- if ($deferred and ContainsDeferred($e, $l)) {
+ if ($deferred and ContainsDeferred($e, $l) and not $array_pointless) {
$self->pidl("for ($counter = 0; $counter < $length; $counter++) {");
$self->indent;
$self->ParseElementPushLevel($e, GetNextLevel($e, $l), $ndr, $var_name, $env, 0, 1);
$self->pidl("NDR_CHECK(".TypeFunctionName("ndr_pull", $l->{DATA_TYPE})."($ndr, $ndr_flags, $var_name));");
- if (my $range = has_property($e, "range")) {
+ my $pl = GetPrevLevel($e, $l);
+
+ my $range = has_property($e, "range");
+ if ($range and $pl->{TYPE} ne "ARRAY") {
$var_name = get_value_of($var_name);
+ my $signed = Parse::Pidl::Typelist::is_signed($l->{DATA_TYPE});
my ($low, $high) = split(/,/, $range, 2);
- $self->pidl("if ($var_name < $low || $var_name > $high) {");
+ if ($low < 0 and not $signed) {
+ warning(0, "$low is invalid for the range of an unsigned type");
+ }
+ if ($low == 0 and not $signed) {
+ $self->pidl("if ($var_name > $high) {");
+ } else {
+ $self->pidl("if ($var_name < $low || $var_name > $high) {");
+ }
$self->pidl("\treturn ndr_pull_error($ndr, NDR_ERR_RANGE, \"value out of range\");");
$self->pidl("}");
}
return undef unless ($l->{TYPE} eq "POINTER" or $l->{TYPE} eq "ARRAY");
- return undef if ($l->{TYPE} eq "ARRAY" and $l->{IS_FIXED});
+ return undef unless ($l->{TYPE} ne "ARRAY" or ArrayDynamicallyAllocated($e,$l));
return undef if has_fast_array($e, $l);
return undef if is_charset_array($e, $l);
} elsif ($l->{TYPE} eq "ARRAY") {
my $length = $self->ParseArrayPullHeader($e, $l, $ndr, $var_name, $env);
+ if (my $range = has_property($e, "range")) {
+ my ($low, $high) = split(/,/, $range, 2);
+ if ($low < 0) {
+ warning(0, "$low is invalid for the range of an array size");
+ }
+ if ($low == 0) {
+ $self->pidl("if ($length > $high) {");
+ } else {
+ $self->pidl("if ($length < $low || $length > $high) {");
+ }
+ $self->pidl("\treturn ndr_pull_error($ndr, NDR_ERR_RANGE, \"value out of range\");");
+ $self->pidl("}");
+ }
+
my $nl = GetNextLevel($e, $l);
if (is_charset_array($e,$l)) {
my $counter = "cntr_$e->{NAME}_$l->{LEVEL_INDEX}";
my $array_name = $var_name;
+ if ($l->{IS_VARYING}) {
+ $length = "ndr_get_array_length($ndr, " . get_pointer_to($var_name) .")";
+ }
+
+ if (my $range = has_property($e, "range")) {
+ my ($low, $high) = split(/,/, $range, 2);
+ if ($low < 0) {
+ warning(0, "$low is invalid for the range of an array size");
+ }
+ if ($low == 0) {
+ $self->pidl("if ($length > $high) {");
+ } else {
+ $self->pidl("if ($length < $low || $length > $high) {");
+ }
+ $self->pidl("\treturn ndr_pull_error($ndr, NDR_ERR_RANGE, \"value out of range\");");
+ $self->pidl("}");
+ }
+
$var_name = get_array_element($var_name, $counter);
$self->ParseMemCtxPullStart($e, $l, $ndr, $array_name);
EnvSubstituteValue($env, $struct);
- $self->DeclareArrayVariables($_) foreach (@{$struct->{ELEMENTS}});
+ $self->DeclareArrayVariablesNoZero($_, $env) foreach (@{$struct->{ELEMENTS}});
$self->start_flags($struct, $ndr);
}
}
+sub DeclareArrayVariablesNoZero($$$)
+{
+ my ($self,$e,$env) = @_;
+
+ foreach my $l (@{$e->{LEVELS}}) {
+ next if has_fast_array($e,$l);
+ next if is_charset_array($e,$l);
+ if ($l->{TYPE} eq "ARRAY") {
+ my $length = ParseExpr($l->{LENGTH_IS}, $env, $e->{ORIGINAL});
+ if ($length eq "0") {
+ warning($e->{ORIGINAL}, "pointless array cntr: 'cntr_$e->{NAME}_$l->{LEVEL_INDEX}': length=$length");
+ } else {
+ $self->pidl("uint32_t cntr_$e->{NAME}_$l->{LEVEL_INDEX};");
+ }
+ }
+ }
+}
+
sub DeclareMemCtxVariables($$)
{
my ($self,$e) = @_;
if (my $flags = has_property($t, "flag")) {
$self->pidl("flags |= $flags;");
}
- $self->pidl("return ndr_size_struct($varname, flags, (ndr_push_flags_fn_t)ndr_push_$name);");
+ $self->pidl("return ndr_size_struct($varname, flags, (ndr_push_flags_fn_t)ndr_push_$name, ic);");
}
sub DeclStruct($$$$)
sub ArgsStructNdrSize($$$)
{
my ($d, $name, $varname) = @_;
- return "const struct $name *$varname, int flags";
+ return "const struct $name *$varname, struct smb_iconv_convenience *ic, int flags";
}
$typefamily{STRUCT} = {
$self->pidl("flags |= $flags;");
}
- $self->pidl("return ndr_size_union($varname, flags, level, (ndr_push_flags_fn_t)ndr_push_$name);");
+ $self->pidl("return ndr_size_union($varname, flags, level, (ndr_push_flags_fn_t)ndr_push_$name, ic);");
}
sub ParseUnionPushPrimitives($$$$)
if ($el->{TYPE} ne "EMPTY") {
$self->indent;
- $self->DeclarePtrVariables($el);
- $self->DeclareArrayVariables($el);
if (defined($e->{PROPERTIES}{relative_base})) {
$self->pidl("NDR_CHECK(ndr_pull_align($ndr, $el->{ALIGN}));");
# set the current offset as base for relative pointers
next if ($el->{TYPE} eq "EMPTY");
next if ($double_cases{"$el->{NAME}"});
$self->DeclareMemCtxVariables($el);
+ $self->DeclarePtrVariables($el);
+ $self->DeclareArrayVariables($el);
$double_cases{"$el->{NAME}"} = 1;
}
sub ArgsUnionNdrSize($$)
{
my ($d,$name) = @_;
- return "const union $name *r, uint32_t level, int flags";
+ return "const union $name *r, uint32_t level, struct smb_iconv_convenience *ic, int flags";
}
$typefamily{UNION} = {
$self->pidl("}");
if (grep(/in/,@{$e->{DIRECTION}}) and
grep(/out/,@{$e->{DIRECTION}})) {
- $self->pidl("memcpy(r->out.$e->{NAME}, r->in.$e->{NAME}, $size * sizeof(*r->in.$e->{NAME}));");
+ $self->pidl("memcpy(r->out.$e->{NAME}, r->in.$e->{NAME}, ($size) * sizeof(*r->in.$e->{NAME}));");
}
return;
}
sub FunctionCallEntry($$)
{
my ($self, $d) = @_;
- return if not defined($d->{OPNUM});
+ return 0 if not defined($d->{OPNUM});
$self->pidl("\t{");
$self->pidl("\t\t\"$d->{NAME}\",");
$self->pidl("\t\tsizeof(struct $d->{NAME}),");
$self->pidl("\t\t(ndr_print_function_t) ndr_print_$d->{NAME},");
$self->pidl("\t\t".($d->{ASYNC}?"true":"false").",");
$self->pidl("\t},");
+ return 1;
}
#####################################################################
$self->pidl("static const struct ndr_interface_call $interface->{NAME}\_calls[] = {");
foreach my $d (@{$interface->{INHERITED_FUNCTIONS}},@{$interface->{FUNCTIONS}}) {
- $self->FunctionCallEntry($d);
- $count++;
+ $count += $self->FunctionCallEntry($d);
}
$self->pidl("\t{ NULL, 0, NULL, NULL, NULL, false }");
$self->pidl("};");
if (is_intree()) {
$self->pidl("#include \"includes.h\"");
} else {
+ $self->pidl("#ifndef _GNU_SOURCE");
$self->pidl("#define _GNU_SOURCE");
+ $self->pidl("#endif");
$self->pidl("#include <stdint.h>");
$self->pidl("#include <stdlib.h>");
$self->pidl("#include <stdio.h>");