diff --git a/glymur/jp2box.py b/glymur/jp2box.py index ab8a6e5..043a1be 100644 --- a/glymur/jp2box.py +++ b/glymur/jp2box.py @@ -145,8 +145,8 @@ class Jp2kBox(object): except KeyError: msg = 'Unrecognized box ({0}) encountered.'.format(box_id) warnings.warn(msg) - box = Jp2kBox(box_id, offset=start, length=num_bytes, - longname='Unknown box') + box = UnknownBox(box_id, offset=start, length=num_bytes, + longname='Unknown') if fptr.tell() != start + 8: # If the file pointer has advanced, then the KeyError @@ -2739,6 +2739,37 @@ class DataEntryURLBox(Jp2kBox): return box +class UnknownBox(Jp2kBox): + """Container for unrecognized boxes. + + Attributes + ---------- + box_id : str + 4-character identifier for the box. + length : int + length of the box in bytes. + offset : int + offset of the box from the start of the file. + longname : str + more verbose description of the box. + """ + def __init__(self, box_id, length=0, offset=-1, longname=''): + Jp2kBox.__init__(self, box_id=box_id, longname=longname) + self.length = length + self.offset = offset + + def __repr__(self): + msg = "glymur.jp2box.UnknownBox({0})".format(self.box_id) + return msg + + def __str__(self): + if len(self.box) > 0: + msg = self._str_superbox() + else: + msg = Jp2kBox.__str__(self) + return msg + + class UUIDBox(Jp2kBox): """Container for UUID box information. diff --git a/glymur/test/fixtures.py b/glymur/test/fixtures.py index 6e0a76c..a7906c5 100644 --- a/glymur/test/fixtures.py +++ b/glymur/test/fixtures.py @@ -690,3 +690,11 @@ file7_rreq = r"""Reader Requirements Box (rreq) @ (44, 24) Feature 060: 0x60 e-sRGB enumerated colorspace Feature 043: 0x40 Deprecated - compositing layer uses restricted ICC profile Vendor Features:""" + +file1_xml = r"""XML Box (xml ) @ (36, 439) + + + 2001-11-01T13:45:00.000-06:00 + Professional 120 Image + + """ diff --git a/glymur/test/test_printing.py b/glymur/test/test_printing.py index 5fe3322..132d1ec 100644 --- a/glymur/test/test_printing.py +++ b/glymur/test/test_printing.py @@ -39,6 +39,7 @@ from .fixtures import text_gbr_27, text_gbr_33, text_gbr_34 class TestPrinting(unittest.TestCase): """Tests for verifying how printing works.""" def setUp(self): + self.jpxfile = glymur.data.jpxfile() self.jp2file = glymur.data.nemo() self.j2kfile = glymur.data.goodstuff() @@ -48,6 +49,31 @@ class TestPrinting(unittest.TestCase): def tearDown(self): pass + @unittest.skipIf(sys.hexversion < 0x03000000, "Needs unittest in 3.x.") + def test_unknown_superbox(self): + """Verify that we can handle an unknown superbox.""" + with tempfile.NamedTemporaryFile(suffix='.jpx') as tfile: + with open(self.jpxfile, 'rb') as ifile: + tfile.write(ifile.read()) + + # Add the header for an unknwon superbox. + write_buffer = struct.pack('>I4s', 20, 'grp '.encode()) + tfile.write(write_buffer) + write_buffer = struct.pack('>I4sI', 12, 'free'.encode(), 0) + tfile.write(write_buffer) + tfile.flush() + + with self.assertWarns(UserWarning): + jpx = Jp2k(tfile.name) + glymur.set_printoptions(short=True) + with patch('sys.stdout', new=StringIO()) as fake_out: + print(jpx.box[-1]) + actual = fake_out.getvalue().strip() + lines = ['Unknown Box (grp ) @ (695609, 20)', + ' Free Box (free) @ (695617, 12)'] + expected = '\n'.join(lines) + self.assertEqual(actual, expected) + def test_printoptions_bad_argument(self): """Verify error when bad parameter to set_printoptions""" with self.assertRaises(TypeError): @@ -602,27 +628,7 @@ class TestPrinting(unittest.TestCase): with patch('sys.stdout', new=StringIO()) as fake_out: print(j.box[2]) actual = fake_out.getvalue().strip() - - lines = ['XML Box (xml ) @ (36, 439)', - ' ', - - ' ', - ' ' - + '2001-11-01T13:45:00.000-06:00' - + '', - - ' ' - + 'Professional 120 Image' - + '', - - ' ', - ' '] - expected = '\n'.join(lines) - self.assertEqual(actual, expected) + self.assertEqual(actual, fixtures.file1_xml) @unittest.skipIf(sys.hexversion < 0x03000000, "Only trusting python3 for printing non-ascii chars")