@@ -353,11 +353,13 @@ def test_controlcharacters(self):
353
353
testString = "string containing %s" % c
354
354
if i >= 32 or c in "\r \n \t " :
355
355
# \r, \n and \t are the only legal control chars in XML
356
- plistlib .dumps (testString , fmt = plistlib .FMT_XML )
356
+ data = plistlib .dumps (testString , fmt = plistlib .FMT_XML )
357
+ if c != "\r " :
358
+ self .assertEqual (plistlib .loads (data ), testString )
357
359
else :
358
- self .assertRaises (ValueError ,
359
- plistlib .dumps ,
360
- testString )
360
+ with self .assertRaises (ValueError ):
361
+ plistlib .dumps ( testString , fmt = plistlib . FMT_XML )
362
+ plistlib . dumps ( testString , fmt = plistlib . FMT_BINARY )
361
363
362
364
def test_non_bmp_characters (self ):
363
365
pl = {'python' : '\U0001f40d ' }
@@ -366,6 +368,14 @@ def test_non_bmp_characters(self):
366
368
data = plistlib .dumps (pl , fmt = fmt )
367
369
self .assertEqual (plistlib .loads (data ), pl )
368
370
371
+ def test_lone_surrogates (self ):
372
+ for fmt in ALL_FORMATS :
373
+ with self .subTest (fmt = fmt ):
374
+ with self .assertRaises (UnicodeEncodeError ):
375
+ plistlib .dumps ('\ud8ff ' , fmt = fmt )
376
+ with self .assertRaises (UnicodeEncodeError ):
377
+ plistlib .dumps ('\udcff ' , fmt = fmt )
378
+
369
379
def test_nondictroot (self ):
370
380
for fmt in ALL_FORMATS :
371
381
with self .subTest (fmt = fmt ):
@@ -442,6 +452,56 @@ def test_large_timestamp(self):
442
452
data = plistlib .dumps (d , fmt = plistlib .FMT_BINARY )
443
453
self .assertEqual (plistlib .loads (data ), d )
444
454
455
+ def test_invalid_binary (self ):
456
+ for data in [
457
+ # too short data
458
+ b'' ,
459
+ # too large offset_table_offset and nonstandard offset_size
460
+ b'\x00 \x08 '
461
+ b'\x00 \x00 \x00 \x00 \x00 \x00 \x03 \x01 '
462
+ b'\x00 \x00 \x00 \x00 \x00 \x00 \x00 \x01 '
463
+ b'\x00 \x00 \x00 \x00 \x00 \x00 \x00 \x00 '
464
+ b'\x00 \x00 \x00 \x00 \x00 \x00 \x00 \x2a ' ,
465
+ # integer overflow in offset_table_offset
466
+ b'\x00 \x08 '
467
+ b'\x00 \x00 \x00 \x00 \x00 \x00 \x01 \x01 '
468
+ b'\x00 \x00 \x00 \x00 \x00 \x00 \x00 \x01 '
469
+ b'\x00 \x00 \x00 \x00 \x00 \x00 \x00 \x00 '
470
+ b'\xff \xff \xff \xff \xff \xff \xff \xff ' ,
471
+ # offset_size = 0
472
+ b'\x00 \x08 '
473
+ b'\x00 \x00 \x00 \x00 \x00 \x00 \x00 \x01 '
474
+ b'\x00 \x00 \x00 \x00 \x00 \x00 \x00 \x01 '
475
+ b'\x00 \x00 \x00 \x00 \x00 \x00 \x00 \x00 '
476
+ b'\x00 \x00 \x00 \x00 \x00 \x00 \x00 \x09 ' ,
477
+ # ref_size = 0
478
+ b'\xa1 \x01 \x00 \x08 \x0a '
479
+ b'\x00 \x00 \x00 \x00 \x00 \x00 \x01 \x00 '
480
+ b'\x00 \x00 \x00 \x00 \x00 \x00 \x00 \x02 '
481
+ b'\x00 \x00 \x00 \x00 \x00 \x00 \x00 \x00 '
482
+ b'\x00 \x00 \x00 \x00 \x00 \x00 \x00 \x0b ' ,
483
+ # integer overflow in offset
484
+ b'\x00 \xff \xff \xff \xff \xff \xff \xff \xff '
485
+ b'\x00 \x00 \x00 \x00 \x00 \x00 \x08 \x01 '
486
+ b'\x00 \x00 \x00 \x00 \x00 \x00 \x00 \x01 '
487
+ b'\x00 \x00 \x00 \x00 \x00 \x00 \x00 \x00 '
488
+ b'\x00 \x00 \x00 \x00 \x00 \x00 \x00 \x09 ' ,
489
+ # invalid ASCII
490
+ b'\x51 \xff \x08 '
491
+ b'\x00 \x00 \x00 \x00 \x00 \x00 \x01 \x01 '
492
+ b'\x00 \x00 \x00 \x00 \x00 \x00 \x00 \x01 '
493
+ b'\x00 \x00 \x00 \x00 \x00 \x00 \x00 \x00 '
494
+ b'\x00 \x00 \x00 \x00 \x00 \x00 \x00 \x0a ' ,
495
+ # invalid UTF-16
496
+ b'\x61 \xd8 \x00 \x08 '
497
+ b'\x00 \x00 \x00 \x00 \x00 \x00 \x01 \x01 '
498
+ b'\x00 \x00 \x00 \x00 \x00 \x00 \x00 \x01 '
499
+ b'\x00 \x00 \x00 \x00 \x00 \x00 \x00 \x00 '
500
+ b'\x00 \x00 \x00 \x00 \x00 \x00 \x00 \x0b ' ,
501
+ ]:
502
+ with self .assertRaises (plistlib .InvalidFileException ):
503
+ plistlib .loads (b'bplist00' + data , fmt = plistlib .FMT_BINARY )
504
+
445
505
446
506
class TestPlistlibDeprecated (unittest .TestCase ):
447
507
def test_io_deprecated (self ):
0 commit comments