#include "k5-platform.h"
#include "k5-utf8.h"
#include "supp-int.h"
size_t krb5int_utf8_bytes(const char *p)
{
size_t bytes;
for (bytes = 0; p[bytes]; bytes++)
;
return bytes;
}
size_t krb5int_utf8_chars(const char *p)
{
size_t chars = 0;
for ( ; *p ; KRB5_UTF8_INCR(p))
chars++;
return chars;
}
size_t krb5int_utf8c_chars(const char *p, size_t length)
{
size_t chars = 0;
const char *end = p + length;
for ( ; p < end; KRB5_UTF8_INCR(p))
chars++;
return chars;
}
int krb5int_utf8_offset(const char *p)
{
return KRB5_UTF8_NEXT(p) - p;
}
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];
}
#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) {
if (!(krb5int_utf8_mintab[*p & 0x1f] & p[1]))
i = 0;
}
return i;
}
int krb5int_utf8_to_ucs4(const char *p, krb5_ucs4 *out)
{
const unsigned char *c = (const unsigned char *) p;
krb5_ucs4 ch;
int len, i;
static unsigned char mask[] = {
0, 0x7f, 0x1f, 0x0f, 0x07, 0x03, 0x01 };
*out = 0;
len = KRB5_UTF8_CHARLEN2(p, len);
if (len == 0)
return -1;
ch = c[0] & mask[len];
for (i = 1; i < len; i++) {
if ((c[i] & 0xc0) != 0x80)
return -1;
ch <<= 6;
ch |= c[i] & 0x3f;
}
*out = ch;
return 0;
}
int krb5int_utf8_to_ucs2(const char *p, krb5_ucs2 *out)
{
krb5_ucs4 ch;
*out = 0;
if (krb5int_utf8_to_ucs4(p, &ch) == -1 || ch > 0xFFFF)
return -1;
*out = (krb5_ucs2) ch;
return 0;
}
size_t krb5int_ucs4_to_utf8(krb5_ucs4 c, char *buf)
{
size_t len = 0;
unsigned char *p = (unsigned char *) buf;
if (c < 0)
return 0;
if (buf == NULL) {
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) {
p[len++] = 0xc0 | ( c >> 6 );
p[len++] = 0x80 | ( c & 0x3f );
} else if (c < 0x10000) {
p[len++] = 0xe0 | ( c >> 12 );
p[len++] = 0x80 | ( (c >> 6) & 0x3f );
p[len++] = 0x80 | ( c & 0x3f );
} else if (c < 0x200000) {
p[len++] = 0xf0 | ( c >> 18 );
p[len++] = 0x80 | ( (c >> 12) & 0x3f );
p[len++] = 0x80 | ( (c >> 6) & 0x3f );
p[len++] = 0x80 | ( c & 0x3f );
} else if (c < 0x4000000) {
p[len++] = 0xf8 | ( c >> 24 );
p[len++] = 0x80 | ( (c >> 18) & 0x3f );
p[len++] = 0x80 | ( (c >> 12) & 0x3f );
p[len++] = 0x80 | ( (c >> 6) & 0x3f );
p[len++] = 0x80 | ( c & 0x3f );
} else {
p[len++] = 0xfc | ( c >> 30 );
p[len++] = 0x80 | ( (c >> 24) & 0x3f );
p[len++] = 0x80 | ( (c >> 18) & 0x3f );
p[len++] = 0x80 | ( (c >> 12) & 0x3f );
p[len++] = 0x80 | ( (c >> 6) & 0x3f );
p[len++] = 0x80 | ( c & 0x3f );
}
return len;
}
size_t krb5int_ucs2_to_utf8(krb5_ucs2 c, char *buf)
{
return krb5int_ucs4_to_utf8((krb5_ucs4)c, buf);
}
#define KRB5_UCS_UTF8LEN(c) \
c < 0 ? 0 : (c < 0x80 ? 1 : (c < 0x800 ? 2 : (c < 0x10000 ? 3 : \
(c < 0x200000 ? 4 : (c < 0x4000000 ? 5 : 6)))))
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];
}
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];
}
int krb5int_utf8_copy(char* dst, const char *src)
{
int i;
const unsigned char *u = (const unsigned char *) src;
dst[0] = src[0];
if (KRB5_UTF8_ISASCII(u)) {
return 1;
}
for (i=1; i<6; i++) {
if ((u[i] & 0xc0) != 0x80) {
return i;
}
dst[i] = src[i];
}
return i;
}
#ifndef UTF8_ALPHA_CTYPE
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;
}
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
char *krb5int_utf8_strchr(const char *str, const char *chr)
{
krb5_ucs4 chs, ch;
if (krb5int_utf8_to_ucs4(chr, &ch) == -1)
return NULL;
for ( ; *str != '\0'; KRB5_UTF8_INCR(str)) {
if (krb5int_utf8_to_ucs4(str, &chs) == 0 && chs == ch)
return (char *)str;
}
return NULL;
}
size_t krb5int_utf8_strcspn(const char *str, const char *set)
{
const char *cstr, *cset;
krb5_ucs4 chstr, chset;
for (cstr = str; *cstr != '\0'; KRB5_UTF8_INCR(cstr)) {
for (cset = set; *cset != '\0'; KRB5_UTF8_INCR(cset)) {
if (krb5int_utf8_to_ucs4(cstr, &chstr) == 0
&& krb5int_utf8_to_ucs4(cset, &chset) == 0 && chstr == chset)
return cstr - str;
}
}
return cstr - str;
}
size_t krb5int_utf8_strspn(const char *str, const char *set)
{
const char *cstr, *cset;
krb5_ucs4 chstr, chset;
for (cstr = str; *cstr != '\0'; KRB5_UTF8_INCR(cstr)) {
for (cset = set; ; KRB5_UTF8_INCR(cset)) {
if (*cset == '\0')
return cstr - str;
if (krb5int_utf8_to_ucs4(cstr, &chstr) == 0
&& krb5int_utf8_to_ucs4(cset, &chset) == 0 && chstr == chset)
break;
}
}
return cstr - str;
}
char *krb5int_utf8_strpbrk(const char *str, const char *set)
{
const char *cset;
krb5_ucs4 chstr, chset;
for ( ; *str != '\0'; KRB5_UTF8_INCR(str)) {
for (cset = set; *cset != '\0'; KRB5_UTF8_INCR(cset)) {
if (krb5int_utf8_to_ucs4(str, &chstr) == 0
&& krb5int_utf8_to_ucs4(cset, &chset) == 0 && chstr == chset)
return (char *)str;
}
}
return NULL;
}
char *krb5int_utf8_strtok(char *str, const char *sep, char **last)
{
char *begin;
char *end;
if (last == NULL)
return NULL;
begin = str ? str : *last;
begin += krb5int_utf8_strspn(begin, sep);
if (*begin == '\0') {
*last = NULL;
return NULL;
}
end = &begin[krb5int_utf8_strcspn(begin, sep)];
if (*end != '\0') {
char *next = KRB5_UTF8_NEXT(end);
*end = '\0';
end = next;
}
*last = end;
return begin;
}