+READERS = {
+ INT: read_signed_integer,
+ UINT: read_unsigned_integer,
+ FLOAT: read_float,
+ STRING: read_string,
+ UNICODE: read_unicode_string,
+ DATE: read_date,
+ BINARY: lambda stream, size: bytearray(stream.read(size))
+}
+
+
+class Stream(object):
+ class Substream(object):
+ def __init__(self, stream, offset, size):
+ self.stream = stream
+ self.offset = offset
+ self.size = size
+
+ def read(self, size):
+ current_offset = self.tell()
+ if current_offset == 0:
+ self.stream.seek(self.offset)
+ if size > self.size:
+ return self.stream.read(self.size)
+ else:
+ return self.stream.read(size)
+ else:
+ if current_offset > self.size:
+ return b''
+ else:
+ max_size = (self.size - current_offset)
+ if size <= max_size:
+ return self.stream.read(size)
+ else:
+ return self.stream.read(max_size)
+
+ def seek(self, offset, whence=os.SEEK_SET):
+ if whence == os.SEEK_SET:
+ desired_offset = self.offset + offset
+ elif whence == os.SEEK_CUR:
+ desired_offset = self.stream.tell() + offset
+ elif whence == os.SEEK_END:
+ desired_offset = self.offset + self.size + offset
+
+ if not self.offset <= desired_offset:
+ raise IOError
+
+ self.stream.seek(desired_offset, os.SEEK_SET)
+
+ def tell(self):
+ stream_offset = self.stream.tell()
+ if stream_offset <= self.offset:
+ return 0
+ else:
+ return stream_offset - self.offset
+
+ def substream(self, offset, size):
+ if offset + size <= self.size:
+ return self.stream.substream(self.offset + offset, size)
+ else:
+ raise IOError
+
+ def __getitem__(self, key):
+ if isinstance(key, (int, long)):
+ self.seek(key)
+ return self.read(1)
+ elif isinstance(key, slice):
+ if key.start is None or key.stop is None or key.step is not None:
+ raise IndexError
+ return self.substream(key.start, (key.stop - key.start))
+ else:
+ raise TypeError
+
+ def __init__(self, file_like):
+ self.file = file_like
+ self.file.seek(0, os.SEEK_END)
+ self.size = self.file.tell()
+ self.file.seek(0, os.SEEK_SET)
+ self.substreams = {}
+
+ def read(self, size):
+ return self.file.read(size)
+
+ def seek(self, offset, whence=os.SEEK_SET):
+ return self.file.seek(offset, whence)
+
+ def tell(self):
+ return self.file.tell()
+
+ def substream(self, offset, size):
+ if offset + size <= self.size:
+ if (offset, size) not in self.substreams:
+ self.substreams[(offset, size)] = self.Substream(self, offset, size)
+ return self.substreams[(offset, size)]
+ else:
+ raise IOError
+
+ def __getitem__(self, key):
+ if isinstance(key, (int, long)):
+ self.seek(key)
+ return self.read(1)
+ elif isinstance(key, slice):
+ if key.start is None or key.stop is None or key.step is not None:
+ raise IndexError
+ return self.substream(key.start, (key.stop - key.start))
+ else:
+ raise TypeError