commons-issues mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From "haruhiko nishi (JIRA)" <j...@apache.org>
Subject [jira] Issue Comment Edited: (IO-218) Introduce new filter input stream with replacement facilities
Date Wed, 09 Sep 2009 15:16:57 GMT

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

haruhiko nishi edited comment on IO-218 at 9/9/09 8:15 AM:
-----------------------------------------------------------

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

usage: 
        PatternList list=new PatternList();
        list.add("src=\"".getBytes("UTF-8"),"\"".getBytes("UTF-8"),new SrcHrefReplacer("UTF8"),Integer.MAX_VALUE);
        list.add("href=\"".getBytes("UTF-8"),"\"".getBytes("UTF-8"),new SrcHrefReplacer("UTF-8"),Integer.MAX_VALUE);


        ByteArrayReplaceInputStream in=new ByteArrayReplaceInputStream(someByteArray,list);
        int bytesRead;
        byte[] buf=new byte[4096];
        while((bytesRead=in.read(buf,0,buf.length))!=-1)
            out.write(buf,0,bytesRead);
        in.close();


{code:title=ByteArrayReplaceInputStream.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}

{code:title=Pattern.java|borderStyle=solid}
abstract class Pattern {
    abstract int length();
    abstract int get(int pos);
    abstract int skip(int value);
    abstract Pattern swap();
}
{code}

{code:title=PatternList.java|borderStyle=solid}
public class PatternList {
    private ReentrantReadWriteLock lock=new ReentrantReadWriteLock();
    private Lock readLock=lock.readLock();
    private Lock writeLock=lock.writeLock();
    private PatternEntry head=new PatternEntry(null,-1,null,null,null);

    public PatternList(){
        head.next=head.previous=head;
    }

    public void add(byte[] bBegin,byte[] bEnd,PatternReplacer handler, int maxOccurence){
        add(new BeginPattern(new PatternTable(bBegin),new PatternTable(bEnd)),maxOccurence,handler);
    }

    public void add(byte[] p,PatternReplacer handler, int maxOccurence){
        add(new SinglePattern(new PatternTable(p)),maxOccurence,handler);
    }

    PatternListIterator iterator(){
        return new PatternListIterator(head.previous);
    }

    private void add(Pattern pattern,int maxOccurence,PatternReplacer handler){
        writeLock.lock();
        try{
            for(PatternEntry tmp=head;;tmp=tmp.next)
                if(tmp.pattern==null||tmp.compareTo(pattern)<=0){
                    PatternEntry newEntry=new PatternEntry(handler,maxOccurence,pattern,tmp,tmp.previous);
                    newEntry.previous.next=newEntry;
                    newEntry.next.previous=newEntry;
                    if(tmp==head)
                        head=newEntry;
                    break;
                }
        }finally{
            writeLock.unlock();
        }
    }

    class PatternListIterator{
        private PatternEntry copyHead;
        
        PatternListIterator(PatternEntry head){
            this.copyHead=head;
        }

        public PatternEntry next(){
            copyHead=copyHead.next;
            return copyHead;
        }

        public PatternEntry previous(){
            copyHead=copyHead.previous;
            return copyHead;
        }

        public boolean hasNext(){
            return copyHead.next.pattern!=null;
        }

        void readLock(){
            readLock.lock();
        }

        void readUnlock(){
            readLock.unlock();
        }

    }

    static class PatternEntry implements Comparable<Pattern>{
        Pattern pattern;
        PatternEntry next;
        PatternEntry previous;
        PatternReplacer handler;
        int maxOccurence;

        private PatternEntry(PatternReplacer handler,int maxOccurence,Pattern element,PatternEntry
next, PatternEntry previous){
            this.handler=handler;
            this.pattern=element;
            this.next=next;
            this.previous=previous;
            this.maxOccurence=maxOccurence;
        }

        byte[] replace(int pos,byte[] match){
            return handler.replace(pos,match);
        }

        int getMaxOccurence() {
            return maxOccurence;
        }

        Pattern getPattern(){
            return pattern;
        }
         
