diff --git a/glymur/_uuid_io.py b/glymur/_uuid_io.py index 399fa99..8cd5bcf 100644 --- a/glymur/_uuid_io.py +++ b/glymur/_uuid_io.py @@ -43,7 +43,7 @@ def tiff_header(read_buffer): endian = '>' else: msg = "Bad byte order indication: {0}".format(read_buffer[6:8]) - raise RuntimeError(msg) + raise IOError(msg) _, offset = struct.unpack(endian + 'HI', read_buffer[8:14]) diff --git a/glymur/jp2box.py b/glymur/jp2box.py index f3f0776..723b5a3 100644 --- a/glymur/jp2box.py +++ b/glymur/jp2box.py @@ -177,6 +177,13 @@ class Jp2kBox(object): """ try: box = _BOX_WITH_ID[box_id].parse(fptr, start, num_bytes) + + except UnicodeDecodeError: + msg = 'Unrecognized box ({0}) encountered.'.format(box_id) + warnings.warn(msg) + box = UnknownBox(' ', offset=start, length=num_bytes, + longname='Unknown') + except KeyError: msg = 'Unrecognized box ({0}) encountered.'.format(box_id) warnings.warn(msg) @@ -194,7 +201,6 @@ class Jp2kBox(object): pos = fptr.tell() read_buffer = fptr.read(8) _, sub_id = struct.unpack('>I4s', read_buffer) - sub_id = sub_id.decode('utf-8') # Regardless of whether or not we recognize the box, rewind back # to properly advance to the next box. @@ -230,16 +236,12 @@ class Jp2kBox(object): break read_buffer = fptr.read(8) - try: - (box_length, box_id) = struct.unpack('>I4s', read_buffer) - except Exception as err: + if len(read_buffer) < 8: msg = "Extra bytes at end of file ignored." warnings.warn(msg) return superbox - if sys.hexversion >= 0x03000000: - box_id = box_id.decode('utf-8') - + (box_length, box_id) = struct.unpack('>I4s', read_buffer) if box_length == 0: # The length of the box is presumed to last until the end of # the file. Compute the effective length of the box. @@ -2998,7 +3000,11 @@ class UUIDBox(Jp2kBox): try: self._parse_raw_data() - except RuntimeError as error: + except KeyError as error: + # Such as when an Exif tag is unrecognized. + warnings.warn(str(error)) + except IOError as error: + # Such as when Exif byte order is unrecognized. warnings.warn(str(error)) def _parse_raw_data(self): @@ -3088,33 +3094,33 @@ class UUIDBox(Jp2kBox): # Map each box ID to the corresponding class. _BOX_WITH_ID = { - 'asoc': AssociationBox, - 'cdef': ChannelDefinitionBox, - 'cmap': ComponentMappingBox, - 'colr': ColourSpecificationBox, - 'dtbl': DataReferenceBox, - 'ftyp': FileTypeBox, - 'ihdr': ImageHeaderBox, - 'jP ': JPEG2000SignatureBox, - 'jpch': CodestreamHeaderBox, - 'jplh': CompositingLayerHeaderBox, - 'jp2c': ContiguousCodestreamBox, - 'free': FreeBox, - 'flst': FragmentListBox, - 'ftbl': FragmentTableBox, - 'jp2h': JP2HeaderBox, - 'lbl ': LabelBox, - 'nlst': NumberListBox, - 'pclr': PaletteBox, - 'res ': ResolutionBox, - 'resc': CaptureResolutionBox, - 'resd': DisplayResolutionBox, - 'rreq': ReaderRequirementsBox, - 'uinf': UUIDInfoBox, - 'ulst': UUIDListBox, - 'url ': DataEntryURLBox, - 'uuid': UUIDBox, - 'xml ': XMLBox} + b'asoc': AssociationBox, + b'cdef': ChannelDefinitionBox, + b'cmap': ComponentMappingBox, + b'colr': ColourSpecificationBox, + b'dtbl': DataReferenceBox, + b'ftyp': FileTypeBox, + b'ihdr': ImageHeaderBox, + b'jP ': JPEG2000SignatureBox, + b'jpch': CodestreamHeaderBox, + b'jplh': CompositingLayerHeaderBox, + b'jp2c': ContiguousCodestreamBox, + b'free': FreeBox, + b'flst': FragmentListBox, + b'ftbl': FragmentTableBox, + b'jp2h': JP2HeaderBox, + b'lbl ': LabelBox, + b'nlst': NumberListBox, + b'pclr': PaletteBox, + b'res ': ResolutionBox, + b'resc': CaptureResolutionBox, + b'resd': DisplayResolutionBox, + b'rreq': ReaderRequirementsBox, + b'uinf': UUIDInfoBox, + b'ulst': UUIDListBox, + b'url ': DataEntryURLBox, + b'uuid': UUIDBox, + b'xml ': XMLBox} _printoptions = {'short': False, 'xml': True, 'codestream': True} diff --git a/glymur/test/test_jp2box_jpx.py b/glymur/test/test_jp2box_jpx.py index f8e9db8..f71f409 100644 --- a/glymur/test/test_jp2box_jpx.py +++ b/glymur/test/test_jp2box_jpx.py @@ -402,7 +402,7 @@ class TestJPX(unittest.TestCase): with self.assertWarns(UserWarning): jpx = Jp2k(tfile.name) - self.assertEqual(jpx.box[-1].box_id, 'grp ') + self.assertEqual(jpx.box[-1].box_id, b'grp ') self.assertEqual(jpx.box[-1].box[0].box_id, 'free') def test_free_box(self): diff --git a/glymur/test/test_jp2k.py b/glymur/test/test_jp2k.py index 10363ab..222cde8 100644 --- a/glymur/test/test_jp2k.py +++ b/glymur/test/test_jp2k.py @@ -758,7 +758,22 @@ class TestJp2k_2_1(unittest.TestCase): class TestJp2kOpjDataRoot(unittest.TestCase): """These tests should be run by just about all configuration.""" - @unittest.skipIf(sys.hexversion < 0x03000000, "Test requires Python 3.3+") + def test_undecodeable_box_id(self): + """Should warn in case of undecodeable box ID but not error out.""" + filename = opj_data_file('input/nonregression/edf_c2_1013627.jp2') + if sys.hexversion < 0x03000000: + with warnings.catch_warnings(): + warnings.simplefilter("ignore") + jp2 = Jp2k(filename) + else: + with self.assertWarns(UserWarning): + jp2 = Jp2k(filename) + + # Now make sure we got all of the boxes. Ignore the last, which was + # bad. + box_ids = [box.box_id for box in jp2.box[:-1]] + self.assertEqual(box_ids, ['jP ', 'ftyp', 'jp2h', 'jp2c']) + def test_invalid_approximation(self): """Should warn in case of bad ftyp brand.""" filename = opj_data_file('input/nonregression/edf_c2_1000290.jp2') diff --git a/glymur/test/test_opj_suite.py b/glymur/test/test_opj_suite.py index 2a49b5d..40bfa68 100644 --- a/glymur/test/test_opj_suite.py +++ b/glymur/test/test_opj_suite.py @@ -5482,7 +5482,7 @@ class TestSuiteDump(unittest.TestCase): jp2 = Jp2k(jfile) ids = [box.box_id for box in jp2.box] - self.assertEqual(ids, ['jP ', 'ftyp', 'jp2h', 'XML ', 'jp2c']) + self.assertEqual(ids, ['jP ', 'ftyp', 'jp2h', b'XML ', 'jp2c']) ids = [box.box_id for box in jp2.box[2].box] self.assertEqual(ids, ['ihdr', 'colr']) diff --git a/glymur/test/test_printing.py b/glymur/test/test_printing.py index 7a17e4e..5cd8347 100644 --- a/glymur/test/test_printing.py +++ b/glymur/test/test_printing.py @@ -78,7 +78,7 @@ class TestPrinting(unittest.TestCase): with patch('sys.stdout', new=StringIO()) as fake_out: print(jpx.box[-1]) actual = fake_out.getvalue().strip() - lines = ['Unknown Box (grp ) @ (695609, 20)', + lines = ["Unknown Box (b'grp ') @ (695609, 20)", ' Free Box (free) @ (695617, 12)'] expected = '\n'.join(lines) self.assertEqual(actual, expected)