[3.14] gh-143346: Fix calculation of the line width for wrapped Base64 in plistlib (GH-143347) (GH-143719)

It was incorrect in case of mixed tabs and spaces in indentation.
(cherry picked from commit 5f28aa2f37)

Co-authored-by: Serhiy Storchaka <storchaka@gmail.com>
This commit is contained in:
Miss Islington (bot) 2026-01-12 10:08:52 +01:00 committed by GitHub
parent ea26c885fd
commit 6447fa3f19
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 66 additions and 2 deletions

View file

@ -384,7 +384,7 @@ def write_bytes(self, data):
self._indent_level -= 1
maxlinelength = max(
16,
76 - len(self.indent.replace(b"\t", b" " * 8) * self._indent_level))
76 - len((self.indent * self._indent_level).expandtabs()))
for line in _encode_base64(data, maxlinelength).split(b"\n"):
if line:

View file

@ -509,6 +509,69 @@ def test_bytes(self):
data2 = plistlib.dumps(pl2)
self.assertEqual(data, data2)
def test_bytes_indent(self):
header = (
b'<?xml version="1.0" encoding="UTF-8"?>\n'
b'<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">\n'
b'<plist version="1.0">\n')
data = [{'bytes': bytes(range(50))}]
pl = plistlib.dumps(data)
self.assertEqual(pl, header +
b'<array>\n'
b'\t<dict>\n'
b'\t\t<key>bytes</key>\n'
b'\t\t<data>\n'
b'\t\tAAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8gISIjJCUmJygpKiss\n'
b'\t\tLS4vMDE=\n'
b'\t\t</data>\n'
b'\t</dict>\n'
b'</array>\n'
b'</plist>\n')
def dumps_with_indent(data, indent):
fp = BytesIO()
writer = plistlib._PlistWriter(fp, indent=indent)
writer.write(data)
return fp.getvalue()
pl = dumps_with_indent(data, b' ')
self.assertEqual(pl, header +
b'<array>\n'
b' <dict>\n'
b' <key>bytes</key>\n'
b' <data>\n'
b' AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8gISIjJCUmJygpKissLS4vMDE=\n'
b' </data>\n'
b' </dict>\n'
b'</array>\n'
b'</plist>\n')
pl = dumps_with_indent(data, b' \t')
self.assertEqual(pl, header +
b'<array>\n'
b' \t<dict>\n'
b' \t \t<key>bytes</key>\n'
b' \t \t<data>\n'
b' \t \tAAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8gISIjJCUmJygpKiss\n'
b' \t \tLS4vMDE=\n'
b' \t \t</data>\n'
b' \t</dict>\n'
b'</array>\n'
b'</plist>\n')
pl = dumps_with_indent(data, b'\t ')
self.assertEqual(pl, header +
b'<array>\n'
b'\t <dict>\n'
b'\t \t <key>bytes</key>\n'
b'\t \t <data>\n'
b'\t \t AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8gISIjJCUmJygp\n'
b'\t \t KissLS4vMDE=\n'
b'\t \t </data>\n'
b'\t </dict>\n'
b'</array>\n'
b'</plist>\n')
def test_loads_str_with_xml_fmt(self):
pl = self._create()
b = plistlib.dumps(pl)
@ -581,7 +644,6 @@ def test_appleformatting(self):
self.assertEqual(data, TESTDATA[fmt],
"generated data was not identical to Apple's output")
def test_appleformattingfromliteral(self):
self.maxDiff = None
for fmt in ALL_FORMATS:

View file

@ -0,0 +1,2 @@
Fix incorrect wrapping of the Base64 data in :class:`!plistlib._PlistWriter`
when the indent contains a mix of tabs and spaces.