import blockreader_base
import os

class blockreader_lseek(blockreader_base.blockreader_base):
    """
    See blockreader_base documentation.
    This blockreader uses os.lseek to allow access to files larger
    than 2GB. As Python can't handle 64 bits integers easily, we have
    to use *ugly* hacks.
    """
    def __init__(self,filename,blocksize):
        blockreader_base.blockreader_base.__init__(self,0,blocksize)
        self.filename = filename
        self.filedesc = os.open(self.filename,os.O_RDONLY)
        # first, go to the end of the file
        try: filesize = os.lseek(self.filedesc,0,2)
        except OSError: pass
        # then, try to count how many blocks we have
        # we lseek negatively until offset is less than blocksize,
        # ignoring errors (error means "offset larger than 2 GB")
        blockcount = 0
        while 1:
            try:
                blockcount += 1
                lastblock = os.lseek(self.filedesc,-blocksize,1)
                if lastblock<blocksize: break
            except OSError: pass
        self.blockcount  = blockcount
        self.lastblock   = lastblock
        self.wholeblocks = blockcount
        if self.lastblock: self.blockcount += 1
        # set some internal pointers
        os.lseek(self.filedesc,0,0)
        self.currentseek = 0 # current position (in blocks)
        self.maxseek = 2000000000/blocksize # max seekable offset (in blocks)
    def getblock(self,blocknumber):
        self.checkblock(blocknumber)
        self.locate(blocknumber)
        block = os.read(self.filedesc,self.blocksize)
        if len(block) != self.blocksize:
            try: os.lseek(self.filedesc,-len(block),1)
            except OSError: pass
        else: self.currentseek += 1
        return block
    def locate(self,blocknumber):
        while blocknumber != self.currentseek:
            remainingoffset = blocknumber - self.currentseek
            sign = abs(remainingoffset)/remainingoffset
            quantity = abs(remainingoffset)
            if quantity > self.maxseek: quantity = self.maxseek
            self.currentseek += sign*quantity
            try: os.lseek(self.filedesc,sign*quantity*self.blocksize,1)
            except OSError: pass
