1*ba7b222eSGlenn Barry /* 2*ba7b222eSGlenn Barry * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 3*ba7b222eSGlenn Barry * Use is subject to license terms. 4*ba7b222eSGlenn Barry */ 5*ba7b222eSGlenn Barry 6*ba7b222eSGlenn Barry /* 7*ba7b222eSGlenn Barry * util/support/utf8_conv.c 8*ba7b222eSGlenn Barry * 9*ba7b222eSGlenn Barry * Copyright 2008 by the Massachusetts Institute of Technology. 10*ba7b222eSGlenn Barry * All Rights Reserved. 11*ba7b222eSGlenn Barry * 12*ba7b222eSGlenn Barry * Export of this software from the United States of America may 13*ba7b222eSGlenn Barry * require a specific license from the United States Government. 14*ba7b222eSGlenn Barry * It is the responsibility of any person or organization contemplating 15*ba7b222eSGlenn Barry * export to obtain such a license before exporting. 16*ba7b222eSGlenn Barry * 17*ba7b222eSGlenn Barry * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and 18*ba7b222eSGlenn Barry * distribute this software and its documentation for any purpose and 19*ba7b222eSGlenn Barry * without fee is hereby granted, provided that the above copyright 20*ba7b222eSGlenn Barry * notice appear in all copies and that both that copyright notice and 21*ba7b222eSGlenn Barry * this permission notice appear in supporting documentation, and that 22*ba7b222eSGlenn Barry * the name of M.I.T. not be used in advertising or publicity pertaining 23*ba7b222eSGlenn Barry * to distribution of the software without specific, written prior 24*ba7b222eSGlenn Barry * permission. Furthermore if you modify this software you must label 25*ba7b222eSGlenn Barry * your software as modified software and not distribute it in such a 26*ba7b222eSGlenn Barry * fashion that it might be confused with the original M.I.T. software. 27*ba7b222eSGlenn Barry * M.I.T. makes no representations about the suitability of 28*ba7b222eSGlenn Barry * this software for any purpose. It is provided "as is" without express 29*ba7b222eSGlenn Barry * or implied warranty. 30*ba7b222eSGlenn Barry */ 31*ba7b222eSGlenn Barry /* This work is part of OpenLDAP Software <http://www.openldap.org/>. 32*ba7b222eSGlenn Barry * 33*ba7b222eSGlenn Barry * Copyright 1998-2008 The OpenLDAP Foundation. 34*ba7b222eSGlenn Barry * All rights reserved. 35*ba7b222eSGlenn Barry * 36*ba7b222eSGlenn Barry * Redistribution and use in source and binary forms, with or without 37*ba7b222eSGlenn Barry * modification, are permitted only as authorized by the OpenLDAP 38*ba7b222eSGlenn Barry * Public License. 39*ba7b222eSGlenn Barry * 40*ba7b222eSGlenn Barry * A copy of this license is available in the file LICENSE in the 41*ba7b222eSGlenn Barry * top-level directory of the distribution or, alternatively, at 42*ba7b222eSGlenn Barry * <http://www.OpenLDAP.org/license.html>. 43*ba7b222eSGlenn Barry */ 44*ba7b222eSGlenn Barry /* Portions Copyright (C) 1999, 2000 Novell, Inc. All Rights Reserved. 45*ba7b222eSGlenn Barry * 46*ba7b222eSGlenn Barry * THIS WORK IS SUBJECT TO U.S. AND INTERNATIONAL COPYRIGHT LAWS AND 47*ba7b222eSGlenn Barry * TREATIES. USE, MODIFICATION, AND REDISTRIBUTION OF THIS WORK IS SUBJECT 48*ba7b222eSGlenn Barry * TO VERSION 2.0.1 OF THE OPENLDAP PUBLIC LICENSE, A COPY OF WHICH IS 49*ba7b222eSGlenn Barry * AVAILABLE AT HTTP://WWW.OPENLDAP.ORG/LICENSE.HTML OR IN THE FILE "LICENSE" 50*ba7b222eSGlenn Barry * IN THE TOP-LEVEL DIRECTORY OF THE DISTRIBUTION. ANY USE OR EXPLOITATION 51*ba7b222eSGlenn Barry * OF THIS WORK OTHER THAN AS AUTHORIZED IN VERSION 2.0.1 OF THE OPENLDAP 52*ba7b222eSGlenn Barry * PUBLIC LICENSE, OR OTHER PRIOR WRITTEN CONSENT FROM NOVELL, COULD SUBJECT 53*ba7b222eSGlenn Barry * THE PERPETRATOR TO CRIMINAL AND CIVIL LIABILITY. 54*ba7b222eSGlenn Barry */ 55*ba7b222eSGlenn Barry 56*ba7b222eSGlenn Barry /* 57*ba7b222eSGlenn Barry * UTF-8 Conversion Routines 58*ba7b222eSGlenn Barry * 59*ba7b222eSGlenn Barry * These routines convert between Wide Character and UTF-8, 60*ba7b222eSGlenn Barry * or between MultiByte and UTF-8 encodings. 61*ba7b222eSGlenn Barry * 62*ba7b222eSGlenn Barry * Both single character and string versions of the functions are provided. 63*ba7b222eSGlenn Barry * All functions return -1 if the character or string cannot be converted. 64*ba7b222eSGlenn Barry */ 65*ba7b222eSGlenn Barry 66*ba7b222eSGlenn Barry #include "k5-platform.h" 67*ba7b222eSGlenn Barry #include "k5-utf8.h" 68*ba7b222eSGlenn Barry #include "supp-int.h" 69*ba7b222eSGlenn Barry #include "errno.h" /* SUNW17PACresync */ 70*ba7b222eSGlenn Barry 71*ba7b222eSGlenn Barry static unsigned char mask[] = { 0, 0x7f, 0x1f, 0x0f, 0x07, 0x03, 0x01 }; 72*ba7b222eSGlenn Barry 73*ba7b222eSGlenn Barry static ssize_t 74*ba7b222eSGlenn Barry k5_utf8s_to_ucs2s(krb5_ucs2 *ucs2str, 75*ba7b222eSGlenn Barry const char *utf8str, 76*ba7b222eSGlenn Barry size_t count, 77*ba7b222eSGlenn Barry int little_endian) 78*ba7b222eSGlenn Barry { 79*ba7b222eSGlenn Barry size_t ucs2len = 0; 80*ba7b222eSGlenn Barry size_t utflen, i; 81*ba7b222eSGlenn Barry krb5_ucs2 ch; 82*ba7b222eSGlenn Barry 83*ba7b222eSGlenn Barry /* If input ptr is NULL or empty... */ 84*ba7b222eSGlenn Barry if (utf8str == NULL || *utf8str == '\0') { 85*ba7b222eSGlenn Barry *ucs2str = 0; 86*ba7b222eSGlenn Barry 87*ba7b222eSGlenn Barry return 0; 88*ba7b222eSGlenn Barry } 89*ba7b222eSGlenn Barry 90*ba7b222eSGlenn Barry /* Examine next UTF-8 character. */ 91*ba7b222eSGlenn Barry while (*utf8str && ucs2len < count) { 92*ba7b222eSGlenn Barry /* Get UTF-8 sequence length from 1st byte */ 93*ba7b222eSGlenn Barry utflen = KRB5_UTF8_CHARLEN2(utf8str, utflen); 94*ba7b222eSGlenn Barry 95*ba7b222eSGlenn Barry if (utflen == 0 || utflen > KRB5_MAX_UTF8_LEN) 96*ba7b222eSGlenn Barry return -1; 97*ba7b222eSGlenn Barry 98*ba7b222eSGlenn Barry /* First byte minus length tag */ 99*ba7b222eSGlenn Barry ch = (krb5_ucs2)(utf8str[0] & mask[utflen]); 100*ba7b222eSGlenn Barry 101*ba7b222eSGlenn Barry for (i = 1; i < utflen; i++) { 102*ba7b222eSGlenn Barry /* Subsequent bytes must start with 10 */ 103*ba7b222eSGlenn Barry if ((utf8str[i] & 0xc0) != 0x80) 104*ba7b222eSGlenn Barry return -1; 105*ba7b222eSGlenn Barry 106*ba7b222eSGlenn Barry ch <<= 6; /* 6 bits of data in each subsequent byte */ 107*ba7b222eSGlenn Barry ch |= (krb5_ucs2)(utf8str[i] & 0x3f); 108*ba7b222eSGlenn Barry } 109*ba7b222eSGlenn Barry 110*ba7b222eSGlenn Barry if (ucs2str != NULL) { 111*ba7b222eSGlenn Barry #ifdef K5_BE 112*ba7b222eSGlenn Barry #ifndef SWAP16 113*ba7b222eSGlenn Barry #define SWAP16(X) ((((X) << 8) | ((X) >> 8)) & 0xFFFF) 114*ba7b222eSGlenn Barry #endif 115*ba7b222eSGlenn Barry if (little_endian) 116*ba7b222eSGlenn Barry ucs2str[ucs2len] = SWAP16(ch); 117*ba7b222eSGlenn Barry else 118*ba7b222eSGlenn Barry #endif 119*ba7b222eSGlenn Barry ucs2str[ucs2len] = ch; 120*ba7b222eSGlenn Barry } 121*ba7b222eSGlenn Barry 122*ba7b222eSGlenn Barry utf8str += utflen; /* Move to next UTF-8 character */ 123*ba7b222eSGlenn Barry ucs2len++; /* Count number of wide chars stored/required */ 124*ba7b222eSGlenn Barry } 125*ba7b222eSGlenn Barry 126*ba7b222eSGlenn Barry assert(ucs2len < count); 127*ba7b222eSGlenn Barry 128*ba7b222eSGlenn Barry if (ucs2str != NULL) { 129*ba7b222eSGlenn Barry /* Add null terminator if there's room in the buffer. */ 130*ba7b222eSGlenn Barry ucs2str[ucs2len] = 0; 131*ba7b222eSGlenn Barry } 132*ba7b222eSGlenn Barry 133*ba7b222eSGlenn Barry return ucs2len; 134*ba7b222eSGlenn Barry } 135*ba7b222eSGlenn Barry 136*ba7b222eSGlenn Barry int 137*ba7b222eSGlenn Barry krb5int_utf8s_to_ucs2s(const char *utf8s, 138*ba7b222eSGlenn Barry krb5_ucs2 **ucs2s, 139*ba7b222eSGlenn Barry size_t *ucs2chars) 140*ba7b222eSGlenn Barry { 141*ba7b222eSGlenn Barry ssize_t len; 142*ba7b222eSGlenn Barry size_t chars; 143*ba7b222eSGlenn Barry 144*ba7b222eSGlenn Barry chars = krb5int_utf8_chars(utf8s); 145*ba7b222eSGlenn Barry *ucs2s = (krb5_ucs2 *)malloc((chars + 1) * sizeof(krb5_ucs2)); 146*ba7b222eSGlenn Barry if (*ucs2s == NULL) { 147*ba7b222eSGlenn Barry return ENOMEM; 148*ba7b222eSGlenn Barry } 149*ba7b222eSGlenn Barry 150*ba7b222eSGlenn Barry len = k5_utf8s_to_ucs2s(*ucs2s, utf8s, chars + 1, 0); 151*ba7b222eSGlenn Barry if (len < 0) { 152*ba7b222eSGlenn Barry free(*ucs2s); 153*ba7b222eSGlenn Barry *ucs2s = NULL; 154*ba7b222eSGlenn Barry return EINVAL; 155*ba7b222eSGlenn Barry } 156*ba7b222eSGlenn Barry 157*ba7b222eSGlenn Barry if (ucs2chars != NULL) { 158*ba7b222eSGlenn Barry *ucs2chars = chars; 159*ba7b222eSGlenn Barry } 160*ba7b222eSGlenn Barry 161*ba7b222eSGlenn Barry return 0; 162*ba7b222eSGlenn Barry } 163*ba7b222eSGlenn Barry 164*ba7b222eSGlenn Barry int 165*ba7b222eSGlenn Barry krb5int_utf8cs_to_ucs2s(const char *utf8s, 166*ba7b222eSGlenn Barry size_t utf8slen, 167*ba7b222eSGlenn Barry krb5_ucs2 **ucs2s, 168*ba7b222eSGlenn Barry size_t *ucs2chars) 169*ba7b222eSGlenn Barry { 170*ba7b222eSGlenn Barry ssize_t len; 171*ba7b222eSGlenn Barry size_t chars; 172*ba7b222eSGlenn Barry 173*ba7b222eSGlenn Barry chars = krb5int_utf8c_chars(utf8s, utf8slen); 174*ba7b222eSGlenn Barry *ucs2s = (krb5_ucs2 *)malloc((chars + 1) * sizeof(krb5_ucs2)); 175*ba7b222eSGlenn Barry if (*ucs2s == NULL) { 176*ba7b222eSGlenn Barry return ENOMEM; 177*ba7b222eSGlenn Barry } 178*ba7b222eSGlenn Barry 179*ba7b222eSGlenn Barry len = k5_utf8s_to_ucs2s(*ucs2s, utf8s, chars + 1, 0); 180*ba7b222eSGlenn Barry if (len < 0) { 181*ba7b222eSGlenn Barry free(*ucs2s); 182*ba7b222eSGlenn Barry *ucs2s = NULL; 183*ba7b222eSGlenn Barry return EINVAL; 184*ba7b222eSGlenn Barry } 185*ba7b222eSGlenn Barry 186*ba7b222eSGlenn Barry if (ucs2chars != NULL) { 187*ba7b222eSGlenn Barry *ucs2chars = chars; 188*ba7b222eSGlenn Barry } 189*ba7b222eSGlenn Barry 190*ba7b222eSGlenn Barry return 0; 191*ba7b222eSGlenn Barry } 192*ba7b222eSGlenn Barry 193*ba7b222eSGlenn Barry int 194*ba7b222eSGlenn Barry krb5int_utf8s_to_ucs2les(const char *utf8s, 195*ba7b222eSGlenn Barry unsigned char **ucs2les, 196*ba7b222eSGlenn Barry size_t *ucs2leslen) 197*ba7b222eSGlenn Barry { 198*ba7b222eSGlenn Barry ssize_t len; 199*ba7b222eSGlenn Barry size_t chars; 200*ba7b222eSGlenn Barry 201*ba7b222eSGlenn Barry chars = krb5int_utf8_chars(utf8s); 202*ba7b222eSGlenn Barry 203*ba7b222eSGlenn Barry *ucs2les = (unsigned char *)malloc((chars + 1) * sizeof(krb5_ucs2)); 204*ba7b222eSGlenn Barry if (*ucs2les == NULL) { 205*ba7b222eSGlenn Barry return ENOMEM; 206*ba7b222eSGlenn Barry } 207*ba7b222eSGlenn Barry 208*ba7b222eSGlenn Barry len = k5_utf8s_to_ucs2s((krb5_ucs2 *)*ucs2les, utf8s, chars + 1, 1); 209*ba7b222eSGlenn Barry if (len < 0) { 210*ba7b222eSGlenn Barry free(*ucs2les); 211*ba7b222eSGlenn Barry *ucs2les = NULL; 212*ba7b222eSGlenn Barry return EINVAL; 213*ba7b222eSGlenn Barry } 214*ba7b222eSGlenn Barry 215*ba7b222eSGlenn Barry if (ucs2leslen != NULL) { 216*ba7b222eSGlenn Barry *ucs2leslen = chars * sizeof(krb5_ucs2); 217*ba7b222eSGlenn Barry } 218*ba7b222eSGlenn Barry 219*ba7b222eSGlenn Barry return 0; 220*ba7b222eSGlenn Barry } 221*ba7b222eSGlenn Barry 222*ba7b222eSGlenn Barry int 223*ba7b222eSGlenn Barry krb5int_utf8cs_to_ucs2les(const char *utf8s, 224*ba7b222eSGlenn Barry size_t utf8slen, 225*ba7b222eSGlenn Barry unsigned char **ucs2les, 226*ba7b222eSGlenn Barry size_t *ucs2leslen) 227*ba7b222eSGlenn Barry { 228*ba7b222eSGlenn Barry ssize_t len; 229*ba7b222eSGlenn Barry size_t chars; 230*ba7b222eSGlenn Barry 231*ba7b222eSGlenn Barry chars = krb5int_utf8c_chars(utf8s, utf8slen); 232*ba7b222eSGlenn Barry 233*ba7b222eSGlenn Barry *ucs2les = (unsigned char *)malloc((chars + 1) * sizeof(krb5_ucs2)); 234*ba7b222eSGlenn Barry if (*ucs2les == NULL) { 235*ba7b222eSGlenn Barry return ENOMEM; 236*ba7b222eSGlenn Barry } 237*ba7b222eSGlenn Barry 238*ba7b222eSGlenn Barry len = k5_utf8s_to_ucs2s((krb5_ucs2 *)*ucs2les, utf8s, chars + 1, 1); 239*ba7b222eSGlenn Barry if (len < 0) { 240*ba7b222eSGlenn Barry free(*ucs2les); 241*ba7b222eSGlenn Barry *ucs2les = NULL; 242*ba7b222eSGlenn Barry return EINVAL; 243*ba7b222eSGlenn Barry } 244*ba7b222eSGlenn Barry 245*ba7b222eSGlenn Barry if (ucs2leslen != NULL) { 246*ba7b222eSGlenn Barry *ucs2leslen = chars * sizeof(krb5_ucs2); 247*ba7b222eSGlenn Barry } 248*ba7b222eSGlenn Barry 249*ba7b222eSGlenn Barry return 0; 250*ba7b222eSGlenn Barry } 251*ba7b222eSGlenn Barry 252*ba7b222eSGlenn Barry /*----------------------------------------------------------------------------- 253*ba7b222eSGlenn Barry Convert a wide char string to a UTF-8 string. 254*ba7b222eSGlenn Barry No more than 'count' bytes will be written to the output buffer. 255*ba7b222eSGlenn Barry Return the # of bytes written to the output buffer, excl null terminator. 256*ba7b222eSGlenn Barry 257*ba7b222eSGlenn Barry ucs2len is -1 if the UCS-2 string is NUL terminated, otherwise it is the 258*ba7b222eSGlenn Barry length of the UCS-2 string in characters 259*ba7b222eSGlenn Barry */ 260*ba7b222eSGlenn Barry static ssize_t 261*ba7b222eSGlenn Barry k5_ucs2s_to_utf8s(char *utf8str, const krb5_ucs2 *ucs2str, 262*ba7b222eSGlenn Barry size_t count, ssize_t ucs2len, int little_endian) 263*ba7b222eSGlenn Barry { 264*ba7b222eSGlenn Barry int len = 0; 265*ba7b222eSGlenn Barry int n; 266*ba7b222eSGlenn Barry char *p = utf8str; 267*ba7b222eSGlenn Barry krb5_ucs2 empty = 0, ch; 268*ba7b222eSGlenn Barry 269*ba7b222eSGlenn Barry if (ucs2str == NULL) /* Treat input ptr NULL as an empty string */ 270*ba7b222eSGlenn Barry ucs2str = ∅ 271*ba7b222eSGlenn Barry 272*ba7b222eSGlenn Barry if (utf8str == NULL) /* Just compute size of output, excl null */ 273*ba7b222eSGlenn Barry { 274*ba7b222eSGlenn Barry while (ucs2len == -1 ? *ucs2str : --ucs2len >= 0) { 275*ba7b222eSGlenn Barry /* Get UTF-8 size of next wide char */ 276*ba7b222eSGlenn Barry ch = *ucs2str++; 277*ba7b222eSGlenn Barry #ifdef K5_BE 278*ba7b222eSGlenn Barry if (little_endian) 279*ba7b222eSGlenn Barry ch = SWAP16(ch); 280*ba7b222eSGlenn Barry #endif 281*ba7b222eSGlenn Barry 282*ba7b222eSGlenn Barry n = krb5int_ucs2_to_utf8(ch, NULL); 283*ba7b222eSGlenn Barry if (n < 1) 284*ba7b222eSGlenn Barry return -1; 285*ba7b222eSGlenn Barry if (len + n < len) 286*ba7b222eSGlenn Barry return -1; /* overflow */ 287*ba7b222eSGlenn Barry len += n; 288*ba7b222eSGlenn Barry } 289*ba7b222eSGlenn Barry 290*ba7b222eSGlenn Barry return len; 291*ba7b222eSGlenn Barry } 292*ba7b222eSGlenn Barry 293*ba7b222eSGlenn Barry /* Do the actual conversion. */ 294*ba7b222eSGlenn Barry 295*ba7b222eSGlenn Barry n = 1; /* In case of empty ucs2str */ 296*ba7b222eSGlenn Barry while (ucs2len == -1 ? *ucs2str != 0 : --ucs2len >= 0) { 297*ba7b222eSGlenn Barry ch = *ucs2str++; 298*ba7b222eSGlenn Barry #ifdef K5_BE 299*ba7b222eSGlenn Barry if (little_endian) 300*ba7b222eSGlenn Barry ch = SWAP16(ch); 301*ba7b222eSGlenn Barry #endif 302*ba7b222eSGlenn Barry 303*ba7b222eSGlenn Barry n = krb5int_ucs2_to_utf8(ch, p); 304*ba7b222eSGlenn Barry 305*ba7b222eSGlenn Barry if (n < 1) 306*ba7b222eSGlenn Barry break; 307*ba7b222eSGlenn Barry 308*ba7b222eSGlenn Barry p += n; 309*ba7b222eSGlenn Barry count -= n; /* Space left in output buffer */ 310*ba7b222eSGlenn Barry } 311*ba7b222eSGlenn Barry 312*ba7b222eSGlenn Barry /* If not enough room for last character, pad remainder with null 313*ba7b222eSGlenn Barry so that return value = original count, indicating buffer full. */ 314*ba7b222eSGlenn Barry if (n == 0) { 315*ba7b222eSGlenn Barry while (count--) 316*ba7b222eSGlenn Barry *p++ = 0; 317*ba7b222eSGlenn Barry } 318*ba7b222eSGlenn Barry /* Add a null terminator if there's room. */ 319*ba7b222eSGlenn Barry else if (count) 320*ba7b222eSGlenn Barry *p = 0; 321*ba7b222eSGlenn Barry 322*ba7b222eSGlenn Barry if (n == -1) /* Conversion encountered invalid wide char. */ 323*ba7b222eSGlenn Barry return -1; 324*ba7b222eSGlenn Barry 325*ba7b222eSGlenn Barry /* Return the number of bytes written to output buffer, excl null. */ 326*ba7b222eSGlenn Barry return (p - utf8str); 327*ba7b222eSGlenn Barry } 328*ba7b222eSGlenn Barry 329*ba7b222eSGlenn Barry int 330*ba7b222eSGlenn Barry krb5int_ucs2s_to_utf8s(const krb5_ucs2 *ucs2s, 331*ba7b222eSGlenn Barry char **utf8s, 332*ba7b222eSGlenn Barry size_t *utf8slen) 333*ba7b222eSGlenn Barry { 334*ba7b222eSGlenn Barry ssize_t len; 335*ba7b222eSGlenn Barry 336*ba7b222eSGlenn Barry len = k5_ucs2s_to_utf8s(NULL, ucs2s, 0, -1, 0); 337*ba7b222eSGlenn Barry if (len < 0) { 338*ba7b222eSGlenn Barry return EINVAL; 339*ba7b222eSGlenn Barry } 340*ba7b222eSGlenn Barry 341*ba7b222eSGlenn Barry *utf8s = (char *)malloc((size_t)len + 1); 342*ba7b222eSGlenn Barry if (*utf8s == NULL) { 343*ba7b222eSGlenn Barry return ENOMEM; 344*ba7b222eSGlenn Barry } 345*ba7b222eSGlenn Barry 346*ba7b222eSGlenn Barry len = k5_ucs2s_to_utf8s(*utf8s, ucs2s, (size_t)len + 1, -1, 0); 347*ba7b222eSGlenn Barry if (len < 0) { 348*ba7b222eSGlenn Barry free(*utf8s); 349*ba7b222eSGlenn Barry *utf8s = NULL; 350*ba7b222eSGlenn Barry return EINVAL; 351*ba7b222eSGlenn Barry } 352*ba7b222eSGlenn Barry 353*ba7b222eSGlenn Barry if (utf8slen != NULL) { 354*ba7b222eSGlenn Barry *utf8slen = len; 355*ba7b222eSGlenn Barry } 356*ba7b222eSGlenn Barry 357*ba7b222eSGlenn Barry return 0; 358*ba7b222eSGlenn Barry } 359*ba7b222eSGlenn Barry 360*ba7b222eSGlenn Barry int 361*ba7b222eSGlenn Barry krb5int_ucs2les_to_utf8s(const unsigned char *ucs2les, 362*ba7b222eSGlenn Barry char **utf8s, 363*ba7b222eSGlenn Barry size_t *utf8slen) 364*ba7b222eSGlenn Barry { 365*ba7b222eSGlenn Barry ssize_t len; 366*ba7b222eSGlenn Barry 367*ba7b222eSGlenn Barry len = k5_ucs2s_to_utf8s(NULL, (krb5_ucs2 *)ucs2les, 0, -1, 1); 368*ba7b222eSGlenn Barry if (len < 0) 369*ba7b222eSGlenn Barry return EINVAL; 370*ba7b222eSGlenn Barry 371*ba7b222eSGlenn Barry *utf8s = (char *)malloc((size_t)len + 1); 372*ba7b222eSGlenn Barry if (*utf8s == NULL) { 373*ba7b222eSGlenn Barry return ENOMEM; 374*ba7b222eSGlenn Barry } 375*ba7b222eSGlenn Barry 376*ba7b222eSGlenn Barry len = k5_ucs2s_to_utf8s(*utf8s, (krb5_ucs2 *)ucs2les, (size_t)len + 1, -1, 1); 377*ba7b222eSGlenn Barry if (len < 0) { 378*ba7b222eSGlenn Barry free(*utf8s); 379*ba7b222eSGlenn Barry *utf8s = NULL; 380*ba7b222eSGlenn Barry return EINVAL; 381*ba7b222eSGlenn Barry } 382*ba7b222eSGlenn Barry 383*ba7b222eSGlenn Barry if (utf8slen != NULL) { 384*ba7b222eSGlenn Barry *utf8slen = len; 385*ba7b222eSGlenn Barry } 386*ba7b222eSGlenn Barry 387*ba7b222eSGlenn Barry return 0; 388*ba7b222eSGlenn Barry } 389*ba7b222eSGlenn Barry 390*ba7b222eSGlenn Barry int 391*ba7b222eSGlenn Barry krb5int_ucs2cs_to_utf8s(const krb5_ucs2 *ucs2s, 392*ba7b222eSGlenn Barry size_t ucs2slen, 393*ba7b222eSGlenn Barry char **utf8s, 394*ba7b222eSGlenn Barry size_t *utf8slen) 395*ba7b222eSGlenn Barry { 396*ba7b222eSGlenn Barry ssize_t len; 397*ba7b222eSGlenn Barry 398*ba7b222eSGlenn Barry if (ucs2slen > SSIZE_MAX) 399*ba7b222eSGlenn Barry return ERANGE; 400*ba7b222eSGlenn Barry 401*ba7b222eSGlenn Barry len = k5_ucs2s_to_utf8s(NULL, (krb5_ucs2 *)ucs2s, 0, 402*ba7b222eSGlenn Barry (ssize_t)ucs2slen, 0); 403*ba7b222eSGlenn Barry if (len < 0) 404*ba7b222eSGlenn Barry return EINVAL; 405*ba7b222eSGlenn Barry 406*ba7b222eSGlenn Barry *utf8s = (char *)malloc((size_t)len + 1); 407*ba7b222eSGlenn Barry if (*utf8s == NULL) { 408*ba7b222eSGlenn Barry return ENOMEM; 409*ba7b222eSGlenn Barry } 410*ba7b222eSGlenn Barry 411*ba7b222eSGlenn Barry len = k5_ucs2s_to_utf8s(*utf8s, (krb5_ucs2 *)ucs2s, 412*ba7b222eSGlenn Barry (size_t)len + 1, (ssize_t)ucs2slen, 0); 413*ba7b222eSGlenn Barry if (len < 0) { 414*ba7b222eSGlenn Barry free(*utf8s); 415*ba7b222eSGlenn Barry *utf8s = NULL; 416*ba7b222eSGlenn Barry return EINVAL; 417*ba7b222eSGlenn Barry } 418*ba7b222eSGlenn Barry 419*ba7b222eSGlenn Barry if (utf8slen != NULL) { 420*ba7b222eSGlenn Barry *utf8slen = len; 421*ba7b222eSGlenn Barry } 422*ba7b222eSGlenn Barry 423*ba7b222eSGlenn Barry return 0; 424*ba7b222eSGlenn Barry } 425*ba7b222eSGlenn Barry 426*ba7b222eSGlenn Barry int 427*ba7b222eSGlenn Barry krb5int_ucs2lecs_to_utf8s(const unsigned char *ucs2les, 428*ba7b222eSGlenn Barry size_t ucs2leslen, 429*ba7b222eSGlenn Barry char **utf8s, 430*ba7b222eSGlenn Barry size_t *utf8slen) 431*ba7b222eSGlenn Barry { 432*ba7b222eSGlenn Barry ssize_t len; 433*ba7b222eSGlenn Barry 434*ba7b222eSGlenn Barry if (ucs2leslen > SSIZE_MAX) 435*ba7b222eSGlenn Barry return ERANGE; 436*ba7b222eSGlenn Barry 437*ba7b222eSGlenn Barry len = k5_ucs2s_to_utf8s(NULL, (krb5_ucs2 *)ucs2les, 0, 438*ba7b222eSGlenn Barry (ssize_t)ucs2leslen, 1); 439*ba7b222eSGlenn Barry if (len < 0) 440*ba7b222eSGlenn Barry return EINVAL; 441*ba7b222eSGlenn Barry 442*ba7b222eSGlenn Barry *utf8s = (char *)malloc((size_t)len + 1); 443*ba7b222eSGlenn Barry if (*utf8s == NULL) { 444*ba7b222eSGlenn Barry return ENOMEM; 445*ba7b222eSGlenn Barry } 446*ba7b222eSGlenn Barry 447*ba7b222eSGlenn Barry len = k5_ucs2s_to_utf8s(*utf8s, (krb5_ucs2 *)ucs2les, 448*ba7b222eSGlenn Barry (size_t)len + 1, (ssize_t)ucs2leslen, 1); 449*ba7b222eSGlenn Barry if (len < 0) { 450*ba7b222eSGlenn Barry free(*utf8s); 451*ba7b222eSGlenn Barry *utf8s = NULL; 452*ba7b222eSGlenn Barry return EINVAL; 453*ba7b222eSGlenn Barry } 454*ba7b222eSGlenn Barry 455*ba7b222eSGlenn Barry if (utf8slen != NULL) { 456*ba7b222eSGlenn Barry *utf8slen = len; 457*ba7b222eSGlenn Barry } 458*ba7b222eSGlenn Barry 459*ba7b222eSGlenn Barry return 0; 460*ba7b222eSGlenn Barry } 461*ba7b222eSGlenn Barry 462