--- ./lib/xmltok.c.orig 2026-03-17 14:51:51.000000000 -0500 +++ ./lib/xmltok.c 2026-08-11 15:01:27.041099208 -0500 @@ -703,9 +703,10 @@ enum XML_Convert_Result res = XML_CONVERT_COMPLETED; \ UNUSED_P(enc); \ fromLim = *fromP + (((fromLim - *fromP) >> 1) << 1); /* shrink to even */ \ - /* Avoid copying first half only of surrogate */ \ + /* Avoid copying the first half (2 bytes) of surrogate pairs (4 bytes) */ \ if (fromLim - *fromP > ((toLim - *toP) << 1) \ - && (GET_HI(fromLim - 2) & 0xF8) == 0xD8) { \ + && /* are the last two bytes a high surrogate (0xD800-0xDBFF)? */ \ + (GET_HI(fromLim - 2) & 0xFC) == 0xD8) { \ fromLim -= 2; \ res = XML_CONVERT_INPUT_INCOMPLETE; \ } \ --- ./lib/xmlparse.c.orig 2026-03-17 14:51:51.000000000 -0500 +++ ./lib/xmlparse.c 2026-08-11 15:01:27.041950456 -0500 @@ -6540,11 +6540,12 @@ // Check if entity is complete, if not, mark down how much of it is // processed. A XML_SUSPENDED check here is not required as // appendAttributeValue will never suspend the parser. - if (textEnd != nextInEntity) { + if (nextInEntity < textEnd) { entity->processed = (int)(nextInEntity - (const char *)entity->textPtr); continue; } + assert(nextInEntity == textEnd); // Entity is complete. We cannot close it here since we need to first // process its possible inner entities (which are added to the