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