# A list of supported compression types
SUPPORTED_COMPRESSION_TYPES = ('bz2', 'gz', 'tar.gz', 'tgz', 'tar.bz2')
-def _fake_seek_forward(self, offset, whence = os.SEEK_SET):
- """ Seek to a specified offset. We only support seeking forward and
- only relative to the beginning of the file and to the current
- position. """
+def _fake_seek_forward(file_obj, cur_pos, offset, whence = os.SEEK_SET):
+ """ This function implements the 'seek()' method for file object
+ 'file_obj'. Oonly seeking forward and is allowed, and 'whence' may be
+ either 'os.SEEK_SET' or 'os.SEEK_CUR'. """
if whence == os.SEEK_SET:
new_pos = offset
elif whence == os.SEEK_CUR:
- new_pos = self._pos + offset
+ new_pos = cur_pos + offset
else:
raise Error("'seek()' method requires the 'whence' argument " \
"to be %d or %d, but %d was passed" \
% (os.SEEK_SET, os.SEEK_CUR, whence))
- if new_pos < self._pos:
+ if new_pos < cur_pos:
raise Error("''seek()' method supports only seeking forward, " \
"seeking from %d to %d is not allowed" \
- % (self._pos, new_pos))
+ % (cur_pos, new_pos))
- length = new_pos - self._pos
+ length = new_pos - cur_pos
to_read = length
while to_read > 0:
- buf = self.read(to_read)
+ buf = file_obj.read(to_read)
if not buf:
break
to_read -= len(buf)
if to_read < 0:
raise Error("seeked too far: %d instead of %d" \
- % (self._pos, new_pos))
+ % (new_pos - to_read, new_pos))
-def _fake_tell(self):
- """ Return the current emulated file position """
-
- return self._pos
-
-def _add_fake_seek(self):
- """ Add a limitef fake 'seek()' and 'tell()' capability to a file-like
- object 'self'. """
-
- assert hasattr(self, "_pos") == False
- assert hasattr(self, "seek") == False
- assert hasattr(self, "tell") == False
-
- self._pos = 0
- self.seek = types.MethodType(_fake_seek_forward, self)
- self.tell = types.MethodType(_fake_tell, self)
+ return new_pos
class Error(Exception):
""" A class for exceptions generated by this module. We currently support
self._file_obj = file_obj
self._decompress_func = decompress_func
+ self._pos = 0
self._buffer = ''
self._buffer_pos = 0
self._eof = False
+ def seek(self, offset, whence = os.SEEK_SET):
+ """ The 'seek()' method, similar to the one file objects have. """
+
+ self._pos = _fake_seek_forward(self, self._pos, offset, whence)
+
+ def tell(self):
+ """ The 'tell()' method, similar to the one file objects have. """
+
+ return self._pos
+
def _read_from_buffer(self, length):
""" Read from the internal buffer. """
""" Read the compressed file, uncompress the data on-the-fly, and
return 'size' bytes of the uncompressed data. """
+ assert self._pos >= 0
assert self._buffer_pos >= 0
assert self._buffer_pos <= len(self._buffer)
size -= len(buf)
- if hasattr(self, "_pos"):
- self._pos += len(data)
+ self._pos += len(data)
return data
decompressor = zlib.decompressobj(16 + zlib.MAX_WBITS)
self._transfile_obj = _CompressedFile(self._file_obj,
decompressor.decompress)
- _add_fake_seek(self._transfile_obj)
elif self.name.endswith('.bz2'):
import bz2
self._transfile_obj = _CompressedFile(self._file_obj,
bz2.BZ2Decompressor().decompress)
- _add_fake_seek(self._transfile_obj)
else:
self.is_compressed = False
self._transfile_obj = self._file_obj
self.is_url = False
self._file_obj = None
self._transfile_obj = None
+ self._pos = 0
try:
self._file_obj = open(self.name, "rb")
""" Read the data from the file or URL and and uncompress it on-the-fly
if necessary. """
- return self._transfile_obj.read(size)
+ buf = self._transfile_obj.read(size)
+ self._pos += len(buf)
+
+ return buf
def __del__(self):
""" The class destructor which closes opened files. """
def seek(self, offset, whence = os.SEEK_SET):
""" The 'seek()' method, similar to the one file objects have. """
- self._transfile_obj.seek(offset, whence)
+
+ if hasattr(self._transfile_obj, "seek"):
+ self._transfile_obj.seek(offset, whence)
+ else:
+ self._pos = _fake_seek_forward(self._transfile_obj, self._pos, \
+ offset, whence)
def tell(self):
""" The 'tell()' method, similar to the one file objects have. """
- return self._transfile_obj.tell()
+
+ if hasattr(self._transfile_obj, "tell"):
+ return self._transfile_obj.tell()
+ else:
+ return self._pos