You are viewing a plain text version of this content. The canonical link for it is here.
Posted to issues@commons.apache.org by "haruhiko nishi (JIRA)" <ji...@apache.org> on 2009/09/09 17:00:58 UTC

[jira] Commented: (IO-218) Introduce new filter input stream with replacement facilities

    [ https://issues.apache.org/jira/browse/IO-218?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=12753115#action_12753115 ] 

haruhiko nishi commented on IO-218:
-----------------------------------

Hi I'm also working on a Stream that can handle pattern replacement.

{code:title=ByteArrayInputStream.java|borderStyle=solid}
public class ByteArrayReplaceInputStream extends InputStream {
    private byte[] buf;
    private int count;
    private PatternList.PatternListIterator itr;
    private Map<PatternList.PatternEntry,Integer> counter=new IdentityHashMap<PatternList.PatternEntry,Integer>();
    private int pos;
    private int mark=0;
    
    public ByteArrayReplaceInputStream(byte[] buf,PatternList list) {
        this.itr=list.iterator();
        this.buf=new byte[buf.length];
        ByteBuffer byteBuffer=ByteBuffer.wrap(buf,0,buf.length);
        itr.readLock();
        try{
            match(byteBuffer,itr.next(),0,byteBuffer.limit());
        }finally{
            itr.readUnlock();
        }
    }

    private void write(ByteBuffer buffer){
        byte[] byteArray=new byte[buffer.remaining()];
        buffer.get(byteArray);
        write(byteArray);
    }

    private void write(byte[] b){
        int newcount=count+b.length;
        if(newcount > buf.length){
            byte newbuf[]=new byte[Math.max(buf.length<<1,newcount)];
            System.arraycopy(buf,0,newbuf,0,count);
            buf=newbuf;
        }
        System.arraycopy(b,0,buf,count,b.length);
        count=newcount;
    }

    private final void match(ByteBuffer src,PatternList.PatternEntry pattern,int start,int end) {
        if(pattern.isSingle())
            single(src,pattern,start,end);
        else
            around(src,pattern,start,end);
    }

    private int count(PatternList.PatternEntry pattern){
        Integer count=counter.get(pattern);
        if(count==null)
            count=counter.put(pattern,1);
        else
            count=counter.put(pattern,count+1);
        return count==null ? 0 : count;
    }

    private boolean isPatternValid(PatternList.PatternEntry pattern){
        Integer count=counter.get(pattern);
        if(count==null)
            return 0<=pattern.getMaxOccurence();
        else
            return count<pattern.getMaxOccurence();
    }

    private final void around(ByteBuffer src,PatternList.PatternEntry patternEntry,int start,int end){
        if(start<0 || start>end || end>src.limit())
            throw new IndexOutOfBoundsException("start:"+start+" end:"+end);
        int pos=start;
        int limit_org=end;
        int mark=0;
        boolean flag=false;
        int j=pos;
        Pattern pattern=patternEntry.getPattern();
        while(isPatternValid(patternEntry) && j<=limit_org-pattern.length()) {
            boolean found=true;
            int cur=j;
            for(int i=0;i<pattern.length();i++){
                if(src.get(cur+i)!=pattern.get(i)){
                    found=false;
                    break;
                }
            }
            if(found){
                if(flag=!flag){
                    j=mark=cur+pattern.length();
                    pattern=pattern.swap();
                }else{
                    src.position(pos).limit(mark);
                    j=cur+pattern.length();
                    if(itr.hasNext())
                        match(src,itr.next(),pos,src.limit());
                    else
                        write(src);
                    pattern=pattern.swap();
                    src.position(mark).limit(cur);
                    if(src.remaining()>0){
                        ByteBuffer target=src.slice();
                        int size=target.remaining();
                        byte[] array=new byte[size];
                        target.get(array);
                        array=patternEntry.replace(count(patternEntry),array);
                        write(array);
                    }
                    pos=src.position(src.limit()).position();
                    src.limit(limit_org);
                }
            }
            if(!found){
                int k=cur+pattern.length();
                if(k>=src.limit())
                    break;
                j +=pattern.skip(src.get(k) & 0xff);
            }
        }
        src.position(pos);
        if(itr.hasNext())
            match(src,itr.next(),pos,src.limit());
        else
            write(src);
        itr.previous();
    }

    private void single(ByteBuffer src,PatternList.PatternEntry patternEntry,int start,int end){
        if(start<0 || start>end || end>src.limit())
            throw new IndexOutOfBoundsException("start:"+start+" end:"+end);
        int pos=start;
        int limit_org=end;
        int j=pos;

        Pattern pattern=patternEntry.getPattern();
        while(isPatternValid(patternEntry) && j<=limit_org-pattern.length()) {
            boolean found=true;
            int cur=j;
            for(int i=0;i<pattern.length();i++){
                if(src.get(cur+i)!=pattern.get(i)){
                    found=false;
                    break;
                }
            }
            if(found){
                src.position(pos).limit(cur);
                j=cur+pattern.length();
                if(itr.hasNext())
                    single(src,itr.next(),pos,src.limit());
                else
                    write(src);
                src.position(cur).limit(j);
                if(src.remaining()>0){
                    ByteBuffer target=src.slice();
                    int size=target.remaining();
                    byte[] array=new byte[size];
                    target.get(array);
                    write(patternEntry.replace(count(patternEntry),array));
                }
                pos=src.position(src.limit()).position();
                src.limit(limit_org);
            }
            if(!found){
                int k=cur+pattern.length();
                if(k>=src.limit())
                    break;
                j +=pattern.skip(src.get(k) & 0xff);
            }
        }
        src.position(pos);
        if(itr.hasNext())
            single(src,itr.next(),pos,src.limit());
        else
            write(src);
        itr.previous();
    }
    
    @Override
    public synchronized int read(){
	    return (pos < count) ? (buf[pos++] & 0xff) : -1;
    }

    @Override
    public synchronized int read(byte b[], int off, int len){
	    if (b == null)
	        throw new NullPointerException();
	    else if(off < 0 || len < 0 || len > b.length - off)
	        throw new IndexOutOfBoundsException();
	    if (pos >= count)
	        return -1;
	    if(pos + len > count)
            len=count - pos;
	    if (len <= 0)
	        return 0;
	    System.arraycopy(buf, pos, b, off, len);
	    pos += len;
	    return len;
    }

    public synchronized long skip(long n){
        if(pos +n>count){
            n=count - pos;
        }
        if(n<0)
            return 0;
        pos +=n;
        return n;
    }

    public synchronized int avaiable(){
        return count - pos;
    }

    public boolean markSupported(){
        return true;
    }

    public synchronized void mark(int readAheadLimit){
        mark=pos;
    }

    public synchronized void reset(){
        pos=mark;
    }

    public void close() throws IOException{
        
    }

}
{code}


> Introduce new filter input stream with replacement facilities
> -------------------------------------------------------------
>
>                 Key: IO-218
>                 URL: https://issues.apache.org/jira/browse/IO-218
>             Project: Commons IO
>          Issue Type: Improvement
>          Components: Filters
>    Affects Versions: 1.4
>         Environment: all environments
>            Reporter: Denis Zhdanov
>             Fix For: 1.4, 2.0
>
>         Attachments: ReplaceFilterInputStream.java, ReplaceFilterInputStreamTest.java
>
>   Original Estimate: 120h
>  Remaining Estimate: 120h
>
> It seems convenient to have a FilterInputStream that allows to apply predefined repalcement rules against the read data. 
> For example we may want to configure the following replacements:
> {noformat}
> {1, } -> {7, 8}
> {1} -> {9}
> {3, 2} -> {}
> {noformat}
> and apply them to the input like
> {noformat}
> {4, 3, 2, 1, 2, 1, 3}
> {noformat}
> in order to get a result like
> {noformat}
> {4, 7, 8, 9, 3}
> {noformat}
> I created the class that allows to do that and attached it to this ticket. Unit test class at junit4 format is attached as well.
> So, the task is to review the provided classes, consider if it's worth to add them to commons-io distribution and perform the inclusion in the case of possible result.

-- 
This message is automatically generated by JIRA.
-
You can reply to this email to add a comment to the issue online.