/*
*
* Copyright 2008 by the Massachusetts Institute of Technology.
* All Rights Reserved.
*
* Export of this software from the United States of America may
* require a specific license from the United States Government.
* It is the responsibility of any person or organization contemplating
* export to obtain such a license before exporting.
*
* WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
* distribute this software and its documentation for any purpose and
* without fee is hereby granted, provided that the above copyright
* notice appear in all copies and that both that copyright notice and
* this permission notice appear in supporting documentation, and that
* the name of M.I.T. not be used in advertising or publicity pertaining
* to distribution of the software without specific, written prior
* permission. Furthermore if you modify this software you must label
* your software as modified software and not distribute it in such a
* fashion that it might be confused with the original M.I.T. software.
* M.I.T. makes no representations about the suitability of
* this software for any purpose. It is provided "as is" without express
* or implied warranty.
*/
/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
*
* Copyright 1998-2008 The OpenLDAP Foundation.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted only as authorized by the OpenLDAP
* Public License.
*
* A copy of this license is available in the file LICENSE in the
* top-level directory of the distribution or, alternatively, at
*/
/* Basic UTF-8 routines
*
* These routines are "dumb". Though they understand UTF-8,
* they don't grok Unicode. That is, they can push bits,
* but don't have a clue what the bits represent. That's
* good enough for use with the KRB5 Client SDK.
*
* These routines are not optimized.
*/
#include "k5-platform.h"
#include "k5-utf8.h"
#include "supp-int.h"
/*
* return the number of bytes required to hold the
* NULL-terminated UTF-8 string NOT INCLUDING the
* termination.
*/
{
;
return bytes;
}
{
/* could be optimized and could check for invalid sequences */
for ( ; *p ; KRB5_UTF8_INCR(p))
chars++;
return chars;
}
{
/* could be optimized and could check for invalid sequences */
for ( ; p < end; KRB5_UTF8_INCR(p))
chars++;
return chars;
}
/* return offset to next character */
int krb5int_utf8_offset(const char *p)
{
return KRB5_UTF8_NEXT(p) - p;
}
/*
* Returns length indicated by first byte.
*/
const char krb5int_utf8_lentab[] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 0, 0 };
int krb5int_utf8_charlen(const char *p)
{
if (!(*p & 0x80))
return 1;
return krb5int_utf8_lentab[*(const unsigned char *)p ^ 0x80];
}
/*
* Make sure the UTF-8 char used the shortest possible encoding
* returns charlen if valid, 0 if not.
*
* Here are the valid UTF-8 encodings, taken from RFC 2279 page 4.
* The table is slightly modified from that of the RFC.
*
* UCS-4 range (hex) UTF-8 sequence (binary)
* 0000 0000-0000 007F 0.......
* 0000 0080-0000 07FF 110++++. 10......
* 0000 0800-0000 FFFF 1110++++ 10+..... 10......
* 0001 0000-001F FFFF 11110+++ 10++.... 10...... 10......
* 0020 0000-03FF FFFF 111110++ 10+++... 10...... 10...... 10......
* 0400 0000-7FFF FFFF 1111110+ 10++++.. 10...... 10...... 10...... 10......
*
* The '.' bits are "don't cares". When validating a UTF-8 sequence,
* at least one of the '+' bits must be set, otherwise the character
* should have been encoded in fewer octets. Note that in the two-octet
* case, only the first octet needs to be validated, and this is done
* in the krb5int_utf8_lentab[] above.
*/
/* mask of required bits in second octet */
#undef c
#define c const char
c krb5int_utf8_mintab[] = {
(c)0x20, (c)0x80, (c)0x80, (c)0x80, (c)0x80, (c)0x80, (c)0x80, (c)0x80,
(c)0x80, (c)0x80, (c)0x80, (c)0x80, (c)0x80, (c)0x80, (c)0x80, (c)0x80,
(c)0x30, (c)0x80, (c)0x80, (c)0x80, (c)0x80, (c)0x80, (c)0x80, (c)0x80,
(c)0x38, (c)0x80, (c)0x80, (c)0x80, (c)0x3c, (c)0x80, (c)0x00, (c)0x00 };
#undef c
int krb5int_utf8_charlen2(const char *p)
{
int i = KRB5_UTF8_CHARLEN(p);
if (i > 2) {
i = 0;
}
return i;
}
/*
* Convert a UTF8 character to a UCS4 character. Return 0 on success,
* -1 on failure.
*/
{
const unsigned char *c = (const unsigned char *) p;
int len, i;
static unsigned char mask[] = {
0, 0x7f, 0x1f, 0x0f, 0x07, 0x03, 0x01 };
*out = 0;
if (len == 0)
return -1;
for (i = 1; i < len; i++) {
if ((c[i] & 0xc0) != 0x80)
return -1;
ch <<= 6;
ch |= c[i] & 0x3f;
}
return 0;
}
{
*out = 0;
return -1;
return 0;
}
/* conv UCS-2 to UTF-8, not used */
{
unsigned char *p = (unsigned char *) buf;
/* not a valid Unicode character */
if (c < 0)
return 0;
/* Just return length, don't convert */
if (c < 0x80) return 1;
else if (c < 0x800) return 2;
else if (c < 0x10000) return 3;
else if (c < 0x200000) return 4;
else if (c < 0x4000000) return 5;
else return 6;
}
if (c < 0x80) {
p[len++] = c;
} else if (c < 0x800) {
} else if (c < 0x10000) {
} else if (c < 0x200000) {
} else if (c < 0x4000000) {
} else /* if( c < 0x80000000 ) */ {
}
return len;
}
{
}
#define KRB5_UCS_UTF8LEN(c) \
c < 0 ? 0 : (c < 0x80 ? 1 : (c < 0x800 ? 2 : (c < 0x10000 ? 3 : \
(c < 0x200000 ? 4 : (c < 0x4000000 ? 5 : 6)))))
/*
* Advance to the next UTF-8 character
*
* Ignores length of multibyte character, instead rely on
* continuation markers to find start of next character.
* This allows for "resyncing" of when invalid characters
* are provided provided the start of the next character
* is appears within the 6 bytes examined.
*/
char *krb5int_utf8_next(const char *p)
{
int i;
const unsigned char *u = (const unsigned char *) p;
if (KRB5_UTF8_ISASCII(u)) {
return (char *) &p[1];
}
for (i = 1; i < 6; i++) {
if ((u[i] & 0xc0) != 0x80) {
return (char *) &p[i];
}
}
return (char *) &p[i];
}
/*
* Advance to the previous UTF-8 character
*
* Ignores length of multibyte character, instead rely on
* continuation markers to find start of next character.
* This allows for "resyncing" of when invalid characters
* are provided provided the start of the next character
* is appears within the 6 bytes examined.
*/
char *krb5int_utf8_prev(const char *p)
{
int i;
const unsigned char *u = (const unsigned char *) p;
for (i = -1; i>-6 ; i--) {
if ((u[i] & 0xc0 ) != 0x80) {
return (char *) &p[i];
}
}
return (char *) &p[i];
}
/*
* Copy one UTF-8 character from src to dst returning
* number of bytes copied.
*
* Ignores length of multibyte character, instead rely on
* continuation markers to find start of next character.
* This allows for "resyncing" of when invalid characters
* are provided provided the start of the next character
* is appears within the 6 bytes examined.
*/
{
int i;
const unsigned char *u = (const unsigned char *) src;
if (KRB5_UTF8_ISASCII(u)) {
return 1;
}
for (i=1; i<6; i++) {
if ((u[i] & 0xc0) != 0x80) {
return i;
}
}
return i;
}
#ifndef UTF8_ALPHA_CTYPE
/*
* UTF-8 ctype routines
* Only deals with characters < 0x80 (ie: US-ASCII)
*/
int krb5int_utf8_isascii(const char * p)
{
unsigned c = * (const unsigned char *) p;
return KRB5_ASCII(c);
}
int krb5int_utf8_isdigit(const char * p)
{
unsigned c = * (const unsigned char *) p;
if (!KRB5_ASCII(c))
return 0;
return KRB5_DIGIT( c );
}
int krb5int_utf8_isxdigit(const char * p)
{
unsigned c = * (const unsigned char *) p;
if (!KRB5_ASCII(c))
return 0;
return KRB5_HEX(c);
}
int krb5int_utf8_isspace(const char * p)
{
unsigned c = * (const unsigned char *) p;
if (!KRB5_ASCII(c))
return 0;
switch(c) {
case ' ':
case '\t':
case '\n':
case '\r':
case '\v':
case '\f':
return 1;
}
return 0;
}
/*
* These are not needed by the C SDK and are
* not "good enough" for general use.
*/
int krb5int_utf8_isalpha(const char * p)
{
unsigned c = * (const unsigned char *) p;
if (!KRB5_ASCII(c))
return 0;
return KRB5_ALPHA(c);
}
int krb5int_utf8_isalnum(const char * p)
{
unsigned c = * (const unsigned char *) p;
if (!KRB5_ASCII(c))
return 0;
return KRB5_ALNUM(c);
}
#if 0
int krb5int_utf8_islower(const char * p)
{
unsigned c = * (const unsigned char *) p;
if (!KRB5_ASCII(c))
return 0;
return KRB5_LOWER(c);
}
int krb5int_utf8_isupper(const char * p)
{
unsigned c = * (const unsigned char *) p;
if (!KRB5_ASCII(c))
return 0;
return KRB5_UPPER(c);
}
#endif
#endif
/*
* UTF-8 string routines
*/
/* like strchr() */
{
return NULL;
return (char *)str;
}
return NULL;
}
/* like strcspn() but returns number of bytes, not characters */
{
}
}
}
/* like strspn() but returns number of bytes, not characters */
{
if (*cset == '\0')
break;
}
}
}
/* like strpbrk(), replaces strchr() as well */
{
const char *cset;
return (char *)str;
}
}
return NULL;
}
/* like strtok_r(), not strtok() */
{
char *begin;
char *end;
return NULL;
if (*begin == '\0') {
return NULL;
}
if (*end != '\0') {
*end = '\0';
}
return begin;
}