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