Start line:  
End line:  

Snippet Preview

Snippet HTML Code

Stack Overflow Questions
  /*
   * ====================================================================
   * Copyright (c) 2004-2006 TMate Software Ltd.  All rights reserved.
   *
   * This software is licensed as described in the file COPYING, which
   * you should have received as part of this distribution.  The terms
   * are also available at http://svnkit.com/license.html
   * If newer versions of this license are posted there, you may use a
   * newer version instead, at your option.
  * ====================================================================
  */
 
 package org.tmatesoft.svn.core.io.diff;
 
 
The SVNDiffWindow class represents a diff window that contains instructions and new data of a delta to apply to a file.

Instructions are not immediately contained in a window. A diff window provides an iterator that reads and constructs one SVNDiffInstruction from provided raw bytes per one iteration. There is even an ability to use a single SVNDiffInstruction object for read and decoded instructions: for subsequent iterations an iterator simply uses the same instruction object to return as a newly read and decoded instruction.

Author(s):
TMate Software Ltd.
Version:
1.1.0
See also:
SVNDiffInstruction
 
 public class SVNDiffWindow {
    
    
Bytes of the delta header of an uncompressed diff window.
 
     public static final byte[] SVN_HEADER = new byte[] {'S''V''N''\0'};

    
Bytes of the delta header of a compressed diff window.

Since:
1.1, new in Subversion 1.4
 
     public static final byte[] SVN1_HEADER = new byte[] {'S''V''N''\1'};
    
    
An empty window (in particular, its instructions length = 0). Corresponds to the case of an empty delta, so, it's passed to a delta consumer to create an empty file.
 
     public static final SVNDiffWindow EMPTY = new SVNDiffWindow(0,0,0,0,0);
     
     private final long mySourceViewOffset;
     private final int mySourceViewLength;
     private final int myTargetViewLength;
     private final int myNewDataLength;
     private int myInstructionsLength;
     
     
     private byte[] myData;
     private int myDataOffset;
     private int myInstructionsCount;
    
    
Constructs an SVNDiffWindow object. This constructor is used when bytes of instructions are not decoded and converted to SVNDiffInstruction objects yet, but are kept elsewhere along with new data.

Parameters:
sourceViewOffset an offset in the source view
sourceViewLength a number of bytes to read from the source view
targetViewLength a length in bytes of the target view it must have after copying bytes
instructionsLength a number of instructions bytes
newDataLength a number of bytes of new data
See also:
SVNDiffInstruction
 
     public SVNDiffWindow(long sourceViewOffsetint sourceViewLengthint targetViewLengthint instructionsLengthint newDataLength) {
          = sourceViewOffset;
          = sourceViewLength;
          = targetViewLength;
          = instructionsLength;
          = newDataLength;
     }
    
    
Returns the length of instructions in bytes.

Returns:
a number of instructions bytes
    public int getInstructionsLength() {
        return ;
    }
    
    
Returns the source view offset.

Returns:
an offset in the source from where the source bytes must be copied
    public long getSourceViewOffset() {
        return ;
    }
    
    
Returns the number of bytes to copy from the source view to the target one.

Returns:
a number of source bytes to copy
    public int getSourceViewLength() {
        return ;
    }
    
    
Returns the length in bytes of the target view. The length of the target view is actually the number of bytes that should be totally copied by all the instructions of this window.

Returns:
a length in bytes of the target view
    public int getTargetViewLength() {
        return ;
    }
    
    
Returns the number of new data bytes to copy to the target view.

Returns:
a number of new data bytes
    public int getNewDataLength() {
        return ;
    }
    
    
Returns an iterator to read instructions in series. Objects returned by an iterator's next() method are separate SVNDiffInstruction objects.

Instructions as well as new data are read from a byte buffer that is passed to this window object via the setData() method.

A call to this routine is equivalent to a call instructions(false).

Returns:
an instructions iterator
See also:
instructions(boolean)
SVNDiffInstruction
    public Iterator instructions() {
        return instructions(false);
    }

    
Returns an iterator to read instructions in series.

If template is true then each instruction returned by the iterator is actually the same SVNDiffInstruction object, but with proper options. This prevents from allocating new memory.

On the other hand, if template is false then the iterator returns a new allocated SVNDiffInstruction object per each instruction read and decoded.

Instructions as well as new data are read from a byte buffer that is passed to this window object via the setData() method.

Parameters:
template to use a single/multiple instruction objects
Returns:
an instructions iterator
See also:
instructions()
SVNDiffInstruction
    public Iterator instructions(boolean template) {
        return new InstructionsIterator(template);
    }
    
    
Applies this window's instructions. The source and target streams are provided by applyBaton.

If this window has got any SVNDiffInstruction.COPY_FROM_SOURCE instructions, then:

  1. At first copies a source view from the source stream of applyBaton to the baton's inner source buffer. SVNDiffInstruction.COPY_FROM_SOURCE instructions of this window are relative to the bounds of that source buffer (source view, in other words).
  2. Second, according to instructions, copies source bytes from the source buffer to the baton's target buffer (or target view, in other words).
  3. Then, if applyBaton is supplied with an MD5 digest, updates it with those bytes in the target buffer. So, after instructions applying completes, it will be the checksum for the full text expanded.
  4. The last step - appends the target buffer bytes to the baton's target stream.

SVNDiffInstruction.COPY_FROM_NEW_DATA instructions rule to copy bytes from the instructions & new data buffer provided to this window object via a call to the setData() method.

SVNDiffInstruction.COPY_FROM_TARGET instructions are relative to the bounds of the target buffer.

Parameters:
applyBaton a baton that provides the source and target views as well as holds the source and targed streams
Throws:
org.tmatesoft.svn.core.SVNException
See also:
apply(byte[],byte[])
    public void apply(SVNDiffWindowApplyBaton applyBatonthrows SVNException {
        // here we have streams and buffer from the previous calls (or nulls).
        
        // 1. buffer for target.
        if (applyBaton.myTargetBuffer == null || applyBaton.myTargetViewSize < getTargetViewLength()) {
            applyBaton.myTargetBuffer = new byte[getTargetViewLength()];
        }
        applyBaton.myTargetViewSize = getTargetViewLength();
        
        // 2. buffer for source.
        int length = 0;
        if (getSourceViewOffset() != applyBaton.mySourceViewOffset || getSourceViewLength() > applyBaton.mySourceViewLength) {
            byte[] oldSourceBuffer = applyBaton.mySourceBuffer;
            // create a new buffer
            applyBaton.mySourceBuffer = new byte[getSourceViewLength()];
            // copy from the old buffer.
            if (applyBaton.mySourceViewOffset + applyBaton.mySourceViewLength > getSourceViewOffset()) {
                // copy overlapping part to the new buffer
                int start = (int) (getSourceViewOffset() - applyBaton.mySourceViewOffset);
                System.arraycopy(oldSourceBufferstartapplyBaton.mySourceBuffer, 0, (applyBaton.mySourceViewLength - start));
                length = (applyBaton.mySourceViewLength - start);
            }            
        }
        if (length < getSourceViewLength()) {
            // fill what remains.
            try {
                int toSkip = (int) (getSourceViewOffset() - (applyBaton.mySourceViewOffset + applyBaton.mySourceViewLength));
                if (toSkip > 0) {
                    applyBaton.mySourceStream.skip(toSkip);
                }
                applyBaton.mySourceStream.read(applyBaton.mySourceBufferlengthapplyBaton.mySourceBuffer.length - length);
            } catch (IOException e) {
                SVNErrorMessage err = SVNErrorMessage.create(.e.getLocalizedMessage());
                SVNErrorManager.error(erre);
            }
        }
        // update offsets in baton.
        applyBaton.mySourceViewLength = getSourceViewLength();
        applyBaton.mySourceViewOffset = getSourceViewOffset();
        
        // apply instructions.
        int tpos = 0;
        int npos = ;
        try {
            for (Iterator instructions = instructions(true); instructions.hasNext();) {
                SVNDiffInstruction instruction = (SVNDiffInstructioninstructions.next();
                int iLength = instruction.length < getTargetViewLength() - tpos ? (intinstruction.length : getTargetViewLength() - tpos
                switch (instruction.type) {
                    case .:
                        System.arraycopy( + nposapplyBaton.myTargetBuffertposiLength);
                        npos += iLength;
                        break;
                    case .:
                        int start = instruction.offset;
                        int end = instruction.offset + iLength;
                        int tIndex = tpos;
                        for(int j = startj < endj++) {
                            applyBaton.myTargetBuffer[tIndex] = applyBaton.myTargetBuffer[j];
                            tIndex++;
                        }
                        break;
                    case .:
                        System.arraycopy(applyBaton.mySourceBufferinstruction.offsetapplyBaton.myTargetBuffertposiLength);
                        break;
                    default:
                }
                tpos += instruction.length;
                if (tpos >= getTargetViewLength()) {
                    break;
                }
            }
            // save tbuffer.
            if (applyBaton.myDigest != null) {
                applyBaton.myDigest.update(applyBaton.myTargetBuffer, 0, getTargetViewLength());
            }
            applyBaton.myTargetStream.write(applyBaton.myTargetBuffer, 0, getTargetViewLength());
        } catch (IOException e) {
            SVNErrorMessage err = SVNErrorMessage.create(.e.getLocalizedMessage());
            SVNErrorManager.error(erre);
        }
    }

    
Applies this window's instructions provided source and target view buffers.

If this window has got any SVNDiffInstruction.COPY_FROM_SOURCE instructions, then appropriate bytes described by such an instruction are copied from the sourceBuffer to the targetBuffer.

SVNDiffInstruction.COPY_FROM_NEW_DATA instructions rule to copy bytes from the instructions & new data buffer provided to this window object via a call to the setData() method.

SVNDiffInstruction.COPY_FROM_TARGET instructions are relative to the bounds of the targetBuffer itself.

Parameters:
sourceBuffer a buffer containing a source view
targetBuffer a buffer to get a target view
Returns:
the size of the resultant target view
See also:
apply(org.tmatesoft.svn.core.io.diff.SVNDiffWindowApplyBaton)
    public int apply(byte[] sourceBufferbyte[] targetBuffer) {
        int dataOffset = ;
        int tpos = 0;
        for (Iterator instructions = instructions(true); instructions.hasNext();) {
            SVNDiffInstruction instruction = (SVNDiffInstructioninstructions.next();
            int iLength = instruction.length < getTargetViewLength() - tpos ? (intinstruction.length : getTargetViewLength() - tpos;
            switch (instruction.type) {
                case .:
                    System.arraycopy( + dataOffsettargetBuffertposiLength);
                    dataOffset += iLength;
                    break;
                case .:
                    int start = instruction.offset;
                    int end = instruction.offset + iLength;
                    int tIndex = tpos;
                    for(int j = startj < endj++) {
                        targetBuffer[tIndex] = targetBuffer[j];
                        tIndex++;
                    }
                    break;
                case .:
                    System.arraycopy(sourceBufferinstruction.offsettargetBuffertposiLength);
                    break;
                default:
            }
            tpos += instruction.length;
            if (tpos >= getTargetViewLength()) {
                break;
            }
        }
        return getTargetViewLength();
    }
    
    
Sets a byte buffer containing instruction and new data bytes of this window.

Instructions will go before new data within the buffer and should start at buffer.position() + buffer.arrayOffset().

Applying a diff window prior to setting instruction and new data bytes may cause a NPE.

Parameters:
buffer an input data buffer
    public void setData(ByteBuffer buffer) {
         = buffer.array();
         = buffer.position() + buffer.arrayOffset();
    }
    
    
Gives a string representation of this object.

Returns:
a string representation of this object
    public String toString() {
        StringBuffer sb = new StringBuffer();
        sb.append(getSourceViewOffset());
        sb.append(":");
        sb.append(getSourceViewLength());
        sb.append(":");
        sb.append(getTargetViewLength());
        sb.append(":");
        sb.append(getInstructionsLength());
        sb.append(":");
        sb.append(getNewDataLength());
        sb.append(":");
        sb.append(getDataLength());
        sb.append(":");
        sb.append();
        return sb.toString();
    }
    
    
Tells if this window is not empty, i.e. has got any instructions.

Returns:
true if has instructions, false if has not
    public boolean hasInstructions() {
        return  > 0;
    }
    
    
Writes this window object to the provided stream.

If writeHeader is true then writes SVN_HEADER bytes also.

Parameters:
os an output stream to write to
writeHeader controls whether the header should be written or not
Throws:
java.io.IOException if an I/O error occurs
    public void writeTo(OutputStream osboolean writeHeaderthrows IOException {
        writeTo(oswriteHeaderfalse);
    }
    
    
Formats and writes this window bytes to the specified output stream.

Parameters:
os an output stream to write the window to
writeHeader if true a window header will be also written
compress if true writes compressed window bytes using SVN1_HEADER to indicate that (if writeHeader is true), otherwise non-compressed window is written with SVN_HEADER (again if writeHeader is true)
Throws:
java.io.IOException
Since:
1.1
    public void writeTo(OutputStream osboolean writeHeaderboolean compressthrows IOException {
        if (writeHeader) {
            os.write(compress ?  : );
        }
        if (!hasInstructions()) {
            return;
        }
        ByteBuffer offsets = ByteBuffer.allocate(100);
        SVNDiffInstruction.writeLong(offsets);
        SVNDiffInstruction.writeInt(offsets);
        SVNDiffInstruction.writeInt(offsets);
        ByteBuffer instructions = null;
        ByteBuffer newData = null;
        int instLength = 0;
        int dataLength = 0;
        if (compress) {
            instructions = inflate();
            instLength = instructions.remaining();
            newData = inflate( + );
            dataLength = newData.remaining();
            SVNDiffInstruction.writeInt(offsetsinstLength);
            SVNDiffInstruction.writeInt(offsetsdataLength);
        } else {
            SVNDiffInstruction.writeInt(offsets);
            SVNDiffInstruction.writeInt(offsets);
        }
        os.write(offsets.array(), offsets.arrayOffset(), offsets.position());
        if (compress) {
            os.write(instructions.array(), instructions.arrayOffset(), instructions.remaining());
            os.write(newData.array(), newData.arrayOffset(), newData.remaining());
        } else {
            os.write();
            if ( > 0) {
                os.write( + );
            }
        }
    }
    
    
Returns the total amount of new data and instruction bytes.

Returns:
new data length + instructions length
    public int getDataLength() {
        return  + ;
    }

    
Tells whether this window contains any copy-from-source instructions.

Returns:
true if this window has got at least one SVNDiffInstruction.COPY_FROM_SOURCE instruction
    public boolean hasCopyFromSourceInstructions() {
        for(Iterator instrs = instructions(true); instrs.hasNext();) {
            SVNDiffInstruction instruction = (SVNDiffInstructioninstrs.next();
            if (instruction.type == .) {
                return true;
            }
        }
        return false;
    }
    
    
Creates an exact copy of this window object.

targetData is written instruction & new data bytes and then is set to a new window object via a call to its setData() method.

Parameters:
targetData a byte buffer to receive a copy of this wondow data
Returns:
a new window object that is an exact copy of this one
    public SVNDiffWindow clone(ByteBuffer targetData) {
        int targetOffset = targetData.position() + targetData.arrayOffset();
        int position = targetData.position();
        targetData.put( + );
        targetData.position(position);
                getInstructionsLength(), getNewDataLength());
        clone.setData(targetData);
        clone.myDataOffset = targetOffset;
        return clone;
    }
    
    private static ByteBuffer inflate(byte[] srcint offsetint lengththrows IOException {
        final ByteBuffer buffer = ByteBuffer.allocate(length*2 + 2);
        SVNDiffInstruction.writeInt(bufferlength);
        if (length < 512) {
            buffer.put(srcoffsetlength);
        } else {
            DeflaterOutputStream out = new DeflaterOutputStream(new OutputStream() {
                public void write(int bthrows IOException {
                    buffer.put((byte) (b & 0xFF));
                }
                public void write(byte[] bint offint lenthrows IOException {
                    buffer.put(bofflen);
                }
                public void write(byte[] bthrows IOException {
                    write(b, 0, b.length);
                }
            });
            out.write(srcoffsetlength);
            out.finish();
            if (buffer.position() >= length) {
                buffer.clear();
                SVNDiffInstruction.writeInt(bufferlength);
                buffer.put(srcoffsetlength);
            }
        }
        buffer.flip();
        return buffer;
    }
    
    private class InstructionsIterator implements Iterator {
        
        private SVNDiffInstruction myNextInsruction;
        private int myOffset;
        private int myNewDataOffset;
        private boolean myIsTemplate;
        
        public InstructionsIterator(boolean useTemplate) {
             = useTemplate;
             = readNextInstruction();
        }
        public boolean hasNext() {
            return  != null;
        }
        public Object next() {
            if ( == null) {
                return null;
            }
        
            if () {
                . = .;
                . = .;
                . = .;
                 = readNextInstruction();
                return ;
            } 
            Object next = ;
             = readNextInstruction();
            return next;
        }
        public void remove() {
        }
        
        private SVNDiffInstruction readNextInstruction() {
            if ( == null ||  >= ) {
                return null;
            }
            SVNDiffInstruction instruction =  ?  : new SVNDiffInstruction();
            instruction.type = ([ + ] & 0xC0) >> 6;
            instruction.length = [ + ] & 0x3f;
            ++;
            if (instruction.length == 0) {
                // read length from next byte                
                instruction.length = readInt();
            } 
            if (instruction.type == 0 || instruction.type == 1) {
                // read offset from next byte (no offset without length).
                instruction.offset = readInt();
            } else { 
                // set offset to offset in newdata.
                instruction.offset = ;
                 += instruction.length;
            }
            return instruction;
        }
        
        private int readInt() {
            int result = 0;
            while(true) {
                byte b = [ + ];
                result = result << 7;
                result = result | (b & 0x7f);
                if ((b & 0x80) != 0) {
                    ++;
                    if ( >= ) {
                        return -1;
                    }
                    continue;
                }
                ++;
                return result;
            }
        }
    }
    
    
Returns an array of instructions of this window.

If target is large enough to receive all instruction objects, then it's simply filled up to the end of instructions. However if it's not, it will be expanded to receive all instructions.

Parameters:
target an instructions receiver
Returns:
an array containing all instructions
        int index = 0;
        for (Iterator instructions = instructions(); instructions.hasNext();) {
            if (index >= target.length) {
                SVNDiffInstruction[] newTarget = new SVNDiffInstruction[index*3/2];
                System.arraycopy(target, 0, newTarget, 0, index);
                target = newTarget;
            }
            target[index] = (SVNDiffInstructioninstructions.next();
            index++;
        }
         = index;
        return target;
    }
    
    
Returns the amount of instructions of this window object.

Returns:
a total number of instructions
    public int getInstructionsCount() {
        return ;
    }

    
Fills a target buffer with the specified number of new data bytes of this window object taken at the specified offset.

Parameters:
target a buffer to copy to
offset an offset relative to the position of the first new data byte of this window object
length a number of new data bytes to copy
    public void writeNewData(ByteBuffer targetint offsetint length) {
        offset +=  + ;
        target.put(offsetlength);
    }
New to GrepCode? Check out our FAQ X