docs: def unpack_stream(self, stream):
          """Unpack bytes from a stream of data field-by-field
  
          In the most basic case, the basic algorithm here is as follows::
  
              for _name, field in self.ordered_fields:
                 length = field.bytes_required
                 data = stream.read(length)
                 field.unpack(data)
  
          This logic is complicated somewhat by the handling of variable length
          greedy fields (there may only be one).  The logic when we see a
          greedy field (bytes_required returns None) in the stream is to
          pivot and parse the remaining fields starting from the last and
          moving through the stream backwards.  There is also some special
          logic present for dealing with checksum fields.
  
          """
          crc_fields = []
          greedy_field = None
          # go through the fields from first to last.  If we hit a greedy
          # field, break out of the loop
          for i, (name, field) in enumerate(self.ordered_fields):
              if isinstance(field, CRCField):
                  crc_fields.append((field, stream.tell()))
              length = field.bytes_required
              if field.is_substructure():
                  remaining_data = stream.getvalue()[stream.tell():]
                  returned_stream = field.unpack(remaining_data, trailing=True)
                  if returned_stream is not None:
                      consumed = returned_stream.tell()
                  else:
                      consumed = 0
                  # We need to fast forward by as much as was consumed by the structure
                  stream.seek(stream.tell() + consumed)
                  continue
              elif length is None:
                  if isinstance(field, FieldArray) and field.num_elements is not None:
                      # Read the data greedily now, and we'll backtrack after enough elements have been read.
                      data = stream.read()
                  else:
                      greedy_field = field
                      break
              else:
                  data = stream.read(length)
                  if len(data) != length:
                      raise SuitcaseParseError("While attempting to parse field "
                                               "%r we tried to read %s bytes but "
                                               "we were only able to read %s." %
                                               (name, length, len(data)))
  
              try:
                  unused_data = field.unpack(data)
                  stream.seek(-len(unused_data or ""), os.SEEK_CUR)
              except SuitcaseException:
                  raise  # just re-raise these
              except Exception:
                  exc_type = SuitcaseParseError
                  _, exc_value, exc_traceback = sys.exc_info()
                  exc_value = exc_type("Unexpected exception while unpacking field %r: %s" % (name, str(exc_value)))
                  six.reraise(exc_type, exc_value, exc_traceback)
  
          if greedy_field is not None:
              remaining_data = stream.read()
              inverted_stream = BytesIO(remaining_data[::-1])
  
              # work through the remaining fields in reverse order in order
              # to narrow in on the right bytes for the greedy field
              reversed_remaining_fields = self.ordered_fields[(i + 1):][::-1]
              for _name, field in reversed_remaining_fields:
                  if isinstance(field, CRCField):
                      crc_fields.append(
                          (field, -inverted_stream.tell() - field.bytes_required))
                  length = field.bytes_required
                  data = inverted_stream.read(length)[::-1]
                  if len(data) != length:
                      raise SuitcaseParseError("While attempting to parse field "
                                               "%r we tried to read %s bytes but "
                                               "we were only able to read %s." %
                                               (_name, length, len(data)))
                  try:
                      field.unpack(data)
                  except SuitcaseException:
                      raise  # just re-raise these
                  except Exception:
                      exc_type = SuitcaseParseError
                      _, exc_value, exc_traceback = sys.exc_info()
                      exc_value = exc_type("Unexpected exception while unpacking field %r: %s" % (name, str(exc_value)))
                      six.reraise(exc_type, exc_value, exc_traceback)
  
              greedy_data_chunk = inverted_stream.read()[::-1]
              greedy_field.unpack(greedy_data_chunk)
  
          if crc_fields:
              data = stream.getvalue()
              for (crc_field, offset) in crc_fields:
                  crc_field.validate(data, offset)