Skip to content

Commit 11342d9

Browse files
committed
gh-160518: Fix hz encoder dropping half of the ~~ escape
Write both bytes of the escape before consuming the input character, so that a retry after the output buffer is enlarged starts at the tilde.
1 parent 3b3c692 commit 11342d9

3 files changed

Lines changed: 19 additions & 4 deletions

File tree

‎Lib/test/test_codecencodings_cn.py‎

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,5 +92,15 @@ class Test_HZ(multibytecodec_support.TestBase, unittest.TestCase):
9292
(b'~{Dc~\n:C~}', 'strict', None), # ~\n only in ASCII mode
9393
)
9494

95+
def test_escape_at_buffer_boundary(self):
96+
# '~~' must not be cut in two when the output buffer is enlarged.
97+
for pairs in range(40):
98+
for letters in range(3):
99+
text = 'a\u4e2d' * pairs + 'x' * letters + '~{'
100+
with self.subTest(pairs=pairs, letters=letters):
101+
encoded = text.encode('hz')
102+
self.assertEndsWith(encoded, b'~~{')
103+
self.assertEqual(encoded.decode('hz'), text)
104+
95105
if __name__ == "__main__":
96106
unittest.main()
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
Fix the ``hz`` codec sometimes encoding ``~`` as a single ``~`` instead of
2+
``~~`` in text that mixes ASCII and Chinese characters, which produced data
3+
that did not decode back to the original text.

‎Modules/cjkcodecs/_codecs_cn.c‎

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -361,11 +361,13 @@ ENCODER(hz)
361361
NEXT_OUT(2);
362362
state->c[CN_STATE_OFFSET] = 0;
363363
}
364-
WRITEBYTE1((unsigned char)c);
365-
NEXT(1, 1);
366364
if (c == '~') {
367-
WRITEBYTE1('~');
368-
NEXT_OUT(1);
365+
WRITEBYTE2('~', '~');
366+
NEXT(1, 2);
367+
}
368+
else {
369+
WRITEBYTE1((unsigned char)c);
370+
NEXT(1, 1);
369371
}
370372
continue;
371373
}

0 commit comments

Comments
 (0)