Merge branch 'master' of ssh://git.samba.org/data/git/samba
[ira/wip.git] / source4 / librpc / ndr / ndr_string.c
1 /* 
2    Unix SMB/CIFS implementation.
3
4    routines for marshalling/unmarshalling string types
5
6    Copyright (C) Andrew Tridgell 2003
7    
8    This program is free software; you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation; either version 3 of the License, or
11    (at your option) any later version.
12    
13    This program is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17    
18    You should have received a copy of the GNU General Public License
19    along with this program.  If not, see <http://www.gnu.org/licenses/>.
20 */
21
22 #include "includes.h"
23 #include "librpc/ndr/libndr.h"
24
25 /**
26   pull a general string from the wire
27 */
28 _PUBLIC_ enum ndr_err_code ndr_pull_string(struct ndr_pull *ndr, int ndr_flags, const char **s)
29 {
30         char *as=NULL;
31         uint32_t len1, ofs, len2;
32         uint16_t len3;
33         int ret;
34         charset_t chset = CH_UTF16;
35         unsigned byte_mul = 2;
36         unsigned flags = ndr->flags;
37         unsigned c_len_term = 0;
38
39         if (!(ndr_flags & NDR_SCALARS)) {
40                 return NDR_ERR_SUCCESS;
41         }
42
43         if (NDR_BE(ndr)) {
44                 chset = CH_UTF16BE;
45         }
46
47         if (flags & LIBNDR_FLAG_STR_ASCII) {
48                 chset = CH_DOS;
49                 byte_mul = 1;
50                 flags &= ~LIBNDR_FLAG_STR_ASCII;
51         }
52
53         if (flags & LIBNDR_FLAG_STR_UTF8) {
54                 chset = CH_UTF8;
55                 byte_mul = 1;
56                 flags &= ~LIBNDR_FLAG_STR_UTF8;
57         }
58
59         flags &= ~LIBNDR_FLAG_STR_CONFORMANT;
60         if (flags & LIBNDR_FLAG_STR_CHARLEN) {
61                 c_len_term = 1;
62                 flags &= ~LIBNDR_FLAG_STR_CHARLEN;
63         }
64
65         switch (flags & LIBNDR_STRING_FLAGS) {
66         case LIBNDR_FLAG_STR_LEN4|LIBNDR_FLAG_STR_SIZE4:
67         case LIBNDR_FLAG_STR_LEN4|LIBNDR_FLAG_STR_SIZE4|LIBNDR_FLAG_STR_NOTERM:
68                 NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &len1));
69                 NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &ofs));
70                 if (ofs != 0) {
71                         return ndr_pull_error(ndr, NDR_ERR_STRING, "non-zero array offset with string flags 0x%x\n",
72                                               ndr->flags & LIBNDR_STRING_FLAGS);
73                 }
74                 NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &len2));
75                 if (len2 > len1) {
76                         return ndr_pull_error(ndr, NDR_ERR_STRING, 
77                                               "Bad string lengths len1=%u ofs=%u len2=%u\n", 
78                                               len1, ofs, len2);
79                 }
80                 NDR_PULL_NEED_BYTES(ndr, (len2 + c_len_term)*byte_mul);
81                 if (len2 == 0) {
82                         as = talloc_strdup(ndr->current_mem_ctx, "");
83                 } else {
84                         ret = convert_string_talloc(ndr->current_mem_ctx,
85                                                     ndr->iconv_convenience, chset, CH_UNIX, 
86                                                     ndr->data+ndr->offset, 
87                                                     (len2 + c_len_term)*byte_mul,
88                                                     (void **)&as);
89                         if (ret == -1) {
90                                 return ndr_pull_error(ndr, NDR_ERR_CHARCNV, 
91                                                       "Bad character conversion");
92                         }
93                 }
94                 NDR_CHECK(ndr_pull_advance(ndr, (len2 + c_len_term)*byte_mul));
95
96                 if (len1 != len2) {
97                         DEBUG(6,("len1[%u] != len2[%u] '%s'\n", len1, len2, as));
98                 }
99
100                 /* this is a way of detecting if a string is sent with the wrong
101                    termination */
102                 if (ndr->flags & LIBNDR_FLAG_STR_NOTERM) {
103                         if (strlen(as) < (len2 + c_len_term)) {
104                                 DEBUG(6,("short string '%s'\n", as));
105                         }
106                 } else {
107                         if (strlen(as) == (len2 + c_len_term)) {
108                                 DEBUG(6,("long string '%s'\n", as));
109                         }
110                 }
111                 *s = as;
112                 break;
113
114         case LIBNDR_FLAG_STR_SIZE4:
115         case LIBNDR_FLAG_STR_SIZE4|LIBNDR_FLAG_STR_NOTERM:
116                 NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &len1));
117                 NDR_PULL_NEED_BYTES(ndr, (len1 + c_len_term)*byte_mul);
118                 if (len1 == 0) {
119                         as = talloc_strdup(ndr->current_mem_ctx, "");
120                 } else {
121                         ret = convert_string_talloc(ndr->current_mem_ctx,
122                                                     ndr->iconv_convenience, 
123                                                     chset, CH_UNIX, 
124                                                     ndr->data+ndr->offset, 
125                                                     (len1 + c_len_term)*byte_mul,
126                                                     (void **)&as);
127                         if (ret == -1) {
128                                 return ndr_pull_error(ndr, NDR_ERR_CHARCNV, 
129                                                       "Bad character conversion");
130                         }
131                 }
132                 NDR_CHECK(ndr_pull_advance(ndr, (len1 + c_len_term)*byte_mul));
133
134                 /* this is a way of detecting if a string is sent with the wrong
135                    termination */
136                 if (ndr->flags & LIBNDR_FLAG_STR_NOTERM) {
137                         if (strlen(as) < (len1 + c_len_term)) {
138                                 DEBUG(6,("short string '%s'\n", as));
139                         }
140                 } else {
141                         if (strlen(as) == (len1 + c_len_term)) {
142                                 DEBUG(6,("long string '%s'\n", as));
143                         }
144                 }
145                 *s = as;
146                 break;
147
148         case LIBNDR_FLAG_STR_LEN4:
149         case LIBNDR_FLAG_STR_LEN4|LIBNDR_FLAG_STR_NOTERM:
150                 NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &ofs));
151                 if (ofs != 0) {
152                         return ndr_pull_error(ndr, NDR_ERR_STRING, "non-zero array offset with string flags 0x%x\n",
153                                               ndr->flags & LIBNDR_STRING_FLAGS);
154                 }
155                 NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &len1));
156                 NDR_PULL_NEED_BYTES(ndr, (len1 + c_len_term)*byte_mul);
157                 if (len1 == 0) {
158                         as = talloc_strdup(ndr->current_mem_ctx, "");
159                 } else {
160                         ret = convert_string_talloc(ndr->current_mem_ctx,
161                                                     ndr->iconv_convenience, 
162                                                     chset, CH_UNIX, 
163                                                     ndr->data+ndr->offset, 
164                                                     (len1 + c_len_term)*byte_mul,
165                                                     (void **)&as);
166                         if (ret == -1) {
167                                 return ndr_pull_error(ndr, NDR_ERR_CHARCNV, 
168                                                       "Bad character conversion");
169                         }
170                 }
171                 NDR_CHECK(ndr_pull_advance(ndr, (len1 + c_len_term)*byte_mul));
172
173                 /* this is a way of detecting if a string is sent with the wrong
174                    termination */
175                 if (ndr->flags & LIBNDR_FLAG_STR_NOTERM) {
176                         if (strlen(as) < (len1 + c_len_term)) {
177                                 DEBUG(6,("short string '%s'\n", as));
178                         }
179                 } else {
180                         if (strlen(as) == (len1 + c_len_term)) {
181                                 DEBUG(6,("long string '%s'\n", as));
182                         }
183                 }
184                 *s = as;
185                 break;
186
187
188         case LIBNDR_FLAG_STR_SIZE2:
189         case LIBNDR_FLAG_STR_SIZE2|LIBNDR_FLAG_STR_NOTERM:
190                 NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &len3));
191                 NDR_PULL_NEED_BYTES(ndr, (len3 + c_len_term)*byte_mul);
192                 if (len3 == 0) {
193                         as = talloc_strdup(ndr->current_mem_ctx, "");
194                 } else {
195                         ret = convert_string_talloc(ndr->current_mem_ctx,
196                                                     ndr->iconv_convenience,
197                                                     chset, CH_UNIX, 
198                                                     ndr->data+ndr->offset, 
199                                                     (len3 + c_len_term)*byte_mul,
200                                                     (void **)&as);
201                         if (ret == -1) {
202                                 return ndr_pull_error(ndr, NDR_ERR_CHARCNV, 
203                                                       "Bad character conversion");
204                         }
205                 }
206                 NDR_CHECK(ndr_pull_advance(ndr, (len3 + c_len_term)*byte_mul));
207
208                 /* this is a way of detecting if a string is sent with the wrong
209                    termination */
210                 if (ndr->flags & LIBNDR_FLAG_STR_NOTERM) {
211                         if (strlen(as) < (len3 + c_len_term)) {
212                                 DEBUG(6,("short string '%s'\n", as));
213                         }
214                 } else {
215                         if (strlen(as) == (len3 + c_len_term)) {
216                                 DEBUG(6,("long string '%s'\n", as));
217                         }
218                 }
219                 *s = as;
220                 break;
221
222         case LIBNDR_FLAG_STR_SIZE2|LIBNDR_FLAG_STR_NOTERM|LIBNDR_FLAG_STR_BYTESIZE:
223                 NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &len3));
224                 NDR_PULL_NEED_BYTES(ndr, len3);
225                 if (len3 == 0) {
226                         as = talloc_strdup(ndr->current_mem_ctx, "");
227                 } else {
228                         ret = convert_string_talloc(ndr->current_mem_ctx,
229                                                     ndr->iconv_convenience, 
230                                                     chset, CH_UNIX, 
231                                                     ndr->data+ndr->offset, 
232                                                     len3,
233                                                     (void **)&as);
234                         if (ret == -1) {
235                                 return ndr_pull_error(ndr, NDR_ERR_CHARCNV, 
236                                                       "Bad character conversion");
237                         }
238                 }
239                 NDR_CHECK(ndr_pull_advance(ndr, len3));
240                 *s = as;
241                 break;
242
243         case LIBNDR_FLAG_STR_NULLTERM:
244                 if (byte_mul == 1) {
245                         len1 = ascii_len_n((const char *)(ndr->data+ndr->offset), ndr->data_size - ndr->offset);
246                 } else {
247                         len1 = utf16_len_n(ndr->data+ndr->offset, ndr->data_size - ndr->offset);
248                 }
249                 ret = convert_string_talloc(ndr->current_mem_ctx,
250                                             ndr->iconv_convenience, chset, CH_UNIX, 
251                                             ndr->data+ndr->offset, 
252                                             len1,
253                                             (void **)&as);
254                 if (ret == -1) {
255                         return ndr_pull_error(ndr, NDR_ERR_CHARCNV, 
256                                               "Bad character conversion");
257                 }
258                 NDR_CHECK(ndr_pull_advance(ndr, len1));
259                 *s = as;
260                 break;
261
262         case LIBNDR_FLAG_STR_NOTERM:
263                 if (!(ndr->flags & LIBNDR_FLAG_REMAINING)) {
264                         return ndr_pull_error(ndr, NDR_ERR_STRING, "Bad string flags 0x%x (missing NDR_REMAINING)\n",
265                                               ndr->flags & LIBNDR_STRING_FLAGS);
266                 }
267
268                 len1 = ndr->data_size - ndr->offset;
269
270                 NDR_PULL_NEED_BYTES(ndr, len1);
271                 if (len1 == 0) {
272                         as = talloc_strdup(ndr->current_mem_ctx, "");
273                 } else {
274                         ret = convert_string_talloc(ndr->current_mem_ctx,
275                                                     ndr->iconv_convenience,
276                                                     chset, CH_UNIX, 
277                                                     ndr->data+ndr->offset, 
278                                                     len1,
279                                                     (void **)&as);
280                         if (ret == -1) {
281                                 return ndr_pull_error(ndr, NDR_ERR_CHARCNV, 
282                                                       "Bad character conversion");
283                         }
284                 }
285                 NDR_CHECK(ndr_pull_advance(ndr, len1));
286
287                 *s = as;
288                 break;
289
290         default:
291                 return ndr_pull_error(ndr, NDR_ERR_STRING, "Bad string flags 0x%x\n",
292                                       ndr->flags & LIBNDR_STRING_FLAGS);
293         }
294
295         return NDR_ERR_SUCCESS;
296 }
297
298
299 /**
300   push a general string onto the wire
301 */
302 _PUBLIC_ enum ndr_err_code ndr_push_string(struct ndr_push *ndr, int ndr_flags, const char *s)
303 {
304         ssize_t s_len, c_len, d_len;
305         int chset = CH_UTF16;
306         unsigned flags = ndr->flags;
307         unsigned byte_mul = 2;
308         uint8_t *dest = NULL;
309
310         if (!(ndr_flags & NDR_SCALARS)) {
311                 return NDR_ERR_SUCCESS;
312         }
313
314         if (NDR_BE(ndr)) {
315                 chset = CH_UTF16BE;
316         }
317         
318         s_len = s?strlen(s):0;
319
320         if (flags & LIBNDR_FLAG_STR_ASCII) {
321                 chset = CH_DOS;
322                 byte_mul = 1;
323                 flags &= ~LIBNDR_FLAG_STR_ASCII;
324         }
325
326         if (flags & LIBNDR_FLAG_STR_UTF8) {
327                 chset = CH_UTF8;
328                 byte_mul = 1;
329                 flags &= ~LIBNDR_FLAG_STR_UTF8;
330         }
331
332         flags &= ~LIBNDR_FLAG_STR_CONFORMANT;
333
334         if (!(flags & LIBNDR_FLAG_STR_NOTERM)) {
335                 s_len++;
336         }
337         d_len = convert_string_talloc(ndr, ndr->iconv_convenience, CH_UNIX, chset, s, s_len, (void **)&dest);
338         if (d_len == -1) {
339                 return ndr_push_error(ndr, NDR_ERR_CHARCNV, 
340                                       "Bad character conversion");
341         }
342
343         if (flags & LIBNDR_FLAG_STR_BYTESIZE) {
344                 c_len = d_len;
345                 flags &= ~LIBNDR_FLAG_STR_BYTESIZE;
346         } else if (flags & LIBNDR_FLAG_STR_CHARLEN) {
347                 c_len = (d_len / byte_mul)-1;
348                 flags &= ~LIBNDR_FLAG_STR_CHARLEN;
349         } else {
350                 c_len = d_len / byte_mul;
351         }
352
353         switch ((flags & LIBNDR_STRING_FLAGS) & ~LIBNDR_FLAG_STR_NOTERM) {
354         case LIBNDR_FLAG_STR_LEN4|LIBNDR_FLAG_STR_SIZE4:
355                 NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, c_len));
356                 NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
357                 NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, c_len));
358                 NDR_CHECK(ndr_push_bytes(ndr, dest, d_len));
359                 break;
360
361         case LIBNDR_FLAG_STR_LEN4:
362                 NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
363                 NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, c_len));
364                 NDR_CHECK(ndr_push_bytes(ndr, dest, d_len));
365                 break;
366
367         case LIBNDR_FLAG_STR_SIZE4:
368                 NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, c_len));
369                 NDR_CHECK(ndr_push_bytes(ndr, dest, d_len));
370                 break;
371
372         case LIBNDR_FLAG_STR_SIZE2:
373                 NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, c_len));
374                 NDR_CHECK(ndr_push_bytes(ndr, dest, d_len));
375                 break;
376
377         case LIBNDR_FLAG_STR_NULLTERM:
378                 NDR_CHECK(ndr_push_bytes(ndr, dest, d_len));
379                 break;
380
381         default:
382                 if (ndr->flags & LIBNDR_FLAG_REMAINING) {
383                         NDR_CHECK(ndr_push_bytes(ndr, dest, d_len));
384                         break;          
385                 }
386
387                 return ndr_push_error(ndr, NDR_ERR_STRING, "Bad string flags 0x%x\n",
388                                       ndr->flags & LIBNDR_STRING_FLAGS);
389         }
390
391         talloc_free(dest);
392
393         return NDR_ERR_SUCCESS;
394 }
395
396 /**
397   push a general string onto the wire
398 */
399 _PUBLIC_ size_t ndr_string_array_size(struct ndr_push *ndr, const char *s)
400 {
401         size_t c_len;
402         unsigned flags = ndr->flags;
403         unsigned byte_mul = 2;
404         unsigned c_len_term = 1;
405
406         c_len = s?strlen_m(s):0;
407
408         if (flags & (LIBNDR_FLAG_STR_ASCII|LIBNDR_FLAG_STR_UTF8)) {
409                 byte_mul = 1;
410         }
411
412         if (flags & LIBNDR_FLAG_STR_NOTERM) {
413                 c_len_term = 0;
414         }
415
416         c_len = c_len + c_len_term;
417
418         if (flags & LIBNDR_FLAG_STR_BYTESIZE) {
419                 c_len = c_len * byte_mul;
420         }
421
422         return c_len;
423 }
424
425 _PUBLIC_ void ndr_print_string(struct ndr_print *ndr, const char *name, const char *s)
426 {
427         if (s) {
428                 ndr->print(ndr, "%-25s: '%s'", name, s);
429         } else {
430                 ndr->print(ndr, "%-25s: NULL", name);
431         }
432 }
433
434 _PUBLIC_ uint32_t ndr_size_string(int ret, const char * const* string, int flags) 
435 {
436         /* FIXME: Is this correct for all strings ? */
437         if(!(*string)) return ret;
438         return ret+strlen(*string)+1;
439 }
440
441 /**
442   pull a general string array from the wire
443 */
444 _PUBLIC_ enum ndr_err_code ndr_pull_string_array(struct ndr_pull *ndr, int ndr_flags, const char ***_a)
445 {
446         const char **a = *_a;
447         uint32_t count;
448         unsigned flags = ndr->flags;
449         unsigned saved_flags = ndr->flags;
450
451         if (!(ndr_flags & NDR_SCALARS)) {
452                 return NDR_ERR_SUCCESS;
453         }
454
455         switch (flags & LIBNDR_STRING_FLAGS) {
456         case LIBNDR_FLAG_STR_NULLTERM:
457                 /* 
458                  * here the strings are null terminated
459                  * but also the array is null terminated
460                  */
461                 for (count = 0;; count++) {
462                         TALLOC_CTX *tmp_ctx;
463                         const char *s = NULL;
464                         a = talloc_realloc(ndr->current_mem_ctx, a, const char *, count + 2);
465                         NDR_ERR_HAVE_NO_MEMORY(a);
466                         a[count]   = NULL;
467                         a[count+1]   = NULL;
468
469                         tmp_ctx = ndr->current_mem_ctx;
470                         ndr->current_mem_ctx = a;
471                         NDR_CHECK(ndr_pull_string(ndr, ndr_flags, &s));
472                         ndr->current_mem_ctx = tmp_ctx;
473                         if (strcmp("", s)==0) {
474                                 a[count] = NULL;
475                                 break;
476                         } else {
477                                 a[count] = s;
478                         }
479                 }
480
481                 *_a =a;
482                 break;
483
484         case LIBNDR_FLAG_STR_NOTERM:
485                 if (!(ndr->flags & LIBNDR_FLAG_REMAINING)) {
486                         return ndr_pull_error(ndr, NDR_ERR_STRING, "Bad string flags 0x%x (missing NDR_REMAINING)\n",
487                                               ndr->flags & LIBNDR_STRING_FLAGS);
488                 }
489                 /*
490                  * here the strings are not null terminated
491                  * but serarated by a null terminator
492                  *
493                  * which means the same as:
494                  * very string is null terminated exept the last
495                  * string is terminated by the end of the buffer
496                  *
497                  * as LIBNDR_FLAG_STR_NULLTERM also end at the end
498                  * of the buffer, we can pull each string with this flag
499                  */
500                 ndr->flags &= ~(LIBNDR_FLAG_STR_NOTERM|LIBNDR_FLAG_REMAINING);
501                 ndr->flags |= LIBNDR_FLAG_STR_NULLTERM;
502
503                 for (count = 0; ((ndr->data_size - ndr->offset) > 0); count++) {
504                         TALLOC_CTX *tmp_ctx;
505                         const char *s = NULL;
506                         a = talloc_realloc(ndr->current_mem_ctx, a, const char *, count + 2);
507                         NDR_ERR_HAVE_NO_MEMORY(a);
508                         a[count]   = NULL;
509                         a[count+1]   = NULL;
510
511                         tmp_ctx = ndr->current_mem_ctx;
512                         ndr->current_mem_ctx = a;
513                         NDR_CHECK(ndr_pull_string(ndr, ndr_flags, &s));
514                         ndr->current_mem_ctx = tmp_ctx;
515                         a[count] = s;
516                 }
517
518                 *_a =a;
519                 break;
520
521         default:
522                 return ndr_pull_error(ndr, NDR_ERR_STRING, "Bad string flags 0x%x\n",
523                                       ndr->flags & LIBNDR_STRING_FLAGS);
524         }
525
526         ndr->flags = saved_flags;
527         return NDR_ERR_SUCCESS;
528 }
529
530 /**
531   push a general string array onto the wire
532 */
533 _PUBLIC_ enum ndr_err_code ndr_push_string_array(struct ndr_push *ndr, int ndr_flags, const char **a)
534 {
535         uint32_t count;
536         unsigned flags = ndr->flags;
537         unsigned saved_flags = ndr->flags;
538
539         if (!(ndr_flags & NDR_SCALARS)) {
540                 return NDR_ERR_SUCCESS;
541         }
542
543         switch (flags & LIBNDR_STRING_FLAGS) {
544         case LIBNDR_FLAG_STR_NULLTERM:
545                 for (count = 0; a && a[count]; count++) {
546                         NDR_CHECK(ndr_push_string(ndr, ndr_flags, a[count]));
547                 }
548
549                 NDR_CHECK(ndr_push_string(ndr, ndr_flags, ""));
550                 break;
551
552         case LIBNDR_FLAG_STR_NOTERM:
553                 if (!(ndr->flags & LIBNDR_FLAG_REMAINING)) {
554                         return ndr_push_error(ndr, NDR_ERR_STRING, "Bad string flags 0x%x (missing NDR_REMAINING)\n",
555                                               ndr->flags & LIBNDR_STRING_FLAGS);
556                 }
557
558                 for (count = 0; a && a[count]; count++) {
559                         if (count > 0) {
560                                 ndr->flags &= ~(LIBNDR_FLAG_STR_NOTERM|LIBNDR_FLAG_REMAINING);
561                                 ndr->flags |= LIBNDR_FLAG_STR_NULLTERM;
562                                 NDR_CHECK(ndr_push_string(ndr, ndr_flags, ""));
563                                 ndr->flags = saved_flags;
564                         }
565                         NDR_CHECK(ndr_push_string(ndr, ndr_flags, a[count]));
566                 }
567
568                 break;
569
570         default:
571                 return ndr_push_error(ndr, NDR_ERR_STRING, "Bad string flags 0x%x\n",
572                                       ndr->flags & LIBNDR_STRING_FLAGS);
573         }
574         
575         ndr->flags = saved_flags;
576         return NDR_ERR_SUCCESS;
577 }
578
579 _PUBLIC_ void ndr_print_string_array(struct ndr_print *ndr, const char *name, const char **a)
580 {
581         uint32_t count;
582         uint32_t i;
583
584         for (count = 0; a && a[count]; count++) {}
585
586         ndr->print(ndr, "%s: ARRAY(%d)", name, count);
587         ndr->depth++;
588         for (i=0;i<count;i++) {
589                 char *idx=NULL;
590                 if (asprintf(&idx, "[%d]", i) != -1) {
591                         ndr_print_string(ndr, idx, a[i]);
592                         free(idx);
593                 }
594         }
595         ndr->depth--;
596 }
597
598 /**
599  * Return number of elements in a string including the last (zeroed) element 
600  */
601 _PUBLIC_ uint32_t ndr_string_length(const void *_var, uint32_t element_size)
602 {
603         uint32_t i;
604         uint8_t zero[4] = {0,0,0,0};
605         const char *var = (const char *)_var;
606
607         for (i = 0; memcmp(var+i*element_size,zero,element_size) != 0; i++);
608
609         return i+1;
610 }
611
612 _PUBLIC_ enum ndr_err_code ndr_check_string_terminator(struct ndr_pull *ndr, uint32_t count, uint32_t element_size)
613 {
614         uint32_t i;
615         uint32_t save_offset;
616
617         save_offset = ndr->offset;
618         ndr_pull_advance(ndr, (count - 1) * element_size);
619         NDR_PULL_NEED_BYTES(ndr, element_size);
620
621         for (i = 0; i < element_size; i++) {
622                  if (ndr->data[ndr->offset+i] != 0) {
623                         ndr->offset = save_offset;
624
625                         return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "String terminator not present or outside string boundaries");
626                  }
627         }
628
629         ndr->offset = save_offset;
630
631         return NDR_ERR_SUCCESS;
632 }
633
634 _PUBLIC_ enum ndr_err_code ndr_pull_charset(struct ndr_pull *ndr, int ndr_flags, const char **var, uint32_t length, uint8_t byte_mul, charset_t chset)
635 {
636         int ret;
637         if (length == 0) {
638                 *var = talloc_strdup(ndr->current_mem_ctx, "");
639                 return NDR_ERR_SUCCESS;
640         }
641
642         if (NDR_BE(ndr) && chset == CH_UTF16) {
643                 chset = CH_UTF16BE;
644         }
645
646         NDR_PULL_NEED_BYTES(ndr, length*byte_mul);
647
648         ret = convert_string_talloc(ndr->current_mem_ctx, 
649                                     ndr->iconv_convenience,
650                                     chset, CH_UNIX, 
651                                     ndr->data+ndr->offset, 
652                                     length*byte_mul,
653                                     discard_const_p(void *, var));
654         if (ret == -1) {
655                 return ndr_pull_error(ndr, NDR_ERR_CHARCNV, 
656                                       "Bad character conversion");
657         }
658         NDR_CHECK(ndr_pull_advance(ndr, length*byte_mul));
659
660         return NDR_ERR_SUCCESS;
661 }
662
663 _PUBLIC_ enum ndr_err_code ndr_push_charset(struct ndr_push *ndr, int ndr_flags, const char *var, uint32_t length, uint8_t byte_mul, charset_t chset)
664 {
665         ssize_t ret, required;
666
667         if (NDR_BE(ndr) && chset == CH_UTF16) {
668                 chset = CH_UTF16BE;
669         }
670
671         required = byte_mul * length;
672         
673         NDR_PUSH_NEED_BYTES(ndr, required);
674         ret = convert_string(ndr->iconv_convenience, CH_UNIX, chset, 
675                              var, strlen(var),
676                              ndr->data+ndr->offset, required);
677         if (ret == -1) {
678                 return ndr_push_error(ndr, NDR_ERR_CHARCNV, 
679                                       "Bad character conversion");
680         }
681
682         /* Make sure the remaining part of the string is filled with zeroes */
683         if (ret < required) {
684                 memset(ndr->data+ndr->offset+ret, 0, required-ret);
685         }
686
687         ndr->offset += required;
688
689         return NDR_ERR_SUCCESS;
690 }
691
692 /* Return number of elements in a string in the specified charset */
693 _PUBLIC_ uint32_t ndr_charset_length(const void *var, charset_t chset)
694 {
695         /* FIXME: Treat special chars special here, taking chset into account */
696         /* Also include 0 byte */
697         return strlen((const char *)var)+1;
698 }