~ubuntu-branches/ubuntu/maverick/samba/maverick-security

« back to all changes in this revision

Viewing changes to source/pidl/lib/Parse/Pidl/Samba4/NDR/Parser.pm

  • Committer: Bazaar Package Importer
  • Author(s): Steve Langasek
  • Date: 2009-03-03 22:02:23 UTC
  • mfrom: (0.28.1 squeeze)
  • Revision ID: james.westby@ubuntu.com-20090303220223-3bdlm2d9fwx1p1ye
Tags: 2:3.3.1-1ubuntu1
* Merge from Debian unstable (LP: #337094), remaining changes:
  + debian/patches/VERSION.patch:
    - setup SAMBA_VERSION_SUFFIX to Ubuntu.
  + debian/smb.conf:
    - add "(Samba, Ubuntu)" to server string.
    - comment out the default [homes] share, and add a comment about
      "valid users = %S" to show users how to restrict access to
      \\server\username to only username.
    - Set 'usershare allow guests', so that usershare admins are 
      allowed to create public shares in addition to authenticated
      ones.
    - add map to guest = Bad user, maps bad username to guest access. 
  + debian/samba-common.config:
    - Do not change priority to high if dhclient3 is installed.
    - Use priority medium instead of high for the workgroup question.
  + debian/mksambapasswd.awk:
    - Do not add user with UID less than 1000 to smbpasswd.
  + debian/control:
    - Make libwbclient0 replace/conflict with hardy's likewise-open.
    - Don't build against ctdb.
  + debian/rules:
    - enable "native" PIE hardening.
  + Add ufw integration:
    - Created debian/samba.ufw.profile
    - debian/rules, debian/samba.dirs, debian/samba.files: install
      profile
    - debian/control: have samba suggest ufw
* Dropped changes, merged in Debian:
  + debian/libpam-smbpass.pam-config, debian/libpam-smbpass.postinst,
    debian/libpam-smbpass.prerm, debian/libpam-smbpass.files,
    debian/rules:
    - Make libpam-smbpasswd depend on libpam-runtime to allow 
      libpam-smbpasswd for auto-configuration.
  + debian/control:
    - Provide a config block for the new PAM framework to auto-configure
      itself
  + debian/samba.postinst:
    - When populating the new sambashare group, it is not an error
      if the user simply does not exist; test for this case and let
      the install continue instead of aborting.
  + debian/winbind.files:
    - include additional files

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
###################################################
 
2
# Samba4 NDR parser generator for IDL structures
 
3
# Copyright tridge@samba.org 2000-2003
 
4
# Copyright tpot@samba.org 2001
 
5
# Copyright jelmer@samba.org 2004-2006
 
6
# released under the GNU GPL
 
7
 
 
8
package Parse::Pidl::Samba4::NDR::Parser;
 
9
 
 
10
require Exporter;
 
11
@ISA = qw(Exporter);
 
12
@EXPORT_OK = qw(check_null_pointer NeededFunction NeededElement NeededType $res NeededInterface TypeFunctionName ParseElementPrint);
 
13
 
 
14
use strict;
 
15
use Parse::Pidl::Typelist qw(hasType getType mapTypeName typeHasBody);
 
16
use Parse::Pidl::Util qw(has_property ParseExpr ParseExprExt print_uuid unmake_str);
 
17
use Parse::Pidl::CUtil qw(get_pointer_to get_value_of get_array_element);
 
18
use Parse::Pidl::NDR qw(GetPrevLevel GetNextLevel ContainsDeferred is_charset_array);
 
19
use Parse::Pidl::Samba4 qw(is_intree choose_header);
 
20
use Parse::Pidl::Samba4::Header qw(GenerateFunctionInEnv GenerateFunctionOutEnv EnvSubstituteValue GenerateStructEnv);
 
21
use Parse::Pidl qw(warning);
 
22
 
 
23
use vars qw($VERSION);
 
24
$VERSION = '0.01';
 
25
 
 
26
# list of known types
 
27
my %typefamily;
 
28
 
 
29
sub new($$) {
 
30
        my ($class) = @_;
 
31
        my $self = { res => "", res_hdr => "", deferred => [], tabs => "", defer_tabs => "" };
 
32
        bless($self, $class);
 
33
}
 
34
 
 
35
sub get_typefamily($)
 
36
{
 
37
        my $n = shift;
 
38
        return $typefamily{$n};
 
39
}
 
40
 
 
41
sub append_prefix($$)
 
42
{
 
43
        my ($e, $var_name) = @_;
 
44
        my $pointers = 0;
 
45
        my $arrays = 0;
 
46
 
 
47
        foreach my $l (@{$e->{LEVELS}}) {
 
48
                if ($l->{TYPE} eq "POINTER") {
 
49
                        $pointers++;
 
50
                } elsif ($l->{TYPE} eq "ARRAY") {
 
51
                        $arrays++;
 
52
                        if (($pointers == 0) and
 
53
                            (not $l->{IS_FIXED}) and
 
54
                            (not $l->{IS_INLINE})) {
 
55
                                return get_value_of($var_name);
 
56
                        }
 
57
                } elsif ($l->{TYPE} eq "DATA") {
 
58
                        if (Parse::Pidl::Typelist::scalar_is_reference($l->{DATA_TYPE})) {
 
59
                                return get_value_of($var_name) unless ($pointers or $arrays);
 
60
                        }
 
61
                }
 
62
        }
 
63
 
 
64
        return $var_name;
 
65
}
 
66
 
 
67
sub has_fast_array($$)
 
68
{
 
69
        my ($e,$l) = @_;
 
70
 
 
71
        return 0 if ($l->{TYPE} ne "ARRAY");
 
72
 
 
73
        my $nl = GetNextLevel($e,$l);
 
74
        return 0 unless ($nl->{TYPE} eq "DATA");
 
75
        return 0 unless (hasType($nl->{DATA_TYPE}));
 
76
 
 
77
        my $t = getType($nl->{DATA_TYPE});
 
78
 
 
79
        # Only uint8 and string have fast array functions at the moment
 
80
        return ($t->{NAME} eq "uint8") or ($t->{NAME} eq "string");
 
81
}
 
82
 
 
83
 
 
84
####################################
 
85
# pidl() is our basic output routine
 
86
sub pidl($$)
 
87
{
 
88
        my ($self, $d) = @_;
 
89
        if ($d) {
 
90
                $self->{res} .= $self->{tabs};
 
91
                $self->{res} .= $d;
 
92
        }
 
93
        $self->{res} .="\n";
 
94
}
 
95
 
 
96
sub pidl_hdr($$) { my ($self, $d) = @_; $self->{res_hdr} .= "$d\n"; }
 
97
 
 
98
####################################
 
99
# defer() is like pidl(), but adds to
 
100
# a deferred buffer which is then added to the
 
101
# output buffer at the end of the structure/union/function
 
102
# This is needed to cope with code that must be pushed back
 
103
# to the end of a block of elements
 
104
sub defer_indent($) { my ($self) = @_; $self->{defer_tabs}.="\t"; }
 
105
sub defer_deindent($) { my ($self) = @_; $self->{defer_tabs}=substr($self->{defer_tabs}, 0, -1); }
 
106
 
 
107
sub defer($$)
 
108
{
 
109
        my ($self, $d) = @_;
 
110
        if ($d) {
 
111
                push(@{$self->{deferred}}, $self->{defer_tabs}.$d);
 
112
        }
 
113
}
 
114
 
 
115
########################################
 
116
# add the deferred content to the current
 
117
# output
 
118
sub add_deferred($)
 
119
{
 
120
        my ($self) = @_;
 
121
        $self->pidl($_) foreach (@{$self->{deferred}});
 
122
        $self->{deferred} = [];
 
123
        $self->{defer_tabs} = "";
 
124
}
 
125
 
 
126
sub indent($)
 
127
{
 
128
        my ($self) = @_;
 
129
        $self->{tabs} .= "\t";
 
130
}
 
131
 
 
132
sub deindent($)
 
133
{
 
134
        my ($self) = @_;
 
135
        $self->{tabs} = substr($self->{tabs}, 0, -1);
 
136
}
 
137
 
 
138
#####################################################################
 
139
# declare a function public or static, depending on its attributes
 
140
sub fn_declare($$$$)
 
141
{
 
142
        my ($self,$type,$fn,$decl) = @_;
 
143
 
 
144
        if (has_property($fn, "no$type")) {
 
145
                $self->pidl_hdr("$decl;");
 
146
                return 0;
 
147
        }
 
148
 
 
149
        if (has_property($fn, "public")) {
 
150
                $self->pidl_hdr("$decl;");
 
151
                $self->pidl("_PUBLIC_ $decl");
 
152
        } else {
 
153
                $self->pidl("static $decl");
 
154
        }
 
155
 
 
156
        return 1;
 
157
}
 
158
 
 
159
###################################################################
 
160
# setup any special flags for an element or structure
 
161
sub start_flags($$$)
 
162
{
 
163
        my ($self, $e, $ndr) = @_;
 
164
        my $flags = has_property($e, "flag");
 
165
        if (defined $flags) {
 
166
                $self->pidl("{");
 
167
                $self->indent;
 
168
                $self->pidl("uint32_t _flags_save_$e->{TYPE} = $ndr->flags;");
 
169
                $self->pidl("ndr_set_flags(&$ndr->flags, $flags);");
 
170
        }
 
171
}
 
172
 
 
173
###################################################################
 
174
# end any special flags for an element or structure
 
175
sub end_flags($$$)
 
176
{
 
177
        my ($self, $e, $ndr) = @_;
 
178
        my $flags = has_property($e, "flag");
 
179
        if (defined $flags) {
 
180
                $self->pidl("$ndr->flags = _flags_save_$e->{TYPE};");
 
181
                $self->deindent;
 
182
                $self->pidl("}");
 
183
        }
 
184
}
 
185
 
 
186
#####################################################################
 
187
# parse the data of an array - push side
 
188
sub ParseArrayPushHeader($$$$$$)
 
189
{
 
190
        my ($self,$e,$l,$ndr,$var_name,$env) = @_;
 
191
 
 
192
        my $size;
 
193
        my $length;
 
194
 
 
195
        if ($l->{IS_ZERO_TERMINATED}) {
 
196
                if (has_property($e, "charset")) {
 
197
                        $size = $length = "ndr_charset_length($var_name, CH_$e->{PROPERTIES}->{charset})";
 
198
                } else {
 
199
                        $size = $length = "ndr_string_length($var_name, sizeof(*$var_name))";
 
200
                }
 
201
        } else {
 
202
                $size = ParseExpr($l->{SIZE_IS}, $env, $e);
 
203
                $length = ParseExpr($l->{LENGTH_IS}, $env, $e);
 
204
        }
 
205
 
 
206
        if ((!$l->{IS_SURROUNDING}) and $l->{IS_CONFORMANT}) {
 
207
                $self->pidl("NDR_CHECK(ndr_push_uint32($ndr, NDR_SCALARS, $size));");
 
208
        }
 
209
 
 
210
        if ($l->{IS_VARYING}) {
 
211
                $self->pidl("NDR_CHECK(ndr_push_uint32($ndr, NDR_SCALARS, 0));");  # array offset
 
212
                $self->pidl("NDR_CHECK(ndr_push_uint32($ndr, NDR_SCALARS, $length));");
 
213
        }
 
214
 
 
215
        return $length;
 
216
}
 
217
 
 
218
sub check_fully_dereferenced($$)
 
219
{
 
220
        my ($element, $env) = @_;
 
221
 
 
222
        return sub ($) {
 
223
                my $origvar = shift;
 
224
                my $check = 0;
 
225
 
 
226
                # Figure out the number of pointers in $ptr
 
227
                my $expandedvar = $origvar;
 
228
                $expandedvar =~ s/^(\**)//;
 
229
                my $ptr = $1;
 
230
 
 
231
                my $var = undef;
 
232
                foreach (keys %$env) {
 
233
                        if ($env->{$_} eq $expandedvar) {
 
234
                                $var = $_;
 
235
                                last;
 
236
                        }
 
237
                }
 
238
 
 
239
                return($origvar) unless (defined($var));
 
240
                my $e;
 
241
                foreach (@{$element->{PARENT}->{ELEMENTS}}) {
 
242
                        if ($_->{NAME} eq $var) {
 
243
                                $e = $_;
 
244
                                last;
 
245
                        }
 
246
                }
 
247
 
 
248
                $e or die("Environment doesn't match siblings");
 
249
 
 
250
                # See if pointer at pointer level $level
 
251
                # needs to be checked.
 
252
                my $nump = 0;
 
253
                foreach (@{$e->{LEVELS}}) {
 
254
                        if ($_->{TYPE} eq "POINTER") {
 
255
                                $nump = $_->{POINTER_INDEX}+1;
 
256
                        }
 
257
                }
 
258
                warning($element->{ORIGINAL}, "Got pointer for `$e->{NAME}', expected fully derefenced variable") if ($nump > length($ptr));
 
259
                return ($origvar);
 
260
        }
 
261
}
 
262
 
 
263
sub check_null_pointer($$$$)
 
264
{
 
265
        my ($element, $env, $print_fn, $return) = @_;
 
266
 
 
267
        return sub ($) {
 
268
                my $expandedvar = shift;
 
269
                my $check = 0;
 
270
 
 
271
                # Figure out the number of pointers in $ptr
 
272
                $expandedvar =~ s/^(\**)//;
 
273
                my $ptr = $1;
 
274
 
 
275
                my $var = undef;
 
276
                foreach (keys %$env) {
 
277
                        if ($env->{$_} eq $expandedvar) {
 
278
                                $var = $_;
 
279
                                last;
 
280
                        }
 
281
                }
 
282
 
 
283
                if (defined($var)) {
 
284
                        my $e;
 
285
                        # lookup ptr in $e
 
286
                        foreach (@{$element->{PARENT}->{ELEMENTS}}) {
 
287
                                if ($_->{NAME} eq $var) {
 
288
                                        $e = $_;
 
289
                                        last;
 
290
                                }
 
291
                        }
 
292
 
 
293
                        $e or die("Environment doesn't match siblings");
 
294
 
 
295
                        # See if pointer at pointer level $level
 
296
                        # needs to be checked.
 
297
                        foreach my $l (@{$e->{LEVELS}}) {
 
298
                                if ($l->{TYPE} eq "POINTER" and
 
299
                                        $l->{POINTER_INDEX} == length($ptr)) {
 
300
                                        # No need to check ref pointers
 
301
                                        $check = ($l->{POINTER_TYPE} ne "ref");
 
302
                                        last;
 
303
                                }
 
304
 
 
305
                                if ($l->{TYPE} eq "DATA") {
 
306
                                        warning($element, "too much dereferences for `$var'");
 
307
                                }
 
308
                        }
 
309
                } else {
 
310
                        warning($element, "unknown dereferenced expression `$expandedvar'");
 
311
                        $check = 1;
 
312
                }
 
313
 
 
314
                $print_fn->("if ($ptr$expandedvar == NULL) $return") if $check;
 
315
        }
 
316
}
 
317
 
 
318
#####################################################################
 
319
# parse an array - pull side
 
320
sub ParseArrayPullHeader($$$$$$)
 
321
{
 
322
        my ($self,$e,$l,$ndr,$var_name,$env) = @_;
 
323
 
 
324
        my $length;
 
325
        my $size;
 
326
 
 
327
        if ($l->{IS_CONFORMANT}) {
 
328
                $length = $size = "ndr_get_array_size($ndr, " . get_pointer_to($var_name) . ")";
 
329
        } elsif ($l->{IS_ZERO_TERMINATED}) { # Noheader arrays
 
330
                $length = $size = "ndr_get_string_size($ndr, sizeof(*$var_name))";
 
331
        } else {
 
332
                $length = $size = ParseExprExt($l->{SIZE_IS}, $env, $e->{ORIGINAL},
 
333
                        check_null_pointer($e, $env, sub { $self->pidl(shift); },
 
334
                                           "return ndr_pull_error($ndr, NDR_ERR_INVALID_POINTER, \"NULL Pointer for size_is()\");"),
 
335
                        check_fully_dereferenced($e, $env));
 
336
        }
 
337
 
 
338
        if ((!$l->{IS_SURROUNDING}) and $l->{IS_CONFORMANT}) {
 
339
                $self->pidl("NDR_CHECK(ndr_pull_array_size($ndr, " . get_pointer_to($var_name) . "));");
 
340
        }
 
341
 
 
342
        if ($l->{IS_VARYING}) {
 
343
                $self->pidl("NDR_CHECK(ndr_pull_array_length($ndr, " . get_pointer_to($var_name) . "));");
 
344
                $length = "ndr_get_array_length($ndr, " . get_pointer_to($var_name) .")";
 
345
        }
 
346
 
 
347
        if ($length ne $size) {
 
348
                $self->pidl("if ($length > $size) {");
 
349
                $self->indent;
 
350
                $self->pidl("return ndr_pull_error($ndr, NDR_ERR_ARRAY_SIZE, \"Bad array size %u should exceed array length %u\", $size, $length);");
 
351
                $self->deindent;
 
352
                $self->pidl("}");
 
353
        }
 
354
 
 
355
        if ($l->{IS_CONFORMANT} and not $l->{IS_ZERO_TERMINATED}) {
 
356
                $self->defer("if ($var_name) {");
 
357
                $self->defer_indent;
 
358
                my $size = ParseExprExt($l->{SIZE_IS}, $env, $e->{ORIGINAL},
 
359
                        check_null_pointer($e, $env, sub { $self->defer(shift); },
 
360
                                           "return ndr_pull_error($ndr, NDR_ERR_INVALID_POINTER, \"NULL Pointer for size_is()\");"),
 
361
                        check_fully_dereferenced($e, $env));
 
362
                $self->defer("NDR_CHECK(ndr_check_array_size($ndr, (void*)" . get_pointer_to($var_name) . ", $size));");
 
363
                $self->defer_deindent;
 
364
                $self->defer("}");
 
365
        }
 
366
 
 
367
        if ($l->{IS_VARYING} and not $l->{IS_ZERO_TERMINATED}) {
 
368
                $self->defer("if ($var_name) {");
 
369
                $self->defer_indent;
 
370
                my $length = ParseExprExt($l->{LENGTH_IS}, $env, $e->{ORIGINAL},
 
371
                        check_null_pointer($e, $env, sub { $self->defer(shift); },
 
372
                                           "return ndr_pull_error($ndr, NDR_ERR_INVALID_POINTER, \"NULL Pointer for length_is()\");"),
 
373
                        check_fully_dereferenced($e, $env));
 
374
                $self->defer("NDR_CHECK(ndr_check_array_length($ndr, (void*)" . get_pointer_to($var_name) . ", $length));");
 
375
                $self->defer_deindent;
 
376
                $self->defer("}");
 
377
        }
 
378
 
 
379
        if (not $l->{IS_FIXED} and not is_charset_array($e, $l)) {
 
380
                $self->AllocateArrayLevel($e,$l,$ndr,$var_name,$size);
 
381
        }
 
382
 
 
383
        return $length;
 
384
}
 
385
 
 
386
sub compression_alg($$)
 
387
{
 
388
        my ($e, $l) = @_;
 
389
        my ($alg, $clen, $dlen) = split(/,/, $l->{COMPRESSION});
 
390
 
 
391
        return $alg;
 
392
}
 
393
 
 
394
sub compression_clen($$$)
 
395
{
 
396
        my ($e, $l, $env) = @_;
 
397
        my ($alg, $clen, $dlen) = split(/,/, $l->{COMPRESSION});
 
398
 
 
399
        return ParseExpr($clen, $env, $e->{ORIGINAL});
 
400
}
 
401
 
 
402
sub compression_dlen($$$)
 
403
{
 
404
        my ($e,$l,$env) = @_;
 
405
        my ($alg, $clen, $dlen) = split(/,/, $l->{COMPRESSION});
 
406
 
 
407
        return ParseExpr($dlen, $env, $e->{ORIGINAL});
 
408
}
 
409
 
 
410
sub ParseCompressionPushStart($$$$$)
 
411
{
 
412
        my ($self,$e,$l,$ndr,$env) = @_;
 
413
        my $comndr = "$ndr\_compressed";
 
414
        my $alg = compression_alg($e, $l);
 
415
        my $dlen = compression_dlen($e, $l, $env);
 
416
 
 
417
        $self->pidl("{");
 
418
        $self->indent;
 
419
        $self->pidl("struct ndr_push *$comndr;");
 
420
        $self->pidl("NDR_CHECK(ndr_push_compression_start($ndr, &$comndr, $alg, $dlen));");
 
421
 
 
422
        return $comndr;
 
423
}
 
424
 
 
425
sub ParseCompressionPushEnd($$$$$)
 
426
{
 
427
        my ($self,$e,$l,$ndr,$env) = @_;
 
428
        my $comndr = "$ndr\_compressed";
 
429
        my $alg = compression_alg($e, $l);
 
430
        my $dlen = compression_dlen($e, $l, $env);
 
431
 
 
432
        $self->pidl("NDR_CHECK(ndr_push_compression_end($ndr, $comndr, $alg, $dlen));");
 
433
        $self->deindent;
 
434
        $self->pidl("}");
 
435
}
 
436
 
 
437
sub ParseCompressionPullStart($$$$$)
 
438
{
 
439
        my ($self,$e,$l,$ndr,$env) = @_;
 
440
        my $comndr = "$ndr\_compressed";
 
441
        my $alg = compression_alg($e, $l);
 
442
        my $dlen = compression_dlen($e, $l, $env);
 
443
 
 
444
        $self->pidl("{");
 
445
        $self->indent;
 
446
        $self->pidl("struct ndr_pull *$comndr;");
 
447
        $self->pidl("NDR_CHECK(ndr_pull_compression_start($ndr, &$comndr, $alg, $dlen));");
 
448
 
 
449
        return $comndr;
 
450
}
 
451
 
 
452
sub ParseCompressionPullEnd($$$$$)
 
453
{
 
454
        my ($self,$e,$l,$ndr,$env) = @_;
 
455
        my $comndr = "$ndr\_compressed";
 
456
        my $alg = compression_alg($e, $l);
 
457
        my $dlen = compression_dlen($e, $l, $env);
 
458
 
 
459
        $self->pidl("NDR_CHECK(ndr_pull_compression_end($ndr, $comndr, $alg, $dlen));");
 
460
        $self->deindent;
 
461
        $self->pidl("}");
 
462
}
 
463
 
 
464
sub ParseSubcontextPushStart($$$$$)
 
465
{
 
466
        my ($self,$e,$l,$ndr,$env) = @_;
 
467
        my $subndr = "_ndr_$e->{NAME}";
 
468
        my $subcontext_size = ParseExpr($l->{SUBCONTEXT_SIZE}, $env, $e->{ORIGINAL});
 
469
 
 
470
        $self->pidl("{");
 
471
        $self->indent;
 
472
        $self->pidl("struct ndr_push *$subndr;");
 
473
        $self->pidl("NDR_CHECK(ndr_push_subcontext_start($ndr, &$subndr, $l->{HEADER_SIZE}, $subcontext_size));");
 
474
 
 
475
        if (defined $l->{COMPRESSION}) {
 
476
                $subndr = $self->ParseCompressionPushStart($e, $l, $subndr, $env);
 
477
        }
 
478
 
 
479
        return $subndr;
 
480
}
 
481
 
 
482
sub ParseSubcontextPushEnd($$$$$)
 
483
{
 
484
        my ($self,$e,$l,$ndr,$env) = @_;
 
485
        my $subndr = "_ndr_$e->{NAME}";
 
486
        my $subcontext_size = ParseExpr($l->{SUBCONTEXT_SIZE}, $env, $e->{ORIGINAL});
 
487
 
 
488
        if (defined $l->{COMPRESSION}) {
 
489
                $self->ParseCompressionPushEnd($e, $l, $subndr, $env);
 
490
        }
 
491
 
 
492
        $self->pidl("NDR_CHECK(ndr_push_subcontext_end($ndr, $subndr, $l->{HEADER_SIZE}, $subcontext_size));");
 
493
        $self->deindent;
 
494
        $self->pidl("}");
 
495
}
 
496
 
 
497
sub ParseSubcontextPullStart($$$$$)
 
498
{
 
499
        my ($self,$e,$l,$ndr,$env) = @_;
 
500
        my $subndr = "_ndr_$e->{NAME}";
 
501
        my $subcontext_size = ParseExpr($l->{SUBCONTEXT_SIZE}, $env, $e->{ORIGINAL});
 
502
 
 
503
        $self->pidl("{");
 
504
        $self->indent;
 
505
        $self->pidl("struct ndr_pull *$subndr;");
 
506
        $self->pidl("NDR_CHECK(ndr_pull_subcontext_start($ndr, &$subndr, $l->{HEADER_SIZE}, $subcontext_size));");
 
507
 
 
508
        if (defined $l->{COMPRESSION}) {
 
509
                $subndr = $self->ParseCompressionPullStart($e, $l, $subndr, $env);
 
510
        }
 
511
 
 
512
        return $subndr;
 
513
}
 
514
 
 
515
sub ParseSubcontextPullEnd($$$$$)
 
516
{
 
517
        my ($self,$e,$l,$ndr,$env) = @_;
 
518
        my $subndr = "_ndr_$e->{NAME}";
 
519
        my $subcontext_size = ParseExpr($l->{SUBCONTEXT_SIZE}, $env, $e->{ORIGINAL});
 
520
 
 
521
        if (defined $l->{COMPRESSION}) {
 
522
                $self->ParseCompressionPullEnd($e, $l, $subndr, $env);
 
523
        }
 
524
 
 
525
        $self->pidl("NDR_CHECK(ndr_pull_subcontext_end($ndr, $subndr, $l->{HEADER_SIZE}, $subcontext_size));");
 
526
        $self->deindent;
 
527
        $self->pidl("}");
 
528
}
 
529
 
 
530
sub ParseElementPushLevel
 
531
{
 
532
        my ($self,$e,$l,$ndr,$var_name,$env,$primitives,$deferred) = @_;
 
533
 
 
534
        my $ndr_flags = CalcNdrFlags($l, $primitives, $deferred);
 
535
 
 
536
        if ($l->{TYPE} eq "ARRAY" and ($l->{IS_CONFORMANT} or $l->{IS_VARYING})) {
 
537
                $var_name = get_pointer_to($var_name);
 
538
        }
 
539
 
 
540
        if (defined($ndr_flags)) {
 
541
                if ($l->{TYPE} eq "SUBCONTEXT") {
 
542
                        my $subndr = $self->ParseSubcontextPushStart($e, $l, $ndr, $env);
 
543
                        $self->ParseElementPushLevel($e, GetNextLevel($e, $l), $subndr, $var_name, $env, 1, 1);
 
544
                        $self->ParseSubcontextPushEnd($e, $l, $ndr, $env);
 
545
                } elsif ($l->{TYPE} eq "POINTER") {
 
546
                        $self->ParsePtrPush($e, $l, $ndr, $var_name);
 
547
                } elsif ($l->{TYPE} eq "ARRAY") {
 
548
                        my $length = $self->ParseArrayPushHeader($e, $l, $ndr, $var_name, $env);
 
549
 
 
550
                        my $nl = GetNextLevel($e, $l);
 
551
 
 
552
                        # Allow speedups for arrays of scalar types
 
553
                        if (is_charset_array($e,$l)) {
 
554
                                $self->pidl("NDR_CHECK(ndr_push_charset($ndr, $ndr_flags, $var_name, $length, sizeof(" . mapTypeName($nl->{DATA_TYPE}) . "), CH_$e->{PROPERTIES}->{charset}));");
 
555
                                return;
 
556
                        } elsif (has_fast_array($e,$l)) {
 
557
                                $self->pidl("NDR_CHECK(ndr_push_array_$nl->{DATA_TYPE}($ndr, $ndr_flags, $var_name, $length));");
 
558
                                return;
 
559
                        }
 
560
                } elsif ($l->{TYPE} eq "SWITCH") {
 
561
                        $self->ParseSwitchPush($e, $l, $ndr, $var_name, $env);
 
562
                } elsif ($l->{TYPE} eq "DATA") {
 
563
                        $self->ParseDataPush($e, $l, $ndr, $var_name, $primitives, $deferred);
 
564
                } elsif ($l->{TYPE} eq "TYPEDEF") {
 
565
                        $typefamily{$e->{DATA}->{TYPE}}->{PUSH_FN_BODY}->($self, $e->{DATA}, $ndr, $var_name);
 
566
                }
 
567
        }
 
568
 
 
569
        if ($l->{TYPE} eq "POINTER" and $deferred) {
 
570
                if ($l->{POINTER_TYPE} ne "ref") {
 
571
                        $self->pidl("if ($var_name) {");
 
572
                        $self->indent;
 
573
                        if ($l->{POINTER_TYPE} eq "relative") {
 
574
                                $self->pidl("NDR_CHECK(ndr_push_relative_ptr2($ndr, $var_name));");
 
575
                        }
 
576
                }
 
577
                $var_name = get_value_of($var_name);
 
578
                $self->ParseElementPushLevel($e, GetNextLevel($e, $l), $ndr, $var_name, $env, 1, 1);
 
579
 
 
580
                if ($l->{POINTER_TYPE} ne "ref") {
 
581
                        $self->deindent;
 
582
                        $self->pidl("}");
 
583
                }
 
584
        } elsif ($l->{TYPE} eq "ARRAY" and not has_fast_array($e,$l) and
 
585
                not is_charset_array($e, $l)) {
 
586
                my $length = ParseExpr($l->{LENGTH_IS}, $env, $e->{ORIGINAL});
 
587
                my $counter = "cntr_$e->{NAME}_$l->{LEVEL_INDEX}";
 
588
 
 
589
                $var_name = get_array_element($var_name, $counter);
 
590
 
 
591
                if (($primitives and not $l->{IS_DEFERRED}) or ($deferred and $l->{IS_DEFERRED})) {
 
592
                        $self->pidl("for ($counter = 0; $counter < $length; $counter++) {");
 
593
                        $self->indent;
 
594
                        $self->ParseElementPushLevel($e, GetNextLevel($e, $l), $ndr, $var_name, $env, 1, 0);
 
595
                        $self->deindent;
 
596
                        $self->pidl("}");
 
597
                }
 
598
 
 
599
                if ($deferred and ContainsDeferred($e, $l)) {
 
600
                        $self->pidl("for ($counter = 0; $counter < $length; $counter++) {");
 
601
                        $self->indent;
 
602
                        $self->ParseElementPushLevel($e, GetNextLevel($e, $l), $ndr, $var_name, $env, 0, 1);
 
603
                        $self->deindent;
 
604
                        $self->pidl("}");
 
605
                }
 
606
        } elsif ($l->{TYPE} eq "SWITCH") {
 
607
                $self->ParseElementPushLevel($e, GetNextLevel($e, $l), $ndr, $var_name, $env, $primitives, $deferred);
 
608
        }
 
609
}
 
610
 
 
611
#####################################################################
 
612
# parse scalars in a structure element
 
613
sub ParseElementPush($$$$$$)
 
614
{
 
615
        my ($self,$e,$ndr,$env,$primitives,$deferred) = @_;
 
616
        my $subndr = undef;
 
617
 
 
618
        my $var_name = $env->{$e->{NAME}};
 
619
 
 
620
        return unless $primitives or ($deferred and ContainsDeferred($e, $e->{LEVELS}[0]));
 
621
 
 
622
        # Representation type is different from transmit_as
 
623
        if ($e->{REPRESENTATION_TYPE} ne $e->{TYPE}) {
 
624
                $self->pidl("{");
 
625
                $self->indent;
 
626
                my $transmit_name = "_transmit_$e->{NAME}";
 
627
                $self->pidl(mapTypeName($e->{TYPE}) ." $transmit_name;");
 
628
                $self->pidl("NDR_CHECK(ndr_$e->{REPRESENTATION_TYPE}_to_$e->{TYPE}($var_name, " . get_pointer_to($transmit_name) . "));");
 
629
                $var_name = $transmit_name;
 
630
        }
 
631
 
 
632
        $var_name = append_prefix($e, $var_name);
 
633
 
 
634
        $self->start_flags($e, $ndr);
 
635
 
 
636
        if (defined(my $value = has_property($e, "value"))) {
 
637
                $var_name = ParseExpr($value, $env, $e->{ORIGINAL});
 
638
        }
 
639
 
 
640
        $self->ParseElementPushLevel($e, $e->{LEVELS}[0], $ndr, $var_name, $env, $primitives, $deferred);
 
641
 
 
642
        $self->end_flags($e, $ndr);
 
643
 
 
644
        if ($e->{REPRESENTATION_TYPE} ne $e->{TYPE}) {
 
645
                $self->deindent;
 
646
                $self->pidl("}");
 
647
        }
 
648
}
 
649
 
 
650
#####################################################################
 
651
# parse a pointer in a struct element or function
 
652
sub ParsePtrPush($$$$$)
 
653
{
 
654
        my ($self,$e,$l,$ndr,$var_name) = @_;
 
655
 
 
656
        if ($l->{POINTER_TYPE} eq "ref") {
 
657
                $self->pidl("if ($var_name == NULL) {");
 
658
                $self->indent;
 
659
                $self->pidl("return ndr_push_error($ndr, NDR_ERR_INVALID_POINTER, \"NULL [ref] pointer\");");
 
660
                $self->deindent;
 
661
                $self->pidl("}");
 
662
                if ($l->{LEVEL} eq "EMBEDDED") {
 
663
                        $self->pidl("NDR_CHECK(ndr_push_ref_ptr(ndr));");
 
664
                }
 
665
        } elsif ($l->{POINTER_TYPE} eq "relative") {
 
666
                $self->pidl("NDR_CHECK(ndr_push_relative_ptr1($ndr, $var_name));");
 
667
        } elsif ($l->{POINTER_TYPE} eq "unique") {
 
668
                $self->pidl("NDR_CHECK(ndr_push_unique_ptr($ndr, $var_name));");
 
669
        } elsif ($l->{POINTER_TYPE} eq "full") {
 
670
                $self->pidl("NDR_CHECK(ndr_push_full_ptr($ndr, $var_name));");
 
671
        } else {
 
672
                die("Unhandled pointer type $l->{POINTER_TYPE}");
 
673
        }
 
674
}
 
675
 
 
676
sub need_pointer_to($$$)
 
677
{
 
678
        my ($e, $l, $scalar_only) = @_;
 
679
 
 
680
        my $t;
 
681
        if (ref($l->{DATA_TYPE})) {
 
682
                $t = "$l->{DATA_TYPE}->{TYPE}_$l->{DATA_TYPE}->{NAME}";
 
683
        } else {
 
684
                $t = $l->{DATA_TYPE};
 
685
        }
 
686
 
 
687
        if (not Parse::Pidl::Typelist::is_scalar($t)) {
 
688
                return 1 if $scalar_only;
 
689
        }
 
690
 
 
691
        my $arrays = 0;
 
692
 
 
693
        foreach my $tl (@{$e->{LEVELS}}) {
 
694
                last if $l == $tl;
 
695
                if ($tl->{TYPE} eq "ARRAY") {
 
696
                        $arrays++;
 
697
                }
 
698
        }
 
699
 
 
700
        if (Parse::Pidl::Typelist::scalar_is_reference($t)) {
 
701
                return 1 unless $arrays;
 
702
        }
 
703
 
 
704
        return 0;
 
705
}
 
706
 
 
707
sub ParseDataPrint($$$$$)
 
708
{
 
709
        my ($self, $e, $l, $ndr, $var_name) = @_;
 
710
 
 
711
        if (not ref($l->{DATA_TYPE}) or defined($l->{DATA_TYPE}->{NAME})) {
 
712
 
 
713
                if (need_pointer_to($e, $l, 1)) {
 
714
                        $var_name = get_pointer_to($var_name);
 
715
                }
 
716
 
 
717
                $self->pidl(TypeFunctionName("ndr_print", $l->{DATA_TYPE})."($ndr, \"$e->{NAME}\", $var_name);");
 
718
        } else {
 
719
                $self->ParseTypePrint($l->{DATA_TYPE}, $ndr, $var_name);
 
720
        }
 
721
}
 
722
 
 
723
#####################################################################
 
724
# print scalars in a structure element
 
725
sub ParseElementPrint($$$$$)
 
726
{
 
727
        my($self, $e, $ndr, $var_name, $env) = @_;
 
728
 
 
729
        return if (has_property($e, "noprint"));
 
730
 
 
731
        if ($e->{REPRESENTATION_TYPE} ne $e->{TYPE}) {
 
732
                $self->pidl("ndr_print_$e->{REPRESENTATION_TYPE}($ndr, \"$e->{NAME}\", $var_name);");
 
733
                return;
 
734
        }
 
735
 
 
736
        $var_name = append_prefix($e, $var_name);
 
737
 
 
738
        if (defined(my $value = has_property($e, "value"))) {
 
739
                $var_name = "($ndr->flags & LIBNDR_PRINT_SET_VALUES)?" . ParseExpr($value,$env, $e->{ORIGINAL}) . ":$var_name";
 
740
        }
 
741
 
 
742
        foreach my $l (@{$e->{LEVELS}}) {
 
743
                if ($l->{TYPE} eq "POINTER") {
 
744
                        $self->pidl("ndr_print_ptr($ndr, \"$e->{NAME}\", $var_name);");
 
745
                        $self->pidl("$ndr->depth++;");
 
746
                        if ($l->{POINTER_TYPE} ne "ref") {
 
747
                                $self->pidl("if ($var_name) {");
 
748
                                $self->indent;
 
749
                        }
 
750
                        $var_name = get_value_of($var_name);
 
751
                } elsif ($l->{TYPE} eq "ARRAY") {
 
752
                        my $length;
 
753
 
 
754
                        if ($l->{IS_CONFORMANT} or $l->{IS_VARYING}) {
 
755
                                $var_name = get_pointer_to($var_name);
 
756
                        }
 
757
 
 
758
                        if ($l->{IS_ZERO_TERMINATED}) {
 
759
                                $length = "ndr_string_length($var_name, sizeof(*$var_name))";
 
760
                        } else {
 
761
                                $length = ParseExprExt($l->{LENGTH_IS}, $env, $e->{ORIGINAL},
 
762
                                                        check_null_pointer($e, $env, sub { $self->pidl(shift); }, "return;"), check_fully_dereferenced($e, $env));
 
763
                        }
 
764
 
 
765
                        if (is_charset_array($e,$l)) {
 
766
                                $self->pidl("ndr_print_string($ndr, \"$e->{NAME}\", $var_name);");
 
767
                                last;
 
768
                        } elsif (has_fast_array($e, $l)) {
 
769
                                my $nl = GetNextLevel($e, $l);
 
770
                                $self->pidl("ndr_print_array_$nl->{DATA_TYPE}($ndr, \"$e->{NAME}\", $var_name, $length);");
 
771
                                last;
 
772
                        } else {
 
773
                                my $counter = "cntr_$e->{NAME}_$l->{LEVEL_INDEX}";
 
774
 
 
775
                                $self->pidl("$ndr->print($ndr, \"\%s: ARRAY(\%d)\", \"$e->{NAME}\", (int)$length);");
 
776
                                $self->pidl("$ndr->depth++;");
 
777
                                $self->pidl("for ($counter=0;$counter<$length;$counter++) {");
 
778
                                $self->indent;
 
779
                                $self->pidl("char *idx_$l->{LEVEL_INDEX}=NULL;");
 
780
                                $self->pidl("if (asprintf(&idx_$l->{LEVEL_INDEX}, \"[\%d]\", $counter) != -1) {");
 
781
                                $self->indent;
 
782
 
 
783
                                $var_name = get_array_element($var_name, $counter);
 
784
                        }
 
785
                } elsif ($l->{TYPE} eq "DATA") {
 
786
                        $self->ParseDataPrint($e, $l, $ndr, $var_name);
 
787
                } elsif ($l->{TYPE} eq "SWITCH") {
 
788
                        my $switch_var = ParseExprExt($l->{SWITCH_IS}, $env, $e->{ORIGINAL},
 
789
                                                check_null_pointer($e, $env, sub { $self->pidl(shift); }, "return;"), check_fully_dereferenced($e, $env));
 
790
                        $self->pidl("ndr_print_set_switch_value($ndr, " . get_pointer_to($var_name) . ", $switch_var);");
 
791
                }
 
792
        }
 
793
 
 
794
        foreach my $l (reverse @{$e->{LEVELS}}) {
 
795
                if ($l->{TYPE} eq "POINTER") {
 
796
                        if ($l->{POINTER_TYPE} ne "ref") {
 
797
                                $self->deindent;
 
798
                                $self->pidl("}");
 
799
                        }
 
800
                        $self->pidl("$ndr->depth--;");
 
801
                } elsif (($l->{TYPE} eq "ARRAY")
 
802
                        and not is_charset_array($e,$l)
 
803
                        and not has_fast_array($e,$l)) {
 
804
                        $self->pidl("free(idx_$l->{LEVEL_INDEX});");
 
805
                        $self->deindent;
 
806
                        $self->pidl("}");
 
807
                        $self->deindent;
 
808
                        $self->pidl("}");
 
809
                        $self->pidl("$ndr->depth--;");
 
810
                }
 
811
        }
 
812
}
 
813
 
 
814
#####################################################################
 
815
# parse scalars in a structure element - pull size
 
816
sub ParseSwitchPull($$$$$$)
 
817
{
 
818
        my($self,$e,$l,$ndr,$var_name,$env) = @_;
 
819
        my $switch_var = ParseExprExt($l->{SWITCH_IS}, $env, $e->{ORIGINAL},
 
820
                check_null_pointer($e, $env, sub { $self->pidl(shift); },
 
821
                                   "return ndr_pull_error($ndr, NDR_ERR_INVALID_POINTER, \"NULL Pointer for switch_is()\");"),
 
822
                check_fully_dereferenced($e, $env));
 
823
 
 
824
        $var_name = get_pointer_to($var_name);
 
825
        $self->pidl("NDR_CHECK(ndr_pull_set_switch_value($ndr, $var_name, $switch_var));");
 
826
}
 
827
 
 
828
#####################################################################
 
829
# push switch element
 
830
sub ParseSwitchPush($$$$$$)
 
831
{
 
832
        my($self,$e,$l,$ndr,$var_name,$env) = @_;
 
833
        my $switch_var = ParseExprExt($l->{SWITCH_IS}, $env, $e->{ORIGINAL},
 
834
                check_null_pointer($e, $env, sub { $self->pidl(shift); },
 
835
                                   "return ndr_push_error($ndr, NDR_ERR_INVALID_POINTER, \"NULL Pointer for switch_is()\");"),
 
836
                check_fully_dereferenced($e, $env));
 
837
 
 
838
        $var_name = get_pointer_to($var_name);
 
839
        $self->pidl("NDR_CHECK(ndr_push_set_switch_value($ndr, $var_name, $switch_var));");
 
840
}
 
841
 
 
842
sub ParseDataPull($$$$$$$)
 
843
{
 
844
        my ($self,$e,$l,$ndr,$var_name,$primitives,$deferred) = @_;
 
845
 
 
846
        if (not ref($l->{DATA_TYPE}) or defined($l->{DATA_TYPE}->{NAME})) {
 
847
 
 
848
                my $ndr_flags = CalcNdrFlags($l, $primitives, $deferred);
 
849
 
 
850
                if (need_pointer_to($e, $l, 0)) {
 
851
                        $var_name = get_pointer_to($var_name);
 
852
                }
 
853
 
 
854
                $var_name = get_pointer_to($var_name);
 
855
 
 
856
                $self->pidl("NDR_CHECK(".TypeFunctionName("ndr_pull", $l->{DATA_TYPE})."($ndr, $ndr_flags, $var_name));");
 
857
 
 
858
                if (my $range = has_property($e, "range")) {
 
859
                        $var_name = get_value_of($var_name);
 
860
                        my ($low, $high) = split(/,/, $range, 2);
 
861
                        $self->pidl("if ($var_name < $low || $var_name > $high) {");
 
862
                        $self->pidl("\treturn ndr_pull_error($ndr, NDR_ERR_RANGE, \"value out of range\");");
 
863
                        $self->pidl("}");
 
864
                }
 
865
        } else {
 
866
                $self->ParseTypePull($l->{DATA_TYPE}, $ndr, $var_name, $primitives, $deferred);
 
867
        }
 
868
}
 
869
 
 
870
sub ParseDataPush($$$$$$$)
 
871
{
 
872
        my ($self,$e,$l,$ndr,$var_name,$primitives,$deferred) = @_;
 
873
 
 
874
        if (not ref($l->{DATA_TYPE}) or defined($l->{DATA_TYPE}->{NAME})) {
 
875
 
 
876
                my $ndr_flags = CalcNdrFlags($l, $primitives, $deferred);
 
877
 
 
878
                # strings are passed by value rather than reference
 
879
                if (need_pointer_to($e, $l, 1)) {
 
880
                        $var_name = get_pointer_to($var_name);
 
881
                }
 
882
 
 
883
                $self->pidl("NDR_CHECK(".TypeFunctionName("ndr_push", $l->{DATA_TYPE})."($ndr, $ndr_flags, $var_name));");
 
884
        } else {
 
885
                $self->ParseTypePush($l->{DATA_TYPE}, $ndr, $var_name, $primitives, $deferred);
 
886
        }
 
887
}
 
888
 
 
889
sub CalcNdrFlags($$$)
 
890
{
 
891
        my ($l,$primitives,$deferred) = @_;
 
892
 
 
893
        my $scalars = 0;
 
894
        my $buffers = 0;
 
895
 
 
896
        # Add NDR_SCALARS if this one is deferred
 
897
        # and deferreds may be pushed
 
898
        $scalars = 1 if ($l->{IS_DEFERRED} and $deferred);
 
899
 
 
900
        # Add NDR_SCALARS if this one is not deferred and
 
901
        # primitives may be pushed
 
902
        $scalars = 1 if (!$l->{IS_DEFERRED} and $primitives);
 
903
 
 
904
        # Add NDR_BUFFERS if this one contains deferred stuff
 
905
        # and deferreds may be pushed
 
906
        $buffers = 1 if ($l->{CONTAINS_DEFERRED} and $deferred);
 
907
 
 
908
        return "NDR_SCALARS|NDR_BUFFERS" if ($scalars and $buffers);
 
909
        return "NDR_SCALARS" if ($scalars);
 
910
        return "NDR_BUFFERS" if ($buffers);
 
911
        return undef;
 
912
}
 
913
 
 
914
sub ParseMemCtxPullFlags($$$$)
 
915
{
 
916
        my ($self, $e, $l) = @_;
 
917
 
 
918
        return undef unless ($l->{TYPE} eq "POINTER" or $l->{TYPE} eq "ARRAY");
 
919
 
 
920
        return undef if ($l->{TYPE} eq "ARRAY" and $l->{IS_FIXED});
 
921
        return undef if has_fast_array($e, $l);
 
922
        return undef if is_charset_array($e, $l);
 
923
 
 
924
        my $mem_flags = "0";
 
925
 
 
926
        if (($l->{TYPE} eq "POINTER") and ($l->{POINTER_TYPE} eq "ref")) {
 
927
                my $nl = GetNextLevel($e, $l);
 
928
                my $next_is_array = ($nl->{TYPE} eq "ARRAY");
 
929
                my $next_is_string = (($nl->{TYPE} eq "DATA") and
 
930
                                        ($nl->{DATA_TYPE} eq "string"));
 
931
                if ($next_is_array or $next_is_string) {
 
932
                        return undef;
 
933
                } elsif ($l->{LEVEL} eq "TOP") {
 
934
                        $mem_flags = "LIBNDR_FLAG_REF_ALLOC";
 
935
                }
 
936
        }
 
937
 
 
938
        return $mem_flags;
 
939
}
 
940
 
 
941
sub ParseMemCtxPullStart($$$$$)
 
942
{
 
943
        my ($self, $e, $l, $ndr, $ptr_name) = @_;
 
944
 
 
945
        my $mem_r_ctx = "_mem_save_$e->{NAME}_$l->{LEVEL_INDEX}";
 
946
        my $mem_c_ctx = $ptr_name;
 
947
        my $mem_c_flags = $self->ParseMemCtxPullFlags($e, $l);
 
948
 
 
949
        return unless defined($mem_c_flags);
 
950
 
 
951
        $self->pidl("$mem_r_ctx = NDR_PULL_GET_MEM_CTX($ndr);");
 
952
        $self->pidl("NDR_PULL_SET_MEM_CTX($ndr, $mem_c_ctx, $mem_c_flags);");
 
953
}
 
954
 
 
955
sub ParseMemCtxPullEnd($$$$)
 
956
{
 
957
        my ($self, $e, $l, $ndr) = @_;
 
958
 
 
959
        my $mem_r_ctx = "_mem_save_$e->{NAME}_$l->{LEVEL_INDEX}";
 
960
        my $mem_r_flags = $self->ParseMemCtxPullFlags($e, $l);
 
961
 
 
962
        return unless defined($mem_r_flags);
 
963
 
 
964
        $self->pidl("NDR_PULL_SET_MEM_CTX($ndr, $mem_r_ctx, $mem_r_flags);");
 
965
}
 
966
 
 
967
sub CheckStringTerminator($$$$$)
 
968
{
 
969
        my ($self,$ndr,$e,$l,$length) = @_;
 
970
        my $nl = GetNextLevel($e, $l);
 
971
 
 
972
        # Make sure last element is zero!
 
973
        $self->pidl("NDR_CHECK(ndr_check_string_terminator($ndr, $length, sizeof($nl->{DATA_TYPE}_t)));");
 
974
}
 
975
 
 
976
sub ParseElementPullLevel
 
977
{
 
978
        my($self,$e,$l,$ndr,$var_name,$env,$primitives,$deferred) = @_;
 
979
 
 
980
        my $ndr_flags = CalcNdrFlags($l, $primitives, $deferred);
 
981
 
 
982
        if ($l->{TYPE} eq "ARRAY" and ($l->{IS_VARYING} or $l->{IS_CONFORMANT})) {
 
983
                $var_name = get_pointer_to($var_name);
 
984
        }
 
985
 
 
986
        # Only pull something if there's actually something to be pulled
 
987
        if (defined($ndr_flags)) {
 
988
                if ($l->{TYPE} eq "SUBCONTEXT") {
 
989
                        my $subndr = $self->ParseSubcontextPullStart($e, $l, $ndr, $env);
 
990
                        $self->ParseElementPullLevel($e, GetNextLevel($e,$l), $subndr, $var_name, $env, 1, 1);
 
991
                        $self->ParseSubcontextPullEnd($e, $l, $ndr, $env);
 
992
                } elsif ($l->{TYPE} eq "ARRAY") {
 
993
                        my $length = $self->ParseArrayPullHeader($e, $l, $ndr, $var_name, $env);
 
994
 
 
995
                        my $nl = GetNextLevel($e, $l);
 
996
 
 
997
                        if (is_charset_array($e,$l)) {
 
998
                                if ($l->{IS_ZERO_TERMINATED}) {
 
999
                                        $self->CheckStringTerminator($ndr, $e, $l, $length);
 
1000
                                }
 
1001
                                $self->pidl("NDR_CHECK(ndr_pull_charset($ndr, $ndr_flags, ".get_pointer_to($var_name).", $length, sizeof(" . mapTypeName($nl->{DATA_TYPE}) . "), CH_$e->{PROPERTIES}->{charset}));");
 
1002
                                return;
 
1003
                        } elsif (has_fast_array($e, $l)) {
 
1004
                                if ($l->{IS_ZERO_TERMINATED}) {
 
1005
                                        $self->CheckStringTerminator($ndr,$e,$l,$length);
 
1006
                                }
 
1007
                                $self->pidl("NDR_CHECK(ndr_pull_array_$nl->{DATA_TYPE}($ndr, $ndr_flags, $var_name, $length));");
 
1008
                                return;
 
1009
                        }
 
1010
                } elsif ($l->{TYPE} eq "POINTER") {
 
1011
                        $self->ParsePtrPull($e, $l, $ndr, $var_name);
 
1012
                } elsif ($l->{TYPE} eq "SWITCH") {
 
1013
                        $self->ParseSwitchPull($e, $l, $ndr, $var_name, $env);
 
1014
                } elsif ($l->{TYPE} eq "DATA") {
 
1015
                        $self->ParseDataPull($e, $l, $ndr, $var_name, $primitives, $deferred);
 
1016
                } elsif ($l->{TYPE} eq "TYPEDEF") {
 
1017
                        $typefamily{$e->{DATA}->{TYPE}}->{PULL_FN_BODY}->($self, $e->{DATA}, $ndr, $var_name);
 
1018
                }
 
1019
        }
 
1020
 
 
1021
        # add additional constructions
 
1022
        if ($l->{TYPE} eq "POINTER" and $deferred) {
 
1023
                if ($l->{POINTER_TYPE} ne "ref") {
 
1024
                        $self->pidl("if ($var_name) {");
 
1025
                        $self->indent;
 
1026
 
 
1027
                        if ($l->{POINTER_TYPE} eq "relative") {
 
1028
                                $self->pidl("uint32_t _relative_save_offset;");
 
1029
                                $self->pidl("_relative_save_offset = $ndr->offset;");
 
1030
                                $self->pidl("NDR_CHECK(ndr_pull_relative_ptr2($ndr, $var_name));");
 
1031
                        }
 
1032
                }
 
1033
 
 
1034
                $self->ParseMemCtxPullStart($e, $l, $ndr, $var_name);
 
1035
 
 
1036
                $var_name = get_value_of($var_name);
 
1037
                $self->ParseElementPullLevel($e, GetNextLevel($e,$l), $ndr, $var_name, $env, 1, 1);
 
1038
 
 
1039
                $self->ParseMemCtxPullEnd($e, $l, $ndr);
 
1040
 
 
1041
                if ($l->{POINTER_TYPE} ne "ref") {
 
1042
                        if ($l->{POINTER_TYPE} eq "relative") {
 
1043
                                $self->pidl("$ndr->offset = _relative_save_offset;");
 
1044
                        }
 
1045
                        $self->deindent;
 
1046
                        $self->pidl("}");
 
1047
                }
 
1048
        } elsif ($l->{TYPE} eq "ARRAY" and
 
1049
                        not has_fast_array($e,$l) and not is_charset_array($e, $l)) {
 
1050
                my $length = ParseExpr($l->{LENGTH_IS}, $env, $e->{ORIGINAL});
 
1051
                my $counter = "cntr_$e->{NAME}_$l->{LEVEL_INDEX}";
 
1052
                my $array_name = $var_name;
 
1053
 
 
1054
                $var_name = get_array_element($var_name, $counter);
 
1055
 
 
1056
                $self->ParseMemCtxPullStart($e, $l, $ndr, $array_name);
 
1057
 
 
1058
                if (($primitives and not $l->{IS_DEFERRED}) or ($deferred and $l->{IS_DEFERRED})) {
 
1059
                        my $nl = GetNextLevel($e,$l);
 
1060
 
 
1061
                        if ($l->{IS_ZERO_TERMINATED}) {
 
1062
                                $self->CheckStringTerminator($ndr,$e,$l,$length);
 
1063
                        }
 
1064
 
 
1065
                        $self->pidl("for ($counter = 0; $counter < $length; $counter++) {");
 
1066
                        $self->indent;
 
1067
                        $self->ParseElementPullLevel($e, $nl, $ndr, $var_name, $env, 1, 0);
 
1068
                        $self->deindent;
 
1069
                        $self->pidl("}");
 
1070
                }
 
1071
 
 
1072
                if ($deferred and ContainsDeferred($e, $l)) {
 
1073
                        $self->pidl("for ($counter = 0; $counter < $length; $counter++) {");
 
1074
                        $self->indent;
 
1075
                        $self->ParseElementPullLevel($e,GetNextLevel($e,$l), $ndr, $var_name, $env, 0, 1);
 
1076
                        $self->deindent;
 
1077
                        $self->pidl("}");
 
1078
                }
 
1079
 
 
1080
                $self->ParseMemCtxPullEnd($e, $l, $ndr);
 
1081
 
 
1082
        } elsif ($l->{TYPE} eq "SWITCH") {
 
1083
                $self->ParseElementPullLevel($e, GetNextLevel($e,$l), $ndr, $var_name, $env, $primitives, $deferred);
 
1084
        }
 
1085
}
 
1086
 
 
1087
#####################################################################
 
1088
# parse scalars in a structure element - pull size
 
1089
sub ParseElementPull($$$$$$)
 
1090
{
 
1091
        my($self,$e,$ndr,$env,$primitives,$deferred) = @_;
 
1092
 
 
1093
        my $var_name = $env->{$e->{NAME}};
 
1094
        my $represent_name;
 
1095
        my $transmit_name;
 
1096
 
 
1097
        return unless $primitives or ($deferred and ContainsDeferred($e, $e->{LEVELS}[0]));
 
1098
 
 
1099
        if ($e->{REPRESENTATION_TYPE} ne $e->{TYPE}) {
 
1100
                $self->pidl("{");
 
1101
                $self->indent;
 
1102
                $represent_name = $var_name;
 
1103
                $transmit_name = "_transmit_$e->{NAME}";
 
1104
                $var_name = $transmit_name;
 
1105
                $self->pidl(mapTypeName($e->{TYPE})." $var_name;");
 
1106
        }
 
1107
 
 
1108
        $var_name = append_prefix($e, $var_name);
 
1109
 
 
1110
        $self->start_flags($e, $ndr);
 
1111
 
 
1112
        $self->ParseElementPullLevel($e,$e->{LEVELS}[0],$ndr,$var_name,$env,$primitives,$deferred);
 
1113
 
 
1114
        $self->end_flags($e, $ndr);
 
1115
 
 
1116
        # Representation type is different from transmit_as
 
1117
        if ($e->{REPRESENTATION_TYPE} ne $e->{TYPE}) {
 
1118
                $self->pidl("NDR_CHECK(ndr_$e->{TYPE}_to_$e->{REPRESENTATION_TYPE}($transmit_name, ".get_pointer_to($represent_name)."));");
 
1119
                $self->deindent;
 
1120
                $self->pidl("}");
 
1121
        }
 
1122
}
 
1123
 
 
1124
#####################################################################
 
1125
# parse a pointer in a struct element or function
 
1126
sub ParsePtrPull($$$$$)
 
1127
{
 
1128
        my($self, $e,$l,$ndr,$var_name) = @_;
 
1129
 
 
1130
        my $nl = GetNextLevel($e, $l);
 
1131
        my $next_is_array = ($nl->{TYPE} eq "ARRAY");
 
1132
        my $next_is_string = (($nl->{TYPE} eq "DATA") and
 
1133
                                                 ($nl->{DATA_TYPE} eq "string"));
 
1134
 
 
1135
        if ($l->{POINTER_TYPE} eq "ref" and $l->{LEVEL} eq "TOP") {
 
1136
 
 
1137
                if (!$next_is_array and !$next_is_string) {
 
1138
                        $self->pidl("if ($ndr->flags & LIBNDR_FLAG_REF_ALLOC) {");
 
1139
                        $self->pidl("\tNDR_PULL_ALLOC($ndr, $var_name);");
 
1140
                        $self->pidl("}");
 
1141
                }
 
1142
 
 
1143
                return;
 
1144
        } elsif ($l->{POINTER_TYPE} eq "ref" and $l->{LEVEL} eq "EMBEDDED") {
 
1145
                $self->pidl("NDR_CHECK(ndr_pull_ref_ptr($ndr, &_ptr_$e->{NAME}));");
 
1146
        } elsif (($l->{POINTER_TYPE} eq "unique") or
 
1147
                 ($l->{POINTER_TYPE} eq "relative") or
 
1148
                 ($l->{POINTER_TYPE} eq "full")) {
 
1149
                $self->pidl("NDR_CHECK(ndr_pull_generic_ptr($ndr, &_ptr_$e->{NAME}));");
 
1150
        } else {
 
1151
                die("Unhandled pointer type $l->{POINTER_TYPE}");
 
1152
        }
 
1153
 
 
1154
        $self->pidl("if (_ptr_$e->{NAME}) {");
 
1155
        $self->indent;
 
1156
 
 
1157
        # Don't do this for arrays, they're allocated at the actual level
 
1158
        # of the array
 
1159
        unless ($next_is_array or $next_is_string) {
 
1160
                $self->pidl("NDR_PULL_ALLOC($ndr, $var_name);");
 
1161
        } else {
 
1162
                # FIXME: Yes, this is nasty.
 
1163
                # We allocate an array twice
 
1164
                # - once just to indicate that it's there,
 
1165
                # - then the real allocation...
 
1166
                $self->pidl("NDR_PULL_ALLOC($ndr, $var_name);");
 
1167
        }
 
1168
 
 
1169
        #$self->pidl("memset($var_name, 0, sizeof($var_name));");
 
1170
        if ($l->{POINTER_TYPE} eq "relative") {
 
1171
                $self->pidl("NDR_CHECK(ndr_pull_relative_ptr1($ndr, $var_name, _ptr_$e->{NAME}));");
 
1172
        }
 
1173
        $self->deindent;
 
1174
        $self->pidl("} else {");
 
1175
        $self->pidl("\t$var_name = NULL;");
 
1176
        $self->pidl("}");
 
1177
}
 
1178
 
 
1179
sub ParseStructPushPrimitives($$$$$)
 
1180
{
 
1181
        my ($self, $struct, $ndr, $varname, $env) = @_;
 
1182
 
 
1183
        # see if the structure contains a conformant array. If it
 
1184
        # does, then it must be the last element of the structure, and
 
1185
        # we need to push the conformant length early, as it fits on
 
1186
        # the wire before the structure (and even before the structure
 
1187
        # alignment)
 
1188
        if (defined($struct->{SURROUNDING_ELEMENT})) {
 
1189
                my $e = $struct->{SURROUNDING_ELEMENT};
 
1190
 
 
1191
                if (defined($e->{LEVELS}[0]) and
 
1192
                        $e->{LEVELS}[0]->{TYPE} eq "ARRAY") {
 
1193
                        my $size;
 
1194
 
 
1195
                        if ($e->{LEVELS}[0]->{IS_ZERO_TERMINATED}) {
 
1196
                                if (has_property($e, "charset")) {
 
1197
                                        $size = "ndr_charset_length($varname->$e->{NAME}, CH_$e->{PROPERTIES}->{charset})";
 
1198
                                } else {
 
1199
                                        $size = "ndr_string_length($varname->$e->{NAME}, sizeof(*$varname->$e->{NAME}))";
 
1200
                                }
 
1201
                        } else {
 
1202
                                $size = ParseExpr($e->{LEVELS}[0]->{SIZE_IS}, $env, $e->{ORIGINAL});
 
1203
                        }
 
1204
 
 
1205
                        $self->pidl("NDR_CHECK(ndr_push_uint32($ndr, NDR_SCALARS, $size));");
 
1206
                } else {
 
1207
                        $self->pidl("NDR_CHECK(ndr_push_uint32($ndr, NDR_SCALARS, ndr_string_array_size($ndr, $varname->$e->{NAME})));");
 
1208
                }
 
1209
        }
 
1210
 
 
1211
        $self->pidl("NDR_CHECK(ndr_push_align($ndr, $struct->{ALIGN}));");
 
1212
 
 
1213
        if (defined($struct->{PROPERTIES}{relative_base})) {
 
1214
                # set the current offset as base for relative pointers
 
1215
                # and store it based on the toplevel struct/union
 
1216
                $self->pidl("NDR_CHECK(ndr_push_setup_relative_base_offset1($ndr, $varname, $ndr->offset));");
 
1217
        }
 
1218
 
 
1219
        $self->ParseElementPush($_, $ndr, $env, 1, 0) foreach (@{$struct->{ELEMENTS}});
 
1220
}
 
1221
 
 
1222
sub ParseStructPushDeferred($$$$)
 
1223
{
 
1224
        my ($self, $struct, $ndr, $varname, $env) = @_;
 
1225
        if (defined($struct->{PROPERTIES}{relative_base})) {
 
1226
                # retrieve the current offset as base for relative pointers
 
1227
                # based on the toplevel struct/union
 
1228
                $self->pidl("NDR_CHECK(ndr_push_setup_relative_base_offset2($ndr, $varname));");
 
1229
        }
 
1230
        $self->ParseElementPush($_, $ndr, $env, 0, 1) foreach (@{$struct->{ELEMENTS}});
 
1231
}
 
1232
 
 
1233
#####################################################################
 
1234
# parse a struct
 
1235
sub ParseStructPush($$$$)
 
1236
{
 
1237
        my ($self, $struct, $ndr, $varname) = @_;
 
1238
 
 
1239
        return unless defined($struct->{ELEMENTS});
 
1240
 
 
1241
        my $env = GenerateStructEnv($struct, $varname);
 
1242
 
 
1243
        EnvSubstituteValue($env, $struct);
 
1244
 
 
1245
        $self->DeclareArrayVariables($_) foreach (@{$struct->{ELEMENTS}});
 
1246
 
 
1247
        $self->start_flags($struct, $ndr);
 
1248
 
 
1249
        $self->pidl("if (ndr_flags & NDR_SCALARS) {");
 
1250
        $self->indent;
 
1251
        $self->ParseStructPushPrimitives($struct, $ndr, $varname, $env);
 
1252
        $self->deindent;
 
1253
        $self->pidl("}");
 
1254
 
 
1255
        $self->pidl("if (ndr_flags & NDR_BUFFERS) {");
 
1256
        $self->indent;
 
1257
        $self->ParseStructPushDeferred($struct, $ndr, $varname, $env);
 
1258
        $self->deindent;
 
1259
        $self->pidl("}");
 
1260
 
 
1261
        $self->end_flags($struct, $ndr);
 
1262
}
 
1263
 
 
1264
#####################################################################
 
1265
# generate a push function for an enum
 
1266
sub ParseEnumPush($$$$)
 
1267
{
 
1268
        my($self,$enum,$ndr,$varname) = @_;
 
1269
        my($type_fn) = $enum->{BASE_TYPE};
 
1270
 
 
1271
        $self->start_flags($enum, $ndr);
 
1272
        $self->pidl("NDR_CHECK(ndr_push_$type_fn($ndr, NDR_SCALARS, $varname));");
 
1273
        $self->end_flags($enum, $ndr);
 
1274
}
 
1275
 
 
1276
#####################################################################
 
1277
# generate a pull function for an enum
 
1278
sub ParseEnumPull($$$$)
 
1279
{
 
1280
        my($self,$enum,$ndr,$varname) = @_;
 
1281
        my($type_fn) = $enum->{BASE_TYPE};
 
1282
        my($type_v_decl) = mapTypeName($type_fn);
 
1283
 
 
1284
        $self->pidl("$type_v_decl v;");
 
1285
        $self->start_flags($enum, $ndr);
 
1286
        $self->pidl("NDR_CHECK(ndr_pull_$type_fn($ndr, NDR_SCALARS, &v));");
 
1287
        $self->pidl("*$varname = v;");
 
1288
 
 
1289
        $self->end_flags($enum, $ndr);
 
1290
}
 
1291
 
 
1292
#####################################################################
 
1293
# generate a print function for an enum
 
1294
sub ParseEnumPrint($$$$$)
 
1295
{
 
1296
        my($self,$enum,$ndr,$name,$varname) = @_;
 
1297
 
 
1298
        $self->pidl("const char *val = NULL;");
 
1299
        $self->pidl("");
 
1300
 
 
1301
        $self->start_flags($enum, $ndr);
 
1302
 
 
1303
        $self->pidl("switch ($varname) {");
 
1304
        $self->indent;
 
1305
        my $els = \@{$enum->{ELEMENTS}};
 
1306
        foreach my $i (0 .. $#{$els}) {
 
1307
                my $e = ${$els}[$i];
 
1308
                chomp $e;
 
1309
                if ($e =~ /^(.*)=/) {
 
1310
                        $e = $1;
 
1311
                }
 
1312
                $self->pidl("case $e: val = \"$e\"; break;");
 
1313
        }
 
1314
 
 
1315
        $self->deindent;
 
1316
        $self->pidl("}");
 
1317
 
 
1318
        $self->pidl("ndr_print_enum($ndr, name, \"$enum->{TYPE}\", val, $varname);");
 
1319
 
 
1320
        $self->end_flags($enum, $ndr);
 
1321
}
 
1322
 
 
1323
sub DeclEnum($$$$)
 
1324
{
 
1325
        my ($e,$t,$name,$varname) = @_;
 
1326
        return "enum $name " .
 
1327
                ($t eq "pull"?"*":"") . $varname;
 
1328
}
 
1329
 
 
1330
$typefamily{ENUM} = {
 
1331
        DECL => \&DeclEnum,
 
1332
        PUSH_FN_BODY => \&ParseEnumPush,
 
1333
        PULL_FN_BODY => \&ParseEnumPull,
 
1334
        PRINT_FN_BODY => \&ParseEnumPrint,
 
1335
};
 
1336
 
 
1337
#####################################################################
 
1338
# generate a push function for a bitmap
 
1339
sub ParseBitmapPush($$$$)
 
1340
{
 
1341
        my($self,$bitmap,$ndr,$varname) = @_;
 
1342
        my($type_fn) = $bitmap->{BASE_TYPE};
 
1343
 
 
1344
        $self->start_flags($bitmap, $ndr);
 
1345
 
 
1346
        $self->pidl("NDR_CHECK(ndr_push_$type_fn($ndr, NDR_SCALARS, $varname));");
 
1347
 
 
1348
        $self->end_flags($bitmap, $ndr);
 
1349
}
 
1350
 
 
1351
#####################################################################
 
1352
# generate a pull function for an bitmap
 
1353
sub ParseBitmapPull($$$$)
 
1354
{
 
1355
        my($self,$bitmap,$ndr,$varname) = @_;
 
1356
        my $type_fn = $bitmap->{BASE_TYPE};
 
1357
        my($type_decl) = mapTypeName($bitmap->{BASE_TYPE});
 
1358
 
 
1359
        $self->pidl("$type_decl v;");
 
1360
        $self->start_flags($bitmap, $ndr);
 
1361
        $self->pidl("NDR_CHECK(ndr_pull_$type_fn($ndr, NDR_SCALARS, &v));");
 
1362
        $self->pidl("*$varname = v;");
 
1363
 
 
1364
        $self->end_flags($bitmap, $ndr);
 
1365
}
 
1366
 
 
1367
#####################################################################
 
1368
# generate a print function for an bitmap
 
1369
sub ParseBitmapPrintElement($$$$$$)
 
1370
{
 
1371
        my($self,$e,$bitmap,$ndr,$name,$varname) = @_;
 
1372
        my($type_decl) = mapTypeName($bitmap->{BASE_TYPE});
 
1373
        my($type_fn) = $bitmap->{BASE_TYPE};
 
1374
        my($flag);
 
1375
 
 
1376
        if ($e =~ /^(\w+) .*$/) {
 
1377
                $flag = "$1";
 
1378
        } else {
 
1379
                die "Bitmap: \"$name\" invalid Flag: \"$e\"";
 
1380
        }
 
1381
 
 
1382
        $self->pidl("ndr_print_bitmap_flag($ndr, sizeof($type_decl), \"$flag\", $flag, $varname);");
 
1383
}
 
1384
 
 
1385
#####################################################################
 
1386
# generate a print function for an bitmap
 
1387
sub ParseBitmapPrint($$$$$)
 
1388
{
 
1389
        my($self,$bitmap,$ndr,$name,$varname) = @_;
 
1390
        my($type_decl) = mapTypeName($bitmap->{TYPE});
 
1391
        my($type_fn) = $bitmap->{BASE_TYPE};
 
1392
 
 
1393
        $self->start_flags($bitmap, $ndr);
 
1394
 
 
1395
        $self->pidl("ndr_print_$type_fn($ndr, name, $varname);");
 
1396
 
 
1397
        $self->pidl("$ndr->depth++;");
 
1398
        foreach my $e (@{$bitmap->{ELEMENTS}}) {
 
1399
                $self->ParseBitmapPrintElement($e, $bitmap, $ndr, $name, $varname);
 
1400
        }
 
1401
        $self->pidl("$ndr->depth--;");
 
1402
 
 
1403
        $self->end_flags($bitmap, $ndr);
 
1404
}
 
1405
 
 
1406
sub DeclBitmap($$$$)
 
1407
{
 
1408
        my ($e,$t,$name,$varname) = @_;
 
1409
        return mapTypeName(Parse::Pidl::Typelist::bitmap_type_fn($e)) .
 
1410
                ($t eq "pull"?" *":" ") . $varname;
 
1411
}
 
1412
 
 
1413
$typefamily{BITMAP} = {
 
1414
        DECL => \&DeclBitmap,
 
1415
        PUSH_FN_BODY => \&ParseBitmapPush,
 
1416
        PULL_FN_BODY => \&ParseBitmapPull,
 
1417
        PRINT_FN_BODY => \&ParseBitmapPrint,
 
1418
};
 
1419
 
 
1420
#####################################################################
 
1421
# generate a struct print function
 
1422
sub ParseStructPrint($$$$$)
 
1423
{
 
1424
        my($self,$struct,$ndr,$name,$varname) = @_;
 
1425
 
 
1426
        return unless defined $struct->{ELEMENTS};
 
1427
 
 
1428
        my $env = GenerateStructEnv($struct, $varname);
 
1429
 
 
1430
        $self->DeclareArrayVariables($_) foreach (@{$struct->{ELEMENTS}});
 
1431
 
 
1432
        $self->pidl("ndr_print_struct($ndr, name, \"$name\");");
 
1433
 
 
1434
        $self->start_flags($struct, $ndr);
 
1435
 
 
1436
        $self->pidl("$ndr->depth++;");
 
1437
 
 
1438
        $self->ParseElementPrint($_, $ndr, $env->{$_->{NAME}}, $env)
 
1439
                foreach (@{$struct->{ELEMENTS}});
 
1440
        $self->pidl("$ndr->depth--;");
 
1441
 
 
1442
        $self->end_flags($struct, $ndr);
 
1443
}
 
1444
 
 
1445
sub DeclarePtrVariables($$)
 
1446
{
 
1447
        my ($self,$e) = @_;
 
1448
        foreach my $l (@{$e->{LEVELS}}) {
 
1449
                if ($l->{TYPE} eq "POINTER" and
 
1450
                        not ($l->{POINTER_TYPE} eq "ref" and $l->{LEVEL} eq "TOP")) {
 
1451
                        $self->pidl("uint32_t _ptr_$e->{NAME};");
 
1452
                        last;
 
1453
                }
 
1454
        }
 
1455
}
 
1456
 
 
1457
sub DeclareArrayVariables($$)
 
1458
{
 
1459
        my ($self,$e) = @_;
 
1460
 
 
1461
        foreach my $l (@{$e->{LEVELS}}) {
 
1462
                next if has_fast_array($e,$l);
 
1463
                next if is_charset_array($e,$l);
 
1464
                if ($l->{TYPE} eq "ARRAY") {
 
1465
                        $self->pidl("uint32_t cntr_$e->{NAME}_$l->{LEVEL_INDEX};");
 
1466
                }
 
1467
        }
 
1468
}
 
1469
 
 
1470
sub DeclareMemCtxVariables($$)
 
1471
{
 
1472
        my ($self,$e) = @_;
 
1473
        foreach my $l (@{$e->{LEVELS}}) {
 
1474
                my $mem_flags = $self->ParseMemCtxPullFlags($e, $l);
 
1475
                if (defined($mem_flags)) {
 
1476
                        $self->pidl("TALLOC_CTX *_mem_save_$e->{NAME}_$l->{LEVEL_INDEX};");
 
1477
                }
 
1478
        }
 
1479
}
 
1480
 
 
1481
sub ParseStructPullPrimitives($$$$$)
 
1482
{
 
1483
        my($self,$struct,$ndr,$varname,$env) = @_;
 
1484
 
 
1485
        if (defined $struct->{SURROUNDING_ELEMENT}) {
 
1486
                $self->pidl("NDR_CHECK(ndr_pull_array_size($ndr, &$varname->$struct->{SURROUNDING_ELEMENT}->{NAME}));");
 
1487
        }
 
1488
 
 
1489
        $self->pidl("NDR_CHECK(ndr_pull_align($ndr, $struct->{ALIGN}));");
 
1490
 
 
1491
        if (defined($struct->{PROPERTIES}{relative_base})) {
 
1492
                # set the current offset as base for relative pointers
 
1493
                # and store it based on the toplevel struct/union
 
1494
                $self->pidl("NDR_CHECK(ndr_pull_setup_relative_base_offset1($ndr, $varname, $ndr->offset));");
 
1495
        }
 
1496
 
 
1497
        $self->ParseElementPull($_, $ndr, $env, 1, 0) foreach (@{$struct->{ELEMENTS}});
 
1498
 
 
1499
        $self->add_deferred();
 
1500
}
 
1501
 
 
1502
sub ParseStructPullDeferred($$$$$)
 
1503
{
 
1504
        my ($self,$struct,$ndr,$varname,$env) = @_;
 
1505
 
 
1506
        if (defined($struct->{PROPERTIES}{relative_base})) {
 
1507
                # retrieve the current offset as base for relative pointers
 
1508
                # based on the toplevel struct/union
 
1509
                $self->pidl("NDR_CHECK(ndr_pull_setup_relative_base_offset2($ndr, $varname));");
 
1510
        }
 
1511
        foreach my $e (@{$struct->{ELEMENTS}}) {
 
1512
                $self->ParseElementPull($e, $ndr, $env, 0, 1);
 
1513
        }
 
1514
 
 
1515
        $self->add_deferred();
 
1516
}
 
1517
 
 
1518
#####################################################################
 
1519
# parse a struct - pull side
 
1520
sub ParseStructPull($$$$)
 
1521
{
 
1522
        my($self,$struct,$ndr,$varname) = @_;
 
1523
 
 
1524
        return unless defined $struct->{ELEMENTS};
 
1525
 
 
1526
        # declare any internal pointers we need
 
1527
        foreach my $e (@{$struct->{ELEMENTS}}) {
 
1528
                $self->DeclarePtrVariables($e);
 
1529
                $self->DeclareArrayVariables($e);
 
1530
                $self->DeclareMemCtxVariables($e);
 
1531
        }
 
1532
 
 
1533
        $self->start_flags($struct, $ndr);
 
1534
 
 
1535
        my $env = GenerateStructEnv($struct, $varname);
 
1536
 
 
1537
        $self->pidl("if (ndr_flags & NDR_SCALARS) {");
 
1538
        $self->indent;
 
1539
        $self->ParseStructPullPrimitives($struct,$ndr,$varname,$env);
 
1540
        $self->deindent;
 
1541
        $self->pidl("}");
 
1542
        $self->pidl("if (ndr_flags & NDR_BUFFERS) {");
 
1543
        $self->indent;
 
1544
        $self->ParseStructPullDeferred($struct,$ndr,$varname,$env);
 
1545
        $self->deindent;
 
1546
        $self->pidl("}");
 
1547
 
 
1548
        $self->end_flags($struct, $ndr);
 
1549
}
 
1550
 
 
1551
#####################################################################
 
1552
# calculate size of ndr struct
 
1553
sub ParseStructNdrSize($$$$)
 
1554
{
 
1555
        my ($self,$t, $name, $varname) = @_;
 
1556
        my $sizevar;
 
1557
 
 
1558
        if (my $flags = has_property($t, "flag")) {
 
1559
                $self->pidl("flags |= $flags;");
 
1560
        }
 
1561
        $self->pidl("return ndr_size_struct($varname, flags, (ndr_push_flags_fn_t)ndr_push_$name);");
 
1562
}
 
1563
 
 
1564
sub DeclStruct($$$$)
 
1565
{
 
1566
        my ($e,$t,$name,$varname) = @_;
 
1567
        return ($t ne "pull"?"const ":"") . "struct $name *$varname";
 
1568
}
 
1569
 
 
1570
sub ArgsStructNdrSize($$$)
 
1571
{
 
1572
        my ($d, $name, $varname) = @_;
 
1573
        return "const struct $name *$varname, int flags";
 
1574
}
 
1575
 
 
1576
$typefamily{STRUCT} = {
 
1577
        PUSH_FN_BODY => \&ParseStructPush,
 
1578
        DECL => \&DeclStruct,
 
1579
        PULL_FN_BODY => \&ParseStructPull,
 
1580
        PRINT_FN_BODY => \&ParseStructPrint,
 
1581
        SIZE_FN_BODY => \&ParseStructNdrSize,
 
1582
        SIZE_FN_ARGS => \&ArgsStructNdrSize,
 
1583
};
 
1584
 
 
1585
#####################################################################
 
1586
# calculate size of ndr struct
 
1587
sub ParseUnionNdrSize($$$)
 
1588
{
 
1589
        my ($self, $t, $name, $varname) = @_;
 
1590
        my $sizevar;
 
1591
 
 
1592
        if (my $flags = has_property($t, "flag")) {
 
1593
                $self->pidl("flags |= $flags;");
 
1594
        }
 
1595
 
 
1596
        $self->pidl("return ndr_size_union($varname, flags, level, (ndr_push_flags_fn_t)ndr_push_$name);");
 
1597
}
 
1598
 
 
1599
sub ParseUnionPushPrimitives($$$$)
 
1600
{
 
1601
        my ($self, $e, $ndr ,$varname) = @_;
 
1602
 
 
1603
        my $have_default = 0;
 
1604
 
 
1605
        $self->pidl("int level = ndr_push_get_switch_value($ndr, $varname);");
 
1606
 
 
1607
        if (defined($e->{SWITCH_TYPE})) {
 
1608
                $self->pidl("NDR_CHECK(ndr_push_$e->{SWITCH_TYPE}($ndr, NDR_SCALARS, level));");
 
1609
        }
 
1610
 
 
1611
        $self->pidl("switch (level) {");
 
1612
        $self->indent;
 
1613
        foreach my $el (@{$e->{ELEMENTS}}) {
 
1614
                if ($el->{CASE} eq "default") {
 
1615
                        $have_default = 1;
 
1616
                }
 
1617
                $self->pidl("$el->{CASE}: {");
 
1618
 
 
1619
                if ($el->{TYPE} ne "EMPTY") {
 
1620
                        $self->indent;
 
1621
                        if (defined($e->{PROPERTIES}{relative_base})) {
 
1622
                                $self->pidl("NDR_CHECK(ndr_push_align($ndr, $el->{ALIGN}));");
 
1623
                                # set the current offset as base for relative pointers
 
1624
                                # and store it based on the toplevel struct/union
 
1625
                                $self->pidl("NDR_CHECK(ndr_push_setup_relative_base_offset1($ndr, $varname, $ndr->offset));");
 
1626
                        }
 
1627
                        $self->DeclareArrayVariables($el);
 
1628
                        $self->ParseElementPush($el, $ndr, {$el->{NAME} => "$varname->$el->{NAME}"}, 1, 0);
 
1629
                        $self->deindent;
 
1630
                }
 
1631
                $self->pidl("break; }");
 
1632
                $self->pidl("");
 
1633
        }
 
1634
        if (! $have_default) {
 
1635
                $self->pidl("default:");
 
1636
                $self->pidl("\treturn ndr_push_error($ndr, NDR_ERR_BAD_SWITCH, \"Bad switch value \%u\", level);");
 
1637
        }
 
1638
        $self->deindent;
 
1639
        $self->pidl("}");
 
1640
}
 
1641
 
 
1642
sub ParseUnionPushDeferred($$$$)
 
1643
{
 
1644
        my ($self,$e,$ndr,$varname) = @_;
 
1645
 
 
1646
        my $have_default = 0;
 
1647
 
 
1648
        $self->pidl("int level = ndr_push_get_switch_value($ndr, $varname);");
 
1649
        if (defined($e->{PROPERTIES}{relative_base})) {
 
1650
                # retrieve the current offset as base for relative pointers
 
1651
                # based on the toplevel struct/union
 
1652
                $self->pidl("NDR_CHECK(ndr_push_setup_relative_base_offset2($ndr, $varname));");
 
1653
        }
 
1654
        $self->pidl("switch (level) {");
 
1655
        $self->indent;
 
1656
        foreach my $el (@{$e->{ELEMENTS}}) {
 
1657
                if ($el->{CASE} eq "default") {
 
1658
                        $have_default = 1;
 
1659
                }
 
1660
 
 
1661
                $self->pidl("$el->{CASE}:");
 
1662
                if ($el->{TYPE} ne "EMPTY") {
 
1663
                        $self->indent;
 
1664
                        $self->ParseElementPush($el, $ndr, {$el->{NAME} => "$varname->$el->{NAME}"}, 0, 1);
 
1665
                        $self->deindent;
 
1666
                }
 
1667
                $self->pidl("break;");
 
1668
                $self->pidl("");
 
1669
        }
 
1670
        if (! $have_default) {
 
1671
                $self->pidl("default:");
 
1672
                $self->pidl("\treturn ndr_push_error($ndr, NDR_ERR_BAD_SWITCH, \"Bad switch value \%u\", level);");
 
1673
        }
 
1674
        $self->deindent;
 
1675
        $self->pidl("}");
 
1676
}
 
1677
 
 
1678
#####################################################################
 
1679
# parse a union - push side
 
1680
sub ParseUnionPush($$$$)
 
1681
{
 
1682
        my ($self,$e,$ndr,$varname) = @_;
 
1683
        my $have_default = 0;
 
1684
 
 
1685
        $self->start_flags($e, $ndr);
 
1686
 
 
1687
        $self->pidl("if (ndr_flags & NDR_SCALARS) {");
 
1688
        $self->indent;
 
1689
        $self->ParseUnionPushPrimitives($e, $ndr, $varname);
 
1690
        $self->deindent;
 
1691
        $self->pidl("}");
 
1692
        $self->pidl("if (ndr_flags & NDR_BUFFERS) {");
 
1693
        $self->indent;
 
1694
        $self->ParseUnionPushDeferred($e, $ndr, $varname);
 
1695
        $self->deindent;
 
1696
        $self->pidl("}");
 
1697
        $self->end_flags($e, $ndr);
 
1698
}
 
1699
 
 
1700
#####################################################################
 
1701
# print a union
 
1702
sub ParseUnionPrint($$$$$)
 
1703
{
 
1704
        my ($self,$e,$ndr,$name,$varname) = @_;
 
1705
        my $have_default = 0;
 
1706
 
 
1707
        $self->pidl("int level;");
 
1708
        foreach my $el (@{$e->{ELEMENTS}}) {
 
1709
                $self->DeclareArrayVariables($el);
 
1710
        }
 
1711
 
 
1712
        $self->start_flags($e, $ndr);
 
1713
 
 
1714
        $self->pidl("level = ndr_print_get_switch_value($ndr, $varname);");
 
1715
 
 
1716
        $self->pidl("ndr_print_union($ndr, name, level, \"$name\");");
 
1717
 
 
1718
        $self->pidl("switch (level) {");
 
1719
        $self->indent;
 
1720
        foreach my $el (@{$e->{ELEMENTS}}) {
 
1721
                if ($el->{CASE} eq "default") {
 
1722
                        $have_default = 1;
 
1723
                }
 
1724
                $self->pidl("$el->{CASE}:");
 
1725
                if ($el->{TYPE} ne "EMPTY") {
 
1726
                        $self->indent;
 
1727
                        $self->ParseElementPrint($el, $ndr, "$varname->$el->{NAME}", {});
 
1728
                        $self->deindent;
 
1729
                }
 
1730
                $self->pidl("break;");
 
1731
                $self->pidl("");
 
1732
        }
 
1733
        if (! $have_default) {
 
1734
                $self->pidl("default:");
 
1735
                $self->pidl("\tndr_print_bad_level($ndr, name, level);");
 
1736
        }
 
1737
        $self->deindent;
 
1738
        $self->pidl("}");
 
1739
 
 
1740
        $self->end_flags($e, $ndr);
 
1741
}
 
1742
 
 
1743
sub ParseUnionPullPrimitives($$$$$)
 
1744
{
 
1745
        my ($self,$e,$ndr,$varname,$switch_type) = @_;
 
1746
        my $have_default = 0;
 
1747
 
 
1748
        if (defined($switch_type)) {
 
1749
                $self->pidl("NDR_CHECK(ndr_pull_$switch_type($ndr, NDR_SCALARS, &_level));");
 
1750
                $self->pidl("if (_level != level) {");
 
1751
                $self->pidl("\treturn ndr_pull_error($ndr, NDR_ERR_BAD_SWITCH, \"Bad switch value %u for $varname\", _level);");
 
1752
                $self->pidl("}");
 
1753
        }
 
1754
 
 
1755
        $self->pidl("switch (level) {");
 
1756
        $self->indent;
 
1757
        foreach my $el (@{$e->{ELEMENTS}}) {
 
1758
                if ($el->{CASE} eq "default") {
 
1759
                        $have_default = 1;
 
1760
                }
 
1761
                $self->pidl("$el->{CASE}: {");
 
1762
 
 
1763
                if ($el->{TYPE} ne "EMPTY") {
 
1764
                        $self->indent;
 
1765
                        $self->DeclarePtrVariables($el);
 
1766
                        $self->DeclareArrayVariables($el);
 
1767
                        if (defined($e->{PROPERTIES}{relative_base})) {
 
1768
                                $self->pidl("NDR_CHECK(ndr_pull_align($ndr, $el->{ALIGN}));");
 
1769
                                # set the current offset as base for relative pointers
 
1770
                                # and store it based on the toplevel struct/union
 
1771
                                $self->pidl("NDR_CHECK(ndr_pull_setup_relative_base_offset1($ndr, $varname, $ndr->offset));");
 
1772
                        }
 
1773
                        $self->ParseElementPull($el, $ndr, {$el->{NAME} => "$varname->$el->{NAME}"}, 1, 0);
 
1774
                        $self->deindent;
 
1775
                }
 
1776
                $self->pidl("break; }");
 
1777
                $self->pidl("");
 
1778
        }
 
1779
        if (! $have_default) {
 
1780
                $self->pidl("default:");
 
1781
                $self->pidl("\treturn ndr_pull_error($ndr, NDR_ERR_BAD_SWITCH, \"Bad switch value \%u\", level);");
 
1782
        }
 
1783
        $self->deindent;
 
1784
        $self->pidl("}");
 
1785
}
 
1786
 
 
1787
sub ParseUnionPullDeferred($$$$)
 
1788
{
 
1789
        my ($self,$e,$ndr,$varname) = @_;
 
1790
        my $have_default = 0;
 
1791
 
 
1792
        if (defined($e->{PROPERTIES}{relative_base})) {
 
1793
                # retrieve the current offset as base for relative pointers
 
1794
                # based on the toplevel struct/union
 
1795
                $self->pidl("NDR_CHECK(ndr_pull_setup_relative_base_offset2($ndr, $varname));");
 
1796
        }
 
1797
        $self->pidl("switch (level) {");
 
1798
        $self->indent;
 
1799
        foreach my $el (@{$e->{ELEMENTS}}) {
 
1800
                if ($el->{CASE} eq "default") {
 
1801
                        $have_default = 1;
 
1802
                }
 
1803
 
 
1804
                $self->pidl("$el->{CASE}:");
 
1805
                if ($el->{TYPE} ne "EMPTY") {
 
1806
                        $self->indent;
 
1807
                        $self->ParseElementPull($el, $ndr, {$el->{NAME} => "$varname->$el->{NAME}"}, 0, 1);
 
1808
                        $self->deindent;
 
1809
                }
 
1810
                $self->pidl("break;");
 
1811
                $self->pidl("");
 
1812
        }
 
1813
        if (! $have_default) {
 
1814
                $self->pidl("default:");
 
1815
                $self->pidl("\treturn ndr_pull_error($ndr, NDR_ERR_BAD_SWITCH, \"Bad switch value \%u\", level);");
 
1816
        }
 
1817
        $self->deindent;
 
1818
        $self->pidl("}");
 
1819
 
 
1820
 
 
1821
}
 
1822
 
 
1823
#####################################################################
 
1824
# parse a union - pull side
 
1825
sub ParseUnionPull($$$$)
 
1826
{
 
1827
        my ($self,$e,$ndr,$varname) = @_;
 
1828
        my $switch_type = $e->{SWITCH_TYPE};
 
1829
 
 
1830
        $self->pidl("int level;");
 
1831
        if (defined($switch_type)) {
 
1832
                if (Parse::Pidl::Typelist::typeIs($switch_type, "ENUM")) {
 
1833
                        $switch_type = Parse::Pidl::Typelist::enum_type_fn(getType($switch_type)->{DATA});
 
1834
                }
 
1835
                $self->pidl(mapTypeName($switch_type) . " _level;");
 
1836
        }
 
1837
 
 
1838
        my %double_cases = ();
 
1839
        foreach my $el (@{$e->{ELEMENTS}}) {
 
1840
                next if ($el->{TYPE} eq "EMPTY");
 
1841
                next if ($double_cases{"$el->{NAME}"});
 
1842
                $self->DeclareMemCtxVariables($el);
 
1843
                $double_cases{"$el->{NAME}"} = 1;
 
1844
        }
 
1845
 
 
1846
        $self->start_flags($e, $ndr);
 
1847
 
 
1848
        $self->pidl("level = ndr_pull_get_switch_value($ndr, $varname);");
 
1849
 
 
1850
        $self->pidl("if (ndr_flags & NDR_SCALARS) {");
 
1851
        $self->indent;
 
1852
        $self->ParseUnionPullPrimitives($e,$ndr,$varname,$switch_type);
 
1853
        $self->deindent;
 
1854
        $self->pidl("}");
 
1855
 
 
1856
        $self->pidl("if (ndr_flags & NDR_BUFFERS) {");
 
1857
        $self->indent;
 
1858
        $self->ParseUnionPullDeferred($e,$ndr,$varname);
 
1859
        $self->deindent;
 
1860
        $self->pidl("}");
 
1861
 
 
1862
        $self->add_deferred();
 
1863
 
 
1864
        $self->end_flags($e, $ndr);
 
1865
}
 
1866
 
 
1867
sub DeclUnion($$$$)
 
1868
{
 
1869
        my ($e,$t,$name,$varname) = @_;
 
1870
        return ($t ne "pull"?"const ":"") . "union $name *$varname";
 
1871
}
 
1872
 
 
1873
sub ArgsUnionNdrSize($$)
 
1874
{
 
1875
        my ($d,$name) = @_;
 
1876
        return "const union $name *r, uint32_t level, int flags";
 
1877
}
 
1878
 
 
1879
$typefamily{UNION} = {
 
1880
        PUSH_FN_BODY => \&ParseUnionPush,
 
1881
        DECL => \&DeclUnion,
 
1882
        PULL_FN_BODY => \&ParseUnionPull,
 
1883
        PRINT_FN_BODY => \&ParseUnionPrint,
 
1884
        SIZE_FN_ARGS => \&ArgsUnionNdrSize,
 
1885
        SIZE_FN_BODY => \&ParseUnionNdrSize,
 
1886
};
 
1887
 
 
1888
#####################################################################
 
1889
# parse a typedef - push side
 
1890
sub ParseTypedefPush($$$$)
 
1891
{
 
1892
        my($self,$e,$ndr,$varname) = @_;
 
1893
 
 
1894
        my $env;
 
1895
 
 
1896
        $env->{$e->{NAME}} = $varname;
 
1897
 
 
1898
        $self->ParseElementPushLevel($e, $e->{LEVELS}[0], $ndr, $varname, $env, 1, 1);
 
1899
}
 
1900
 
 
1901
#####################################################################
 
1902
# parse a typedef - pull side
 
1903
sub ParseTypedefPull($$$$)
 
1904
{
 
1905
        my($self,$e,$ndr,$varname) = @_;
 
1906
 
 
1907
        my $env;
 
1908
 
 
1909
        $env->{$e->{NAME}} = $varname;
 
1910
 
 
1911
        $self->ParseElementPullLevel($e, $e->{LEVELS}[0], $ndr, $varname, $env, 1, 1);
 
1912
}
 
1913
 
 
1914
#####################################################################
 
1915
# parse a typedef - print side
 
1916
sub ParseTypedefPrint($$$$$)
 
1917
{
 
1918
        my($self,$e,$ndr,$name,$varname) = @_;
 
1919
 
 
1920
        $typefamily{$e->{DATA}->{TYPE}}->{PRINT_FN_BODY}->($self, $e->{DATA}, $ndr, $name, $varname);
 
1921
}
 
1922
 
 
1923
#####################################################################
 
1924
## calculate the size of a structure
 
1925
sub ParseTypedefNdrSize($$$$)
 
1926
{
 
1927
        my($self,$t,$name,$varname) = @_;
 
1928
 
 
1929
        $typefamily{$t->{DATA}->{TYPE}}->{SIZE_FN_BODY}->($self, $t->{DATA}, $name, $varname);
 
1930
}
 
1931
 
 
1932
sub DeclTypedef($$$$)
 
1933
{
 
1934
        my ($e, $t, $name, $varname) = @_;
 
1935
 
 
1936
        return $typefamily{$e->{DATA}->{TYPE}}->{DECL}->($e->{DATA}, $t, $name, $varname);
 
1937
}
 
1938
 
 
1939
sub ArgsTypedefNdrSize($$$)
 
1940
{
 
1941
        my ($d, $name, $varname) = @_;
 
1942
        return $typefamily{$d->{DATA}->{TYPE}}->{SIZE_FN_ARGS}->($d->{DATA}, $name, $varname);
 
1943
}
 
1944
 
 
1945
$typefamily{TYPEDEF} = {
 
1946
        PUSH_FN_BODY => \&ParseTypedefPush,
 
1947
        DECL => \&DeclTypedef,
 
1948
        PULL_FN_BODY => \&ParseTypedefPull,
 
1949
        PRINT_FN_BODY => \&ParseTypedefPrint,
 
1950
        SIZE_FN_ARGS => \&ArgsTypedefNdrSize,
 
1951
        SIZE_FN_BODY => \&ParseTypedefNdrSize,
 
1952
};
 
1953
 
 
1954
#####################################################################
 
1955
# parse a function - print side
 
1956
sub ParseFunctionPrint($$)
 
1957
{
 
1958
        my($self, $fn) = @_;
 
1959
        my $ndr = "ndr";
 
1960
 
 
1961
        $self->pidl_hdr("void ndr_print_$fn->{NAME}(struct ndr_print *$ndr, const char *name, int flags, const struct $fn->{NAME} *r);");
 
1962
 
 
1963
        return if has_property($fn, "noprint");
 
1964
 
 
1965
        $self->pidl("_PUBLIC_ void ndr_print_$fn->{NAME}(struct ndr_print *$ndr, const char *name, int flags, const struct $fn->{NAME} *r)");
 
1966
        $self->pidl("{");
 
1967
        $self->indent;
 
1968
 
 
1969
        foreach my $e (@{$fn->{ELEMENTS}}) {
 
1970
                $self->DeclareArrayVariables($e);
 
1971
        }
 
1972
 
 
1973
        $self->pidl("ndr_print_struct($ndr, name, \"$fn->{NAME}\");");
 
1974
        $self->pidl("$ndr->depth++;");
 
1975
 
 
1976
        $self->pidl("if (flags & NDR_SET_VALUES) {");
 
1977
        $self->pidl("\t$ndr->flags |= LIBNDR_PRINT_SET_VALUES;");
 
1978
        $self->pidl("}");
 
1979
 
 
1980
        $self->pidl("if (flags & NDR_IN) {");
 
1981
        $self->indent;
 
1982
        $self->pidl("ndr_print_struct($ndr, \"in\", \"$fn->{NAME}\");");
 
1983
        $self->pidl("$ndr->depth++;");
 
1984
 
 
1985
        my $env = GenerateFunctionInEnv($fn);
 
1986
 
 
1987
        foreach my $e (@{$fn->{ELEMENTS}}) {
 
1988
                if (grep(/in/,@{$e->{DIRECTION}})) {
 
1989
                        $self->ParseElementPrint($e, $ndr, $env->{$e->{NAME}}, $env);
 
1990
                }
 
1991
        }
 
1992
        $self->pidl("$ndr->depth--;");
 
1993
        $self->deindent;
 
1994
        $self->pidl("}");
 
1995
 
 
1996
        $self->pidl("if (flags & NDR_OUT) {");
 
1997
        $self->indent;
 
1998
        $self->pidl("ndr_print_struct($ndr, \"out\", \"$fn->{NAME}\");");
 
1999
        $self->pidl("$ndr->depth++;");
 
2000
 
 
2001
        $env = GenerateFunctionOutEnv($fn);
 
2002
        foreach my $e (@{$fn->{ELEMENTS}}) {
 
2003
                if (grep(/out/,@{$e->{DIRECTION}})) {
 
2004
                        $self->ParseElementPrint($e, $ndr, $env->{$e->{NAME}}, $env);
 
2005
                }
 
2006
        }
 
2007
        if ($fn->{RETURN_TYPE}) {
 
2008
                $self->pidl("ndr_print_$fn->{RETURN_TYPE}($ndr, \"result\", r->out.result);");
 
2009
        }
 
2010
        $self->pidl("$ndr->depth--;");
 
2011
        $self->deindent;
 
2012
        $self->pidl("}");
 
2013
 
 
2014
        $self->pidl("$ndr->depth--;");
 
2015
        $self->deindent;
 
2016
        $self->pidl("}");
 
2017
        $self->pidl("");
 
2018
}
 
2019
 
 
2020
#####################################################################
 
2021
# parse a function
 
2022
sub ParseFunctionPush($$)
 
2023
{
 
2024
        my($self, $fn) = @_;
 
2025
        my $ndr = "ndr";
 
2026
 
 
2027
        $self->fn_declare("push", $fn, "enum ndr_err_code ndr_push_$fn->{NAME}(struct ndr_push *$ndr, int flags, const struct $fn->{NAME} *r)") or return;
 
2028
 
 
2029
        return if has_property($fn, "nopush");
 
2030
 
 
2031
        $self->pidl("{");
 
2032
        $self->indent;
 
2033
 
 
2034
        foreach my $e (@{$fn->{ELEMENTS}}) {
 
2035
                $self->DeclareArrayVariables($e);
 
2036
        }
 
2037
 
 
2038
        $self->pidl("if (flags & NDR_IN) {");
 
2039
        $self->indent;
 
2040
 
 
2041
        my $env = GenerateFunctionInEnv($fn);
 
2042
 
 
2043
        EnvSubstituteValue($env, $fn);
 
2044
 
 
2045
        foreach my $e (@{$fn->{ELEMENTS}}) {
 
2046
                if (grep(/in/,@{$e->{DIRECTION}})) {
 
2047
                        $self->ParseElementPush($e, $ndr, $env, 1, 1);
 
2048
                }
 
2049
        }
 
2050
 
 
2051
        $self->deindent;
 
2052
        $self->pidl("}");
 
2053
 
 
2054
        $self->pidl("if (flags & NDR_OUT) {");
 
2055
        $self->indent;
 
2056
 
 
2057
        $env = GenerateFunctionOutEnv($fn);
 
2058
        foreach my $e (@{$fn->{ELEMENTS}}) {
 
2059
                if (grep(/out/,@{$e->{DIRECTION}})) {
 
2060
                        $self->ParseElementPush($e, $ndr, $env, 1, 1);
 
2061
                }
 
2062
        }
 
2063
 
 
2064
        if ($fn->{RETURN_TYPE}) {
 
2065
                $self->pidl("NDR_CHECK(ndr_push_$fn->{RETURN_TYPE}($ndr, NDR_SCALARS, r->out.result));");
 
2066
        }
 
2067
 
 
2068
        $self->deindent;
 
2069
        $self->pidl("}");
 
2070
        $self->pidl("return NDR_ERR_SUCCESS;");
 
2071
        $self->deindent;
 
2072
        $self->pidl("}");
 
2073
        $self->pidl("");
 
2074
}
 
2075
 
 
2076
sub AllocateArrayLevel($$$$$$)
 
2077
{
 
2078
        my ($self,$e,$l,$ndr,$var,$size) = @_;
 
2079
 
 
2080
        my $pl = GetPrevLevel($e, $l);
 
2081
        if (defined($pl) and
 
2082
            $pl->{TYPE} eq "POINTER" and
 
2083
            $pl->{POINTER_TYPE} eq "ref"
 
2084
            and not $l->{IS_ZERO_TERMINATED}) {
 
2085
                $self->pidl("if ($ndr->flags & LIBNDR_FLAG_REF_ALLOC) {");
 
2086
                $self->pidl("\tNDR_PULL_ALLOC_N($ndr, $var, $size);");
 
2087
                $self->pidl("}");
 
2088
                if (grep(/in/,@{$e->{DIRECTION}}) and
 
2089
                    grep(/out/,@{$e->{DIRECTION}})) {
 
2090
                        $self->pidl("memcpy(r->out.$e->{NAME}, r->in.$e->{NAME}, $size * sizeof(*r->in.$e->{NAME}));");
 
2091
                }
 
2092
                return;
 
2093
        }
 
2094
 
 
2095
        $self->pidl("NDR_PULL_ALLOC_N($ndr, $var, $size);");
 
2096
}
 
2097
 
 
2098
#####################################################################
 
2099
# parse a function
 
2100
sub ParseFunctionPull($$)
 
2101
{
 
2102
        my($self,$fn) = @_;
 
2103
        my $ndr = "ndr";
 
2104
 
 
2105
        # pull function args
 
2106
        $self->fn_declare("pull", $fn, "enum ndr_err_code ndr_pull_$fn->{NAME}(struct ndr_pull *$ndr, int flags, struct $fn->{NAME} *r)") or return;
 
2107
 
 
2108
        $self->pidl("{");
 
2109
        $self->indent;
 
2110
 
 
2111
        # declare any internal pointers we need
 
2112
        foreach my $e (@{$fn->{ELEMENTS}}) {
 
2113
                $self->DeclarePtrVariables($e);
 
2114
                $self->DeclareArrayVariables($e);
 
2115
        }
 
2116
 
 
2117
        my %double_cases = ();
 
2118
        foreach my $e (@{$fn->{ELEMENTS}}) {
 
2119
                next if ($e->{TYPE} eq "EMPTY");
 
2120
                next if ($double_cases{"$e->{NAME}"});
 
2121
                $self->DeclareMemCtxVariables($e);
 
2122
                $double_cases{"$e->{NAME}"} = 1;
 
2123
        }
 
2124
 
 
2125
        $self->pidl("if (flags & NDR_IN) {");
 
2126
        $self->indent;
 
2127
 
 
2128
        # auto-init the out section of a structure. I originally argued that
 
2129
        # this was a bad idea as it hides bugs, but coping correctly
 
2130
        # with initialisation and not wiping ref vars is turning
 
2131
        # out to be too tricky (tridge)
 
2132
        foreach my $e (@{$fn->{ELEMENTS}}) {
 
2133
                next unless grep(/out/, @{$e->{DIRECTION}});
 
2134
                $self->pidl("ZERO_STRUCT(r->out);");
 
2135
                $self->pidl("");
 
2136
                last;
 
2137
        }
 
2138
 
 
2139
        my $env = GenerateFunctionInEnv($fn);
 
2140
 
 
2141
        foreach my $e (@{$fn->{ELEMENTS}}) {
 
2142
                next unless (grep(/in/, @{$e->{DIRECTION}}));
 
2143
                $self->ParseElementPull($e, $ndr, $env, 1, 1);
 
2144
        }
 
2145
 
 
2146
        # allocate the "simple" out ref variables. FIXME: Shouldn't this have it's
 
2147
        # own flag rather than be in NDR_IN ?
 
2148
 
 
2149
        foreach my $e (@{$fn->{ELEMENTS}}) {
 
2150
                next unless (grep(/out/, @{$e->{DIRECTION}}));
 
2151
                next unless ($e->{LEVELS}[0]->{TYPE} eq "POINTER" and
 
2152
                             $e->{LEVELS}[0]->{POINTER_TYPE} eq "ref");
 
2153
                next if (($e->{LEVELS}[1]->{TYPE} eq "DATA") and
 
2154
                                 ($e->{LEVELS}[1]->{DATA_TYPE} eq "string"));
 
2155
                next if (($e->{LEVELS}[1]->{TYPE} eq "ARRAY")
 
2156
                        and   $e->{LEVELS}[1]->{IS_ZERO_TERMINATED});
 
2157
 
 
2158
                if ($e->{LEVELS}[1]->{TYPE} eq "ARRAY") {
 
2159
                        my $size = ParseExprExt($e->{LEVELS}[1]->{SIZE_IS}, $env, $e->{ORIGINAL},
 
2160
                                check_null_pointer($e, $env, sub { $self->pidl(shift); },
 
2161
                                                   "return ndr_pull_error($ndr, NDR_ERR_INVALID_POINTER, \"NULL Pointer for size_is()\");"),
 
2162
                                check_fully_dereferenced($e, $env));
 
2163
                        $self->pidl("NDR_PULL_ALLOC_N($ndr, r->out.$e->{NAME}, $size);");
 
2164
 
 
2165
                        if (grep(/in/, @{$e->{DIRECTION}})) {
 
2166
                                $self->pidl("memcpy(r->out.$e->{NAME}, r->in.$e->{NAME}, ($size) * sizeof(*r->in.$e->{NAME}));");
 
2167
                        } else {
 
2168
                                $self->pidl("memset(r->out.$e->{NAME}, 0, ($size) * sizeof(*r->out.$e->{NAME}));");
 
2169
                        }
 
2170
                } else {
 
2171
                        $self->pidl("NDR_PULL_ALLOC($ndr, r->out.$e->{NAME});");
 
2172
 
 
2173
                        if (grep(/in/, @{$e->{DIRECTION}})) {
 
2174
                                $self->pidl("*r->out.$e->{NAME} = *r->in.$e->{NAME};");
 
2175
                        } else {
 
2176
                                $self->pidl("ZERO_STRUCTP(r->out.$e->{NAME});");
 
2177
                        }
 
2178
                }
 
2179
        }
 
2180
 
 
2181
        $self->add_deferred();
 
2182
        $self->deindent;
 
2183
        $self->pidl("}");
 
2184
 
 
2185
        $self->pidl("if (flags & NDR_OUT) {");
 
2186
        $self->indent;
 
2187
 
 
2188
        $env = GenerateFunctionOutEnv($fn);
 
2189
        foreach my $e (@{$fn->{ELEMENTS}}) {
 
2190
                next unless grep(/out/, @{$e->{DIRECTION}});
 
2191
                $self->ParseElementPull($e, $ndr, $env, 1, 1);
 
2192
        }
 
2193
 
 
2194
        if ($fn->{RETURN_TYPE}) {
 
2195
                $self->pidl("NDR_CHECK(ndr_pull_$fn->{RETURN_TYPE}($ndr, NDR_SCALARS, &r->out.result));");
 
2196
        }
 
2197
 
 
2198
        $self->add_deferred();
 
2199
        $self->deindent;
 
2200
        $self->pidl("}");
 
2201
 
 
2202
        $self->pidl("return NDR_ERR_SUCCESS;");
 
2203
        $self->deindent;
 
2204
        $self->pidl("}");
 
2205
        $self->pidl("");
 
2206
}
 
2207
 
 
2208
sub AuthServiceStruct($$$)
 
2209
{
 
2210
        my ($self, $ifacename, $authservice) = @_;
 
2211
        my @a = split /,/, $authservice;
 
2212
        my $authservice_count = $#a + 1;
 
2213
 
 
2214
        $self->pidl("static const char * const $ifacename\_authservice_strings[] = {");
 
2215
        foreach my $ap (@a) {
 
2216
                $self->pidl("\t$ap, ");
 
2217
        }
 
2218
        $self->pidl("};");
 
2219
        $self->pidl("");
 
2220
 
 
2221
        $self->pidl("static const struct ndr_interface_string_array $ifacename\_authservices = {");
 
2222
        $self->pidl("\t.count\t= $authservice_count,");
 
2223
        $self->pidl("\t.names\t= $ifacename\_authservice_strings");
 
2224
        $self->pidl("};");
 
2225
        $self->pidl("");
 
2226
}
 
2227
 
 
2228
sub FunctionCallEntry($$)
 
2229
{
 
2230
        my ($self, $d) = @_;
 
2231
        return if not defined($d->{OPNUM});
 
2232
        $self->pidl("\t{");
 
2233
        $self->pidl("\t\t\"$d->{NAME}\",");
 
2234
        $self->pidl("\t\tsizeof(struct $d->{NAME}),");
 
2235
        $self->pidl("\t\t(ndr_push_flags_fn_t) ndr_push_$d->{NAME},");
 
2236
        $self->pidl("\t\t(ndr_pull_flags_fn_t) ndr_pull_$d->{NAME},");
 
2237
        $self->pidl("\t\t(ndr_print_function_t) ndr_print_$d->{NAME},");
 
2238
        $self->pidl("\t\t".($d->{ASYNC}?"true":"false").",");
 
2239
        $self->pidl("\t},");
 
2240
}
 
2241
 
 
2242
#####################################################################
 
2243
# produce a function call table
 
2244
sub FunctionTable($$)
 
2245
{
 
2246
        my($self,$interface) = @_;
 
2247
        my $count = 0;
 
2248
        my $uname = uc $interface->{NAME};
 
2249
 
 
2250
        return if ($#{$interface->{FUNCTIONS}}+1 == 0);
 
2251
        return unless defined ($interface->{PROPERTIES}->{uuid});
 
2252
 
 
2253
        $self->pidl("static const struct ndr_interface_call $interface->{NAME}\_calls[] = {");
 
2254
 
 
2255
        foreach my $d (@{$interface->{INHERITED_FUNCTIONS}},@{$interface->{FUNCTIONS}}) {
 
2256
                $self->FunctionCallEntry($d);
 
2257
                $count++;
 
2258
        }
 
2259
        $self->pidl("\t{ NULL, 0, NULL, NULL, NULL, false }");
 
2260
        $self->pidl("};");
 
2261
        $self->pidl("");
 
2262
 
 
2263
        $self->pidl("static const char * const $interface->{NAME}\_endpoint_strings[] = {");
 
2264
        foreach my $ep (@{$interface->{ENDPOINTS}}) {
 
2265
                $self->pidl("\t$ep, ");
 
2266
        }
 
2267
        my $endpoint_count = $#{$interface->{ENDPOINTS}}+1;
 
2268
 
 
2269
        $self->pidl("};");
 
2270
        $self->pidl("");
 
2271
 
 
2272
        $self->pidl("static const struct ndr_interface_string_array $interface->{NAME}\_endpoints = {");
 
2273
        $self->pidl("\t.count\t= $endpoint_count,");
 
2274
        $self->pidl("\t.names\t= $interface->{NAME}\_endpoint_strings");
 
2275
        $self->pidl("};");
 
2276
        $self->pidl("");
 
2277
 
 
2278
        if (! defined $interface->{PROPERTIES}->{authservice}) {
 
2279
                $interface->{PROPERTIES}->{authservice} = "\"host\"";
 
2280
        }
 
2281
 
 
2282
        $self->AuthServiceStruct($interface->{NAME},
 
2283
                                     $interface->{PROPERTIES}->{authservice});
 
2284
 
 
2285
        $self->pidl("\nconst struct ndr_interface_table ndr_table_$interface->{NAME} = {");
 
2286
        $self->pidl("\t.name\t\t= \"$interface->{NAME}\",");
 
2287
        $self->pidl("\t.syntax_id\t= {");
 
2288
        $self->pidl("\t\t" . print_uuid($interface->{UUID}) .",");
 
2289
        $self->pidl("\t\tNDR_$uname\_VERSION");
 
2290
        $self->pidl("\t},");
 
2291
        $self->pidl("\t.helpstring\t= NDR_$uname\_HELPSTRING,");
 
2292
        $self->pidl("\t.num_calls\t= $count,");
 
2293
        $self->pidl("\t.calls\t\t= $interface->{NAME}\_calls,");
 
2294
        $self->pidl("\t.endpoints\t= &$interface->{NAME}\_endpoints,");
 
2295
        $self->pidl("\t.authservices\t= &$interface->{NAME}\_authservices");
 
2296
        $self->pidl("};");
 
2297
        $self->pidl("");
 
2298
 
 
2299
}
 
2300
 
 
2301
#####################################################################
 
2302
# generate include statements for imported idl files
 
2303
sub HeaderImport
 
2304
{
 
2305
        my $self = shift;
 
2306
        my @imports = @_;
 
2307
        foreach (@imports) {
 
2308
                $_ = unmake_str($_);
 
2309
                s/\.idl$//;
 
2310
                $self->pidl(choose_header("librpc/gen_ndr/ndr_$_\.h", "gen_ndr/ndr_$_.h"));
 
2311
        }
 
2312
}
 
2313
 
 
2314
#####################################################################
 
2315
# generate include statements for included header files
 
2316
sub HeaderInclude
 
2317
{
 
2318
        my $self = shift;
 
2319
        my @includes = @_;
 
2320
        foreach (@includes) {
 
2321
                $self->pidl_hdr("#include $_");
 
2322
        }
 
2323
}
 
2324
 
 
2325
#####################################################################
 
2326
# generate prototypes and defines for the interface definitions
 
2327
# FIXME: these prototypes are for the DCE/RPC client functions, not the
 
2328
# NDR parser and so do not belong here, technically speaking
 
2329
sub HeaderInterface($$$)
 
2330
{
 
2331
        my($self,$interface,$needed) = @_;
 
2332
 
 
2333
        my $count = 0;
 
2334
 
 
2335
        if ($needed->{"compression"}) {
 
2336
                $self->pidl(choose_header("librpc/ndr/ndr_compression.h", "ndr/compression.h"));
 
2337
        }
 
2338
 
 
2339
        if (has_property($interface, "object")) {
 
2340
                $self->pidl(choose_header("librpc/gen_ndr/ndr_orpc.h", "ndr/orpc.h"));
 
2341
        }
 
2342
 
 
2343
        if (defined $interface->{PROPERTIES}->{helper}) {
 
2344
                $self->HeaderInclude(split /,/, $interface->{PROPERTIES}->{helper});
 
2345
        }
 
2346
 
 
2347
        if (defined $interface->{PROPERTIES}->{uuid}) {
 
2348
                my $name = uc $interface->{NAME};
 
2349
                $self->pidl_hdr("#define NDR_$name\_UUID " .
 
2350
                Parse::Pidl::Util::make_str(lc($interface->{PROPERTIES}->{uuid})));
 
2351
 
 
2352
                if(!defined $interface->{PROPERTIES}->{version}) { $interface->{PROPERTIES}->{version} = "0.0"; }
 
2353
                $self->pidl_hdr("#define NDR_$name\_VERSION $interface->{PROPERTIES}->{version}");
 
2354
 
 
2355
                $self->pidl_hdr("#define NDR_$name\_NAME \"$interface->{NAME}\"");
 
2356
 
 
2357
                if(!defined $interface->{PROPERTIES}->{helpstring}) { $interface->{PROPERTIES}->{helpstring} = "NULL"; }
 
2358
                $self->pidl_hdr("#define NDR_$name\_HELPSTRING $interface->{PROPERTIES}->{helpstring}");
 
2359
 
 
2360
                $self->pidl_hdr("extern const struct ndr_interface_table ndr_table_$interface->{NAME};");
 
2361
        }
 
2362
 
 
2363
        foreach (@{$interface->{FUNCTIONS}}) {
 
2364
                next if has_property($_, "noopnum");
 
2365
                next if grep(/^$_->{NAME}$/,@{$interface->{INHERITED_FUNCTIONS}});
 
2366
                my $u_name = uc $_->{NAME};
 
2367
 
 
2368
                my $val = sprintf("0x%02x", $count);
 
2369
                if (defined($interface->{BASE})) {
 
2370
                        $val .= " + NDR_" . uc $interface->{BASE} . "_CALL_COUNT";
 
2371
                }
 
2372
 
 
2373
                $self->pidl_hdr("#define NDR_$u_name ($val)");
 
2374
 
 
2375
                $self->pidl_hdr("");
 
2376
                $count++;
 
2377
        }
 
2378
 
 
2379
        my $val = $count;
 
2380
 
 
2381
        if (defined($interface->{BASE})) {
 
2382
                $val .= " + NDR_" . uc $interface->{BASE} . "_CALL_COUNT";
 
2383
        }
 
2384
 
 
2385
        $self->pidl_hdr("#define NDR_" . uc $interface->{NAME} . "_CALL_COUNT ($val)");
 
2386
 
 
2387
}
 
2388
 
 
2389
sub ParseTypePush($$$$$$)
 
2390
{
 
2391
        my ($self,$e, $ndr, $varname, $primitives, $deferred) = @_;
 
2392
 
 
2393
        # save the old relative_base_offset
 
2394
        $self->pidl("uint32_t _save_relative_base_offset = ndr_push_get_relative_base_offset($ndr);") if defined(has_property($e, "relative_base"));
 
2395
        $typefamily{$e->{TYPE}}->{PUSH_FN_BODY}->($self, $e, $ndr, $varname);
 
2396
        # restore the old relative_base_offset
 
2397
        $self->pidl("ndr_push_restore_relative_base_offset($ndr, _save_relative_base_offset);") if defined(has_property($e, "relative_base"));
 
2398
}
 
2399
 
 
2400
sub ParseTypePushFunction($$$)
 
2401
{
 
2402
        my ($self, $e, $varname) = @_;
 
2403
        my $ndr = "ndr";
 
2404
 
 
2405
        my $args = $typefamily{$e->{TYPE}}->{DECL}->($e, "push", $e->{NAME}, $varname);
 
2406
 
 
2407
        $self->fn_declare("push", $e, "enum ndr_err_code ".TypeFunctionName("ndr_push", $e)."(struct ndr_push *$ndr, int ndr_flags, $args)") or return;
 
2408
 
 
2409
        $self->pidl("{");
 
2410
        $self->indent;
 
2411
        $self->ParseTypePush($e, $ndr, $varname, 1, 1);
 
2412
        $self->pidl("return NDR_ERR_SUCCESS;");
 
2413
        $self->deindent;
 
2414
        $self->pidl("}");
 
2415
        $self->pidl("");;
 
2416
}
 
2417
 
 
2418
sub ParseTypePull($$$$$$)
 
2419
{
 
2420
        my ($self, $e, $ndr, $varname, $primitives, $deferred) = @_;
 
2421
 
 
2422
        # save the old relative_base_offset
 
2423
        $self->pidl("uint32_t _save_relative_base_offset = ndr_pull_get_relative_base_offset($ndr);") if defined(has_property($e, "relative_base"));
 
2424
        $typefamily{$e->{TYPE}}->{PULL_FN_BODY}->($self, $e, $ndr, $varname);
 
2425
        # restore the old relative_base_offset
 
2426
        $self->pidl("ndr_pull_restore_relative_base_offset($ndr, _save_relative_base_offset);") if defined(has_property($e, "relative_base"));
 
2427
}
 
2428
 
 
2429
sub ParseTypePullFunction($$)
 
2430
{
 
2431
        my ($self, $e, $varname) = @_;
 
2432
        my $ndr = "ndr";
 
2433
 
 
2434
        my $args = $typefamily{$e->{TYPE}}->{DECL}->($e, "pull", $e->{NAME}, $varname);
 
2435
 
 
2436
        $self->fn_declare("pull", $e, "enum ndr_err_code ".TypeFunctionName("ndr_pull", $e)."(struct ndr_pull *$ndr, int ndr_flags, $args)") or return;
 
2437
 
 
2438
        $self->pidl("{");
 
2439
        $self->indent;
 
2440
        $self->ParseTypePull($e, $ndr, $varname, 1, 1);
 
2441
        $self->pidl("return NDR_ERR_SUCCESS;");
 
2442
        $self->deindent;
 
2443
        $self->pidl("}");
 
2444
        $self->pidl("");
 
2445
}
 
2446
 
 
2447
sub ParseTypePrint($$$$)
 
2448
{
 
2449
        my ($self, $e, $ndr, $varname) = @_;
 
2450
 
 
2451
        $typefamily{$e->{TYPE}}->{PRINT_FN_BODY}->($self, $e, $ndr, $e->{NAME}, $varname);
 
2452
}
 
2453
 
 
2454
sub ParseTypePrintFunction($$$)
 
2455
{
 
2456
        my ($self, $e, $varname) = @_;
 
2457
        my $ndr = "ndr";
 
2458
 
 
2459
        my $args = $typefamily{$e->{TYPE}}->{DECL}->($e, "print", $e->{NAME}, $varname);
 
2460
 
 
2461
        $self->pidl_hdr("void ".TypeFunctionName("ndr_print", $e)."(struct ndr_print *ndr, const char *name, $args);");
 
2462
 
 
2463
        return if (has_property($e, "noprint"));
 
2464
 
 
2465
        $self->pidl("_PUBLIC_ void ".TypeFunctionName("ndr_print", $e)."(struct ndr_print *$ndr, const char *name, $args)");
 
2466
        $self->pidl("{");
 
2467
        $self->indent;
 
2468
        $self->ParseTypePrint($e, $ndr, $varname);
 
2469
        $self->deindent;
 
2470
        $self->pidl("}");
 
2471
        $self->pidl("");
 
2472
}
 
2473
 
 
2474
sub ParseTypeNdrSize($$)
 
2475
{
 
2476
        my ($self,$t) = @_;
 
2477
 
 
2478
        my $varname = "r";
 
2479
        my $tf = $typefamily{$t->{TYPE}};
 
2480
        my $args = $tf->{SIZE_FN_ARGS}->($t, $t->{NAME}, $varname);
 
2481
 
 
2482
        $self->fn_declare("size", $t, "size_t ndr_size_$t->{NAME}($args)") or return;
 
2483
 
 
2484
        $self->pidl("{");
 
2485
        $self->indent;
 
2486
        $typefamily{$t->{TYPE}}->{SIZE_FN_BODY}->($self,$t, $t->{NAME}, $varname);
 
2487
        $self->deindent;
 
2488
        $self->pidl("}");
 
2489
        $self->pidl("");
 
2490
}
 
2491
 
 
2492
#####################################################################
 
2493
# parse the interface definitions
 
2494
sub ParseInterface($$$)
 
2495
{
 
2496
        my($self,$interface,$needed) = @_;
 
2497
 
 
2498
        $self->pidl_hdr("#ifndef _HEADER_NDR_$interface->{NAME}");
 
2499
        $self->pidl_hdr("#define _HEADER_NDR_$interface->{NAME}");
 
2500
 
 
2501
        $self->pidl_hdr("");
 
2502
 
 
2503
        $self->HeaderInterface($interface, $needed);
 
2504
 
 
2505
        # Typedefs
 
2506
        foreach my $d (@{$interface->{TYPES}}) {
 
2507
                next unless(typeHasBody($d));
 
2508
 
 
2509
                ($needed->{TypeFunctionName("ndr_push", $d)}) && $self->ParseTypePushFunction($d, "r");
 
2510
                ($needed->{TypeFunctionName("ndr_pull", $d)}) && $self->ParseTypePullFunction($d, "r");
 
2511
                ($needed->{TypeFunctionName("ndr_print", $d)}) && $self->ParseTypePrintFunction($d, "r");
 
2512
 
 
2513
                # Make sure we don't generate a function twice...
 
2514
                $needed->{TypeFunctionName("ndr_push", $d)} =
 
2515
                    $needed->{TypeFunctionName("ndr_pull", $d)} =
 
2516
                        $needed->{TypeFunctionName("ndr_print", $d)} = 0;
 
2517
 
 
2518
                ($needed->{"ndr_size_$d->{NAME}"}) && $self->ParseTypeNdrSize($d);
 
2519
        }
 
2520
 
 
2521
        # Functions
 
2522
        foreach my $d (@{$interface->{FUNCTIONS}}) {
 
2523
                ($needed->{"ndr_push_$d->{NAME}"}) && $self->ParseFunctionPush($d);
 
2524
                ($needed->{"ndr_pull_$d->{NAME}"}) && $self->ParseFunctionPull($d);
 
2525
                ($needed->{"ndr_print_$d->{NAME}"}) && $self->ParseFunctionPrint($d);
 
2526
 
 
2527
                # Make sure we don't generate a function twice...
 
2528
                $needed->{"ndr_push_$d->{NAME}"} = $needed->{"ndr_pull_$d->{NAME}"} =
 
2529
                        $needed->{"ndr_print_$d->{NAME}"} = 0;
 
2530
        }
 
2531
 
 
2532
        $self->FunctionTable($interface);
 
2533
 
 
2534
        $self->pidl_hdr("#endif /* _HEADER_NDR_$interface->{NAME} */");
 
2535
}
 
2536
 
 
2537
sub GenerateIncludes($)
 
2538
{
 
2539
        my ($self) = @_;
 
2540
        if (is_intree()) {
 
2541
                $self->pidl("#include \"includes.h\"");
 
2542
        } else {
 
2543
                $self->pidl("#define _GNU_SOURCE");
 
2544
                $self->pidl("#include <stdint.h>");
 
2545
                $self->pidl("#include <stdlib.h>");
 
2546
                $self->pidl("#include <stdio.h>");
 
2547
                $self->pidl("#include <stdbool.h>");
 
2548
                $self->pidl("#include <stdarg.h>");
 
2549
                $self->pidl("#include <string.h>");
 
2550
        }
 
2551
}
 
2552
 
 
2553
#####################################################################
 
2554
# parse a parsed IDL structure back into an IDL file
 
2555
sub Parse($$$$)
 
2556
{
 
2557
        my($self, $ndr,$gen_header,$ndr_header) = @_;
 
2558
 
 
2559
        $self->pidl_hdr("/* header auto-generated by pidl */");
 
2560
        $self->pidl_hdr("");
 
2561
        $self->pidl_hdr(choose_header("librpc/ndr/libndr.h", "ndr.h"));
 
2562
        $self->pidl_hdr("#include \"$gen_header\"") if ($gen_header);
 
2563
        $self->pidl_hdr("");
 
2564
 
 
2565
        $self->pidl("/* parser auto-generated by pidl */");
 
2566
        $self->pidl("");
 
2567
        $self->GenerateIncludes();
 
2568
        $self->pidl("#include \"$ndr_header\"") if ($ndr_header);
 
2569
        $self->pidl("");
 
2570
 
 
2571
        my %needed = ();
 
2572
 
 
2573
        foreach (@{$ndr}) {
 
2574
                ($_->{TYPE} eq "INTERFACE") && NeededInterface($_, \%needed);
 
2575
        }
 
2576
 
 
2577
        foreach (@{$ndr}) {
 
2578
                ($_->{TYPE} eq "INTERFACE") && $self->ParseInterface($_, \%needed);
 
2579
                ($_->{TYPE} eq "IMPORT") && $self->HeaderImport(@{$_->{PATHS}});
 
2580
                ($_->{TYPE} eq "INCLUDE") && $self->HeaderInclude(@{$_->{PATHS}});
 
2581
        }
 
2582
 
 
2583
        return ($self->{res_hdr}, $self->{res});
 
2584
}
 
2585
 
 
2586
sub NeededElement($$$)
 
2587
{
 
2588
        my ($e, $dir, $needed) = @_;
 
2589
 
 
2590
        return if ($e->{TYPE} eq "EMPTY");
 
2591
 
 
2592
        return if (ref($e->{TYPE}) eq "HASH" and
 
2593
                       not defined($e->{TYPE}->{NAME}));
 
2594
 
 
2595
        my ($t, $rt);
 
2596
        if (ref($e->{TYPE}) eq "HASH") {
 
2597
                $t = $e->{TYPE}->{TYPE}."_".$e->{TYPE}->{NAME};
 
2598
        } else {
 
2599
                $t = $e->{TYPE};
 
2600
        }
 
2601
 
 
2602
        if (ref($e->{REPRESENTATION_TYPE}) eq "HASH") {
 
2603
                $rt = $e->{REPRESENTATION_TYPE}->{TYPE}."_".$e->{REPRESENTATION_TYPE}->{NAME};
 
2604
        } else {
 
2605
                $rt = $e->{REPRESENTATION_TYPE};
 
2606
        }
 
2607
 
 
2608
        die ("$e->{NAME} $t, $rt FOO") unless ($rt ne "");
 
2609
 
 
2610
        my @fn = ();
 
2611
        if ($dir eq "print") {
 
2612
                push(@fn, TypeFunctionName("ndr_print", $e->{REPRESENTATION_TYPE}));
 
2613
        } elsif ($dir eq "pull") {
 
2614
                push (@fn, TypeFunctionName("ndr_pull", $e->{TYPE}));
 
2615
                push (@fn, "ndr_$t\_to_$rt")
 
2616
                        if ($rt ne $t);
 
2617
        } elsif ($dir eq "push") {
 
2618
                push (@fn, TypeFunctionName("ndr_push", $e->{TYPE}));
 
2619
                push (@fn, "ndr_$rt\_to_$t")
 
2620
                        if ($rt ne $t);
 
2621
        } else {
 
2622
                die("invalid direction `$dir'");
 
2623
        }
 
2624
 
 
2625
        foreach (@fn) {
 
2626
                unless (defined($needed->{$_})) {
 
2627
                        $needed->{$_} = 1;
 
2628
                }
 
2629
        }
 
2630
}
 
2631
 
 
2632
sub NeededFunction($$)
 
2633
{
 
2634
        my ($fn,$needed) = @_;
 
2635
        $needed->{"ndr_pull_$fn->{NAME}"} = 1;
 
2636
        $needed->{"ndr_push_$fn->{NAME}"} = 1;
 
2637
        $needed->{"ndr_print_$fn->{NAME}"} = 1;
 
2638
        foreach my $e (@{$fn->{ELEMENTS}}) {
 
2639
                $e->{PARENT} = $fn;
 
2640
                NeededElement($e, $_, $needed) foreach ("pull", "push", "print");
 
2641
        }
 
2642
}
 
2643
 
 
2644
sub NeededType($$$)
 
2645
{
 
2646
        sub NeededType($$$);
 
2647
        my ($t,$needed,$req) = @_;
 
2648
 
 
2649
        NeededType($t->{DATA}, $needed, $req) if ($t->{TYPE} eq "TYPEDEF");
 
2650
 
 
2651
        if ($t->{TYPE} eq "STRUCT" or $t->{TYPE} eq "UNION") {
 
2652
                return unless defined($t->{ELEMENTS});
 
2653
                for my $e (@{$t->{ELEMENTS}}) {
 
2654
                        $e->{PARENT} = $t;
 
2655
                        if (has_property($e, "compression")) {
 
2656
                                $needed->{"compression"} = 1;
 
2657
                        }
 
2658
                        NeededElement($e, $req, $needed);
 
2659
                        NeededType($e->{TYPE}, $needed, $req) if (ref($e->{TYPE}) eq "HASH");
 
2660
                }
 
2661
        }
 
2662
}
 
2663
 
 
2664
#####################################################################
 
2665
# work out what parse functions are needed
 
2666
sub NeededInterface($$)
 
2667
{
 
2668
        my ($interface,$needed) = @_;
 
2669
        NeededFunction($_, $needed) foreach (@{$interface->{FUNCTIONS}});
 
2670
        foreach (reverse @{$interface->{TYPES}}) {
 
2671
                if (has_property($_, "public")) {
 
2672
                        $needed->{TypeFunctionName("ndr_pull", $_)} = $needed->{TypeFunctionName("ndr_push", $_)} =
 
2673
                                $needed->{TypeFunctionName("ndr_print", $_)} = 1;
 
2674
                }
 
2675
 
 
2676
                NeededType($_, $needed, "pull") if ($needed->{TypeFunctionName("ndr_pull", $_)});
 
2677
                NeededType($_, $needed, "push") if ($needed->{TypeFunctionName("ndr_push", $_)});
 
2678
                NeededType($_, $needed, "print") if ($needed->{TypeFunctionName("ndr_print", $_)});
 
2679
                if (has_property($_, "gensize")) {
 
2680
                        $needed->{"ndr_size_$_->{NAME}"} = 1;
 
2681
                }
 
2682
        }
 
2683
}
 
2684
 
 
2685
sub TypeFunctionName($$)
 
2686
{
 
2687
        my ($prefix, $t) = @_;
 
2688
 
 
2689
        return "$prefix\_$t->{NAME}" if (ref($t) eq "HASH" and
 
2690
                        $t->{TYPE} eq "TYPEDEF");
 
2691
        return "$prefix\_$t->{TYPE}_$t->{NAME}" if (ref($t) eq "HASH");
 
2692
        return "$prefix\_$t";
 
2693
}
 
2694
 
 
2695
1;