StreamHub: loop UTF-8 tail repair to match Go CalConfig.Normalise()
The single-pass repair left invalid bytes when the candidate lead byte had class 0 (illegal 0xF8-0xFF bytes, or a bare continuation byte reached after the 3-byte backward-scan cap). Convert to a loop with a `cut` flag mirroring Go's loop: each iteration either makes no cut (exits) or strictly reduces ulen by >= 1 byte (terminates in <= 16 iterations). Also treat expected==0 as a cut target, matching Go's behaviour of stripping any byte that decodes as an invalid one-byte sequence. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 4.6
parent
93e00d0c21
commit
bdc74f5fd2
@@ -791,38 +791,55 @@ bool StreamHub::SetCalibrationEntry(const char *source, const char *signal,
|
||||
u[kMaxUnitLen] = '\0';
|
||||
uint32 ulen = kMaxUnitLen;
|
||||
|
||||
/* Scan back over continuation bytes (up to 3). */
|
||||
uint32 cont = 0u;
|
||||
while ((cont < 3u) && (cont < ulen)) {
|
||||
const unsigned char b =
|
||||
static_cast<unsigned char>(u[ulen - 1u - cont]);
|
||||
if ((b & 0xC0u) == 0x80u) {
|
||||
cont++;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
/* Repair any split or invalid rune at the tail.
|
||||
* Mirror Go's loop: keep stripping until the tail is valid or empty.
|
||||
* Each iteration either makes no cut (loop exits) or strictly reduces
|
||||
* ulen by at least 1 byte, so termination is guaranteed. */
|
||||
bool cut = true;
|
||||
while (cut && (ulen > 0u)) {
|
||||
cut = false;
|
||||
|
||||
/* The byte at index ulen-1-cont is the candidate lead byte. */
|
||||
if (cont < ulen) {
|
||||
const unsigned char lead =
|
||||
static_cast<unsigned char>(u[ulen - 1u - cont]);
|
||||
uint32 expected = 0u;
|
||||
if ((lead & 0x80u) == 0x00u) { expected = 1u; }
|
||||
else if ((lead & 0xE0u) == 0xC0u) { expected = 2u; }
|
||||
else if ((lead & 0xF0u) == 0xE0u) { expected = 3u; }
|
||||
else if ((lead & 0xF8u) == 0xF0u) { expected = 4u; }
|
||||
/* bytes present in the sequence = cont + 1 (the lead itself) */
|
||||
if ((expected > 1u) && ((cont + 1u) < expected)) {
|
||||
/* Incomplete multi-byte sequence: drop from the lead byte. */
|
||||
ulen = ulen - 1u - cont;
|
||||
u[ulen] = '\0';
|
||||
/* Scan back over continuation bytes (up to 3). */
|
||||
uint32 cont = 0u;
|
||||
while ((cont < 3u) && (cont < ulen)) {
|
||||
const unsigned char b =
|
||||
static_cast<unsigned char>(u[ulen - 1u - cont]);
|
||||
if ((b & 0xC0u) == 0x80u) {
|
||||
cont++;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* The byte at index ulen-1-cont is the candidate lead byte. */
|
||||
if (cont < ulen) {
|
||||
const unsigned char lead =
|
||||
static_cast<unsigned char>(u[ulen - 1u - cont]);
|
||||
uint32 expected = 0u;
|
||||
if ((lead & 0x80u) == 0x00u) { expected = 1u; }
|
||||
else if ((lead & 0xE0u) == 0xC0u) { expected = 2u; }
|
||||
else if ((lead & 0xF0u) == 0xE0u) { expected = 3u; }
|
||||
else if ((lead & 0xF8u) == 0xF0u) { expected = 4u; }
|
||||
/* expected==0: lead byte is not a valid UTF-8 lead class
|
||||
* (0xF8-0xFF or a bare continuation); drop it too, like Go. */
|
||||
if (expected == 0u) {
|
||||
/* Invalid lead byte: strip from that position. */
|
||||
ulen = ulen - 1u - cont;
|
||||
u[ulen] = '\0';
|
||||
cut = true;
|
||||
} else if ((cont + 1u) < expected) {
|
||||
/* Incomplete multi-byte sequence: drop from the lead byte. */
|
||||
ulen = ulen - 1u - cont;
|
||||
u[ulen] = '\0';
|
||||
cut = true;
|
||||
}
|
||||
/* else: complete sequence — nothing to do, loop exits. */
|
||||
} else {
|
||||
/* Every byte was a continuation byte with no lead: discard all. */
|
||||
ulen = 0u;
|
||||
u[0] = '\0';
|
||||
/* cut stays false; loop will exit cleanly. */
|
||||
}
|
||||
/* else: complete sequence (expected==1 ASCII, or cont+1==expected)
|
||||
* — nothing to do. */
|
||||
} else {
|
||||
/* Every byte was a continuation byte with no lead: discard all. */
|
||||
u[0] = '\0';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user