def data_element_generator(fp, is_implicit_VR, is_little_endian, stop_when=None, defer_size=None): """:return: (tag, VR, length, value, value_tell, is_implicit_VR, is_little_endian) """ if is_little_endian: endian_chr = "<" else: endian_chr = ">" if is_implicit_VR: element_struct = Struct(endian_chr + "HHL") else: # Explicit VR # tag, VR, 2-byte length (or 0 if special VRs) element_struct = Struct(endian_chr + "HH2sH") extra_length_struct = Struct(endian_chr + "L") # for special VRs extra_length_unpack = extra_length_struct.unpack # for lookup speed # Make local variables so have faster lookup fp_read = fp.read fp_tell = fp.tell element_struct_unpack = element_struct.unpack while True: # Read tag, VR, length, get ready to read value bytes_read = fp_read(8) if len(bytes_read) < 8: raise StopIteration # at end of file if is_implicit_VR: # must reset VR each time; could have set last iteration (e.g. SQ) VR = None group, elem, length = element_struct_unpack(bytes_read) else: # explicit VR group, elem, VR, length = element_struct_unpack(bytes_read) if VR in extra_length_VRs_b: bytes_read = fp_read(4) length = extra_length_unpack(bytes_read)[0] # Positioned to read the value, but may not want to -- check stop_when value_tell = fp_tell() if stop_when is not None: if stop_when(group, elem): rewind_length = 8 if not is_implicit_VR and VR in extra_length_VRs_b: rewind_length += 4 fp.seek(value_tell - rewind_length) raise StopIteration # Reading the value # First case (most common): reading a value with a defined length if length != 0xFFFFFFFF: if defer_size is not None and length > defer_size: # Flag as deferred by setting value to None, and skip bytes value = None fp.seek(fp_tell() + length) else: value = fp_read(length) # import pdb;pdb.set_trace() yield ((group, elem), VR, length, value, value_tell) # Second case: undefined length - must seek to delimiter, # unless is SQ type, in which case is easier to parse it, because # undefined length SQs and items of undefined lengths can be nested # and it would be error-prone to read to the correct outer delimiter else: # Try to look up type to see if is a SQ # if private tag, won't be able to look it up in dictionary, # in which case just ignore it and read the bytes unless it is # identified as a Sequence if VR is None: try: VR = dictionaryVR(tag) except KeyError: # Look ahead to see if it consists of items and is thus a SQ next_tag = TupleTag(unpack(endian_chr + "HH", fp_read(4))) # Rewind the file fp.seek(fp_tell() - 4) if next_tag == ItemTag: VR = b'SQ' if VR == b'SQ': yield ((group, elem), VR, length, None, value_tell) # seq = read_sequence(fp, is_implicit_VR, # is_little_endian, length, encoding) # yield DataElement(tag, VR, seq, value_tell, # is_undefined_length=True) else: raise NotImplementedError( "This reader does not handle undefined length except for SQ" ) from pydicom.fileio.fileutil import read_undefined_length_value delimiter = SequenceDelimiterTag value = read_undefined_length_value(fp, is_little_endian, delimiter, defer_size) yield ((group, elem), VR, length, value, value_tell)
def data_element_generator(fp, is_implicit_VR, is_little_endian, stop_when=None, defer_size=None): """:return: (tag, VR, length, value, value_tell, is_implicit_VR, is_little_endian) """ if is_little_endian: endian_chr = "<" else: endian_chr = ">" if is_implicit_VR: element_struct = Struct(endian_chr + "HHL") else: # Explicit VR # tag, VR, 2-byte length (or 0 if special VRs) element_struct = Struct(endian_chr + "HH2sH") extra_length_struct = Struct(endian_chr + "L") # for special VRs extra_length_unpack = extra_length_struct.unpack # for lookup speed # Make local variables so have faster lookup fp_read = fp.read fp_tell = fp.tell element_struct_unpack = element_struct.unpack defer_size = size_in_bytes(defer_size) while True: # Read tag, VR, length, get ready to read value bytes_read = fp_read(8) if len(bytes_read) < 8: raise StopIteration # at end of file if is_implicit_VR: # must reset VR each time; could have set last iteration (e.g. SQ) VR = None group, elem, length = element_struct_unpack(bytes_read) else: # explicit VR group, elem, VR, length = element_struct_unpack(bytes_read) if VR in extra_length_VRs_b: bytes_read = fp_read(4) length = extra_length_unpack(bytes_read)[0] # Positioned to read the value, but may not want to -- check stop_when value_tell = fp_tell() if stop_when is not None: if stop_when(group, elem): rewind_length = 8 if not is_implicit_VR and VR in extra_length_VRs_b: rewind_length += 4 fp.seek(value_tell - rewind_length) raise StopIteration # Reading the value # First case (most common): reading a value with a defined length if length != 0xFFFFFFFF: if defer_size is not None and length > defer_size: # Flag as deferred by setting value to None, and skip bytes value = None fp.seek(fp_tell() + length) else: value = fp_read(length) # import pdb;pdb.set_trace() yield ((group, elem), VR, length, value, value_tell) # Second case: undefined length - must seek to delimiter, # unless is SQ type, in which case is easier to parse it, because # undefined length SQs and items of undefined lengths can be nested # and it would be error-prone to read to the correct outer delimiter else: # Try to look up type to see if is a SQ # if private tag, won't be able to look it up in dictionary, # in which case just ignore it and read the bytes unless it is # identified as a Sequence if VR is None: try: VR = dictionary_VR(tag) except KeyError: # Look ahead to see if it consists of items and # is thus a SQ next_tag = TupleTag(unpack(endian_chr + "HH", fp_read(4))) # Rewind the file fp.seek(fp_tell() - 4) if next_tag == ItemTag: VR = b'SQ' if VR == b'SQ': yield ((group, elem), VR, length, None, value_tell) # seq = read_sequence(fp, is_implicit_VR, # is_little_endian, length, encoding) # yield DataElement(tag, VR, seq, value_tell, # is_undefined_length=True) else: raise NotImplementedError("This reader does not handle " "undefined length except for SQ") from pydicom.fileio.fileutil import read_undefined_length_value delimiter = SequenceDelimiterTag value = read_undefined_length_value(fp, is_little_endian, delimiter, defer_size) yield ((group, elem), VR, length, value, value_tell)