Not decoding box ID anymore. #197

We don't actually use the box ID as parsed from the file, so there was
no need to decode it.  This means that unrecognized box IDs are actually
kept as bytes, but no big deal.  The code is simplified a bit because of
this.
This commit is contained in:
John Evans 2014-03-19 15:15:55 -04:00
commit 55a01cbc39
6 changed files with 61 additions and 40 deletions

View file

@ -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])

View file

@ -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}

View file

@ -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):

View file

@ -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')

View file

@ -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'])

View file

@ -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)