Merge branch 'issue170' into devel

This commit is contained in:
John Evans 2014-02-11 13:57:55 -05:00
commit a2df4d6c79

View file

@ -1115,6 +1115,18 @@ def _validate_jp2_box_sequence(boxes):
This is non-exhaustive.
"""
_validate_signature_compatibility(boxes)
_validate_jp2h(boxes)
_validate_jp2c(boxes)
_validate_association(boxes)
_validate_jpx_brand(boxes, boxes[1].brand)
_validate_jpx_compatibility(boxes, boxes[1].compatibility_list)
_validate_singletons(boxes)
_validate_top_level(boxes)
def _validate_signature_compatibility(boxes):
"""Validate the file signature and compatibility status."""
# Check for a bad sequence of boxes.
# 1st two boxes must be 'jP ' and 'ftyp'
if boxes[0].box_id != 'jP ' or boxes[1].box_id != 'ftyp':
@ -1122,6 +1134,14 @@ def _validate_jp2_box_sequence(boxes):
msg += "must be the file type box."
raise IOError(msg)
# The compatibility list must contain at a minimum 'jp2 '.
if 'jp2 ' not in boxes[1].compatibility_list:
msg = "The ftyp box must contain 'jp2 ' in the compatibility list."
raise IOError(msg)
def _validate_jp2c(boxes):
"""Validate the codestream box in relation to other boxes."""
# jp2c must be preceeded by jp2h
jp2h_lst = [idx for (idx, box) in enumerate(boxes)
if box.box_id == 'jp2h']
@ -1138,14 +1158,20 @@ def _validate_jp2_box_sequence(boxes):
msg = "The codestream box must be preceeded by a jp2 header box."
raise IOError(msg)
def _validate_jp2h(boxes):
"""Validate the JP2 Header box."""
_check_jp2h_child_boxes(boxes, 'top-level')
jp2h_lst = [box for box in boxes if box.box_id == 'jp2h']
jp2h = jp2h_lst[0]
# 1st jp2 header box cannot be empty.
jp2h = boxes[jp2h_idx]
if len(jp2h.box) == 0:
msg = "The JP2 header superbox cannot be empty."
raise IOError(msg)
# 1st jp2 header box must be ihdr
jp2h = boxes[jp2h_idx]
if jp2h.box[0].box_id != 'ihdr':
msg = "The first box in the jp2 header box must be the image "
msg += "header box."
@ -1159,15 +1185,12 @@ def _validate_jp2_box_sequence(boxes):
raise IOError(msg)
colr = jp2h.box[colr_lst[0]]
# Any cdef box must be in the jp2 header following the image header.
cdef_lst = [j for (j, box) in enumerate(boxes) if box.box_id == 'cdef']
if len(cdef_lst) != 0:
msg = "Any channel defintion box must be in the JP2 header "
msg += "following the image header."
raise IOError(msg)
_validate_channel_definition(jp2h, colr)
cdef_lst = [j for (j, box) in enumerate(jp2h.box)
if box.box_id == 'cdef']
def _validate_channel_definition(jp2h, colr):
"""Validate the channel definition box."""
cdef_lst = [j for (j, box) in enumerate(jp2h.box) if box.box_id == 'cdef']
if len(cdef_lst) > 1:
msg = "Only one channel definition box is allowed in the "
msg += "JP2 header."
@ -1186,19 +1209,7 @@ def _validate_jp2_box_sequence(boxes):
msg = "All color channels must be defined in the "
msg += "channel definition box."
raise IOError(msg)
# The compatibility list must contain at a minimum 'jp2 '.
if 'jp2 ' not in boxes[1].compatibility_list:
msg = "The ftyp box must contain 'jp2 ' in the compatibility list."
raise IOError(msg)
# JPX checks.
_asoc_check(boxes)
_jpx_brand(boxes, boxes[1].brand)
_jpx_compatibility(boxes, boxes[1].compatibility_list)
_check_for_singletons(boxes)
_check_top_level(boxes)
_check_jp2h_child_boxes(boxes, 'top-level')
JP2H_CHILDREN = set(['bpcc', 'cmap', 'ihdr', 'pclr'])
def _check_jp2h_child_boxes(boxes, parent_box_name):
@ -1243,7 +1254,7 @@ def _check_superbox_for_top_levels(boxes):
if hasattr(box, 'box'):
_check_superbox_for_top_levels(box.box)
def _check_top_level(boxes):
def _validate_top_level(boxes):
"""Several boxes can only occur at the top level."""
# Add the counts in the superboxes.
for box in boxes:
@ -1256,7 +1267,7 @@ def _check_top_level(boxes):
if 'dtbl' in multiples:
raise IOError('There can only be one dtbl box in a file.')
def _check_for_singletons(boxes):
def _validate_singletons(boxes):
"""Several boxes can only occur once."""
count = _collect_box_count(boxes)
# Which boxes occur more than once?
@ -1264,7 +1275,7 @@ def _check_for_singletons(boxes):
if 'dtbl' in multiples:
raise IOError('There can only be one dtbl box in a file.')
def _jpx_brand(boxes, brand):
def _validate_jpx_brand(boxes, brand):
"""
If there is a JPX box then the brand must be 'jpx '.
"""
@ -1276,9 +1287,9 @@ def _jpx_brand(boxes, brand):
raise RuntimeError(msg)
if hasattr(box, 'box') != 0:
# Same set of checks on any child boxes.
_jpx_brand(box.box, brand)
_validate_jpx_brand(box.box, brand)
def _jpx_compatibility(boxes, compatibility_list):
def _validate_jpx_compatibility(boxes, compatibility_list):
"""
If there is a JPX box then the compatibility list must also contain 'jpx '.
"""
@ -1290,10 +1301,10 @@ def _jpx_compatibility(boxes, compatibility_list):
raise RuntimeError(msg)
if hasattr(box, 'box') != 0:
# Same set of checks on any child boxes.
_jpx_compatibility(box.box, compatibility_list)
_validate_jpx_compatibility(box.box, compatibility_list)
def _asoc_check(boxes):
def _validate_association(boxes):
"""
Association boxes can only contain number list boxes and xml boxes, as far
as we know.
@ -1306,7 +1317,7 @@ def _asoc_check(boxes):
raise RuntimeError(msg)
if hasattr(box, 'box') != 0:
# Same set of checks on any child boxes.
_asoc_check(box.box)
_validate_association(box.box)