Source Code Cross Referenced for SVNDiffWindow.java in  » Source-Control » tmatesoft-SVN » org » tmatesoft » svn » core » io » diff » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » Source Control » tmatesoft SVN » org.tmatesoft.svn.core.io.diff 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


001:        /*
002:         * ====================================================================
003:         * Copyright (c) 2004-2008 TMate Software Ltd.  All rights reserved.
004:         *
005:         * This software is licensed as described in the file COPYING, which
006:         * you should have received as part of this distribution.  The terms
007:         * are also available at http://svnkit.com/license.html
008:         * If newer versions of this license are posted there, you may use a
009:         * newer version instead, at your option.
010:         * ====================================================================
011:         */
012:
013:        package org.tmatesoft.svn.core.io.diff;
014:
015:        import java.io.IOException;
016:        import java.io.OutputStream;
017:        import java.nio.ByteBuffer;
018:        import java.util.Iterator;
019:        import java.util.zip.DeflaterOutputStream;
020:
021:        import org.tmatesoft.svn.core.SVNErrorCode;
022:        import org.tmatesoft.svn.core.SVNErrorMessage;
023:        import org.tmatesoft.svn.core.SVNException;
024:        import org.tmatesoft.svn.core.internal.wc.SVNErrorManager;
025:
026:        /**
027:         * The <b>SVNDiffWindow</b> class represents a diff window that
028:         * contains instructions and new data of a delta to apply to a file.
029:         * 
030:         * <p>
031:         * Instructions are not immediately contained in a window. A diff window 
032:         * provides an iterator that reads and constructs one <b>SVNDiffInstruction</b> 
033:         * from provided raw bytes per one iteration. There is even an ability to 
034:         * use a single <b>SVNDiffInstruction</b> object for read and decoded instructions: 
035:         * for subsequent iterations an iterator simply uses the same instruction object 
036:         * to return as a newly read and decoded instruction.      
037:         * 
038:         * @version 1.1.1
039:         * @author  TMate Software Ltd.
040:         * @see     SVNDiffInstruction
041:         */
042:        public class SVNDiffWindow {
043:
044:            /**
045:             * Bytes of the delta header of an uncompressed diff window. 
046:             */
047:            public static final byte[] SVN_HEADER = new byte[] { 'S', 'V', 'N',
048:                    '\0' };
049:
050:            /**
051:             * Bytes of the delta header of a compressed diff window.
052:             * @since 1.1, new in Subversion 1.4 
053:             */
054:            public static final byte[] SVN1_HEADER = new byte[] { 'S', 'V',
055:                    'N', '\1' };
056:
057:            /**
058:             * An empty window (in particular, its instructions length = 0). Corresponds 
059:             * to the case of an empty delta, so, it's passed to a delta consumer to 
060:             * create an empty file. 
061:             */
062:            public static final SVNDiffWindow EMPTY = new SVNDiffWindow(0, 0,
063:                    0, 0, 0);
064:
065:            private final long mySourceViewOffset;
066:            private final int mySourceViewLength;
067:            private final int myTargetViewLength;
068:            private final int myNewDataLength;
069:            private int myInstructionsLength;
070:
071:            private SVNDiffInstruction myTemplateInstruction = new SVNDiffInstruction(
072:                    0, 0, 0);
073:            private SVNDiffInstruction myTemplateNextInstruction = new SVNDiffInstruction(
074:                    0, 0, 0);
075:
076:            private byte[] myData;
077:            private int myDataOffset;
078:            private int myInstructionsCount;
079:
080:            /**
081:             * Constructs an <b>SVNDiffWindow</b> object. This constructor is
082:             * used when bytes of instructions are not decoded and converted to
083:             * <b>SVNDiffInstruction</b> objects yet, but are kept elsewhere 
084:             * along with new data.
085:             * 
086:             * @param sourceViewOffset    an offset in the source view
087:             * @param sourceViewLength    a number of bytes to read from the
088:             *                            source view
089:             * @param targetViewLength    a length in bytes of the target view 
090:             *                            it must have after copying bytes
091:             * @param instructionsLength  a number of instructions bytes  
092:             * @param newDataLength       a number of bytes of new data
093:             * @see                       SVNDiffInstruction
094:             */
095:            public SVNDiffWindow(long sourceViewOffset, int sourceViewLength,
096:                    int targetViewLength, int instructionsLength,
097:                    int newDataLength) {
098:                mySourceViewOffset = sourceViewOffset;
099:                mySourceViewLength = sourceViewLength;
100:                myTargetViewLength = targetViewLength;
101:                myInstructionsLength = instructionsLength;
102:                myNewDataLength = newDataLength;
103:            }
104:
105:            /**
106:             * Returns the length of instructions in bytes. 
107:             * 
108:             * @return a number of instructions bytes
109:             */
110:            public int getInstructionsLength() {
111:                return myInstructionsLength;
112:            }
113:
114:            /**
115:             * Returns the source view offset.
116:             * 
117:             * @return an offset in the source from where the source bytes
118:             *         must be copied
119:             */
120:            public long getSourceViewOffset() {
121:                return mySourceViewOffset;
122:            }
123:
124:            /**
125:             * Returns the number of bytes to copy from the source view to the target one.
126:             * 
127:             * @return a number of source bytes to copy
128:             */
129:            public int getSourceViewLength() {
130:                return mySourceViewLength;
131:            }
132:
133:            /**
134:             * Returns the length in bytes of the target view. The length of the target
135:             * view is actually the number of bytes that should be totally copied by all the 
136:             * instructions of this window.
137:             * 
138:             * @return a length in bytes of the target view
139:             */
140:            public int getTargetViewLength() {
141:                return myTargetViewLength;
142:            }
143:
144:            /**
145:             * Returns the number of new data bytes to copy to the target view.
146:             * 
147:             * @return a number of new data bytes
148:             */
149:            public int getNewDataLength() {
150:                return myNewDataLength;
151:            }
152:
153:            /**
154:             * Returns an iterator to read instructions in series. 
155:             * Objects returned by an iterator's <code>next()</code> method 
156:             * are separate <b>SVNDiffInstruction</b> objects.
157:             * 
158:             * <p>
159:             * Instructions as well as new data are read from a byte 
160:             * buffer that is passed to this window object via the 
161:             * {@link #setData(ByteBuffer) setData()} method.   
162:             * 
163:             * <p>
164:             * A call to this routine is equivalent to a call 
165:             * <code>instructions(false)</code>.
166:             * 
167:             * @return an instructions iterator
168:             * @see    #instructions(boolean)
169:             * @see    SVNDiffInstruction 
170:             */
171:            public Iterator instructions() {
172:                return instructions(false);
173:            }
174:
175:            /**
176:             * Returns an iterator to read instructions in series. 
177:             * 
178:             * <p>
179:             * If <code>template</code> is <span class="javakeyword">true</span> 
180:             * then each instruction returned by the iterator is actually the 
181:             * same <b>SVNDiffInstruction</b> object, but with proper options. 
182:             * This prevents from allocating new memory.  
183:             * 
184:             * <p>
185:             * On the other hand, if <code>template</code> is <span class="javakeyword">false</span> 
186:             * then the iterator returns a new allocated <b>SVNDiffInstruction</b> object per 
187:             * each instruction read and decoded.
188:             * 
189:             * <p>
190:             * Instructions as well as new data are read from a byte buffer that is 
191:             * passed to this window object via the 
192:             * {@link #setData(ByteBuffer) setData()} method.   
193:             * 
194:             * @param  template  to use a single/multiple instruction objects
195:             * @return           an instructions iterator
196:             * @see              #instructions()
197:             * @see              SVNDiffInstruction 
198:             */
199:            public Iterator instructions(boolean template) {
200:                return new InstructionsIterator(template);
201:            }
202:
203:            /**
204:             * Applies this window's instructions. The source and target streams
205:             * are provided by <code>applyBaton</code>. 
206:             * 
207:             * <p>
208:             * If this window has got any {@link SVNDiffInstruction#COPY_FROM_SOURCE} instructions, then: 
209:             * <ol>
210:             * <li>At first copies a source view from the source stream 
211:             *     of <code>applyBaton</code> to the baton's inner source buffer.  
212:             *    {@link SVNDiffInstruction#COPY_FROM_SOURCE} instructions of this window are 
213:             *    relative to the bounds of that source buffer (source view, in other words).
214:             * <li>Second, according to instructions, copies source bytes from the source buffer
215:             *     to the baton's target buffer (or target view, in other words). 
216:             * <li>Then, if <code>applyBaton</code> is supplied with an MD5 digest, updates it with those bytes
217:             *     in the target buffer. So, after instructions applying completes, it will be the checksum for
218:             *     the full text expanded.
219:             * <li>The last step - appends the target buffer bytes to the baton's 
220:             *     target stream.        
221:             * </ol> 
222:             * 
223:             * <p>
224:             * {@link SVNDiffInstruction#COPY_FROM_NEW_DATA} instructions rule to copy bytes from 
225:             * the instructions & new data buffer provided to this window object via a call to the 
226:             * {@link #setData(ByteBuffer) setData()} method.
227:             * 
228:             * <p>
229:             * {@link SVNDiffInstruction#COPY_FROM_TARGET} instructions are relative to the bounds of
230:             * the target buffer. 
231:             * 
232:             * @param  applyBaton    a baton that provides the source and target 
233:             *                       views as well as holds the source and targed 
234:             *                       streams 
235:             * @throws SVNException
236:             * @see                  #apply(byte[], byte[])
237:             */
238:            public void apply(SVNDiffWindowApplyBaton applyBaton)
239:                    throws SVNException {
240:                // here we have streams and buffer from the previous calls (or nulls).
241:
242:                // 1. buffer for target.
243:                if (applyBaton.myTargetBuffer == null
244:                        || applyBaton.myTargetViewSize < getTargetViewLength()) {
245:                    applyBaton.myTargetBuffer = new byte[getTargetViewLength()];
246:                }
247:                applyBaton.myTargetViewSize = getTargetViewLength();
248:
249:                // 2. buffer for source.
250:                int length = 0;
251:                if (getSourceViewOffset() != applyBaton.mySourceViewOffset
252:                        || getSourceViewLength() > applyBaton.mySourceViewLength) {
253:                    byte[] oldSourceBuffer = applyBaton.mySourceBuffer;
254:                    // create a new buffer
255:                    applyBaton.mySourceBuffer = new byte[getSourceViewLength()];
256:                    // copy from the old buffer.
257:                    if (applyBaton.mySourceViewOffset
258:                            + applyBaton.mySourceViewLength > getSourceViewOffset()) {
259:                        // copy overlapping part to the new buffer
260:                        int start = (int) (getSourceViewOffset() - applyBaton.mySourceViewOffset);
261:                        System.arraycopy(oldSourceBuffer, start,
262:                                applyBaton.mySourceBuffer, 0,
263:                                (applyBaton.mySourceViewLength - start));
264:                        length = (applyBaton.mySourceViewLength - start);
265:                    }
266:                }
267:                if (length < getSourceViewLength()) {
268:                    // fill what remains.
269:                    try {
270:                        int toSkip = (int) (getSourceViewOffset() - (applyBaton.mySourceViewOffset + applyBaton.mySourceViewLength));
271:                        if (toSkip > 0) {
272:                            applyBaton.mySourceStream.skip(toSkip);
273:                        }
274:                        applyBaton.mySourceStream.read(
275:                                applyBaton.mySourceBuffer, length,
276:                                applyBaton.mySourceBuffer.length - length);
277:                    } catch (IOException e) {
278:                        SVNErrorMessage err = SVNErrorMessage.create(
279:                                SVNErrorCode.IO_ERROR, e.getLocalizedMessage());
280:                        SVNErrorManager.error(err, e);
281:                    }
282:                }
283:                // update offsets in baton.
284:                applyBaton.mySourceViewLength = getSourceViewLength();
285:                applyBaton.mySourceViewOffset = getSourceViewOffset();
286:
287:                // apply instructions.
288:                int tpos = 0;
289:                int npos = myInstructionsLength;
290:                try {
291:                    for (Iterator instructions = instructions(true); instructions
292:                            .hasNext();) {
293:                        SVNDiffInstruction instruction = (SVNDiffInstruction) instructions
294:                                .next();
295:                        int iLength = instruction.length < getTargetViewLength()
296:                                - tpos ? (int) instruction.length
297:                                : getTargetViewLength() - tpos;
298:                        switch (instruction.type) {
299:                        case SVNDiffInstruction.COPY_FROM_NEW_DATA:
300:                            System.arraycopy(myData, myDataOffset + npos,
301:                                    applyBaton.myTargetBuffer, tpos, iLength);
302:                            npos += iLength;
303:                            break;
304:                        case SVNDiffInstruction.COPY_FROM_TARGET:
305:                            int start = instruction.offset;
306:                            int end = instruction.offset + iLength;
307:                            int tIndex = tpos;
308:                            for (int j = start; j < end; j++) {
309:                                applyBaton.myTargetBuffer[tIndex] = applyBaton.myTargetBuffer[j];
310:                                tIndex++;
311:                            }
312:                            break;
313:                        case SVNDiffInstruction.COPY_FROM_SOURCE:
314:                            System.arraycopy(applyBaton.mySourceBuffer,
315:                                    instruction.offset,
316:                                    applyBaton.myTargetBuffer, tpos, iLength);
317:                            break;
318:                        default:
319:                        }
320:                        tpos += instruction.length;
321:                        if (tpos >= getTargetViewLength()) {
322:                            break;
323:                        }
324:                    }
325:                    // save tbuffer.
326:                    if (applyBaton.myDigest != null) {
327:                        applyBaton.myDigest.update(applyBaton.myTargetBuffer,
328:                                0, getTargetViewLength());
329:                    }
330:                    applyBaton.myTargetStream.write(applyBaton.myTargetBuffer,
331:                            0, getTargetViewLength());
332:                } catch (IOException e) {
333:                    SVNErrorMessage err = SVNErrorMessage.create(
334:                            SVNErrorCode.IO_ERROR, e.getLocalizedMessage());
335:                    SVNErrorManager.error(err, e);
336:                }
337:            }
338:
339:            /**
340:             * Applies this window's instructions provided source and target view buffers. 
341:             * 
342:             * <p>
343:             * If this window has got any {@link SVNDiffInstruction#COPY_FROM_SOURCE} instructions, then 
344:             * appropriate bytes described by such an instruction are copied from the <code>sourceBuffer</code> 
345:             * to the <code>targetBuffer</code>.
346:             *   
347:             * <p>
348:             * {@link SVNDiffInstruction#COPY_FROM_NEW_DATA} instructions rule to copy bytes from 
349:             * the instructions & new data buffer provided to this window object via a call to the 
350:             * {@link #setData(ByteBuffer) setData()} method.
351:             * 
352:             * <p>
353:             * {@link SVNDiffInstruction#COPY_FROM_TARGET} instructions are relative to the bounds of
354:             * the <code>targetBuffer</code> itself. 
355:             * 
356:             * @param sourceBuffer  a buffer containing a source view
357:             * @param targetBuffer  a buffer to get a target view
358:             * @return              the size of the resultant target view
359:             * @see                 #apply(SVNDiffWindowApplyBaton)
360:             */
361:            public int apply(byte[] sourceBuffer, byte[] targetBuffer) {
362:                int dataOffset = myInstructionsLength;
363:                int tpos = 0;
364:                for (Iterator instructions = instructions(true); instructions
365:                        .hasNext();) {
366:                    SVNDiffInstruction instruction = (SVNDiffInstruction) instructions
367:                            .next();
368:                    int iLength = instruction.length < getTargetViewLength()
369:                            - tpos ? (int) instruction.length
370:                            : getTargetViewLength() - tpos;
371:                    switch (instruction.type) {
372:                    case SVNDiffInstruction.COPY_FROM_NEW_DATA:
373:                        System.arraycopy(myData, myDataOffset + dataOffset,
374:                                targetBuffer, tpos, iLength);
375:                        dataOffset += iLength;
376:                        break;
377:                    case SVNDiffInstruction.COPY_FROM_TARGET:
378:                        int start = instruction.offset;
379:                        int end = instruction.offset + iLength;
380:                        int tIndex = tpos;
381:                        for (int j = start; j < end; j++) {
382:                            targetBuffer[tIndex] = targetBuffer[j];
383:                            tIndex++;
384:                        }
385:                        break;
386:                    case SVNDiffInstruction.COPY_FROM_SOURCE:
387:                        System.arraycopy(sourceBuffer, instruction.offset,
388:                                targetBuffer, tpos, iLength);
389:                        break;
390:                    default:
391:                    }
392:                    tpos += instruction.length;
393:                    if (tpos >= getTargetViewLength()) {
394:                        break;
395:                    }
396:                }
397:                return getTargetViewLength();
398:            }
399:
400:            /**
401:             * Sets a byte buffer containing instruction and new data bytes 
402:             * of this window. 
403:             * 
404:             * <p>
405:             * Instructions will go before new data within the buffer and should start 
406:             * at <code>buffer.position() + buffer.arrayOffset()</code>.
407:             * 
408:             * <p>
409:             * Applying a diff window prior to setting instruction and new data bytes 
410:             * may cause a NPE.  
411:             * 
412:             * @param buffer an input data buffer
413:             */
414:            public void setData(ByteBuffer buffer) {
415:                myData = buffer.array();
416:                myDataOffset = buffer.position() + buffer.arrayOffset();
417:            }
418:
419:            /**
420:             * Gives a string representation of this object.
421:             * 
422:             * @return a string representation of this object
423:             */
424:            public String toString() {
425:                StringBuffer sb = new StringBuffer();
426:                sb.append(getSourceViewOffset());
427:                sb.append(":");
428:                sb.append(getSourceViewLength());
429:                sb.append(":");
430:                sb.append(getTargetViewLength());
431:                sb.append(":");
432:                sb.append(getInstructionsLength());
433:                sb.append(":");
434:                sb.append(getNewDataLength());
435:                sb.append(":");
436:                sb.append(getDataLength());
437:                sb.append(":");
438:                sb.append(myDataOffset);
439:                return sb.toString();
440:            }
441:
442:            /**
443:             * Tells if this window is not empty, i.e. has got any instructions.
444:             * 
445:             * @return <span class="javakeyword">true</span> if has instructions, 
446:             *         <span class="javakeyword">false</span> if has not 
447:             */
448:            public boolean hasInstructions() {
449:                return myInstructionsLength > 0;
450:            }
451:
452:            /**
453:             * Writes this window object to the provided stream.
454:             * 
455:             * <p>
456:             * If <code>writeHeader</code> is <span class="javakeyword">true</span> 
457:             * then writes {@link #SVN_HEADER} bytes also.
458:             * 
459:             * @param os             an output stream to write to 
460:             * @param writeHeader    controls whether the header should be written 
461:             *                       or not
462:             * @throws IOException   if an I/O error occurs
463:             */
464:            public void writeTo(OutputStream os, boolean writeHeader)
465:                    throws IOException {
466:                writeTo(os, writeHeader, false);
467:            }
468:
469:            /**
470:             * Formats and writes this window bytes to the specified output stream.
471:             * 
472:             * @param os              an output stream to write the window to
473:             * @param writeHeader     if <span class="javakeyword">true</span> a window
474:             *                        header will be also written
475:             * @param compress        if <span class="javakeyword">true</span> writes  
476:             *                        compressed window bytes using {@link #SVN1_HEADER} 
477:             *                        to indicate that (if <code>writeHeader</code> is 
478:             *                        <span class="javakeyword">true</span>), otherwise 
479:             *                        non-compressed window is written with {@link #SVN_HEADER} 
480:             *                        (again if <code>writeHeader</code> is <span class="javakeyword">true</span>) 
481:             * @throws IOException
482:             * @since                 1.1
483:             */
484:            public void writeTo(OutputStream os, boolean writeHeader,
485:                    boolean compress) throws IOException {
486:                if (writeHeader) {
487:                    os.write(compress ? SVN1_HEADER : SVN_HEADER);
488:                }
489:                if (!hasInstructions()) {
490:                    return;
491:                }
492:                ByteBuffer offsets = ByteBuffer.allocate(100);
493:                SVNDiffInstruction.writeLong(offsets, mySourceViewOffset);
494:                SVNDiffInstruction.writeInt(offsets, mySourceViewLength);
495:                SVNDiffInstruction.writeInt(offsets, myTargetViewLength);
496:
497:                ByteBuffer instructions = null;
498:                ByteBuffer newData = null;
499:                int instLength = 0;
500:                int dataLength = 0;
501:                if (compress) {
502:                    instructions = inflate(myData, myDataOffset,
503:                            myInstructionsLength);
504:                    instLength = instructions.remaining();
505:                    newData = inflate(myData, myDataOffset
506:                            + myInstructionsLength, myNewDataLength);
507:                    dataLength = newData.remaining();
508:                    SVNDiffInstruction.writeInt(offsets, instLength);
509:                    SVNDiffInstruction.writeInt(offsets, dataLength);
510:                } else {
511:                    SVNDiffInstruction.writeInt(offsets, myInstructionsLength);
512:                    SVNDiffInstruction.writeInt(offsets, myNewDataLength);
513:                }
514:                os.write(offsets.array(), offsets.arrayOffset(), offsets
515:                        .position());
516:                if (compress) {
517:                    os.write(instructions.array(), instructions.arrayOffset(),
518:                            instructions.remaining());
519:                    os.write(newData.array(), newData.arrayOffset(), newData
520:                            .remaining());
521:                } else {
522:                    os.write(myData, myDataOffset, myInstructionsLength);
523:                    if (myNewDataLength > 0) {
524:                        os.write(myData, myDataOffset + myInstructionsLength,
525:                                myNewDataLength);
526:                    }
527:                }
528:            }
529:
530:            /**
531:             * Returns the total amount of new data and instruction bytes.
532:             * 
533:             * @return new data length + instructions length
534:             */
535:            public int getDataLength() {
536:                return myNewDataLength + myInstructionsLength;
537:            }
538:
539:            /**
540:             * Tells whether this window contains any copy-from-source 
541:             * instructions. 
542:             * 
543:             * @return <span class="javakeyword">true</span> if this window 
544:             *         has got at least one {@link SVNDiffInstruction#COPY_FROM_SOURCE} 
545:             *         instruction
546:             */
547:            public boolean hasCopyFromSourceInstructions() {
548:                for (Iterator instrs = instructions(true); instrs.hasNext();) {
549:                    SVNDiffInstruction instruction = (SVNDiffInstruction) instrs
550:                            .next();
551:                    if (instruction.type == SVNDiffInstruction.COPY_FROM_SOURCE) {
552:                        return true;
553:                    }
554:                }
555:                return false;
556:            }
557:
558:            /**
559:             * Creates an exact copy of this window object. 
560:             * 
561:             * <p> 
562:             * <code>targetData</code> is written instruction & new data bytes and 
563:             * then is set to a new window object via a call to its {@link #setData(ByteBuffer) setData()} 
564:             * method.
565:             * 
566:             * @param  targetData a byte buffer to receive a copy of this wondow data
567:             * @return            a new window object that is an exact copy of this one
568:             */
569:            public SVNDiffWindow clone(ByteBuffer targetData) {
570:                int targetOffset = targetData.position()
571:                        + targetData.arrayOffset();
572:                int position = targetData.position();
573:                targetData.put(myData, myDataOffset, myInstructionsLength
574:                        + myNewDataLength);
575:                targetData.position(position);
576:                SVNDiffWindow clone = new SVNDiffWindow(getSourceViewOffset(),
577:                        getSourceViewLength(), getTargetViewLength(),
578:                        getInstructionsLength(), getNewDataLength());
579:                clone.setData(targetData);
580:                clone.myDataOffset = targetOffset;
581:                return clone;
582:            }
583:
584:            private static ByteBuffer inflate(byte[] src, int offset, int length)
585:                    throws IOException {
586:                final ByteBuffer buffer = ByteBuffer.allocate(length * 2 + 2);
587:                SVNDiffInstruction.writeInt(buffer, length);
588:                if (length < 512) {
589:                    buffer.put(src, offset, length);
590:                } else {
591:                    DeflaterOutputStream out = new DeflaterOutputStream(
592:                            new OutputStream() {
593:                                public void write(int b) throws IOException {
594:                                    buffer.put((byte) (b & 0xFF));
595:                                }
596:
597:                                public void write(byte[] b, int off, int len)
598:                                        throws IOException {
599:                                    buffer.put(b, off, len);
600:                                }
601:
602:                                public void write(byte[] b) throws IOException {
603:                                    write(b, 0, b.length);
604:                                }
605:                            });
606:                    out.write(src, offset, length);
607:                    out.finish();
608:                    if (buffer.position() >= length) {
609:                        buffer.clear();
610:                        SVNDiffInstruction.writeInt(buffer, length);
611:                        buffer.put(src, offset, length);
612:                    }
613:                }
614:                buffer.flip();
615:                return buffer;
616:            }
617:
618:            private class InstructionsIterator implements  Iterator {
619:
620:                private SVNDiffInstruction myNextInsruction;
621:                private int myOffset;
622:                private int myNewDataOffset;
623:                private boolean myIsTemplate;
624:
625:                public InstructionsIterator(boolean useTemplate) {
626:                    myIsTemplate = useTemplate;
627:                    myNextInsruction = readNextInstruction();
628:                }
629:
630:                public boolean hasNext() {
631:                    return myNextInsruction != null;
632:                }
633:
634:                public Object next() {
635:                    if (myNextInsruction == null) {
636:                        return null;
637:                    }
638:
639:                    if (myIsTemplate) {
640:                        myTemplateNextInstruction.type = myNextInsruction.type;
641:                        myTemplateNextInstruction.length = myNextInsruction.length;
642:                        myTemplateNextInstruction.offset = myNextInsruction.offset;
643:                        myNextInsruction = readNextInstruction();
644:                        return myTemplateNextInstruction;
645:                    }
646:                    Object next = myNextInsruction;
647:                    myNextInsruction = readNextInstruction();
648:                    return next;
649:                }
650:
651:                public void remove() {
652:                }
653:
654:                private SVNDiffInstruction readNextInstruction() {
655:                    if (myData == null || myOffset >= myInstructionsLength) {
656:                        return null;
657:                    }
658:                    SVNDiffInstruction instruction = myIsTemplate ? myTemplateInstruction
659:                            : new SVNDiffInstruction();
660:                    instruction.type = (myData[myDataOffset + myOffset] & 0xC0) >> 6;
661:                    instruction.length = myData[myDataOffset + myOffset] & 0x3f;
662:                    myOffset++;
663:                    if (instruction.length == 0) {
664:                        // read length from next byte                
665:                        instruction.length = readInt();
666:                    }
667:                    if (instruction.type == 0 || instruction.type == 1) {
668:                        // read offset from next byte (no offset without length).
669:                        instruction.offset = readInt();
670:                    } else {
671:                        // set offset to offset in newdata.
672:                        instruction.offset = myNewDataOffset;
673:                        myNewDataOffset += instruction.length;
674:                    }
675:                    return instruction;
676:                }
677:
678:                private int readInt() {
679:                    int result = 0;
680:                    while (true) {
681:                        byte b = myData[myDataOffset + myOffset];
682:                        result = result << 7;
683:                        result = result | (b & 0x7f);
684:                        if ((b & 0x80) != 0) {
685:                            myOffset++;
686:                            if (myOffset >= myInstructionsLength) {
687:                                return -1;
688:                            }
689:                            continue;
690:                        }
691:                        myOffset++;
692:                        return result;
693:                    }
694:                }
695:            }
696:
697:            /**
698:             * Returns an array of instructions of this window.
699:             * 
700:             * <p>
701:             * If <code>target</code> is large enough to receive all instruction 
702:             * objects, then it's simply filled up to the end of instructions.
703:             * However if it's not, it will be expanded to receive all instructions. 
704:             * 
705:             * @param  target  an instructions receiver 
706:             * @return         an array  containing all instructions
707:             */
708:            public SVNDiffInstruction[] loadDiffInstructions(
709:                    SVNDiffInstruction[] target) {
710:                int index = 0;
711:                for (Iterator instructions = instructions(); instructions
712:                        .hasNext();) {
713:                    if (index >= target.length) {
714:                        SVNDiffInstruction[] newTarget = new SVNDiffInstruction[index * 3 / 2];
715:                        System.arraycopy(target, 0, newTarget, 0, index);
716:                        target = newTarget;
717:                    }
718:                    target[index] = (SVNDiffInstruction) instructions.next();
719:                    index++;
720:                }
721:                myInstructionsCount = index;
722:                return target;
723:            }
724:
725:            /**
726:             * Returns the amount of instructions of this window object.
727:             * 
728:             * @return a total number of instructions
729:             */
730:            public int getInstructionsCount() {
731:                return myInstructionsCount;
732:            }
733:
734:            /**
735:             * Fills a target buffer with the specified number of new data bytes 
736:             * of this window object taken at the specified offset.  
737:             * 
738:             * @param target a buffer to copy to
739:             * @param offset an offset relative to the position of the first 
740:             *               new data byte of this window object 
741:             * @param length a number of new data bytes to copy
742:             */
743:            public void writeNewData(ByteBuffer target, int offset, int length) {
744:                offset += myDataOffset + myInstructionsLength;
745:                target.put(myData, offset, length);
746:            }
747:
748:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.