        public int compareTo(Pattern other) {

            if(this.pattern instanceof SinglePattern && other instanceof BeginPattern)
                return -1;
            else if(this.pattern instanceof BeginPattern && other instanceof SinglePattern)
                return 1;
            else{
                return ((ComparablePattern)this.pattern).size-((ComparablePattern)other).size;
            }
        }

        boolean isSingle(){
            return pattern instanceof SinglePattern;
        }


    }

    private static abstract class ComparablePattern extends Pattern{
        int size;
        ComparablePattern(int size){
            this.size=size;
        }
    }

    private static class SinglePattern extends ComparablePattern {
        PatternTable pattern;

        private SinglePattern(PatternTable pattern){
            super(pattern.length());
            this.pattern=pattern;
        }

        @Override
        int length() {
            return pattern.length();
        }

        @Override
        int get(int pos) {
            return pattern.get(pos);
        }

        @Override
        int skip(int value) {
            return pattern.skip(value);
        }

        @Override
        protected Pattern swap() {
            throw new UnsupportedOperationException("single pattern cannot be swapped.");
        }
    }

    private static class EndPattern extends Pattern {
        PatternTable end;
        Pattern nextMatcher;

        private EndPattern(PatternTable end,Pattern nextMatcher){
            this.end=end;
            this.nextMatcher=nextMatcher;
        }

        @Override
        int length() {
            return end.length();
        }

        @Override
        int get(int pos) {
            return end.get(pos);
        }

        @Override
        int skip(int value) {
            return end.skip(value);
        }

        @Override
        protected Pattern swap() {
            return nextMatcher;
        }
    }

    private static class BeginPattern extends ComparablePattern{
        PatternTable begin;
        Pattern nextMatcher;

        private BeginPattern(PatternTable begin,PatternTable end){
            super(begin.length()+end.length());
            this.begin=begin;
            nextMatcher=new EndPattern(end,this);
        }

        @Override
        int length() {
            return begin.length();
        }

        @Override
        int get(int pos) {
            return begin.get(pos);
        }

        @Override
        int skip(int value) {
            return begin.skip(value);
        }

        @Override
        protected Pattern swap() {
            return nextMatcher;
        }
    }

    private static class PatternTable {
        private final int[] pattern;
        private int[] skip;

        PatternTable(byte[] target){
            pattern=new int[target.length];
            for(int i=0;i<target.length;i++)
                pattern[i]=target[i] & 0xff;
            this.skip=getSkipArray(target);
        }

        int length(){
            return pattern.length;
        }

        int get(int i){
            return pattern[i];
        }

        int skip(int i){
            return skip[i];
        }

        private static int[] getSkipArray(byte[] pattern){
            int[] skip=new int[256];
            int i;
            for(i=0; i<skip.length;i++)
                skip[i]=pattern.length+1;
            for(i=0; i<pattern.length;i++)
                skip[pattern[i] & 0xff]=pattern.length -i;
            return skip;
        }
    }
}
{code}

{code:title=PatternReplacer.java|borderStyle=solid}
public interface PatternReplacer {
    byte[] replace(int pos,final byte[] matched);
}
{code}

{code:title=StringPatternReplacer.java|borderStyle=solid}
public abstract class StringPatternReplacer implements PatternReplacer{
    private String charset;

    protected StringPatternReplacer(String charset){
        this.charset=charset;
    }
    
    public final byte[] replace(int pos, byte[] matched) {
        String replaced;
        try {
            replaced = replace(pos,new String(matched,charset));
            if(replaced!=null)
                return replaced.getBytes(charset);
        } catch (UnsupportedEncodingException e) {

        }
        return null;
    }

    protected abstract String replace(int pos,String matched);

}
{code}
{code:title=SrcHrefReplacer.java|borderStyle=solid}
public class SrcHrefReplacer extends StringPatternReplacer {
    
    public SrcHrefReplacer(String charset){
        super(charset);
    }

