}
/*
-=for apidoc Am|U8* s|utf8_to_uv_chk|STRLEN curlen|I32 *retlen|I32 checking
+=for apidoc Am|U8* s|utf8_to_uv|STRLEN curlen|I32 *retlen|U32 flags
Returns the character value of the first character in the string C<s>
which is assumed to be in UTF8 encoding and no longer than C<curlen>;
and the pointer C<s> will be advanced to the end of the character.
If C<s> does not point to a well-formed UTF8 character, the behaviour
-is dependent on the value of C<checking>: if this is true, it is
-assumed that the caller will raise a warning, and this function will
-set C<retlen> to C<-1> and return. If C<checking> is not true, an optional UTF8
-warning is produced.
+is dependent on the value of C<flags>: if it contains UTF8_CHECK_ONLY,
+it is assumed that the caller will raise a warning, and this function
+will set C<retlen> to C<-1> and return. The C<flags> can also contain
+various flags to allow deviations from the strict UTF-8 encoding.
-=cut
-*/
+=cut */
UV
-Perl_utf8_to_uv_chk(pTHX_ U8* s, STRLEN curlen, STRLEN* retlen, bool checking)
+Perl_utf8_to_uv(pTHX_ U8* s, STRLEN curlen, STRLEN* retlen, U32 flags)
{
dTHR;
UV uv = *s, ouv;
return *s;
}
- if (uv >= 0x80 && uv <= 0xbf) {
+ if ((uv >= 0x80 && uv <= 0xbf) &&
+ !(flags & UTF8_ALLOW_CONTINUATION)) {
if (dowarn)
Perl_warner(aTHX_ WARN_UTF8,
"Malformed UTF-8 character (unexpected continuation byte 0x%02x)",
goto malformed;
}
- if (uv >= 0xc0 && uv <= 0xfd && curlen > 1 && s[1] < 0x80) {
+ if ((uv >= 0xc0 && uv <= 0xfd && curlen >1 && s[1] < 0x80) &&
+ !(flags & UTF8_ALLOW_NON_CONTINUATION)) {
if (dowarn)
Perl_warner(aTHX_ WARN_UTF8,
"Malformed UTF-8 character (unexpected non-continuation byte 0x%02x after byte 0x%02x)",
s[1], uv);
goto malformed;
}
-
- if ((uv == 0xfe || uv == 0xff) && IN_UTF8){
+
+ if ((uv == 0xfe || uv == 0xff) &&
+ !(flags & UTF8_ALLOW_FE_FF)) {
if (dowarn)
Perl_warner(aTHX_ WARN_UTF8,
- "Malformed UTF-8 character (impossible byte 0x%02x)",
+ "Malformed UTF-8 character (byte 0x%02x)",
uv);
goto malformed;
}
-
+
if (!(uv & 0x20)) { len = 2; uv &= 0x1f; }
else if (!(uv & 0x10)) { len = 3; uv &= 0x0f; }
else if (!(uv & 0x08)) { len = 4; uv &= 0x07; }
else if (!(uv & 0x02)) { len = 6; uv &= 0x01; }
else if (!(uv & 0x01)) { len = 7; uv = 0; }
else { len = 13; uv = 0; } /* whoa! */
-
+
if (retlen)
*retlen = len;
expectlen = len;
- if (curlen < expectlen) {
+ if ((curlen < expectlen) &&
+ !(flags & UTF8_ALLOW_SHORT)) {
if (dowarn)
Perl_warner(aTHX_ WARN_UTF8,
"Malformed UTF-8 character (%d byte%s, need %d)",
else
uv = (uv << 6) | (*s & 0x3f);
if (uv < ouv) {
+ /* This cannot be allowed. */
if (dowarn)
Perl_warner(aTHX_ WARN_UTF8,
"Malformed UTF-8 character (overflow at 0x%"UVxf", byte 0x%02x)",
ouv = uv;
}
- if (uv >= 0xd800 && uv <= 0xdfff) {
+ if ((uv >= 0xd800 && uv <= 0xdfff) &&
+ !(flags & UTF8_ALLOW_SURROGATE)) {
if (dowarn)
Perl_warner(aTHX_ WARN_UTF8,
"Malformed UTF-8 character (UTF-16 surrogate 0x%04"UVxf")",
uv);
goto malformed;
- } else if (uv == 0xfffe) {
+ } else if ((uv == 0xfffe) &&
+ !(flags & UTF8_ALLOW_BOM)) {
if (dowarn)
Perl_warner(aTHX_ WARN_UTF8,
"Malformed UTF-8 character (byte order mark 0x%04"UVxf")",
uv);
goto malformed;
- } else if (uv == 0xffff && IN_UTF8) {
+ } else if ((uv == 0xffff) &&
+ !(flags & UTF8_ALLOW_FFFF)) {
if (dowarn)
Perl_warner(aTHX_ WARN_UTF8,
- "Malformed UTF-8 character (impossible character 0x%04"UVxf")",
+ "Malformed UTF-8 character (character 0x%04"UVxf")",
uv);
goto malformed;
- } else if (expectlen > UNISKIP(uv)) {
+ } else if ((expectlen > UNISKIP(uv)) &&
+ !(flags & UTF8_ALLOW_LONG)) {
if (dowarn)
Perl_warner(aTHX_ WARN_UTF8,
"Malformed UTF-8 character (%d byte%s, need %d)",
malformed:
- if (checking) {
+ if (flags & UTF8_CHECK_ONLY) {
if (retlen)
*retlen = len;
return 0;
}
/*
-=for apidoc Am|U8* s|utf8_to_uv|STRLEN *retlen
+=for apidoc Am|U8* s|utf8_to_uv_simple|STRLEN *retlen
Returns the character value of the first character in the string C<s>
which is assumed to be in UTF8 encoding; C<retlen> will be set to the
*/
UV
-Perl_utf8_to_uv(pTHX_ U8* s, STRLEN* retlen)
+Perl_utf8_to_uv_simple(pTHX_ U8* s, STRLEN* retlen)
{
- return Perl_utf8_to_uv_chk(aTHX_ s, (STRLEN)-1, retlen, 0);
+ return Perl_utf8_to_uv(aTHX_ s, (STRLEN)-1, retlen, 0);
}
/* utf8_distance(a,b) returns the number of UTF8 characters between
U8 *
Perl_utf8_to_bytes(pTHX_ U8* s, STRLEN *len)
{
- dTHR;
U8 *send;
U8 *d;
- U8 *save;
-
- send = s + *len;
- d = save = s;
+ U8 *save = s;
/* ensure valid UTF8 and chars < 256 before updating string */
- while (s < send) {
- U8 c = *s++;
+ for (send = s + *len; s < send; ) {
+ U8 c = *s++;
+
if (c >= 0x80 &&
- ( (s >= send) || ((*s++ & 0xc0) != 0x80) || ((c & 0xfe) != 0xc2))) {
- *len = -1;
- return 0;
- }
+ ((s >= send) ||
+ ((*s++ & 0xc0) != 0x80) || ((c & 0xfe) != 0xc2))) {
+ *len = -1;
+ return 0;
+ }
}
- s = save;
+
+ d = s = save;
while (s < send) {
- if (*s < 0x80)
- *d++ = *s++;
+ if (*s < 0x80) {
+ *d++ = *s++;
+ }
else {
STRLEN ulen;
- *d++ = (U8)utf8_to_uv(s, &ulen);
+ *d++ = (U8)utf8_to_uv_simple(s, &ulen);
s += ulen;
}
}
if (!PL_utf8_toupper)
PL_utf8_toupper = swash_init("utf8", "ToUpper", &PL_sv_undef, 4, 0);
uv = swash_fetch(PL_utf8_toupper, p);
- return uv ? uv : utf8_to_uv_chk(p,STRLEN_MAX,0,0);
+ return uv ? uv : utf8_to_uv(p,STRLEN_MAX,0,0);
}
UV
if (!PL_utf8_totitle)
PL_utf8_totitle = swash_init("utf8", "ToTitle", &PL_sv_undef, 4, 0);
uv = swash_fetch(PL_utf8_totitle, p);
- return uv ? uv : utf8_to_uv_chk(p,STRLEN_MAX,0,0);
+ return uv ? uv : utf8_to_uv(p,STRLEN_MAX,0,0);
}
UV
if (!PL_utf8_tolower)
PL_utf8_tolower = swash_init("utf8", "ToLower", &PL_sv_undef, 4, 0);
uv = swash_fetch(PL_utf8_tolower, p);
- return uv ? uv : utf8_to_uv_chk(p,STRLEN_MAX,0,0);
+ return uv ? uv : utf8_to_uv(p,STRLEN_MAX,0,0);
}
/* a "swash" is a swatch hash */
PUSHMARK(SP);
EXTEND(SP,3);
PUSHs((SV*)sv);
- PUSHs(sv_2mortal(newSViv(utf8_to_uv_chk(ptr, STRLEN_MAX, 0, 0) & ~(needents - 1))));
+ PUSHs(sv_2mortal(newSViv(utf8_to_uv(ptr, STRLEN_MAX, 0, 0) & ~(needents - 1))));
PUSHs(sv_2mortal(newSViv(needents)));
PUTBACK;
if (call_method("SWASHGET", G_SCALAR))