Home | History | Annotate | Line # | Download | only in libldap
utf-8-conv.c revision 1.1.1.1.6.2
      1  1.1.1.1.6.2  wrstuden /* $OpenLDAP: pkg/ldap/libraries/libldap/utf-8-conv.c,v 1.16.2.3 2008/02/11 23:26:41 kurt Exp $ */
      2  1.1.1.1.6.2  wrstuden /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
      3  1.1.1.1.6.2  wrstuden  *
      4  1.1.1.1.6.2  wrstuden  * Copyright 1998-2008 The OpenLDAP Foundation.
      5  1.1.1.1.6.2  wrstuden  * All rights reserved.
      6  1.1.1.1.6.2  wrstuden  *
      7  1.1.1.1.6.2  wrstuden  * Redistribution and use in source and binary forms, with or without
      8  1.1.1.1.6.2  wrstuden  * modification, are permitted only as authorized by the OpenLDAP
      9  1.1.1.1.6.2  wrstuden  * Public License.
     10  1.1.1.1.6.2  wrstuden  *
     11  1.1.1.1.6.2  wrstuden  * A copy of this license is available in the file LICENSE in the
     12  1.1.1.1.6.2  wrstuden  * top-level directory of the distribution or, alternatively, at
     13  1.1.1.1.6.2  wrstuden  * <http://www.OpenLDAP.org/license.html>.
     14  1.1.1.1.6.2  wrstuden  */
     15  1.1.1.1.6.2  wrstuden /* Portions Copyright (C) 1999, 2000 Novell, Inc. All Rights Reserved.
     16  1.1.1.1.6.2  wrstuden  *
     17  1.1.1.1.6.2  wrstuden  * THIS WORK IS SUBJECT TO U.S. AND INTERNATIONAL COPYRIGHT LAWS AND
     18  1.1.1.1.6.2  wrstuden  * TREATIES. USE, MODIFICATION, AND REDISTRIBUTION OF THIS WORK IS SUBJECT
     19  1.1.1.1.6.2  wrstuden  * TO VERSION 2.0.1 OF THE OPENLDAP PUBLIC LICENSE, A COPY OF WHICH IS
     20  1.1.1.1.6.2  wrstuden  * AVAILABLE AT HTTP://WWW.OPENLDAP.ORG/LICENSE.HTML OR IN THE FILE "LICENSE"
     21  1.1.1.1.6.2  wrstuden  * IN THE TOP-LEVEL DIRECTORY OF THE DISTRIBUTION. ANY USE OR EXPLOITATION
     22  1.1.1.1.6.2  wrstuden  * OF THIS WORK OTHER THAN AS AUTHORIZED IN VERSION 2.0.1 OF THE OPENLDAP
     23  1.1.1.1.6.2  wrstuden  * PUBLIC LICENSE, OR OTHER PRIOR WRITTEN CONSENT FROM NOVELL, COULD SUBJECT
     24  1.1.1.1.6.2  wrstuden  * THE PERPETRATOR TO CRIMINAL AND CIVIL LIABILITY.
     25  1.1.1.1.6.2  wrstuden  *---
     26  1.1.1.1.6.2  wrstuden  * Note: A verbatim copy of version 2.0.1 of the OpenLDAP Public License
     27  1.1.1.1.6.2  wrstuden  * can be found in the file "build/LICENSE-2.0.1" in this distribution
     28  1.1.1.1.6.2  wrstuden  * of OpenLDAP Software.
     29  1.1.1.1.6.2  wrstuden  */
     30  1.1.1.1.6.2  wrstuden 
     31  1.1.1.1.6.2  wrstuden /*
     32  1.1.1.1.6.2  wrstuden  * UTF-8 Conversion Routines
     33  1.1.1.1.6.2  wrstuden  *
     34  1.1.1.1.6.2  wrstuden  * These routines convert between Wide Character and UTF-8,
     35  1.1.1.1.6.2  wrstuden  * or between MultiByte and UTF-8 encodings.
     36  1.1.1.1.6.2  wrstuden  *
     37  1.1.1.1.6.2  wrstuden  * Both single character and string versions of the functions are provided.
     38  1.1.1.1.6.2  wrstuden  * All functions return -1 if the character or string cannot be converted.
     39  1.1.1.1.6.2  wrstuden  */
     40  1.1.1.1.6.2  wrstuden 
     41  1.1.1.1.6.2  wrstuden #include "portable.h"
     42  1.1.1.1.6.2  wrstuden 
     43  1.1.1.1.6.2  wrstuden #if SIZEOF_WCHAR_T >= 4
     44  1.1.1.1.6.2  wrstuden /* These routines assume ( sizeof(wchar_t) >= 4 ) */
     45  1.1.1.1.6.2  wrstuden 
     46  1.1.1.1.6.2  wrstuden #include <stdio.h>
     47  1.1.1.1.6.2  wrstuden #include <ac/stdlib.h>		/* For wctomb, wcstombs, mbtowc, mbstowcs */
     48  1.1.1.1.6.2  wrstuden #include <ac/string.h>
     49  1.1.1.1.6.2  wrstuden #include <ac/time.h>		/* for time_t */
     50  1.1.1.1.6.2  wrstuden 
     51  1.1.1.1.6.2  wrstuden #include "ldap-int.h"
     52  1.1.1.1.6.2  wrstuden 
     53  1.1.1.1.6.2  wrstuden #include <ldap_utf8.h>
     54  1.1.1.1.6.2  wrstuden 
     55  1.1.1.1.6.2  wrstuden static unsigned char mask[] = { 0, 0x7f, 0x1f, 0x0f, 0x07, 0x03, 0x01 };
     56  1.1.1.1.6.2  wrstuden 
     57  1.1.1.1.6.2  wrstuden 
     58  1.1.1.1.6.2  wrstuden /*-----------------------------------------------------------------------------
     59  1.1.1.1.6.2  wrstuden 					UTF-8 Format Summary
     60  1.1.1.1.6.2  wrstuden 
     61  1.1.1.1.6.2  wrstuden ASCII chars 						7 bits
     62  1.1.1.1.6.2  wrstuden     0xxxxxxx
     63  1.1.1.1.6.2  wrstuden 
     64  1.1.1.1.6.2  wrstuden 2-character UTF-8 sequence:        11 bits
     65  1.1.1.1.6.2  wrstuden     110xxxxx  10xxxxxx
     66  1.1.1.1.6.2  wrstuden 
     67  1.1.1.1.6.2  wrstuden 3-character UTF-8                  16 bits
     68  1.1.1.1.6.2  wrstuden     1110xxxx  10xxxxxx  10xxxxxx
     69  1.1.1.1.6.2  wrstuden 
     70  1.1.1.1.6.2  wrstuden 4-char UTF-8                       21 bits
     71  1.1.1.1.6.2  wrstuden     11110xxx  10xxxxxx  10xxxxxx  10xxxxxx
     72  1.1.1.1.6.2  wrstuden 
     73  1.1.1.1.6.2  wrstuden 5-char UTF-8                       26 bits
     74  1.1.1.1.6.2  wrstuden     111110xx  10xxxxxx  10xxxxxx  10xxxxxx  10xxxxxx
     75  1.1.1.1.6.2  wrstuden 
     76  1.1.1.1.6.2  wrstuden 6-char UTF-8                       31 bits
     77  1.1.1.1.6.2  wrstuden     1111110x  10xxxxxx  10xxxxxx  10xxxxxx  10xxxxxx  10xxxxxx
     78  1.1.1.1.6.2  wrstuden 
     79  1.1.1.1.6.2  wrstuden Unicode address space   (0 - 0x10FFFF)    21 bits
     80  1.1.1.1.6.2  wrstuden ISO-10646 address space (0 - 0x7FFFFFFF)  31 bits
     81  1.1.1.1.6.2  wrstuden 
     82  1.1.1.1.6.2  wrstuden Note: This code does not prevent UTF-8 sequences which are longer than
     83  1.1.1.1.6.2  wrstuden       necessary from being decoded.
     84  1.1.1.1.6.2  wrstuden */
     85  1.1.1.1.6.2  wrstuden 
     86  1.1.1.1.6.2  wrstuden /*-----------------------------------------------------------------------------
     87  1.1.1.1.6.2  wrstuden    Convert a UTF-8 character to a wide char.
     88  1.1.1.1.6.2  wrstuden    Return the length of the UTF-8 input character in bytes.
     89  1.1.1.1.6.2  wrstuden */
     90  1.1.1.1.6.2  wrstuden int
     91  1.1.1.1.6.2  wrstuden ldap_x_utf8_to_wc ( wchar_t *wchar, const char *utf8char )
     92  1.1.1.1.6.2  wrstuden {
     93  1.1.1.1.6.2  wrstuden 	int utflen, i;
     94  1.1.1.1.6.2  wrstuden 	wchar_t ch;
     95  1.1.1.1.6.2  wrstuden 
     96  1.1.1.1.6.2  wrstuden 	if (utf8char == NULL) return -1;
     97  1.1.1.1.6.2  wrstuden 
     98  1.1.1.1.6.2  wrstuden 	/* Get UTF-8 sequence length from 1st byte */
     99  1.1.1.1.6.2  wrstuden 	utflen = LDAP_UTF8_CHARLEN2(utf8char, utflen);
    100  1.1.1.1.6.2  wrstuden 
    101  1.1.1.1.6.2  wrstuden 	if( utflen==0 || utflen > (int)LDAP_MAX_UTF8_LEN ) return -1;
    102  1.1.1.1.6.2  wrstuden 
    103  1.1.1.1.6.2  wrstuden 	/* First byte minus length tag */
    104  1.1.1.1.6.2  wrstuden 	ch = (wchar_t)(utf8char[0] & mask[utflen]);
    105  1.1.1.1.6.2  wrstuden 
    106  1.1.1.1.6.2  wrstuden 	for(i=1; i < utflen; i++) {
    107  1.1.1.1.6.2  wrstuden 		/* Subsequent bytes must start with 10 */
    108  1.1.1.1.6.2  wrstuden 		if ((utf8char[i] & 0xc0) != 0x80) return -1;
    109  1.1.1.1.6.2  wrstuden 
    110  1.1.1.1.6.2  wrstuden 		ch <<= 6;			/* 6 bits of data in each subsequent byte */
    111  1.1.1.1.6.2  wrstuden 		ch |= (wchar_t)(utf8char[i] & 0x3f);
    112  1.1.1.1.6.2  wrstuden 	}
    113  1.1.1.1.6.2  wrstuden 
    114  1.1.1.1.6.2  wrstuden 	if (wchar) *wchar = ch;
    115  1.1.1.1.6.2  wrstuden 
    116  1.1.1.1.6.2  wrstuden 	return utflen;
    117  1.1.1.1.6.2  wrstuden }
    118  1.1.1.1.6.2  wrstuden 
    119  1.1.1.1.6.2  wrstuden /*-----------------------------------------------------------------------------
    120  1.1.1.1.6.2  wrstuden    Convert a UTF-8 string to a wide char string.
    121  1.1.1.1.6.2  wrstuden    No more than 'count' wide chars will be written to the output buffer.
    122  1.1.1.1.6.2  wrstuden    Return the size of the converted string in wide chars, excl null terminator.
    123  1.1.1.1.6.2  wrstuden */
    124  1.1.1.1.6.2  wrstuden int
    125  1.1.1.1.6.2  wrstuden ldap_x_utf8s_to_wcs ( wchar_t *wcstr, const char *utf8str, size_t count )
    126  1.1.1.1.6.2  wrstuden {
    127  1.1.1.1.6.2  wrstuden 	size_t wclen = 0;
    128  1.1.1.1.6.2  wrstuden 	int utflen, i;
    129  1.1.1.1.6.2  wrstuden 	wchar_t ch;
    130  1.1.1.1.6.2  wrstuden 
    131  1.1.1.1.6.2  wrstuden 
    132  1.1.1.1.6.2  wrstuden 	/* If input ptr is NULL or empty... */
    133  1.1.1.1.6.2  wrstuden 	if (utf8str == NULL || !*utf8str) {
    134  1.1.1.1.6.2  wrstuden 		if ( wcstr )
    135  1.1.1.1.6.2  wrstuden 			*wcstr = 0;
    136  1.1.1.1.6.2  wrstuden 		return 0;
    137  1.1.1.1.6.2  wrstuden 	}
    138  1.1.1.1.6.2  wrstuden 
    139  1.1.1.1.6.2  wrstuden 	/* Examine next UTF-8 character.  If output buffer is NULL, ignore count */
    140  1.1.1.1.6.2  wrstuden 	while ( *utf8str && (wcstr==NULL || wclen<count) ) {
    141  1.1.1.1.6.2  wrstuden 		/* Get UTF-8 sequence length from 1st byte */
    142  1.1.1.1.6.2  wrstuden 		utflen = LDAP_UTF8_CHARLEN2(utf8str, utflen);
    143  1.1.1.1.6.2  wrstuden 
    144  1.1.1.1.6.2  wrstuden 		if( utflen==0 || utflen > (int)LDAP_MAX_UTF8_LEN ) return -1;
    145  1.1.1.1.6.2  wrstuden 
    146  1.1.1.1.6.2  wrstuden 		/* First byte minus length tag */
    147  1.1.1.1.6.2  wrstuden 		ch = (wchar_t)(utf8str[0] & mask[utflen]);
    148  1.1.1.1.6.2  wrstuden 
    149  1.1.1.1.6.2  wrstuden 		for(i=1; i < utflen; i++) {
    150  1.1.1.1.6.2  wrstuden 			/* Subsequent bytes must start with 10 */
    151  1.1.1.1.6.2  wrstuden 			if ((utf8str[i] & 0xc0) != 0x80) return -1;
    152  1.1.1.1.6.2  wrstuden 
    153  1.1.1.1.6.2  wrstuden 			ch <<= 6;			/* 6 bits of data in each subsequent byte */
    154  1.1.1.1.6.2  wrstuden 			ch |= (wchar_t)(utf8str[i] & 0x3f);
    155  1.1.1.1.6.2  wrstuden 		}
    156  1.1.1.1.6.2  wrstuden 
    157  1.1.1.1.6.2  wrstuden 		if (wcstr) wcstr[wclen] = ch;
    158  1.1.1.1.6.2  wrstuden 
    159  1.1.1.1.6.2  wrstuden 		utf8str += utflen;	/* Move to next UTF-8 character */
    160  1.1.1.1.6.2  wrstuden 		wclen++;			/* Count number of wide chars stored/required */
    161  1.1.1.1.6.2  wrstuden 	}
    162  1.1.1.1.6.2  wrstuden 
    163  1.1.1.1.6.2  wrstuden 	/* Add null terminator if there's room in the buffer. */
    164  1.1.1.1.6.2  wrstuden 	if (wcstr && wclen < count) wcstr[wclen] = 0;
    165  1.1.1.1.6.2  wrstuden 
    166  1.1.1.1.6.2  wrstuden 	return wclen;
    167  1.1.1.1.6.2  wrstuden }
    168  1.1.1.1.6.2  wrstuden 
    169  1.1.1.1.6.2  wrstuden 
    170  1.1.1.1.6.2  wrstuden /*-----------------------------------------------------------------------------
    171  1.1.1.1.6.2  wrstuden    Convert one wide char to a UTF-8 character.
    172  1.1.1.1.6.2  wrstuden    Return the length of the converted UTF-8 character in bytes.
    173  1.1.1.1.6.2  wrstuden    No more than 'count' bytes will be written to the output buffer.
    174  1.1.1.1.6.2  wrstuden */
    175  1.1.1.1.6.2  wrstuden int
    176  1.1.1.1.6.2  wrstuden ldap_x_wc_to_utf8 ( char *utf8char, wchar_t wchar, size_t count )
    177  1.1.1.1.6.2  wrstuden {
    178  1.1.1.1.6.2  wrstuden 	int len=0;
    179  1.1.1.1.6.2  wrstuden 
    180  1.1.1.1.6.2  wrstuden 	if (utf8char == NULL)   /* Just determine the required UTF-8 char length. */
    181  1.1.1.1.6.2  wrstuden 	{						/* Ignore count */
    182  1.1.1.1.6.2  wrstuden 		if( wchar < 0 )
    183  1.1.1.1.6.2  wrstuden 			return -1;
    184  1.1.1.1.6.2  wrstuden 		if( wchar < 0x80 )
    185  1.1.1.1.6.2  wrstuden 			return 1;
    186  1.1.1.1.6.2  wrstuden 		if( wchar < 0x800 )
    187  1.1.1.1.6.2  wrstuden 			return 2;
    188  1.1.1.1.6.2  wrstuden 		if( wchar < 0x10000 )
    189  1.1.1.1.6.2  wrstuden 			return 3;
    190  1.1.1.1.6.2  wrstuden 		if( wchar < 0x200000 )
    191  1.1.1.1.6.2  wrstuden 			return 4;
    192  1.1.1.1.6.2  wrstuden 		if( wchar < 0x4000000 )
    193  1.1.1.1.6.2  wrstuden 			return 5;
    194  1.1.1.1.6.2  wrstuden 		if( wchar < 0x80000000 )
    195  1.1.1.1.6.2  wrstuden 			return 6;
    196  1.1.1.1.6.2  wrstuden 		return -1;
    197  1.1.1.1.6.2  wrstuden 	}
    198  1.1.1.1.6.2  wrstuden 
    199  1.1.1.1.6.2  wrstuden 
    200  1.1.1.1.6.2  wrstuden 	if ( wchar < 0 ) {				/* Invalid wide character */
    201  1.1.1.1.6.2  wrstuden 		len = -1;
    202  1.1.1.1.6.2  wrstuden 
    203  1.1.1.1.6.2  wrstuden 	} else if( wchar < 0x80 ) {
    204  1.1.1.1.6.2  wrstuden 		if (count >= 1) {
    205  1.1.1.1.6.2  wrstuden 			utf8char[len++] = (char)wchar;
    206  1.1.1.1.6.2  wrstuden 		}
    207  1.1.1.1.6.2  wrstuden 
    208  1.1.1.1.6.2  wrstuden 	} else if( wchar < 0x800 ) {
    209  1.1.1.1.6.2  wrstuden 		if (count >=2) {
    210  1.1.1.1.6.2  wrstuden 			utf8char[len++] = 0xc0 | ( wchar >> 6 );
    211  1.1.1.1.6.2  wrstuden 			utf8char[len++] = 0x80 | ( wchar & 0x3f );
    212  1.1.1.1.6.2  wrstuden 		}
    213  1.1.1.1.6.2  wrstuden 
    214  1.1.1.1.6.2  wrstuden 	} else if( wchar < 0x10000 ) {
    215  1.1.1.1.6.2  wrstuden 		if (count >= 3) {
    216  1.1.1.1.6.2  wrstuden 			utf8char[len++] = 0xe0 | ( wchar >> 12 );
    217  1.1.1.1.6.2  wrstuden 			utf8char[len++] = 0x80 | ( (wchar >> 6) & 0x3f );
    218  1.1.1.1.6.2  wrstuden 			utf8char[len++] = 0x80 | ( wchar & 0x3f );
    219  1.1.1.1.6.2  wrstuden 		}
    220  1.1.1.1.6.2  wrstuden 
    221  1.1.1.1.6.2  wrstuden 	} else if( wchar < 0x200000 ) {
    222  1.1.1.1.6.2  wrstuden 		if (count >= 4) {
    223  1.1.1.1.6.2  wrstuden 			utf8char[len++] = 0xf0 | ( wchar >> 18 );
    224  1.1.1.1.6.2  wrstuden 			utf8char[len++] = 0x80 | ( (wchar >> 12) & 0x3f );
    225  1.1.1.1.6.2  wrstuden 			utf8char[len++] = 0x80 | ( (wchar >> 6) & 0x3f );
    226  1.1.1.1.6.2  wrstuden 			utf8char[len++] = 0x80 | ( wchar & 0x3f );
    227  1.1.1.1.6.2  wrstuden 		}
    228  1.1.1.1.6.2  wrstuden 
    229  1.1.1.1.6.2  wrstuden 	} else if( wchar < 0x4000000 ) {
    230  1.1.1.1.6.2  wrstuden 		if (count >= 5) {
    231  1.1.1.1.6.2  wrstuden 			utf8char[len++] = 0xf8 | ( wchar >> 24 );
    232  1.1.1.1.6.2  wrstuden 			utf8char[len++] = 0x80 | ( (wchar >> 18) & 0x3f );
    233  1.1.1.1.6.2  wrstuden 			utf8char[len++] = 0x80 | ( (wchar >> 12) & 0x3f );
    234  1.1.1.1.6.2  wrstuden 			utf8char[len++] = 0x80 | ( (wchar >> 6) & 0x3f );
    235  1.1.1.1.6.2  wrstuden 			utf8char[len++] = 0x80 | ( wchar & 0x3f );
    236  1.1.1.1.6.2  wrstuden 		}
    237  1.1.1.1.6.2  wrstuden 
    238  1.1.1.1.6.2  wrstuden 	} else if( wchar < 0x80000000 ) {
    239  1.1.1.1.6.2  wrstuden 		if (count >= 6) {
    240  1.1.1.1.6.2  wrstuden 			utf8char[len++] = 0xfc | ( wchar >> 30 );
    241  1.1.1.1.6.2  wrstuden 			utf8char[len++] = 0x80 | ( (wchar >> 24) & 0x3f );
    242  1.1.1.1.6.2  wrstuden 			utf8char[len++] = 0x80 | ( (wchar >> 18) & 0x3f );
    243  1.1.1.1.6.2  wrstuden 			utf8char[len++] = 0x80 | ( (wchar >> 12) & 0x3f );
    244  1.1.1.1.6.2  wrstuden 			utf8char[len++] = 0x80 | ( (wchar >> 6) & 0x3f );
    245  1.1.1.1.6.2  wrstuden 			utf8char[len++] = 0x80 | ( wchar & 0x3f );
    246  1.1.1.1.6.2  wrstuden 		}
    247  1.1.1.1.6.2  wrstuden 
    248  1.1.1.1.6.2  wrstuden 	} else
    249  1.1.1.1.6.2  wrstuden 		len = -1;
    250  1.1.1.1.6.2  wrstuden 
    251  1.1.1.1.6.2  wrstuden 	return len;
    252  1.1.1.1.6.2  wrstuden 
    253  1.1.1.1.6.2  wrstuden }
    254  1.1.1.1.6.2  wrstuden 
    255  1.1.1.1.6.2  wrstuden 
    256  1.1.1.1.6.2  wrstuden /*-----------------------------------------------------------------------------
    257  1.1.1.1.6.2  wrstuden    Convert a wide char string to a UTF-8 string.
    258  1.1.1.1.6.2  wrstuden    No more than 'count' bytes will be written to the output buffer.
    259  1.1.1.1.6.2  wrstuden    Return the # of bytes written to the output buffer, excl null terminator.
    260  1.1.1.1.6.2  wrstuden */
    261  1.1.1.1.6.2  wrstuden int
    262  1.1.1.1.6.2  wrstuden ldap_x_wcs_to_utf8s ( char *utf8str, const wchar_t *wcstr, size_t count )
    263  1.1.1.1.6.2  wrstuden {
    264  1.1.1.1.6.2  wrstuden 	int len = 0;
    265  1.1.1.1.6.2  wrstuden 	int n;
    266  1.1.1.1.6.2  wrstuden 	char *p = utf8str;
    267  1.1.1.1.6.2  wrstuden 	wchar_t empty = 0;		/* To avoid use of L"" construct */
    268  1.1.1.1.6.2  wrstuden 
    269  1.1.1.1.6.2  wrstuden 	if (wcstr == NULL)		/* Treat input ptr NULL as an empty string */
    270  1.1.1.1.6.2  wrstuden 		wcstr = &empty;
    271  1.1.1.1.6.2  wrstuden 
    272  1.1.1.1.6.2  wrstuden 	if (utf8str == NULL)	/* Just compute size of output, excl null */
    273  1.1.1.1.6.2  wrstuden 	{
    274  1.1.1.1.6.2  wrstuden 		while (*wcstr)
    275  1.1.1.1.6.2  wrstuden 		{
    276  1.1.1.1.6.2  wrstuden 			/* Get UTF-8 size of next wide char */
    277  1.1.1.1.6.2  wrstuden 			n = ldap_x_wc_to_utf8( NULL, *wcstr++, LDAP_MAX_UTF8_LEN);
    278  1.1.1.1.6.2  wrstuden 			if (n == -1)
    279  1.1.1.1.6.2  wrstuden 				return -1;
    280  1.1.1.1.6.2  wrstuden 			len += n;
    281  1.1.1.1.6.2  wrstuden 		}
    282  1.1.1.1.6.2  wrstuden 
    283  1.1.1.1.6.2  wrstuden 		return len;
    284  1.1.1.1.6.2  wrstuden 	}
    285  1.1.1.1.6.2  wrstuden 
    286  1.1.1.1.6.2  wrstuden 
    287  1.1.1.1.6.2  wrstuden 	/* Do the actual conversion. */
    288  1.1.1.1.6.2  wrstuden 
    289  1.1.1.1.6.2  wrstuden 	n = 1;					/* In case of empty wcstr */
    290  1.1.1.1.6.2  wrstuden 	while (*wcstr)
    291  1.1.1.1.6.2  wrstuden 	{
    292  1.1.1.1.6.2  wrstuden 		n = ldap_x_wc_to_utf8( p, *wcstr++, count);
    293  1.1.1.1.6.2  wrstuden 
    294  1.1.1.1.6.2  wrstuden 		if (n <= 0)  		/* If encoding error (-1) or won't fit (0), quit */
    295  1.1.1.1.6.2  wrstuden 			break;
    296  1.1.1.1.6.2  wrstuden 
    297  1.1.1.1.6.2  wrstuden 		p += n;
    298  1.1.1.1.6.2  wrstuden 		count -= n;			/* Space left in output buffer */
    299  1.1.1.1.6.2  wrstuden 	}
    300  1.1.1.1.6.2  wrstuden 
    301  1.1.1.1.6.2  wrstuden 	/* If not enough room for last character, pad remainder with null
    302  1.1.1.1.6.2  wrstuden 	   so that return value = original count, indicating buffer full. */
    303  1.1.1.1.6.2  wrstuden 	if (n == 0)
    304  1.1.1.1.6.2  wrstuden 	{
    305  1.1.1.1.6.2  wrstuden 		while (count--)
    306  1.1.1.1.6.2  wrstuden 			*p++ = 0;
    307  1.1.1.1.6.2  wrstuden 	}
    308  1.1.1.1.6.2  wrstuden 
    309  1.1.1.1.6.2  wrstuden 	/* Add a null terminator if there's room. */
    310  1.1.1.1.6.2  wrstuden 	else if (count)
    311  1.1.1.1.6.2  wrstuden 		*p = 0;
    312  1.1.1.1.6.2  wrstuden 
    313  1.1.1.1.6.2  wrstuden 	if (n == -1)			/* Conversion encountered invalid wide char. */
    314  1.1.1.1.6.2  wrstuden 		return -1;
    315  1.1.1.1.6.2  wrstuden 
    316  1.1.1.1.6.2  wrstuden 	/* Return the number of bytes written to output buffer, excl null. */
    317  1.1.1.1.6.2  wrstuden 	return (p - utf8str);
    318  1.1.1.1.6.2  wrstuden }
    319  1.1.1.1.6.2  wrstuden 
    320  1.1.1.1.6.2  wrstuden 
    321  1.1.1.1.6.2  wrstuden /*-----------------------------------------------------------------------------
    322  1.1.1.1.6.2  wrstuden    Convert a UTF-8 character to a MultiByte character.
    323  1.1.1.1.6.2  wrstuden    Return the size of the converted character in bytes.
    324  1.1.1.1.6.2  wrstuden */
    325  1.1.1.1.6.2  wrstuden int
    326  1.1.1.1.6.2  wrstuden ldap_x_utf8_to_mb ( char *mbchar, const char *utf8char,
    327  1.1.1.1.6.2  wrstuden 		int (*f_wctomb)(char *mbchar, wchar_t wchar) )
    328  1.1.1.1.6.2  wrstuden {
    329  1.1.1.1.6.2  wrstuden 	wchar_t wchar;
    330  1.1.1.1.6.2  wrstuden 	int n;
    331  1.1.1.1.6.2  wrstuden 	char tmp[6];				/* Large enough for biggest multibyte char */
    332  1.1.1.1.6.2  wrstuden 
    333  1.1.1.1.6.2  wrstuden 	if (f_wctomb == NULL)		/* If no conversion function was given... */
    334  1.1.1.1.6.2  wrstuden 		f_wctomb = wctomb;		/*    use the local ANSI C function */
    335  1.1.1.1.6.2  wrstuden 
    336  1.1.1.1.6.2  wrstuden 	/* First convert UTF-8 char to a wide char */
    337  1.1.1.1.6.2  wrstuden 	n = ldap_x_utf8_to_wc( &wchar, utf8char);
    338  1.1.1.1.6.2  wrstuden 
    339  1.1.1.1.6.2  wrstuden 	if (n == -1)
    340  1.1.1.1.6.2  wrstuden 		return -1;		/* Invalid UTF-8 character */
    341  1.1.1.1.6.2  wrstuden 
    342  1.1.1.1.6.2  wrstuden 	if (mbchar == NULL)
    343  1.1.1.1.6.2  wrstuden 		n = f_wctomb( tmp, wchar );
    344  1.1.1.1.6.2  wrstuden 	else
    345  1.1.1.1.6.2  wrstuden 		n = f_wctomb( mbchar, wchar);
    346  1.1.1.1.6.2  wrstuden 
    347  1.1.1.1.6.2  wrstuden 	return n;
    348  1.1.1.1.6.2  wrstuden }
    349  1.1.1.1.6.2  wrstuden 
    350  1.1.1.1.6.2  wrstuden /*-----------------------------------------------------------------------------
    351  1.1.1.1.6.2  wrstuden    Convert a UTF-8 string to a MultiByte string.
    352  1.1.1.1.6.2  wrstuden    No more than 'count' bytes will be written to the output buffer.
    353  1.1.1.1.6.2  wrstuden    Return the size of the converted string in bytes, excl null terminator.
    354  1.1.1.1.6.2  wrstuden */
    355  1.1.1.1.6.2  wrstuden int
    356  1.1.1.1.6.2  wrstuden ldap_x_utf8s_to_mbs ( char *mbstr, const char *utf8str, size_t count,
    357  1.1.1.1.6.2  wrstuden 		size_t (*f_wcstombs)(char *mbstr, const wchar_t *wcstr, size_t count) )
    358  1.1.1.1.6.2  wrstuden {
    359  1.1.1.1.6.2  wrstuden 	wchar_t *wcs;
    360  1.1.1.1.6.2  wrstuden 	size_t wcsize;
    361  1.1.1.1.6.2  wrstuden     int n;
    362  1.1.1.1.6.2  wrstuden 
    363  1.1.1.1.6.2  wrstuden 	if (f_wcstombs == NULL)		/* If no conversion function was given... */
    364  1.1.1.1.6.2  wrstuden 		f_wcstombs = wcstombs;	/*    use the local ANSI C function */
    365  1.1.1.1.6.2  wrstuden 
    366  1.1.1.1.6.2  wrstuden 	if (utf8str == NULL || *utf8str == 0)	/* NULL or empty input string */
    367  1.1.1.1.6.2  wrstuden 	{
    368  1.1.1.1.6.2  wrstuden 		if (mbstr)
    369  1.1.1.1.6.2  wrstuden 			*mbstr = 0;
    370  1.1.1.1.6.2  wrstuden 		return 0;
    371  1.1.1.1.6.2  wrstuden 	}
    372  1.1.1.1.6.2  wrstuden 
    373  1.1.1.1.6.2  wrstuden /* Allocate memory for the maximum size wchar string that we could get. */
    374  1.1.1.1.6.2  wrstuden 	wcsize = strlen(utf8str) + 1;
    375  1.1.1.1.6.2  wrstuden 	wcs = (wchar_t *)LDAP_MALLOC(wcsize * sizeof(wchar_t));
    376  1.1.1.1.6.2  wrstuden 	if (wcs == NULL)
    377  1.1.1.1.6.2  wrstuden 		return -1;				/* Memory allocation failure. */
    378  1.1.1.1.6.2  wrstuden 
    379  1.1.1.1.6.2  wrstuden 	/* First convert the UTF-8 string to a wide char string */
    380  1.1.1.1.6.2  wrstuden 	n = ldap_x_utf8s_to_wcs( wcs, utf8str, wcsize);
    381  1.1.1.1.6.2  wrstuden 
    382  1.1.1.1.6.2  wrstuden 	/* Then convert wide char string to multi-byte string */
    383  1.1.1.1.6.2  wrstuden 	if (n != -1)
    384  1.1.1.1.6.2  wrstuden 	{
    385  1.1.1.1.6.2  wrstuden 		n = f_wcstombs(mbstr, wcs, count);
    386  1.1.1.1.6.2  wrstuden 	}
    387  1.1.1.1.6.2  wrstuden 
    388  1.1.1.1.6.2  wrstuden 	LDAP_FREE(wcs);
    389  1.1.1.1.6.2  wrstuden 
    390  1.1.1.1.6.2  wrstuden 	return n;
    391  1.1.1.1.6.2  wrstuden }
    392  1.1.1.1.6.2  wrstuden 
    393  1.1.1.1.6.2  wrstuden /*-----------------------------------------------------------------------------
    394  1.1.1.1.6.2  wrstuden    Convert a MultiByte character to a UTF-8 character.
    395  1.1.1.1.6.2  wrstuden    'mbsize' indicates the number of bytes of 'mbchar' to check.
    396  1.1.1.1.6.2  wrstuden    Returns the number of bytes written to the output character.
    397  1.1.1.1.6.2  wrstuden */
    398  1.1.1.1.6.2  wrstuden int
    399  1.1.1.1.6.2  wrstuden ldap_x_mb_to_utf8 ( char *utf8char, const char *mbchar, size_t mbsize,
    400  1.1.1.1.6.2  wrstuden 		int (*f_mbtowc)(wchar_t *wchar, const char *mbchar, size_t count) )
    401  1.1.1.1.6.2  wrstuden {
    402  1.1.1.1.6.2  wrstuden     wchar_t wchar;
    403  1.1.1.1.6.2  wrstuden     int n;
    404  1.1.1.1.6.2  wrstuden 
    405  1.1.1.1.6.2  wrstuden 	if (f_mbtowc == NULL)		/* If no conversion function was given... */
    406  1.1.1.1.6.2  wrstuden 		f_mbtowc = mbtowc;		/*    use the local ANSI C function */
    407  1.1.1.1.6.2  wrstuden 
    408  1.1.1.1.6.2  wrstuden     if (mbsize == 0)				/* 0 is not valid. */
    409  1.1.1.1.6.2  wrstuden         return -1;
    410  1.1.1.1.6.2  wrstuden 
    411  1.1.1.1.6.2  wrstuden     if (mbchar == NULL || *mbchar == 0)
    412  1.1.1.1.6.2  wrstuden     {
    413  1.1.1.1.6.2  wrstuden         if (utf8char)
    414  1.1.1.1.6.2  wrstuden             *utf8char = 0;
    415  1.1.1.1.6.2  wrstuden         return 1;
    416  1.1.1.1.6.2  wrstuden     }
    417  1.1.1.1.6.2  wrstuden 
    418  1.1.1.1.6.2  wrstuden 	/* First convert the MB char to a Wide Char */
    419  1.1.1.1.6.2  wrstuden 	n = f_mbtowc( &wchar, mbchar, mbsize);
    420  1.1.1.1.6.2  wrstuden 
    421  1.1.1.1.6.2  wrstuden 	if (n == -1)
    422  1.1.1.1.6.2  wrstuden 		return -1;
    423  1.1.1.1.6.2  wrstuden 
    424  1.1.1.1.6.2  wrstuden 	/* Convert the Wide Char to a UTF-8 character. */
    425  1.1.1.1.6.2  wrstuden 	n = ldap_x_wc_to_utf8( utf8char, wchar, LDAP_MAX_UTF8_LEN);
    426  1.1.1.1.6.2  wrstuden 
    427  1.1.1.1.6.2  wrstuden 	return n;
    428  1.1.1.1.6.2  wrstuden }
    429  1.1.1.1.6.2  wrstuden 
    430  1.1.1.1.6.2  wrstuden 
    431  1.1.1.1.6.2  wrstuden /*-----------------------------------------------------------------------------
    432  1.1.1.1.6.2  wrstuden    Convert a MultiByte string to a UTF-8 string.
    433  1.1.1.1.6.2  wrstuden    No more than 'count' bytes will be written to the output buffer.
    434  1.1.1.1.6.2  wrstuden    Return the size of the converted string in bytes, excl null terminator.
    435  1.1.1.1.6.2  wrstuden */
    436  1.1.1.1.6.2  wrstuden int
    437  1.1.1.1.6.2  wrstuden ldap_x_mbs_to_utf8s ( char *utf8str, const char *mbstr, size_t count,
    438  1.1.1.1.6.2  wrstuden 		size_t (*f_mbstowcs)(wchar_t *wcstr, const char *mbstr, size_t count) )
    439  1.1.1.1.6.2  wrstuden {
    440  1.1.1.1.6.2  wrstuden 	wchar_t *wcs;
    441  1.1.1.1.6.2  wrstuden 	int n;
    442  1.1.1.1.6.2  wrstuden 	size_t wcsize;
    443  1.1.1.1.6.2  wrstuden 
    444  1.1.1.1.6.2  wrstuden 	if (mbstr == NULL)		   /* Treat NULL input string as an empty string */
    445  1.1.1.1.6.2  wrstuden 		mbstr = "";
    446  1.1.1.1.6.2  wrstuden 
    447  1.1.1.1.6.2  wrstuden 	if (f_mbstowcs == NULL)		/* If no conversion function was given... */
    448  1.1.1.1.6.2  wrstuden 		f_mbstowcs = mbstowcs;	/*    use the local ANSI C function */
    449  1.1.1.1.6.2  wrstuden 
    450  1.1.1.1.6.2  wrstuden 	/* Allocate memory for the maximum size wchar string that we could get. */
    451  1.1.1.1.6.2  wrstuden 	wcsize = strlen(mbstr) + 1;
    452  1.1.1.1.6.2  wrstuden 	wcs = (wchar_t *)LDAP_MALLOC( wcsize * sizeof(wchar_t) );
    453  1.1.1.1.6.2  wrstuden 	if (wcs == NULL)
    454  1.1.1.1.6.2  wrstuden 		return -1;
    455  1.1.1.1.6.2  wrstuden 
    456  1.1.1.1.6.2  wrstuden 	/* First convert multi-byte string to a wide char string */
    457  1.1.1.1.6.2  wrstuden 	n = f_mbstowcs(wcs, mbstr, wcsize);
    458  1.1.1.1.6.2  wrstuden 
    459  1.1.1.1.6.2  wrstuden 	/* Convert wide char string to UTF-8 string */
    460  1.1.1.1.6.2  wrstuden 	if (n != -1)
    461  1.1.1.1.6.2  wrstuden 	{
    462  1.1.1.1.6.2  wrstuden 		n = ldap_x_wcs_to_utf8s( utf8str, wcs, count);
    463  1.1.1.1.6.2  wrstuden 	}
    464  1.1.1.1.6.2  wrstuden 
    465  1.1.1.1.6.2  wrstuden 	LDAP_FREE(wcs);
    466  1.1.1.1.6.2  wrstuden 
    467  1.1.1.1.6.2  wrstuden 	return n;
    468  1.1.1.1.6.2  wrstuden }
    469  1.1.1.1.6.2  wrstuden 
    470  1.1.1.1.6.2  wrstuden #endif
    471