    public String replace(int pos, String matched) {
      if(matched.endsWith(".jpg")||matched.endsWith(".gif"))
          return matched;
       if(matched.contains("somedomain.com"))
           return matched;
      return matched.replaceAll("somedomain.com","mydomain.com");

    }
}
{code}

      was (Author: hanishi):
    Hi I'm also working on a Stream that can handle pattern replacement.

usage: 
        PatternList list=new PatternList();
        list.add("src=\"".getBytes("UTF-8"),"\"".getBytes("UTF-8"),new SrcHrefReplacer("UTF8"),Integer.MAX_VALUE);
        list.add("href=\"".getBytes("UTF-8"),"\"".getBytes("UTF-8"),new SrcHrefReplacer("UTF-8"),Integer.MAX_VALUE);


        ByteArrayReplaceInputStream in=new ByteArrayReplaceInputStream(someByteArray,list);
        int bytesRead;
        byte[] buf=new byte[4096];
        while((bytesRead=in.read(buf,0,buf.length))!=-1)
            out.write(buf,0,bytesRead);
        in.close();


{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}

{code:title=Pattern.java|borderStyle=solid}
abstract class Pattern {
    abstract int length();
    abstract int get(int pos);
    abstract int skip(int value);
    abstract Pattern swap();
}
{code}

{code:title=PatternList.java|borderStyle=solid}
public class PatternList {
    private ReentrantReadWriteLock lock=new ReentrantReadWriteLock();
    private Lock readLock=lock.readLock();
    private Lock writeLock=lock.writeLock();
    private PatternEntry head=new PatternEntry(null,-1,null,null,null);

    public PatternList(){
        head.next=head.previous=head;
    }

    public void add(byte[] bBegin,byte[] bEnd,PatternReplacer handler, int maxOccurence){
        add(new BeginPattern(new PatternTable(bBegin),new PatternTable(bEnd)),maxOccurence,handler);
    }

    public void add(byte[] p,PatternReplacer handler, int maxOccurence){
        add(new SinglePattern(new PatternTable(p)),maxOccurence,handler);
    }

    PatternListIterator iterator(){
        return new PatternListIterator(head.previous);
    }

    private void add(Pattern pattern,int maxOccurence,PatternReplacer handler){
        writeLock.lock();
        try{
            for(PatternEntry tmp=head;;tmp=tmp.next)
                if(tmp.pattern==null||tmp.compareTo(pattern)<=0){
                    PatternEntry newEntry=new PatternEntry(handler,maxOccurence,pattern,tmp,tmp.previous);
                    newEntry.previous.next=newEntry;
                    newEntry.next.previous=newEntry;
                    if(tmp==head)
                        head=newEntry;
                    break;
                }
        }finally{
            writeLock.unlock();
        }
    }

    class PatternListIterator{
        private PatternEntry copyHead;
        
        PatternListIterator(PatternEntry head){
            this.copyHead=head;
        }

        public PatternEntry next(){
            copyHead=copyHead.next;
            return copyHead;
        }

        public PatternEntry previous(){
            copyHead=copyHead.previous;
            return copyHead;
        }

        public boolean hasNext(){
            return copyHead.next.pattern!=null;
        }

        void readLock(){
            readLock.lock();
        }

        void readUnlock(){
            readLock.unlock();
        }

    }

    static class PatternEntry implements Comparable<Pattern>{
        Pattern pattern;
        PatternEntry next;
        PatternEntry previous;
        PatternReplacer handler;
        int maxOccurence;

        private PatternEntry(PatternReplacer handler,int maxOccurence,Pattern element,PatternEntry
next, PatternEntry previous){
            this.handler=handler;
            this.pattern=element;
            this.next=next;
            this.previous=previous;
            this.maxOccurence=maxOccurence;
        }

        byte[] replace(int pos,byte[] match){
            return handler.replace(pos,match);
        }

        int getMaxOccurence() {
            return maxOccurence;
        }

        Pattern getPattern(){
            return pattern;
        }
         
        public int compareTo(Pattern other) {

            if(this.pattern instanceof SinglePattern && other instanceof BeginPattern)
                return -1;
            else if(this.pattern instanceof BeginPattern && other instanceof SinglePattern)
                return 1;
            else{
                return ((ComparablePattern)this.pattern).size-((ComparablePattern)other).size;
            }
        }

