diff --git a/glymur/test/test_jp2box.py b/glymur/test/test_jp2box.py
index 71dbd72..72b9f9d 100644
--- a/glymur/test/test_jp2box.py
+++ b/glymur/test/test_jp2box.py
@@ -320,113 +320,6 @@ class TestChannelDefinition(unittest.TestCase):
association=association)
-@unittest.skipIf(os.name == "nt", "Temporary file issue on window.")
-class TestXML(unittest.TestCase):
- """Test suite for XML boxes."""
-
- def setUp(self):
- self.jp2file = glymur.data.nemo()
- self.j2kfile = glymur.data.goodstuff()
-
- raw_xml = b"""
-
-
- 1
- 2008
- 141100
-
-
-
-
- 4
- 2011
- 59900
-
-
-
- 68
- 2011
- 13600
-
-
-
- """
- with tempfile.NamedTemporaryFile(suffix=".xml", delete=False) as tfile:
- tfile.write(raw_xml)
- tfile.flush()
- self.xmlfile = tfile.name
-
- j2k = Jp2k(self.j2kfile)
- codestream = j2k.get_codestream()
- height = codestream.segment[1].ysiz
- width = codestream.segment[1].xsiz
- num_components = len(codestream.segment[1].xrsiz)
-
- self.jp2b = JPEG2000SignatureBox()
- self.ftyp = FileTypeBox()
- self.jp2h = JP2HeaderBox()
- self.jp2c = ContiguousCodestreamBox()
- self.ihdr = ImageHeaderBox(height=height, width=width,
- num_components=num_components)
- self.colr = ColourSpecificationBox(colorspace=glymur.core.SRGB)
-
- def tearDown(self):
- os.unlink(self.xmlfile)
-
- def test_negative_file_and_xml(self):
- """The XML should come from only one source."""
- xml_object = ET.parse(self.xmlfile)
- with self.assertRaises((IOError, OSError)):
- glymur.jp2box.XMLBox(filename=self.xmlfile, xml=xml_object)
-
- @unittest.skipIf(os.name == "nt",
- "Problems using NamedTemporaryFile on windows.")
- def test_basic_xml(self):
- """Should be able to write a basic XMLBox"""
- j2k = Jp2k(self.j2kfile)
-
- self.jp2h.box = [self.ihdr, self.colr]
-
- the_xml = ET.fromstring('0')
- xmlb = glymur.jp2box.XMLBox(xml=the_xml)
- self.assertEqual(ET.tostring(xmlb.xml),
- b'0')
-
- boxes = [self.jp2b, self.ftyp, self.jp2h, xmlb, self.jp2c]
-
- with tempfile.NamedTemporaryFile(suffix=".jp2") as tfile:
- j2k.wrap(tfile.name, boxes=boxes)
- jp2 = Jp2k(tfile.name)
- self.assertEqual(jp2.box[3].box_id, 'xml ')
- self.assertEqual(ET.tostring(jp2.box[3].xml.getroot()),
- b'0')
-
- @unittest.skipIf(os.name == "nt",
- "Problems using NamedTemporaryFile on windows.")
- def test_xml_from_file(self):
- """Must be able to create an XML box from an XML file."""
- j2k = Jp2k(self.j2kfile)
-
- self.jp2h.box = [self.ihdr, self.colr]
-
- xmlb = glymur.jp2box.XMLBox(filename=self.xmlfile)
- boxes = [self.jp2b, self.ftyp, self.jp2h, xmlb, self.jp2c]
- with tempfile.NamedTemporaryFile(suffix=".jp2") as tfile:
- j2k.wrap(tfile.name, boxes=boxes)
- jp2 = Jp2k(tfile.name)
-
- output_boxes = [box.box_id for box in jp2.box]
- self.assertEqual(output_boxes, ['jP ', 'ftyp', 'jp2h', 'xml ',
- 'jp2c'])
-
- elts = jp2.box[3].xml.findall('country')
- self.assertEqual(len(elts), 3)
-
- neighbor = elts[1].find('neighbor')
- self.assertEqual(neighbor.attrib['name'], 'Malaysia')
- self.assertEqual(neighbor.attrib['direction'], 'N')
-
-
class TestColourSpecificationBox(unittest.TestCase):
"""Test suite for colr box instantiation."""
@@ -856,5 +749,264 @@ class TestJpxBoxes(unittest.TestCase):
self.assertEqual(len(jpx.box[5].box), 0)
+@unittest.skipIf(os.name == "nt", "Temporary file issue on window.")
+class TestChannelDefinition(unittest.TestCase):
+ """Test suite for channel definition boxes."""
+
+ @classmethod
+ def setUpClass(cls):
+ """Need a one_plane plane image for greyscale testing."""
+ j2k = Jp2k(glymur.data.goodstuff())
+ data = j2k.read()
+ # Write the first component back out to file.
+ with tempfile.NamedTemporaryFile(suffix=".j2k", delete=False) as tfile:
+ grey_j2k = Jp2k(tfile.name, 'wb')
+ grey_j2k.write(data[:, :, 0])
+ cls.one_plane = tfile.name
+ # Write the first two components back out to file.
+ with tempfile.NamedTemporaryFile(suffix=".j2k", delete=False) as tfile:
+ grey_j2k = Jp2k(tfile.name, 'wb')
+ grey_j2k.write(data[:, :, 0:1])
+ cls.two_planes = tfile.name
+ # Write four components back out to file.
+ with tempfile.NamedTemporaryFile(suffix=".j2k", delete=False) as tfile:
+ rgba_jp2 = Jp2k(tfile.name, 'wb')
+ shape = (data.shape[0], data.shape[1], 1)
+ alpha = np.zeros((shape), dtype=data.dtype)
+ data4 = np.concatenate((data, alpha), axis=2)
+ rgba_jp2.write(data4)
+ cls.four_planes = tfile.name
+
+ @classmethod
+ def tearDownClass(cls):
+ os.unlink(cls.one_plane)
+ os.unlink(cls.two_planes)
+ os.unlink(cls.four_planes)
+
+ def setUp(self):
+ self.jp2file = glymur.data.nemo()
+ self.j2kfile = glymur.data.goodstuff()
+
+ j2k = Jp2k(self.j2kfile)
+ codestream = j2k.get_codestream()
+ height = codestream.segment[1].ysiz
+ width = codestream.segment[1].xsiz
+ num_components = len(codestream.segment[1].xrsiz)
+
+ self.jp2b = JPEG2000SignatureBox()
+ self.ftyp = FileTypeBox()
+ self.jp2h = JP2HeaderBox()
+ self.jp2c = ContiguousCodestreamBox()
+ self.ihdr = ImageHeaderBox(height=height, width=width,
+ num_components=num_components)
+ self.colr_rgb = ColourSpecificationBox(colorspace=glymur.core.SRGB)
+ self.colr_gr = ColourSpecificationBox(colorspace=glymur.core.GREYSCALE)
+
+ def tearDown(self):
+ pass
+
+ def test_cdef_no_inputs(self):
+ """channel_type and association are required inputs."""
+ with self.assertRaises(IOError):
+ glymur.jp2box.ChannelDefinitionBox()
+
+ def test_rgb_with_index(self):
+ """Just regular RGB."""
+ j2k = Jp2k(self.j2kfile)
+ channel_type = [COLOR, COLOR, COLOR]
+ association = [RED, GREEN, BLUE]
+ cdef = glymur.jp2box.ChannelDefinitionBox(index=[0, 1, 2],
+ channel_type=channel_type,
+ association=association)
+ boxes = [self.ihdr, self.colr_rgb, cdef]
+ self.jp2h.box = boxes
+ boxes = [self.jp2b, self.ftyp, self.jp2h, self.jp2c]
+ with tempfile.NamedTemporaryFile(suffix=".jp2") as tfile:
+ j2k.wrap(tfile.name, boxes=boxes)
+
+ jp2 = Jp2k(tfile.name)
+ jp2h = jp2.box[2]
+ boxes = [box.box_id for box in jp2h.box]
+ self.assertEqual(boxes, ['ihdr', 'colr', 'cdef'])
+ self.assertEqual(jp2h.box[2].index, (0, 1, 2))
+ self.assertEqual(jp2h.box[2].channel_type,
+ (COLOR, COLOR, COLOR))
+ self.assertEqual(jp2h.box[2].association,
+ (RED, GREEN, BLUE))
+
+ def test_rgb(self):
+ """Just regular RGB, but don't supply the optional index."""
+ j2k = Jp2k(self.j2kfile)
+ channel_type = [COLOR, COLOR, COLOR]
+ association = [RED, GREEN, BLUE]
+ cdef = glymur.jp2box.ChannelDefinitionBox(channel_type=channel_type,
+ association=association)
+ boxes = [self.ihdr, self.colr_rgb, cdef]
+ self.jp2h.box = boxes
+ boxes = [self.jp2b, self.ftyp, self.jp2h, self.jp2c]
+ with tempfile.NamedTemporaryFile(suffix=".jp2") as tfile:
+ j2k.wrap(tfile.name, boxes=boxes)
+
+ jp2 = Jp2k(tfile.name)
+ jp2h = jp2.box[2]
+ boxes = [box.box_id for box in jp2h.box]
+ self.assertEqual(boxes, ['ihdr', 'colr', 'cdef'])
+ self.assertEqual(jp2h.box[2].index, (0, 1, 2))
+ self.assertEqual(jp2h.box[2].channel_type,
+ (COLOR, COLOR, COLOR))
+ self.assertEqual(jp2h.box[2].association,
+ (RED, GREEN, BLUE))
+
+ def test_rgba(self):
+ """Just regular RGBA."""
+ j2k = Jp2k(self.four_planes)
+ channel_type = (COLOR, COLOR, COLOR, OPACITY)
+ association = (RED, GREEN, BLUE, WHOLE_IMAGE)
+ cdef = glymur.jp2box.ChannelDefinitionBox(channel_type=channel_type,
+ association=association)
+ boxes = [self.ihdr, self.colr_rgb, cdef]
+ self.jp2h.box = boxes
+ boxes = [self.jp2b, self.ftyp, self.jp2h, self.jp2c]
+ with tempfile.NamedTemporaryFile(suffix=".jp2") as tfile:
+ j2k.wrap(tfile.name, boxes=boxes)
+
+ jp2 = Jp2k(tfile.name)
+ jp2h = jp2.box[2]
+ boxes = [box.box_id for box in jp2h.box]
+ self.assertEqual(boxes, ['ihdr', 'colr', 'cdef'])
+ self.assertEqual(jp2h.box[2].index, (0, 1, 2, 3))
+ self.assertEqual(jp2h.box[2].channel_type, channel_type)
+ self.assertEqual(jp2h.box[2].association, association)
+
+ def test_bad_rgba(self):
+ """R, G, and B must be specified."""
+ j2k = Jp2k(self.four_planes)
+ channel_type = (COLOR, COLOR, OPACITY, OPACITY)
+ association = (RED, GREEN, BLUE, WHOLE_IMAGE)
+ cdef = glymur.jp2box.ChannelDefinitionBox(channel_type=channel_type,
+ association=association)
+ boxes = [self.ihdr, self.colr_rgb, cdef]
+ self.jp2h.box = boxes
+ boxes = [self.jp2b, self.ftyp, self.jp2h, self.jp2c]
+ with tempfile.NamedTemporaryFile(suffix=".jp2") as tfile:
+ with self.assertRaises(IOError):
+ j2k.wrap(tfile.name, boxes=boxes)
+
+ def test_grey(self):
+ """Just regular greyscale."""
+ j2k = Jp2k(self.one_plane)
+ channel_type = (COLOR,)
+ association = (GREY,)
+ cdef = glymur.jp2box.ChannelDefinitionBox(channel_type=channel_type,
+ association=association)
+ boxes = [self.ihdr, self.colr_gr, cdef]
+ self.jp2h.box = boxes
+ boxes = [self.jp2b, self.ftyp, self.jp2h, self.jp2c]
+ with tempfile.NamedTemporaryFile(suffix=".jp2") as tfile:
+ j2k.wrap(tfile.name, boxes=boxes)
+
+ jp2 = Jp2k(tfile.name)
+ jp2h = jp2.box[2]
+ boxes = [box.box_id for box in jp2h.box]
+ self.assertEqual(boxes, ['ihdr', 'colr', 'cdef'])
+ self.assertEqual(jp2h.box[2].index, (0,))
+ self.assertEqual(jp2h.box[2].channel_type, channel_type)
+ self.assertEqual(jp2h.box[2].association, association)
+
+ def test_grey_alpha(self):
+ """Just regular greyscale plus alpha."""
+ j2k = Jp2k(self.two_planes)
+ channel_type = (COLOR, OPACITY)
+ association = (GREY, WHOLE_IMAGE)
+ cdef = glymur.jp2box.ChannelDefinitionBox(channel_type=channel_type,
+ association=association)
+ boxes = [self.ihdr, self.colr_gr, cdef]
+ self.jp2h.box = boxes
+ boxes = [self.jp2b, self.ftyp, self.jp2h, self.jp2c]
+ with tempfile.NamedTemporaryFile(suffix=".jp2") as tfile:
+ j2k.wrap(tfile.name, boxes=boxes)
+
+ jp2 = Jp2k(tfile.name)
+ jp2h = jp2.box[2]
+ boxes = [box.box_id for box in jp2h.box]
+ self.assertEqual(boxes, ['ihdr', 'colr', 'cdef'])
+ self.assertEqual(jp2h.box[2].index, (0, 1))
+ self.assertEqual(jp2h.box[2].channel_type, channel_type)
+ self.assertEqual(jp2h.box[2].association, association)
+
+ def test_bad_grey_alpha(self):
+ """A greyscale image with alpha layer must specify a color channel"""
+ j2k = Jp2k(self.two_planes)
+
+ channel_type = (OPACITY, OPACITY)
+ association = (GREY, WHOLE_IMAGE)
+
+ # This cdef box
+ cdef = glymur.jp2box.ChannelDefinitionBox(channel_type=channel_type,
+ association=association)
+ boxes = [self.ihdr, self.colr_gr, cdef]
+ self.jp2h.box = boxes
+ boxes = [self.jp2b, self.ftyp, self.jp2h, self.jp2c]
+ with tempfile.NamedTemporaryFile(suffix=".jp2") as tfile:
+ with self.assertRaises((OSError, IOError)):
+ j2k.wrap(tfile.name, boxes=boxes)
+
+ def test_only_one_cdef_in_jp2h(self):
+ """There can only be one channel definition box in the jp2 header."""
+ j2k = Jp2k(self.j2kfile)
+
+ channel_type = (COLOR, COLOR, COLOR)
+ association = (RED, GREEN, BLUE)
+ cdef = glymur.jp2box.ChannelDefinitionBox(channel_type=channel_type,
+ association=association)
+
+ boxes = [self.ihdr, cdef, self.colr_rgb, cdef]
+ self.jp2h.box = boxes
+
+ boxes = [self.jp2b, self.ftyp, self.jp2h, self.jp2c]
+
+ with tempfile.NamedTemporaryFile(suffix=".jp2") as tfile:
+ with self.assertRaises(IOError):
+ j2k.wrap(tfile.name, boxes=boxes)
+
+ def test_not_in_jp2h(self):
+ """need cdef in jp2h"""
+ j2k = Jp2k(self.j2kfile)
+ boxes = [self.ihdr, self.colr_rgb]
+ self.jp2h.box = boxes
+
+ channel_type = (COLOR, COLOR, COLOR)
+ association = (RED, GREEN, BLUE)
+ cdef = glymur.jp2box.ChannelDefinitionBox(channel_type=channel_type,
+ association=association)
+
+ boxes = [self.jp2b, self.ftyp, self.jp2h, cdef, self.jp2c]
+
+ with tempfile.NamedTemporaryFile(suffix=".jp2") as tfile:
+ with self.assertRaises(IOError):
+ j2k.wrap(tfile.name, boxes=boxes)
+
+ def test_bad_type(self):
+ """Channel types are limited to 0, 1, 2, 65535
+ Should reject if not all of index, channel_type, association the
+ same length.
+ """
+ channel_type = (COLOR, COLOR, 3)
+ association = (RED, GREEN, BLUE)
+ with self.assertRaises(IOError):
+ glymur.jp2box.ChannelDefinitionBox(channel_type=channel_type,
+ association=association)
+
+ def test_wrong_lengths(self):
+ """Should reject if not all of index, channel_type, association the
+ same length.
+ """
+ channel_type = (COLOR, COLOR)
+ association = (RED, GREEN, BLUE)
+ with self.assertRaises(IOError):
+ glymur.jp2box.ChannelDefinitionBox(channel_type=channel_type,
+ association=association)
+
+
if __name__ == "__main__":
unittest.main()
diff --git a/glymur/test/test_jp2box_xml.py b/glymur/test/test_jp2box_xml.py
new file mode 100644
index 0000000..ba1ff15
--- /dev/null
+++ b/glymur/test/test_jp2box_xml.py
@@ -0,0 +1,266 @@
+"""
+Test suite specifically targeting JP2 box layout.
+"""
+# E1103: return value from read may be list or np array
+# pylint: disable=E1103
+
+# F0401: unittest2 is needed on python-2.6 (pylint on 2.7)
+# pylint: disable=F0401
+
+# R0902: More than 7 instance attributes are just fine for testing.
+# pylint: disable=R0902
+
+# R0904: Seems like pylint is fooled in this situation
+# pylint: disable=R0904
+
+# W0613: load_tests doesn't need to use ignore or loader arguments.
+# pylint: disable=W0613
+
+import os
+import struct
+import sys
+import tempfile
+import warnings
+import xml.etree.cElementTree as ET
+
+if sys.hexversion < 0x02070000:
+ import unittest2 as unittest
+else:
+ import unittest
+
+import glymur
+from glymur import Jp2k
+from glymur.jp2box import ColourSpecificationBox, ContiguousCodestreamBox
+from glymur.jp2box import FileTypeBox, ImageHeaderBox, JP2HeaderBox
+from glymur.jp2box import JPEG2000SignatureBox
+
+
+@unittest.skipIf(os.name == "nt", "Temporary file issue on window.")
+class TestXML(unittest.TestCase):
+ """Test suite for XML boxes."""
+
+ def setUp(self):
+ self.jp2file = glymur.data.nemo()
+ self.j2kfile = glymur.data.goodstuff()
+
+ raw_xml = b"""
+
+
+ 1
+ 2008
+ 141100
+
+
+
+
+ 4
+ 2011
+ 59900
+
+
+
+ 68
+ 2011
+ 13600
+
+
+
+ """
+ with tempfile.NamedTemporaryFile(suffix=".xml", delete=False) as tfile:
+ tfile.write(raw_xml)
+ tfile.flush()
+ self.xmlfile = tfile.name
+
+ j2k = Jp2k(self.j2kfile)
+ codestream = j2k.get_codestream()
+ height = codestream.segment[1].ysiz
+ width = codestream.segment[1].xsiz
+ num_components = len(codestream.segment[1].xrsiz)
+
+ self.jp2b = JPEG2000SignatureBox()
+ self.ftyp = FileTypeBox()
+ self.jp2h = JP2HeaderBox()
+ self.jp2c = ContiguousCodestreamBox()
+ self.ihdr = ImageHeaderBox(height=height, width=width,
+ num_components=num_components)
+ self.colr = ColourSpecificationBox(colorspace=glymur.core.SRGB)
+
+ def tearDown(self):
+ os.unlink(self.xmlfile)
+
+ def test_negative_file_and_xml(self):
+ """The XML should come from only one source."""
+ xml_object = ET.parse(self.xmlfile)
+ with self.assertRaises((IOError, OSError)):
+ glymur.jp2box.XMLBox(filename=self.xmlfile, xml=xml_object)
+
+ @unittest.skipIf(os.name == "nt",
+ "Problems using NamedTemporaryFile on windows.")
+ def test_basic_xml(self):
+ """Should be able to write a basic XMLBox"""
+ j2k = Jp2k(self.j2kfile)
+
+ self.jp2h.box = [self.ihdr, self.colr]
+
+ the_xml = ET.fromstring('0')
+ xmlb = glymur.jp2box.XMLBox(xml=the_xml)
+ self.assertEqual(ET.tostring(xmlb.xml),
+ b'0')
+
+ boxes = [self.jp2b, self.ftyp, self.jp2h, xmlb, self.jp2c]
+
+ with tempfile.NamedTemporaryFile(suffix=".jp2") as tfile:
+ j2k.wrap(tfile.name, boxes=boxes)
+ jp2 = Jp2k(tfile.name)
+ self.assertEqual(jp2.box[3].box_id, 'xml ')
+ self.assertEqual(ET.tostring(jp2.box[3].xml.getroot()),
+ b'0')
+
+ @unittest.skipIf(os.name == "nt",
+ "Problems using NamedTemporaryFile on windows.")
+ def test_xml_from_file(self):
+ """Must be able to create an XML box from an XML file."""
+ j2k = Jp2k(self.j2kfile)
+
+ self.jp2h.box = [self.ihdr, self.colr]
+
+ xmlb = glymur.jp2box.XMLBox(filename=self.xmlfile)
+ boxes = [self.jp2b, self.ftyp, self.jp2h, xmlb, self.jp2c]
+ with tempfile.NamedTemporaryFile(suffix=".jp2") as tfile:
+ j2k.wrap(tfile.name, boxes=boxes)
+ jp2 = Jp2k(tfile.name)
+
+ output_boxes = [box.box_id for box in jp2.box]
+ self.assertEqual(output_boxes, ['jP ', 'ftyp', 'jp2h', 'xml ',
+ 'jp2c'])
+
+ elts = jp2.box[3].xml.findall('country')
+ self.assertEqual(len(elts), 3)
+
+ neighbor = elts[1].find('neighbor')
+ self.assertEqual(neighbor.attrib['name'], 'Malaysia')
+ self.assertEqual(neighbor.attrib['direction'], 'N')
+
+
+@unittest.skipIf(os.name == "nt", "NamedTemporaryFile issue on windows")
+class TestJp2kBadXmlFile(unittest.TestCase):
+ """Test suite for bad XML box situations"""
+
+ @classmethod
+ def setUpClass(cls):
+ """Setup a JP2 file with a bad XML box. We only need to do this once
+ per class rather than once per test.
+ """
+ jp2file = glymur.data.nemo()
+ with tempfile.NamedTemporaryFile(suffix='.jp2', delete=False) as tfile:
+ cls._bad_xml_file = tfile.name
+ with open(jp2file, 'rb') as ifile:
+ # Everything up until the UUID box.
+ write_buffer = ifile.read(77)
+ tfile.write(write_buffer)
+
+ # Write the xml box with bad xml
+ # Length = 28, id is 'xml '.
+ write_buffer = struct.pack('>I4s', int(28), b'xml ')
+ tfile.write(write_buffer)
+
+ write_buffer = 'this is a test'
+ write_buffer = write_buffer.encode()
+ tfile.write(write_buffer)
+
+ # Get the rest of the input file.
+ write_buffer = ifile.read()
+ tfile.write(write_buffer)
+ tfile.flush()
+
+ @classmethod
+ def tearDownClass(cls):
+ os.unlink(cls._bad_xml_file)
+
+ def setUp(self):
+ self.jp2file = glymur.data.nemo()
+ self.j2kfile = glymur.data.goodstuff()
+
+ def tearDown(self):
+ pass
+
+ @unittest.skipIf(sys.hexversion < 0x03020000,
+ "Uses features introduced in 3.2.")
+ def test_invalid_xml_box_warning(self):
+ """Should warn in case of bad XML"""
+ with self.assertWarns(UserWarning):
+ Jp2k(self._bad_xml_file)
+
+ def test_invalid_xml_box(self):
+ """Should be able to recover info from xml box with bad xml."""
+ with warnings.catch_warnings():
+ warnings.simplefilter("ignore")
+ jp2k = Jp2k(self._bad_xml_file)
+
+ self.assertEqual(jp2k.box[3].box_id, 'xml ')
+ self.assertEqual(jp2k.box[3].offset, 77)
+ self.assertEqual(jp2k.box[3].length, 28)
+ self.assertIsNone(jp2k.box[3].xml)
+
+
+@unittest.skipIf(os.name == "nt", "NamedTemporaryFile issue on windows")
+class TestBadButRecoverableXmlFile(unittest.TestCase):
+ """Test suite for XML box that is bad, but we can still recover the XML."""
+
+ @classmethod
+ def setUpClass(cls):
+ """Setup a JP2 file with bad bytes preceding the XML. We only need
+ to do this once per class rather than once per test.
+ """
+ jp2file = glymur.data.nemo()
+ with tempfile.NamedTemporaryFile(suffix='.jp2', delete=False) as tfile:
+ cls._bad_xml_file = tfile.name
+ with open(jp2file, 'rb') as ifile:
+ # Everything up until the UUID box.
+ write_buffer = ifile.read(77)
+ tfile.write(write_buffer)
+
+ # Write the xml box with bad xml
+ # Length = 64, id is 'xml '.
+ write_buffer = struct.pack('>I4s', int(64), b'xml ')
+ tfile.write(write_buffer)
+
+ # Write out 8 bad bytes.
+ write_buffer = b'\x00\x00\x07\x90xml '
+ tfile.write(write_buffer)
+
+ # Write out 48 good bytes constituting the XML payload.
+ write_buffer = b''
+ tfile.write(write_buffer)
+ write_buffer = b'this is a test'
+ tfile.write(write_buffer)
+
+ # Get the rest of the input file.
+ write_buffer = ifile.read()
+ tfile.write(write_buffer)
+ tfile.flush()
+
+ @classmethod
+ def tearDownClass(cls):
+ os.unlink(cls._bad_xml_file)
+
+ @unittest.skipIf(sys.hexversion < 0x03020000,
+ "Uses features introduced in 3.2.")
+ def test_bad_xml_box_warning(self):
+ """Should warn in case of bad XML"""
+ with self.assertWarns(UserWarning):
+ Jp2k(self._bad_xml_file)
+
+ def test_recover_from_bad_xml(self):
+ """Should be able to recover info from xml box with bad xml."""
+ with warnings.catch_warnings():
+ warnings.simplefilter("ignore")
+ jp2 = Jp2k(self._bad_xml_file)
+
+ self.assertEqual(jp2.box[3].box_id, 'xml ')
+ self.assertEqual(jp2.box[3].offset, 77)
+ self.assertEqual(jp2.box[3].length, 64)
+ self.assertEqual(ET.tostring(jp2.box[3].xml.getroot()),
+ b'this is a test')
+
+
diff --git a/glymur/test/test_jp2k.py b/glymur/test/test_jp2k.py
index 4f06745..0a7f509 100644
--- a/glymur/test/test_jp2k.py
+++ b/glymur/test/test_jp2k.py
@@ -55,129 +55,6 @@ def load_tests(loader, tests, ignore):
return tests
-@unittest.skipIf(os.name == "nt", "NamedTemporaryFile issue on windows")
-@unittest.skipIf(glymur.lib.openjp2.OPENJP2 is None,
- "Missing openjp2 library.")
-class TestJp2kBadXmlFile(unittest.TestCase):
- """Test suite for bad XML box situations"""
-
- @classmethod
- def setUpClass(cls):
- """Setup a JP2 file with a bad XML box. We only need to do this once
- per class rather than once per test.
- """
- jp2file = pkg_resources.resource_filename(glymur.__name__,
- "data/nemo.jp2")
- with tempfile.NamedTemporaryFile(suffix='.jp2', delete=False) as tfile:
- cls._bad_xml_file = tfile.name
- with open(jp2file, 'rb') as ifile:
- # Everything up until the UUID box.
- write_buffer = ifile.read(77)
- tfile.write(write_buffer)
-
- # Write the xml box with bad xml
- # Length = 28, id is 'xml '.
- write_buffer = struct.pack('>I4s', int(28), b'xml ')
- tfile.write(write_buffer)
-
- write_buffer = 'this is a test'
- write_buffer = write_buffer.encode()
- tfile.write(write_buffer)
-
- # Get the rest of the input file.
- write_buffer = ifile.read()
- tfile.write(write_buffer)
- tfile.flush()
-
- @classmethod
- def tearDownClass(cls):
- os.unlink(cls._bad_xml_file)
-
- def setUp(self):
- self.jp2file = glymur.data.nemo()
- self.j2kfile = glymur.data.goodstuff()
-
- def tearDown(self):
- pass
-
- @unittest.skipIf(sys.hexversion < 0x03020000,
- "Uses features introduced in 3.2.")
- def test_invalid_xml_box_warning(self):
- """Should warn in case of bad XML"""
- with self.assertWarns(UserWarning):
- Jp2k(self._bad_xml_file)
-
- def test_invalid_xml_box(self):
- """Should be able to recover info from xml box with bad xml."""
- with warnings.catch_warnings():
- warnings.simplefilter("ignore")
- jp2k = Jp2k(self._bad_xml_file)
-
- self.assertEqual(jp2k.box[3].box_id, 'xml ')
- self.assertEqual(jp2k.box[3].offset, 77)
- self.assertEqual(jp2k.box[3].length, 28)
- self.assertIsNone(jp2k.box[3].xml)
-
-
-@unittest.skipIf(os.name == "nt", "NamedTemporaryFile issue on windows")
-class TestBadButRecoverableXmlFile(unittest.TestCase):
- """Test suite for XML box that is bad, but we can still recover the XML."""
-
- @classmethod
- def setUpClass(cls):
- """Setup a JP2 file with bad bytes preceding the XML. We only need
- to do this once per class rather than once per test.
- """
- jp2file = glymur.data.nemo()
- with tempfile.NamedTemporaryFile(suffix='.jp2', delete=False) as tfile:
- cls._bad_xml_file = tfile.name
- with open(jp2file, 'rb') as ifile:
- # Everything up until the UUID box.
- write_buffer = ifile.read(77)
- tfile.write(write_buffer)
-
- # Write the xml box with bad xml
- # Length = 64, id is 'xml '.
- write_buffer = struct.pack('>I4s', int(64), b'xml ')
- tfile.write(write_buffer)
-
- # Write out 8 bad bytes.
- write_buffer = b'\x00\x00\x07\x90xml '
- tfile.write(write_buffer)
-
- # Write out 48 good bytes constituting the XML payload.
- write_buffer = b'this is a test'
- tfile.write(write_buffer)
-
- # Get the rest of the input file.
- write_buffer = ifile.read()
- tfile.write(write_buffer)
- tfile.flush()
-
- @classmethod
- def tearDownClass(cls):
- os.unlink(cls._bad_xml_file)
-
- @unittest.skipIf(sys.hexversion < 0x03020000,
- "Uses features introduced in 3.2.")
- def test_bad_xml_box_warning(self):
- """Should warn in case of bad XML"""
- with self.assertWarns(UserWarning):
- Jp2k(self._bad_xml_file)
-
- def test_recover_from_bad_xml(self):
- """Should be able to recover info from xml box with bad xml."""
- with warnings.catch_warnings():
- warnings.simplefilter("ignore")
- jp2 = Jp2k(self._bad_xml_file)
-
- self.assertEqual(jp2.box[3].box_id, 'xml ')
- self.assertEqual(jp2.box[3].offset, 77)
- self.assertEqual(jp2.box[3].length, 64)
- self.assertEqual(ET.tostring(jp2.box[3].xml.getroot()),
- b'this is a test')
-
-
@unittest.skipIf(glymur.lib.openjp2.OPENJP2 is None and
not OPENJP2_IS_V2_OFFICIAL,
"Missing openjp2 library version 2.0+.")