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