r15260: Don't dereference NULL pointers to obtain array lengths - found by
[samba.git] / source / pidl / lib / Parse / Pidl / Samba4 / TDR.pm
1 ###################################################
2 # Trivial Parser Generator
3 # Copyright jelmer@samba.org 2005
4 # released under the GNU GPL
5
6 package Parse::Pidl::Samba4::TDR;
7 use Parse::Pidl::Util qw(has_property ParseExpr is_constant);
8 use Parse::Pidl::Samba4 qw(is_intree choose_header);
9
10 use vars qw($VERSION);
11 $VERSION = '0.01';
12
13 use strict;
14
15 my $ret;
16 my $ret_hdr;
17 my $tabs = "";
18
19 sub indent() { $tabs.="\t"; }
20 sub deindent() { $tabs = substr($tabs, 1); }
21 sub pidl($) { $ret .= $tabs.(shift)."\n"; }
22 sub pidl_hdr($) { $ret_hdr .= (shift)."\n"; }
23 sub fatal($$) { my ($e,$s) = @_; die("$e->{FILE}:$e->{LINE}: $s\n"); }
24 sub typearg($) { 
25         my $t = shift; 
26         return(", const char *name") if ($t eq "print");
27         return(", TALLOC_CTX *mem_ctx") if ($t eq "pull");
28         return("");
29 }
30
31 sub fn_declare($$)
32 {
33         my ($p, $d) = @_;
34         if ($p) { pidl $d; pidl_hdr "$d;"; } else { pidl "static $d"; }
35 }
36
37 sub ContainsArray($)
38 {
39         my $e = shift;
40         foreach (@{$e->{ELEMENTS}}) {
41                 next if (has_property($_, "charset") and
42                         scalar(@{$_->{ARRAY_LEN}}) == 1);
43                 return 1 if (defined($_->{ARRAY_LEN}) and 
44                                 scalar(@{$_->{ARRAY_LEN}}) > 0);
45         }
46         return 0;
47 }
48
49 sub ParserElement($$$)
50 {
51         my ($e,$t,$env) = @_;
52         my $switch = "";
53         my $array = "";
54         my $name = "";
55         my $mem_ctx = "mem_ctx";
56
57         fatal($e,"Pointers not supported in TDR") if ($e->{POINTERS} > 0);
58         fatal($e,"size_is() not supported in TDR") if (has_property($e, "size_is"));
59         fatal($e,"length_is() not supported in TDR") if (has_property($e, "length_is"));
60
61         if ($t eq "print") {
62                 $name = ", \"$e->{NAME}\"$array";
63         }
64
65         if (has_property($e, "flag")) {
66                 pidl "{";
67                 indent;
68                 pidl "uint32_t saved_flags = tdr->flags;";
69                 pidl "tdr->flags |= $e->{PROPERTIES}->{flag};";
70         }
71
72         if (has_property($e, "charset")) {
73                 fatal($e,"charset() on non-array element") unless (defined($e->{ARRAY_LEN}) and scalar(@{$e->{ARRAY_LEN}}) > 0);
74                 
75                 my $len = ParseExpr(@{$e->{ARRAY_LEN}}[0], $env);
76                 if ($len eq "*") { $len = "-1"; }
77                 $name = ", mem_ctx" if ($t eq "pull");
78                 pidl "TDR_CHECK(tdr_$t\_charset(tdr$name, &v->$e->{NAME}, $len, sizeof($e->{TYPE}_t), CH_$e->{PROPERTIES}->{charset}));";
79                 return;
80         }
81
82         if (has_property($e, "switch_is")) {
83                 $switch = ", " . ParseExpr($e->{PROPERTIES}->{switch_is}, $env);
84         }
85
86         if (defined($e->{ARRAY_LEN}) and scalar(@{$e->{ARRAY_LEN}}) > 0) {
87                 my $len = ParseExpr($e->{ARRAY_LEN}[0], $env);
88
89                 if ($t eq "pull" and not is_constant($len)) {
90                         pidl "TDR_ALLOC(mem_ctx, v->$e->{NAME}, $len);";
91                         $mem_ctx = "v->$e->{NAME}";
92                 }
93
94                 pidl "for (i = 0; i < $len; i++) {";
95                 indent;
96                 $array = "[i]";
97         }
98
99         if ($t eq "pull") {
100                 $name = ", $mem_ctx";
101         }
102
103         if (has_property($e, "value") && $t eq "push") {
104                 pidl "v->$e->{NAME} = ".ParseExpr($e->{PROPERTIES}->{value}, $env).";";
105         }
106
107         pidl "TDR_CHECK(tdr_$t\_$e->{TYPE}(tdr$name$switch, &v->$e->{NAME}$array));";
108
109         if ($array) { deindent; pidl "}"; }
110
111         if (has_property($e, "flag")) {
112                 pidl "tdr->flags = saved_flags;";
113                 deindent;
114                 pidl "}";
115         }
116 }
117
118 sub ParserStruct($$$$)
119 {
120         my ($e,$n,$t,$p) = @_;
121
122         fn_declare($p,,"NTSTATUS tdr_$t\_$n (struct tdr_$t *tdr".typearg($t).", struct $n *v)");
123         pidl "{"; indent;
124         pidl "int i;" if (ContainsArray($e));
125
126         if ($t eq "print") {
127                 pidl "tdr->print(tdr, \"\%-25s: struct $n\", name);";
128                 pidl "tdr->level++;";
129         }
130
131         my %env = map { $_->{NAME} => "v->$_->{NAME}" } @{$e->{ELEMENTS}};
132         $env{"this"} = "v";
133         ParserElement($_, $t, \%env) foreach (@{$e->{ELEMENTS}});
134         
135         if ($t eq "print") {
136                 pidl "tdr->level--;";
137         }
138
139         pidl "return NT_STATUS_OK;";
140
141         deindent; pidl "}";
142 }
143
144 sub ParserUnion($$$$)
145 {
146         my ($e,$n,$t,$p) = @_;
147
148         fn_declare($p,"NTSTATUS tdr_$t\_$n(struct tdr_$t *tdr".typearg($t).", int level, union $n *v)");
149         pidl "{"; indent;
150         pidl "int i;" if (ContainsArray($e));
151
152         if ($t eq "print") {
153                 pidl "tdr->print(tdr, \"\%-25s: union $n\", name);";
154                 pidl "tdr->level++;";
155         }
156         
157         pidl "switch (level) {"; indent;
158         foreach (@{$e->{ELEMENTS}}) {
159                 if (has_property($_, "case")) {
160                         pidl "case " . $_->{PROPERTIES}->{case} . ":";
161                 } elsif (has_property($_, "default")) {
162                         pidl "default:";
163                 }
164                 indent; ParserElement($_, $t, {}); deindent;
165                 pidl "break;";
166         }
167         deindent; pidl "}";
168
169         if ($t eq "print") {
170                 pidl "tdr->level--;";
171         }
172         
173         pidl "return NT_STATUS_OK;\n";
174         deindent; pidl "}";
175 }
176
177 sub ParserBitmap($$$$)
178 {
179         my ($e,$n,$t,$p) = @_;
180         return if ($p);
181         pidl "#define tdr_$t\_$n tdr_$t\_" . Parse::Pidl::Typelist::bitmap_type_fn($e);
182 }
183
184 sub ParserEnum($$$$)
185 {
186         my ($e,$n,$t,$p) = @_;
187         my $bt = ($e->{PROPERTIES}->{base_type} or "uint8");
188         
189         fn_declare($p, "NTSTATUS tdr_$t\_$n (struct tdr_$t *tdr".typearg($t).", enum $n *v)");
190         pidl "{";
191         if ($t eq "pull") {
192                 pidl "\t$bt\_t r;";
193                 pidl "\tTDR_CHECK(tdr_$t\_$bt(tdr, mem_ctx, \&r));";
194                 pidl "\t*v = r;";
195         } elsif ($t eq "push") {
196                 pidl "\tTDR_CHECK(tdr_$t\_$bt(tdr, ($bt\_t *)v));";
197         } elsif ($t eq "print") {
198                 pidl "\t/* FIXME */";
199         }
200         pidl "\treturn NT_STATUS_OK;";
201         pidl "}";
202 }
203
204 sub ParserTypedef($$)
205 {
206         my ($e,$t) = @_;
207
208         return if (has_property($e, "no$t"));
209
210         $e->{DATA}->{PROPERTIES} = $e->{PROPERTIES};
211
212         { STRUCT => \&ParserStruct, UNION => \&ParserUnion, 
213                 ENUM => \&ParserEnum, BITMAP => \&ParserBitmap
214         }->{$e->{DATA}->{TYPE}}->($e->{DATA}, $e->{NAME}, $t, has_property($e, "public"));
215
216         pidl "";
217 }
218
219 sub ParserInterface($)
220 {
221         my $x = shift;
222         
223         pidl_hdr "#ifndef __TDR_$x->{NAME}_HEADER__";
224         pidl_hdr "#define __TDR_$x->{NAME}_HEADER__";
225
226         foreach (@{$x->{DATA}}) {
227                 next if ($_->{TYPE} ne "TYPEDEF");
228                 ParserTypedef($_, "pull");
229                 ParserTypedef($_, "push");
230                 ParserTypedef($_, "print");
231         }
232
233         pidl_hdr "#endif /* __TDR_$x->{NAME}_HEADER__ */";
234 }
235
236 sub Parser($$$)
237 {
238         my ($idl,$hdrname,$baseheader) = @_;
239         $ret = ""; $ret_hdr = "";
240         pidl "/* autogenerated by pidl */";
241         if (is_intree()) {
242                 pidl "#include \"includes.h\"";
243         } else {
244                 pidl "#include <stdio.h>";
245                 pidl "#include <stdbool.h>";
246                 pidl "#include <stdlib.h>";
247                 pidl "#include <stdint.h>";
248                 pidl "#include <stdarg.h>";
249                 pidl "#include <string.h>";
250                 pidl "#include <core/nterr.h>";
251         }
252         pidl "#include \"$hdrname\"";
253         pidl "";
254         pidl_hdr "/* autogenerated by pidl */";
255         pidl_hdr "#include \"$baseheader\"";
256         pidl_hdr choose_header("tdr/tdr.h", "tdr.h");
257         pidl_hdr "";
258
259         foreach (@$idl) { ParserInterface($_) if ($_->{TYPE} eq "INTERFACE"); } 
260         return ($ret_hdr, $ret);
261 }
262
263 1;