blob: 8953ae0f00b5c769ca2897ab6bc3a1c6a9f7eef8 [file]
/* See LICENSE file for copyright and license details. */
#include "utf.h"
/* lookup table for the number of bytes expected in a sequence */
static const unsigned char lookup[] = {
0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* 1100xxxx */
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* 1101xxxx */
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, /* 1110xxxx */
4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 0, 0, /* 1111xxxx */
};
int
charntorune(Rune *p, const char *s, size_t len)
{
unsigned char c, i, n, x;
Rune r;
if(len == 0) /* can't even look at s[0] */
return 0;
c = s[0];
if(!(c & 0200)) { /* basic byte */
*p = c;
return 1;
}
if(!(c & 0100)) { /* continuation byte */
*p = Runeerror;
return 1;
}
n = lookup[c & 077];
if(n == 0) { /* illegal byte */
*p = Runeerror;
return 1;
}
if(len == 1) /* reached len limit */
return 0;
x = 0377 >> n;
r = c & x;
c = s[1];
if((c & 0300) != 0200) { /* not a continuation byte */
*p = Runeerror;
return 1;
}
r = (r << 6) | (c & 077);
if(n == 2) {
*p = r;
return 2;
}
if(r <= x) { /* overlong sequence */
*p = Runeerror;
return 2;
}
if(len > n)
len = n;
/* add values from continuation bytes */
for(i = 2; i < len; i++) {
c = s[i];
if((c & 0300) != 0200) { /* not a continuation byte */
*p = Runeerror;
return i;
}
r = (r << 6) | (c & 077);
}
if(i < n) /* must have reached len limit */
return 0;
*p = r;
return i;
}
int
chartorune(Rune *p, const char *s)
{
return charntorune(p, s, UTFmax);
}
int
fullrune(const char *s, size_t len)
{
unsigned char c, i, n, x;
Rune r;
if(len == 0) /* can't even look at s[0] */
return 0;
c = s[0];
if ((c & 0300) != 0300) /* basic or continuation byte */
return 1;
n = lookup[c & 077];
if(len >= n) /* must be long enough */
return 1;
if(len == 1) /* reached len limit */
return 0;
/* check if an error means this rune is full */
x = 0377 >> n;
r = c & x;
c = s[1];
if((c & 0300) != 0200) /* not a continuation byte */
return 1;
r = (r << 6) | (c & 077);
if(r <= x) /* overlong sequence */
return 1;
for(i = 2; i < len; i++) {
c = s[i];
if((c & 0300) != 0200) /* not a continuation byte */
return 1;
}
return 0;
}