All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.jclarion.clarion.file.RingBufferedInputStreamClarionFile Maven / Gradle / Ivy

package org.jclarion.clarion.file;

import java.io.IOException;
import java.io.InputStream;
import org.jclarion.clarion.ClarionRandomAccessFile;


public abstract class RingBufferedInputStreamClarionFile extends ClarionRandomAccessFile
{
    private byte buffer[]=new byte[16384]; // ring buffer
    private int head;
    private int tail;
    

    private boolean						tailLoop; // track if tail has looped. Used for figuring back buffer
    private long                        pos;
    private long						nextPos;
    private InputStream                 stream;

    public RingBufferedInputStreamClarionFile()
    {
    }
    
    @Override
    public void close() throws IOException 
    {
        closeStream();
    }

    private long lengthCache=-1;
    @Override
    public long length() throws IOException 
    {
        if (lengthCache==-1) {
            byte buffer[]=null;
            InputStream is = createStream();
            try {
                lengthCache=0;
                while (true) {
                    long len = is.skip(65536);
                    if (len>0) {
                        lengthCache+=len;
                        continue;
                    }
                    if (buffer==null) {
                        if (is.read()==-1) break;
                        lengthCache++;
                        buffer=new byte[1024];
                    } else {
                        len = is.read(buffer);
                        if (len<=0) break;
                        lengthCache+=len;
                    }       
                } 
            } finally {
                is.close();
            }
        }
        return lengthCache;
    }

    @Override
    public int read(byte[] target, int ofs, int len) throws IOException 
    {
    	seekToNextPos();
    	
        if (head==tail) fillBuffer();
        if (head==tail) return 0;
        
        int end=tail;
        if (endend) {
            len=end-head;
        }
        
        System.arraycopy(buffer,head,target,ofs,len);

        head+=len;
        if (head==buffer.length) head=0;

        pos+=len;
        nextPos+=len;
        return len;
    }

    @Override
    public void seek(long ofs) throws IOException 
    {
    	nextPos=ofs;
    }
    
    private void seekToNextPos() throws IOException
    {
        // read backwards - into ring buffer
        if (nextPosbackbuffer) {
                back=backbuffer;
            }
            
            head=head-(int)back;
            if (head<0) head+=buffer.length;
            pos=pos-back;
        }

        // read backwards - start all over
        if (nextPospos+buffer.length) {
        	// position is way infront. skip input stream to correct positioning
        	
        	// calculate actual position of input stream
        	long actualPos=pos;
        	if (tail>head) {
        		actualPos+=(tail-head);
        	}
        	if (tail0) {
        		pos=actualPos;
           		initBuffer();
        		head=0;
        		tail=0;
        		tailLoop=false;
        		while (skip>0) {
        			long thisSkip = stream.skip(skip);
        			if (thisSkip<=0) break;
        			pos+=thisSkip;
        			skip-=thisSkip;
        		}
        	}
        }
        
        // read ahead
        while (nextPos>pos) {
            if (head==tail) fillBuffer();
            if (head==tail) break;
            
            long len = nextPos-pos;
            
            int end=tail;
            if (endend) {
                len=end-head;
            }
            
            head+=(int)len;
            if (head==buffer.length) head=0;
            pos+=len;
        }
    }

    @Override
    public void write(byte[] arg0, int arg1, int arg2) throws IOException 
    {
        throw new IOException("Not supported");
    }
    
    protected abstract InputStream createStream() throws IOException;

    private void initBuffer() throws IOException
    {
        if (stream==null) {
            stream=createStream();
            head=0;
            tail=0;
            pos=0;
            tailLoop=false;
        }            	
    }
    
    private void fillBuffer() throws IOException
    {
    	initBuffer();
    	
        int read=buffer.length-tail;
        
        // only read half buffer at a time so that we have some backbuffer
        if (read>buffer.length/2) read=buffer.length/2;
        
        // do not allow tail to overrun head
        if (tail=head) read = head-tail-1;
        if (read==0) return;
     
        read = stream.read(buffer,tail,read);
        if (read<=0) return;
        tail+=read;
        if (tail==buffer.length) {
        	tail=0;
        	tailLoop=true;
        }
    }
    
    protected void closeStream() throws IOException
    {
        try {
            if (stream!=null) {
                stream.close();
            }
        } finally {
            stream=null;
            head=0;
            tail=0;
            pos=0;
        }
    }

    @Override
    public long position() throws IOException {
        return nextPos;
    }
    
    protected void adjustPosition(long adjust)
    {
    	nextPos=nextPos+adjust;
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy