first pass at updating head branch to be to be the same as the SAMBA_2_0 branch
[sfrench/samba-autobuild/.git] / source3 / lib / util_unistr.c
1 /* 
2    Unix SMB/Netbios implementation.
3    Version 1.9.
4    Samba utility functions
5    Copyright (C) Andrew Tridgell 1992-1998
6    
7    This program is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 2 of the License, or
10    (at your option) any later version.
11    
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16    
17    You should have received a copy of the GNU General Public License
18    along with this program; if not, write to the Free Software
19    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 */
21
22 #include "includes.h"
23
24 extern int DEBUGLEVEL;
25
26 /*
27  * The following are the codepage to ucs2 and vica versa maps.
28  * These are dynamically loaded from a unicode translation file.
29  */
30
31 static smb_ucs2_t *doscp_to_ucs2;
32 static uint16 *ucs2_to_doscp;
33
34 static smb_ucs2_t *unixcp_to_ucs2;
35 static uint16 *ucs2_to_unixcp;
36
37 #ifndef MAXUNI
38 #define MAXUNI 1024
39 #endif
40
41 /*******************************************************************
42  Write a string in (little-endian) unicode format. src is in
43  the current DOS codepage. len is the length in bytes of the
44  string pointed to by dst.
45
46  the return value is the length of the string *without* the trailing 
47  two bytes of zero
48 ********************************************************************/
49
50 int dos_PutUniCode(char *dst,const char *src, ssize_t len)
51 {
52         int ret = 0;
53         while (*src && (len > 2)) {
54                 size_t skip = skip_multibyte_char(*src);
55                 smb_ucs2_t val = (*src & 0xff);
56
57                 /*
58                  * If this is a multibyte character (and all DOS/Windows
59                  * codepages have at maximum 2 byte multibyte characters)
60                  * then work out the index value for the unicode conversion.
61                  */
62
63                 if (skip == 2)
64                         val = ((val << 8) | src[1]);
65
66                 SSVAL(dst,ret,doscp_to_ucs2[val]);
67                 ret += 2;
68                 len -= 2;
69                 if (skip)
70                         src += skip;
71                 else
72                         src++;
73         }
74         SSVAL(dst,ret,0);
75         return(ret);
76 }
77
78 /*******************************************************************
79  Skip past some unicode strings in a buffer.
80 ********************************************************************/
81
82 char *skip_unicode_string(char *buf,int n)
83 {
84         while (n--) {
85                 while (*buf)
86                         buf += 2;
87                 buf += 2;
88         }
89         return(buf);
90 }
91
92 /*******************************************************************
93  Return a DOS codepage version of a little-endian unicode string.
94  Hack alert: uses fixed buffer(s).
95 ********************************************************************/
96
97 char *dos_unistrn2(uint16 *src, int len)
98 {
99         static char lbufs[8][MAXUNI];
100         static int nexti;
101         char *lbuf = lbufs[nexti];
102         char *p;
103
104         nexti = (nexti+1)%8;
105
106         for (p = lbuf; (len > 0) && (p-lbuf < MAXUNI-3) && *src; len--, src++) {
107                 uint16 ucs2_val = SVAL(src,0);
108                 uint16 cp_val = ucs2_to_doscp[ucs2_val];
109
110                 if (cp_val < 256)
111                         *p++ = (char)cp_val;
112                 else {
113                         *p++ = (cp_val >> 8) & 0xff;
114                         *p++ = (cp_val & 0xff);
115                 }
116         }
117
118         *p = 0;
119         return lbuf;
120 }
121
122 static char lbufs[8][MAXUNI];
123 static int nexti;
124
125 /*******************************************************************
126  Return a DOS codepage version of a little-endian unicode string.
127  Hack alert: uses fixed buffer(s).
128 ********************************************************************/
129
130 char *dos_unistr2(uint16 *src)
131 {
132         char *lbuf = lbufs[nexti];
133         char *p;
134
135         nexti = (nexti+1)%8;
136
137         for (p = lbuf; *src && (p-lbuf < MAXUNI-3); src++) {
138                 uint16 ucs2_val = SVAL(src,0);
139                 uint16 cp_val = ucs2_to_doscp[ucs2_val];
140
141                 if (cp_val < 256)
142                         *p++ = (char)cp_val;
143                 else {
144                         *p++ = (cp_val >> 8) & 0xff;
145                         *p++ = (cp_val & 0xff);
146                 }
147         }
148
149         *p = 0;
150         return lbuf;
151 }
152
153 /*******************************************************************
154 Return a DOS codepage version of a little-endian unicode string
155 ********************************************************************/
156
157 char *dos_unistr2_to_str(UNISTR2 *str)
158 {
159         char *lbuf = lbufs[nexti];
160         char *p;
161         uint16 *src = str->buffer;
162         int max_size = MIN(sizeof(str->buffer)-3, str->uni_str_len);
163
164         nexti = (nexti+1)%8;
165
166         for (p = lbuf; *src && p-lbuf < max_size; src++) {
167                 uint16 ucs2_val = SVAL(src,0);
168                 uint16 cp_val = ucs2_to_doscp[ucs2_val];
169
170                 if (cp_val < 256)
171                         *p++ = (char)cp_val;
172                 else {
173                         *p++ = (cp_val >> 8) & 0xff;
174                         *p++ = (cp_val & 0xff);
175                 }
176         }
177
178         *p = 0;
179         return lbuf;
180 }
181
182 /*******************************************************************
183 Return a number stored in a buffer
184 ********************************************************************/
185
186 uint32 buffer2_to_uint32(BUFFER2 *str)
187 {
188         if (str->buf_len == 4)
189                 return IVAL(str->buffer, 0);
190         else
191                 return 0;
192 }
193
194 /*******************************************************************
195 Return a DOS codepage version of a NOTunicode string
196 ********************************************************************/
197
198 char *dos_buffer2_to_str(BUFFER2 *str)
199 {
200         char *lbuf = lbufs[nexti];
201         char *p;
202         uint16 *src = str->buffer;
203         int max_size = MIN(sizeof(str->buffer)-3, str->buf_len/2);
204
205         nexti = (nexti+1)%8;
206
207         for (p = lbuf; *src && p-lbuf < max_size; src++) {
208                 uint16 ucs2_val = SVAL(src,0);
209                 uint16 cp_val = ucs2_to_doscp[ucs2_val];
210
211                 if (cp_val < 256)
212                         *p++ = (char)cp_val;
213                 else {
214                         *p++ = (cp_val >> 8) & 0xff;
215                         *p++ = (cp_val & 0xff);
216                 }
217         }
218
219         *p = 0;
220         return lbuf;
221 }
222
223 /*******************************************************************
224  Return a dos codepage version of a NOTunicode string
225 ********************************************************************/
226
227 char *dos_buffer2_to_multistr(BUFFER2 *str)
228 {
229         char *lbuf = lbufs[nexti];
230         char *p;
231         uint16 *src = str->buffer;
232         int max_size = MIN(sizeof(str->buffer)-3, str->buf_len/2);
233
234         nexti = (nexti+1)%8;
235
236         for (p = lbuf; p-lbuf < max_size; src++) {
237                 if (*src == 0) {
238                         *p++ = ' ';
239                 } else {
240                         uint16 ucs2_val = SVAL(src,0);
241                         uint16 cp_val = ucs2_to_doscp[ucs2_val];
242
243                         if (cp_val < 256)
244                                 *p++ = (char)cp_val;
245                         else {
246                                 *p++ = (cp_val >> 8) & 0xff;
247                                 *p++ = (cp_val & 0xff);
248                         }
249                 }
250         }
251
252         *p = 0;
253         return lbuf;
254 }
255
256 /*******************************************************************
257  Create a null-terminated unicode string from a null-terminated DOS
258  codepage string.
259  Return number of unicode chars copied, excluding the null character.
260  Unicode strings created are in little-endian format.
261 ********************************************************************/
262
263 size_t dos_struni2(char *dst, const char *src, size_t max_len)
264 {
265         size_t len = 0;
266
267         if (dst == NULL)
268                 return 0;
269
270         if (src != NULL) {
271                 for (; *src && len < max_len-2; len++, dst +=2) {
272                         size_t skip = skip_multibyte_char(*src);
273                         smb_ucs2_t val = (*src & 0xff);
274
275                         /*
276                          * If this is a multibyte character (and all DOS/Windows
277                          * codepages have at maximum 2 byte multibyte characters)
278                          * then work out the index value for the unicode conversion.
279                          */
280
281                         if (skip == 2)
282                                 val = ((val << 8) | src[1]);
283
284                         SSVAL(dst,0,doscp_to_ucs2[val]);
285                         if (skip)
286                                 src += skip;
287                         else
288                                 src++;
289                 }
290         }
291
292         SSVAL(dst,0,0);
293
294         return len;
295 }
296
297 /*******************************************************************
298  Return a DOS codepage version of a little-endian unicode string.
299  Hack alert: uses fixed buffer(s).
300 ********************************************************************/
301
302 char *dos_unistr(char *buf)
303 {
304         char *lbuf = lbufs[nexti];
305         uint16 *src = (uint16 *)buf;
306         char *p;
307
308         nexti = (nexti+1)%8;
309
310         for (p = lbuf; *src && p-lbuf < MAXUNI-3; src++) {
311                 uint16 ucs2_val = SVAL(src,0);
312                 uint16 cp_val = ucs2_to_doscp[ucs2_val];
313
314                 if (cp_val < 256)
315                         *p++ = (char)cp_val;
316                 else {
317                         *p++ = (cp_val >> 8) & 0xff;
318                         *p++ = (cp_val & 0xff);
319                 }
320         }
321
322         *p = 0;
323         return lbuf;
324 }
325
326 /*******************************************************************
327  Strcpy for unicode strings.  returns length (in num of wide chars)
328 ********************************************************************/
329
330 int unistrcpy(char *dst, char *src)
331 {
332         int num_wchars = 0;
333         uint16 *wsrc = (uint16 *)src;
334         uint16 *wdst = (uint16 *)dst;
335
336         while (*wsrc) {
337                 *wdst++ = *wsrc++;
338                 num_wchars++;
339         }
340         *wdst = 0;
341
342         return num_wchars;
343 }
344
345
346
347 /*******************************************************************
348  free any existing maps
349 ********************************************************************/
350 static void free_maps(smb_ucs2_t **pp_cp_to_ucs2, uint16 **pp_ucs2_to_cp)
351 {
352         /* this handles identity mappings where we share the pointer */
353         if (*pp_ucs2_to_cp == *pp_cp_to_ucs2) {
354                 *pp_ucs2_to_cp = NULL;
355         }
356
357         if (*pp_cp_to_ucs2) {
358                 free(*pp_cp_to_ucs2);
359                 *pp_cp_to_ucs2 = NULL;
360         }
361
362         if (*pp_ucs2_to_cp) {
363                 free(*pp_ucs2_to_cp);
364                 *pp_ucs2_to_cp = NULL;
365         }
366 }
367
368
369 /*******************************************************************
370  Build a default (null) codepage to unicode map.
371 ********************************************************************/
372
373 void default_unicode_map(smb_ucs2_t **pp_cp_to_ucs2, uint16 **pp_ucs2_to_cp)
374 {
375   int i;
376
377   free_maps(pp_cp_to_ucs2, pp_ucs2_to_cp);
378
379   if ((*pp_ucs2_to_cp = (uint16 *)malloc(2*65536)) == NULL) {
380     DEBUG(0,("default_unicode_map: malloc fail for ucs2_to_cp size %u.\n", 2*65536));
381     abort();
382   }
383
384   *pp_cp_to_ucs2 = *pp_ucs2_to_cp; /* Default map is an identity. */
385   for (i = 0; i < 65536; i++)
386     (*pp_cp_to_ucs2)[i] = i;
387 }
388
389 /*******************************************************************
390  Load a codepage to unicode and vica-versa map.
391 ********************************************************************/
392
393 BOOL load_unicode_map(const char *codepage, smb_ucs2_t **pp_cp_to_ucs2, uint16 **pp_ucs2_to_cp)
394 {
395   pstring unicode_map_file_name;
396   FILE *fp = NULL;
397   SMB_STRUCT_STAT st;
398   smb_ucs2_t *cp_to_ucs2 = *pp_cp_to_ucs2;
399   uint16 *ucs2_to_cp = *pp_ucs2_to_cp;
400   size_t cp_to_ucs2_size;
401   size_t ucs2_to_cp_size;
402   size_t i;
403   size_t size;
404   char buf[UNICODE_MAP_HEADER_SIZE];
405
406   DEBUG(5, ("load_unicode_map: loading unicode map for codepage %s.\n", codepage));
407
408   if (*codepage == '\0')
409     goto clean_and_exit;
410
411   if(strlen(CODEPAGEDIR) + 13 + strlen(codepage) > sizeof(unicode_map_file_name)) {
412     DEBUG(0,("load_unicode_map: filename too long to load\n"));
413     goto clean_and_exit;
414   }
415
416   pstrcpy(unicode_map_file_name, CODEPAGEDIR);
417   pstrcat(unicode_map_file_name, "/");
418   pstrcat(unicode_map_file_name, "unicode_map.");
419   pstrcat(unicode_map_file_name, codepage);
420
421   if(sys_stat(unicode_map_file_name,&st)!=0) {
422     DEBUG(0,("load_unicode_map: filename %s does not exist.\n",
423               unicode_map_file_name));
424     goto clean_and_exit;
425   }
426
427   size = st.st_size;
428
429   if ((size != UNICODE_MAP_HEADER_SIZE + 4*65536) && (size != UNICODE_MAP_HEADER_SIZE +(2*256 + 2*65536))) {
430     DEBUG(0,("load_unicode_map: file %s is an incorrect size for a \
431 unicode map file (size=%d).\n", unicode_map_file_name, (int)size));
432     goto clean_and_exit;
433   }
434
435   if((fp = sys_fopen( unicode_map_file_name, "r")) == NULL) {
436     DEBUG(0,("load_unicode_map: cannot open file %s. Error was %s\n",
437               unicode_map_file_name, strerror(errno)));
438     goto clean_and_exit;
439   }
440
441   if(fread( buf, 1, UNICODE_MAP_HEADER_SIZE, fp)!=UNICODE_MAP_HEADER_SIZE) {
442     DEBUG(0,("load_unicode_map: cannot read header from file %s. Error was %s\n",
443               unicode_map_file_name, strerror(errno)));
444     goto clean_and_exit;
445   }
446
447   /* Check the version value */
448   if(SVAL(buf,UNICODE_MAP_VERSION_OFFSET) != UNICODE_MAP_FILE_VERSION_ID) {
449     DEBUG(0,("load_unicode_map: filename %s has incorrect version id. \
450 Needed %hu, got %hu.\n",
451           unicode_map_file_name, (uint16)UNICODE_MAP_FILE_VERSION_ID,
452           SVAL(buf,UNICODE_MAP_VERSION_OFFSET)));
453     goto clean_and_exit;
454   }
455
456   /* Check the codepage value */
457   if(!strequal(&buf[UNICODE_MAP_CLIENT_CODEPAGE_OFFSET], codepage)) {
458     DEBUG(0,("load_unicode_map: codepage %s in file %s is not the same as that \
459 requested (%s).\n", &buf[UNICODE_MAP_CLIENT_CODEPAGE_OFFSET], unicode_map_file_name, codepage ));
460     goto clean_and_exit;
461   }
462
463   ucs2_to_cp_size = 2*65536;
464   if (size == UNICODE_MAP_HEADER_SIZE + 4*65536) {
465     /* 
466      * This is a multibyte code page.
467      */
468     cp_to_ucs2_size = 2*65536;
469   } else {
470     /*
471      * Single byte code page.
472      */
473     cp_to_ucs2_size = 2*256;
474   }
475
476   /* 
477    * Free any old translation tables.
478    */
479
480   free_maps(pp_cp_to_ucs2, pp_ucs2_to_cp);
481
482   if ((cp_to_ucs2 = (smb_ucs2_t *)malloc(cp_to_ucs2_size)) == NULL) {
483     DEBUG(0,("load_unicode_map: malloc fail for cp_to_ucs2 size %u.\n", cp_to_ucs2_size ));
484     goto clean_and_exit;
485   }
486
487   if ((ucs2_to_cp = (uint16 *)malloc(ucs2_to_cp_size)) == NULL) {
488     DEBUG(0,("load_unicode_map: malloc fail for ucs2_to_cp size %u.\n", ucs2_to_cp_size ));
489     goto clean_and_exit;
490   }
491
492   if(fread( (char *)cp_to_ucs2, 1, cp_to_ucs2_size, fp)!=cp_to_ucs2_size) {
493     DEBUG(0,("load_unicode_map: cannot read cp_to_ucs2 from file %s. Error was %s\n",
494               unicode_map_file_name, strerror(errno)));
495     goto clean_and_exit;
496   }
497
498   if(fread( (char *)ucs2_to_cp, 1, ucs2_to_cp_size, fp)!=ucs2_to_cp_size) {
499     DEBUG(0,("load_unicode_map: cannot read ucs2_to_cp from file %s. Error was %s\n",
500               unicode_map_file_name, strerror(errno)));
501     goto clean_and_exit;
502   }
503
504   /*
505    * Now ensure the 16 bit values are in the correct endianness.
506    */
507
508   for (i = 0; i < cp_to_ucs2_size/2; i++)
509     cp_to_ucs2[i] = SVAL(cp_to_ucs2,i*2);
510
511   for (i = 0; i < ucs2_to_cp_size/2; i++)
512     ucs2_to_cp[i] = SVAL(ucs2_to_cp,i*2);
513
514   fclose(fp);
515
516   *pp_cp_to_ucs2 = cp_to_ucs2;
517   *pp_ucs2_to_cp = ucs2_to_cp;
518
519   return True;
520
521 clean_and_exit:
522
523   /* pseudo destructor :-) */
524
525   if(fp != NULL)
526     fclose(fp);
527
528   free_maps(pp_cp_to_ucs2, pp_ucs2_to_cp);
529
530   default_unicode_map(pp_cp_to_ucs2, pp_ucs2_to_cp);
531
532   return False;
533 }
534
535 /*******************************************************************
536  Load a dos codepage to unicode and vica-versa map.
537 ********************************************************************/
538
539 BOOL load_dos_unicode_map(int codepage)
540 {
541   fstring codepage_str;
542
543   slprintf(codepage_str, sizeof(fstring)-1, "%03d", codepage);
544   return load_unicode_map(codepage_str, &doscp_to_ucs2, &ucs2_to_doscp);
545 }
546
547 /*******************************************************************
548  Load a UNIX codepage to unicode and vica-versa map.
549 ********************************************************************/
550
551 BOOL load_unix_unicode_map(const char *unix_char_set)
552 {
553   fstring upper_unix_char_set;
554
555   fstrcpy(upper_unix_char_set, unix_char_set);
556   strupper(upper_unix_char_set);
557   return load_unicode_map(upper_unix_char_set, &unixcp_to_ucs2, &ucs2_to_unixcp);
558 }