def normalize_stream(stream_name, stream): """Take manifest stream and return a list of tokens in normalized format. :stream_name: The name of the stream. :stream: A dict mapping each filename to a list of `_range.LocatorAndRange` objects. """ stream_name = stream_name.replace(' ', '\\040') stream_tokens = [stream_name] sortedfiles = list(stream.keys()) sortedfiles.sort() blocks = {} streamoffset = 0L # Go through each file and add each referenced block exactly once. for streamfile in sortedfiles: for segment in stream[streamfile]: if segment.locator not in blocks: stream_tokens.append(segment.locator) blocks[segment.locator] = streamoffset streamoffset += segment.block_size # Add the empty block if the stream is otherwise empty. if len(stream_tokens) == 1: stream_tokens.append(config.EMPTY_BLOCK_LOCATOR) for streamfile in sortedfiles: # Add in file segments current_span = None fout = streamfile.replace(' ', '\\040') for segment in stream[streamfile]: # Collapse adjacent segments streamoffset = blocks[segment.locator] + segment.segment_offset if current_span is None: current_span = [streamoffset, streamoffset + segment.segment_size] else: if streamoffset == current_span[1]: current_span[1] += segment.segment_size else: stream_tokens.append("{0}:{1}:{2}".format(current_span[0], current_span[1] - current_span[0], fout)) current_span = [streamoffset, streamoffset + segment.segment_size] if current_span is not None: stream_tokens.append("{0}:{1}:{2}".format(current_span[0], current_span[1] - current_span[0], fout)) if not stream[streamfile]: stream_tokens.append("0:0:{0}".format(fout)) return stream_tokens