        boolean isSingle(){
            return pattern instanceof SinglePattern;
        }


    }

    private static abstract class ComparablePattern extends Pattern{
        int size;
        ComparablePattern(int size){
            this.size=size;
        }
    }

    private static class SinglePattern extends ComparablePattern {
        PatternTable pattern;

        private SinglePattern(PatternTable pattern){
            super(pattern.length());
            this.pattern=pattern;
        }

        @Override
        int length() {
            return pattern.length();
        }

        @Override
        int get(int pos) {
            return pattern.get(pos);
        }

        @Override
        int skip(int value) {
            return pattern.skip(value);
        }

        @Override
        protected Pattern swap() {
            throw new UnsupportedOperationException("single pattern cannot be swapped.");
        }
    }

    private static class EndPattern extends Pattern {
        PatternTable end;
        Pattern nextMatcher;

        private EndPattern(PatternTable end,Pattern nextMatcher){
            this.end=end;
            this.nextMatcher=nextMatcher;
        }

        @Override
        int length() {
            return end.length();
        }

        @Override
        int get(int pos) {
            return end.get(pos);
        }

        @Override
        int skip(int value) {
            return end.skip(value);
        }

        @Override
        protected Pattern swap() {
            return nextMatcher;
        }
    }

    private static class BeginPattern extends ComparablePattern{
        PatternTable begin;
        Pattern nextMatcher;

        private BeginPattern(PatternTable begin,PatternTable end){
            super(begin.length()+end.length());
            this.begin=begin;
            nextMatcher=new EndPattern(end,this);
        }

        @Override
        int length() {
            return begin.length();
        }

        @Override
        int get(int pos) {
            return begin.get(pos);
        }

        @Override
        int skip(int value) {
            return begin.skip(value);
        }

        @Override
        protected Pattern swap() {
            return nextMatcher;
        }
    }

    private static class PatternTable {
        private final int[] pattern;
        private int[] skip;

        PatternTable(byte[] target){
            pattern=new int[target.length];
            for(int i=0;i<target.length;i++)
                pattern[i]=target[i] & 0xff;
            this.skip=getSkipArray(target);
        }

        int length(){
            return pattern.length;
        }

        int get(int i){
            return pattern[i];
        }

        int skip(int i){
            return skip[i];
        }

        private static int[] getSkipArray(byte[] pattern){
            int[] skip=new int[256];
            int i;
            for(i=0; i<skip.length;i++)
                skip[i]=pattern.length+1;
            for(i=0; i<pattern.length;i++)
                skip[pattern[i] & 0xff]=pattern.length -i;
            return skip;
        }
    }
}
{code}

{code:title=PatternReplacer.java|borderStyle=solid}
public interface PatternReplacer {
    byte[] replace(int pos,final byte[] matched);
}
{code}

{code:title=StringPatternReplacer.java|borderStyle=solid}
public abstract class StringPatternReplacer implements PatternReplacer{
    private String charset;

    protected StringPatternReplacer(String charset){
        this.charset=charset;
    }
    
    public final byte[] replace(int pos, byte[] matched) {
        String replaced;
        try {
            replaced = replace(pos,new String(matched,charset));
            if(replaced!=null)
                return replaced.getBytes(charset);
        } catch (UnsupportedEncodingException e) {

        }
        return null;
    }

    protected abstract String replace(int pos,String matched);

}
{code}
{code:title=SrcHrefReplacer.java|borderStyle=solid}
public class SrcHrefReplacer extends StringPatternReplacer {
    
    public SrcHrefReplacer(String charset){
        super(charset);
    }

    public String replace(int pos, String matched) {
      if(matched.endsWith(".jpg")||matched.endsWith(".gif"))
          return matched;
       if(matched.contains("somedomain.com"))
           return matched;
      return matched.replaceAll("somedomain.com","mydomain.com");

    }
}
{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.


Mime
View raw message