1 /*
2 * Copyright (C) 2008-2009, Google Inc.
3 * Copyright (C) 2007, Robin Rosenberg <robin.rosenberg@dewire.com>
4 * Copyright (C) 2008, Shawn O. Pearce <spearce@spearce.org>
5 * and other copyright owners as documented in the project's IP log.
6 *
7 * This program and the accompanying materials are made available
8 * under the terms of the Eclipse Distribution License v1.0 which
9 * accompanies this distribution, is reproduced below, and is
10 * available at http://www.eclipse.org/org/documents/edl-v10.php
11 *
12 * All rights reserved.
13 *
14 * Redistribution and use in source and binary forms, with or
15 * without modification, are permitted provided that the following
16 * conditions are met:
17 *
18 * - Redistributions of source code must retain the above copyright
19 * notice, this list of conditions and the following disclaimer.
20 *
21 * - Redistributions in binary form must reproduce the above
22 * copyright notice, this list of conditions and the following
23 * disclaimer in the documentation and/or other materials provided
24 * with the distribution.
25 *
26 * - Neither the name of the Eclipse Foundation, Inc. nor the
27 * names of its contributors may be used to endorse or promote
28 * products derived from this software without specific prior
29 * written permission.
30 *
31 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
32 * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
33 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
34 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
35 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
36 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
37 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
38 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
39 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
40 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
41 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
42 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
43 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
44 */
45
46 package org.eclipse.jgit.treewalk;
47
48 import java.io.IOException;
49 import java.nio.ByteBuffer;
50 import java.nio.CharBuffer;
51
52 import org.eclipse.jgit.attributes.AttributesHandler;
53 import org.eclipse.jgit.attributes.AttributesNode;
54 import org.eclipse.jgit.errors.CorruptObjectException;
55 import org.eclipse.jgit.errors.IncorrectObjectTypeException;
56 import org.eclipse.jgit.lib.Constants;
57 import org.eclipse.jgit.lib.FileMode;
58 import org.eclipse.jgit.lib.MutableObjectId;
59 import org.eclipse.jgit.lib.ObjectId;
60 import org.eclipse.jgit.lib.ObjectReader;
61 import org.eclipse.jgit.util.Paths;
62
63 /**
64 * Walks a Git tree (directory) in Git sort order.
65 * <p>
66 * A new iterator instance should be positioned on the first entry, or at eof.
67 * Data for the first entry (if not at eof) should be available immediately.
68 * <p>
69 * Implementors must walk a tree in the Git sort order, which has the following
70 * odd sorting:
71 * <ol>
72 * <li>A.c</li>
73 * <li>A/c</li>
74 * <li>A0c</li>
75 * </ol>
76 * <p>
77 * In the second item, <code>A</code> is the name of a subtree and
78 * <code>c</code> is a file within that subtree. The other two items are files
79 * in the root level tree.
80 *
81 * @see CanonicalTreeParser
82 */
83 public abstract class AbstractTreeIterator {
84 /** Default size for the {@link #path} buffer. */
85 protected static final int DEFAULT_PATH_SIZE = 128;
86
87 /** A dummy object id buffer that matches the zero ObjectId. */
88 protected static final byte[] zeroid = new byte[Constants.OBJECT_ID_LENGTH];
89
90 /**
91 * Iterator for the parent tree; null if we are the root iterator.
92 * <p>
93 * Used by {@link TreeWalk} and {@link AttributesHandler}
94 *
95 * @since 4.3
96 */
97 public final AbstractTreeIterator parent;
98
99 /** The iterator this current entry is path equal to. */
100 AbstractTreeIterator matches;
101
102 /**
103 * Parsed rules of .gitattributes file if it exists.
104 *
105 * @since 4.2
106 */
107 protected AttributesNode attributesNode;
108
109 /**
110 * Number of entries we moved forward to force a D/F conflict match.
111 *
112 * @see NameConflictTreeWalk
113 */
114 int matchShift;
115
116 /**
117 * Mode bits for the current entry.
118 * <p>
119 * A numerical value from FileMode is usually faster for an iterator to
120 * obtain from its data source so this is the preferred representation.
121 *
122 * @see org.eclipse.jgit.lib.FileMode
123 */
124 protected int mode;
125
126 /**
127 * Path buffer for the current entry.
128 * <p>
129 * This buffer is pre-allocated at the start of walking and is shared from
130 * parent iterators down into their subtree iterators. The sharing allows
131 * the current entry to always be a full path from the root, while each
132 * subtree only needs to populate the part that is under their control.
133 */
134 protected byte[] path;
135
136 /**
137 * Position within {@link #path} this iterator starts writing at.
138 * <p>
139 * This is the first offset in {@link #path} that this iterator must
140 * populate during {@link #next}. At the root level (when {@link #parent}
141 * is null) this is 0. For a subtree iterator the index before this position
142 * should have the value '/'.
143 */
144 protected final int pathOffset;
145
146 /**
147 * Total length of the current entry's complete path from the root.
148 * <p>
149 * This is the number of bytes within {@link #path} that pertain to the
150 * current entry. Values at this index through the end of the array are
151 * garbage and may be randomly populated from prior entries.
152 */
153 protected int pathLen;
154
155 /**
156 * Create a new iterator with no parent.
157 */
158 protected AbstractTreeIterator() {
159 parent = null;
160 path = new byte[DEFAULT_PATH_SIZE];
161 pathOffset = 0;
162 }
163
164 /**
165 * Create a new iterator with no parent and a prefix.
166 * <p>
167 * The prefix path supplied is inserted in front of all paths generated by
168 * this iterator. It is intended to be used when an iterator is being
169 * created for a subsection of an overall repository and needs to be
170 * combined with other iterators that are created to run over the entire
171 * repository namespace.
172 *
173 * @param prefix
174 * position of this iterator in the repository tree. The value
175 * may be null or the empty string to indicate the prefix is the
176 * root of the repository. A trailing slash ('/') is
177 * automatically appended if the prefix does not end in '/'.
178 */
179 protected AbstractTreeIterator(final String prefix) {
180 parent = null;
181
182 if (prefix != null && prefix.length() > 0) {
183 final ByteBuffer b;
184
185 b = Constants.CHARSET.encode(CharBuffer.wrap(prefix));
186 pathLen = b.limit();
187 path = new byte[Math.max(DEFAULT_PATH_SIZE, pathLen + 1)];
188 b.get(path, 0, pathLen);
189 if (path[pathLen - 1] != '/')
190 path[pathLen++] = '/';
191 pathOffset = pathLen;
192 } else {
193 path = new byte[DEFAULT_PATH_SIZE];
194 pathOffset = 0;
195 }
196 }
197
198 /**
199 * Create a new iterator with no parent and a prefix.
200 * <p>
201 * The prefix path supplied is inserted in front of all paths generated by
202 * this iterator. It is intended to be used when an iterator is being
203 * created for a subsection of an overall repository and needs to be
204 * combined with other iterators that are created to run over the entire
205 * repository namespace.
206 *
207 * @param prefix
208 * position of this iterator in the repository tree. The value
209 * may be null or the empty array to indicate the prefix is the
210 * root of the repository. A trailing slash ('/') is
211 * automatically appended if the prefix does not end in '/'.
212 */
213 protected AbstractTreeIterator(final byte[] prefix) {
214 parent = null;
215
216 if (prefix != null && prefix.length > 0) {
217 pathLen = prefix.length;
218 path = new byte[Math.max(DEFAULT_PATH_SIZE, pathLen + 1)];
219 System.arraycopy(prefix, 0, path, 0, pathLen);
220 if (path[pathLen - 1] != '/')
221 path[pathLen++] = '/';
222 pathOffset = pathLen;
223 } else {
224 path = new byte[DEFAULT_PATH_SIZE];
225 pathOffset = 0;
226 }
227 }
228
229 /**
230 * Create an iterator for a subtree of an existing iterator.
231 *
232 * @param p
233 * parent tree iterator.
234 */
235 protected AbstractTreeIterator(final AbstractTreeIterator p) {
236 parent = p;
237 path = p.path;
238 pathOffset = p.pathLen + 1;
239
240 try {
241 path[pathOffset - 1] = '/';
242 } catch (ArrayIndexOutOfBoundsException e) {
243 growPath(p.pathLen);
244 path[pathOffset - 1] = '/';
245 }
246 }
247
248 /**
249 * Create an iterator for a subtree of an existing iterator.
250 * <p>
251 * The caller is responsible for setting up the path of the child iterator.
252 *
253 * @param p
254 * parent tree iterator.
255 * @param childPath
256 * path array to be used by the child iterator. This path must
257 * contain the path from the top of the walk to the first child
258 * and must end with a '/'.
259 * @param childPathOffset
260 * position within <code>childPath</code> where the child can
261 * insert its data. The value at
262 * <code>childPath[childPathOffset-1]</code> must be '/'.
263 */
264 protected AbstractTreeIterator(final AbstractTreeIterator p,
265 final byte[] childPath, final int childPathOffset) {
266 parent = p;
267 path = childPath;
268 pathOffset = childPathOffset;
269 }
270
271 /**
272 * Grow the path buffer larger.
273 *
274 * @param len
275 * number of live bytes in the path buffer. This many bytes will
276 * be moved into the larger buffer.
277 */
278 protected void growPath(final int len) {
279 setPathCapacity(path.length << 1, len);
280 }
281
282 /**
283 * Ensure that path is capable to hold at least {@code capacity} bytes
284 *
285 * @param capacity
286 * the amount of bytes to hold
287 * @param len
288 * the amount of live bytes in path buffer
289 */
290 protected void ensurePathCapacity(final int capacity, final int len) {
291 if (path.length >= capacity)
292 return;
293 final byte[] o = path;
294 int current = o.length;
295 int newCapacity = current;
296 while (newCapacity < capacity && newCapacity > 0)
297 newCapacity <<= 1;
298 setPathCapacity(newCapacity, len);
299 }
300
301 /**
302 * Set path buffer capacity to the specified size
303 *
304 * @param capacity
305 * the new size
306 * @param len
307 * the amount of bytes to copy
308 */
309 private void setPathCapacity(int capacity, int len) {
310 final byte[] o = path;
311 final byte[] n = new byte[capacity];
312 System.arraycopy(o, 0, n, 0, len);
313 for (AbstractTreeIterator p = this; p != null && p.path == o; p = p.parent)
314 p.path = n;
315 }
316
317 /**
318 * Compare the path of this current entry to another iterator's entry.
319 *
320 * @param p
321 * the other iterator to compare the path against.
322 * @return -1 if this entry sorts first; 0 if the entries are equal; 1 if
323 * p's entry sorts first.
324 */
325 public int pathCompare(final AbstractTreeIterator p) {
326 return pathCompare(p, p.mode);
327 }
328
329 int pathCompare(final AbstractTreeIterator p, final int pMode) {
330 // Its common when we are a subtree for both parents to match;
331 // when this happens everything in path[0..cPos] is known to
332 // be equal and does not require evaluation again.
333 //
334 int cPos = alreadyMatch(this, p);
335 return pathCompare(p.path, cPos, p.pathLen, pMode, cPos);
336 }
337
338 /**
339 * Seek the iterator on a file, if present.
340 *
341 * @param name
342 * file name to find (will not find a directory).
343 * @return true if the file exists in this tree; false otherwise.
344 * @throws org.eclipse.jgit.errors.CorruptObjectException
345 * tree is invalid.
346 * @since 4.2
347 */
348 public boolean findFile(String name) throws CorruptObjectException {
349 return findFile(Constants.encode(name));
350 }
351
352 /**
353 * Seek the iterator on a file, if present.
354 *
355 * @param name
356 * file name to find (will not find a directory).
357 * @return true if the file exists in this tree; false otherwise.
358 * @throws org.eclipse.jgit.errors.CorruptObjectException
359 * tree is invalid.
360 * @since 4.2
361 */
362 public boolean findFile(byte[] name) throws CorruptObjectException {
363 for (; !eof(); next(1)) {
364 int cmp = pathCompare(name, 0, name.length, 0, pathOffset);
365 if (cmp == 0) {
366 return true;
367 } else if (cmp > 0) {
368 return false;
369 }
370 }
371 return false;
372 }
373
374 /**
375 * Compare the path of this current entry to a raw buffer.
376 *
377 * @param buf
378 * the raw path buffer.
379 * @param pos
380 * position to start reading the raw buffer.
381 * @param end
382 * one past the end of the raw buffer (length is end - pos).
383 * @param pathMode
384 * the mode of the path.
385 * @return -1 if this entry sorts first; 0 if the entries are equal; 1 if
386 * p's entry sorts first.
387 */
388 public int pathCompare(byte[] buf, int pos, int end, int pathMode) {
389 return pathCompare(buf, pos, end, pathMode, 0);
390 }
391
392 private int pathCompare(byte[] b, int bPos, int bEnd, int bMode, int aPos) {
393 return Paths.compare(
394 path, aPos, pathLen, mode,
395 b, bPos, bEnd, bMode);
396 }
397
398 private static int alreadyMatch(AbstractTreeIterator a,
399 AbstractTreeIterator b) {
400 for (;;) {
401 final AbstractTreeIterator ap = a.parent;
402 final AbstractTreeIterator bp = b.parent;
403 if (ap == null || bp == null)
404 return 0;
405 if (ap.matches == bp.matches)
406 return a.pathOffset;
407 a = ap;
408 b = bp;
409 }
410 }
411
412 /**
413 * Check if the current entry of both iterators has the same id.
414 * <p>
415 * This method is faster than {@link #getEntryObjectId()} as it does not
416 * require copying the bytes out of the buffers. A direct {@link #idBuffer}
417 * compare operation is performed.
418 *
419 * @param otherIterator
420 * the other iterator to test against.
421 * @return true if both iterators have the same object id; false otherwise.
422 */
423 public boolean idEqual(final AbstractTreeIterator otherIterator) {
424 return ObjectId.equals(idBuffer(), idOffset(),
425 otherIterator.idBuffer(), otherIterator.idOffset());
426 }
427
428 /**
429 * Whether the entry has a valid ObjectId.
430 *
431 * @return {@code true} if the entry has a valid ObjectId.
432 */
433 public abstract boolean hasId();
434
435 /**
436 * Get the object id of the current entry.
437 *
438 * @return an object id for the current entry.
439 */
440 public ObjectId getEntryObjectId() {
441 return ObjectId.fromRaw(idBuffer(), idOffset());
442 }
443
444 /**
445 * Obtain the ObjectId for the current entry.
446 *
447 * @param out
448 * buffer to copy the object id into.
449 */
450 public void getEntryObjectId(final MutableObjectId out) {
451 out.fromRaw(idBuffer(), idOffset());
452 }
453
454 /**
455 * Get the file mode of the current entry.
456 *
457 * @return the file mode of the current entry.
458 */
459 public FileMode getEntryFileMode() {
460 return FileMode.fromBits(mode);
461 }
462
463 /**
464 * Get the file mode of the current entry as bits.
465 *
466 * @return the file mode of the current entry as bits.
467 */
468 public int getEntryRawMode() {
469 return mode;
470 }
471
472 /**
473 * Get path of the current entry, as a string.
474 *
475 * @return path of the current entry, as a string.
476 */
477 public String getEntryPathString() {
478 return TreeWalk.pathOf(this);
479 }
480
481 /**
482 * Get the current entry path buffer.
483 * <p>
484 * Note that the returned byte[] has to be used together with
485 * {@link #getEntryPathLength()} (only use bytes up to this length).
486 *
487 * @return the internal buffer holding the current path.
488 */
489 public byte[] getEntryPathBuffer() {
490 return path;
491 }
492
493 /**
494 * Get length of the path in {@link #getEntryPathBuffer()}.
495 *
496 * @return length of the path in {@link #getEntryPathBuffer()}.
497 */
498 public int getEntryPathLength() {
499 return pathLen;
500 }
501
502 /**
503 * Get the current entry's path hash code.
504 * <p>
505 * This method computes a hash code on the fly for this path, the hash is
506 * suitable to cluster objects that may have similar paths together.
507 *
508 * @return path hash code; any integer may be returned.
509 */
510 public int getEntryPathHashCode() {
511 int hash = 0;
512 for (int i = Math.max(0, pathLen - 16); i < pathLen; i++) {
513 byte c = path[i];
514 if (c != ' ')
515 hash = (hash >>> 2) + (c << 24);
516 }
517 return hash;
518 }
519
520 /**
521 * Get the byte array buffer object IDs must be copied out of.
522 * <p>
523 * The id buffer contains the bytes necessary to construct an ObjectId for
524 * the current entry of this iterator. The buffer can be the same buffer for
525 * all entries, or it can be a unique buffer per-entry. Implementations are
526 * encouraged to expose their private buffer whenever possible to reduce
527 * garbage generation and copying costs.
528 *
529 * @return byte array the implementation stores object IDs within.
530 * @see #getEntryObjectId()
531 */
532 public abstract byte[] idBuffer();
533
534 /**
535 * Get the position within {@link #idBuffer()} of this entry's ObjectId.
536 *
537 * @return offset into the array returned by {@link #idBuffer()} where the
538 * ObjectId must be copied out of.
539 */
540 public abstract int idOffset();
541
542 /**
543 * Create a new iterator for the current entry's subtree.
544 * <p>
545 * The parent reference of the iterator must be <code>this</code>,
546 * otherwise the caller would not be able to exit out of the subtree
547 * iterator correctly and return to continue walking <code>this</code>.
548 *
549 * @param reader
550 * reader to load the tree data from.
551 * @return a new parser that walks over the current subtree.
552 * @throws org.eclipse.jgit.errors.IncorrectObjectTypeException
553 * the current entry is not actually a tree and cannot be parsed
554 * as though it were a tree.
555 * @throws java.io.IOException
556 * a loose object or pack file could not be read.
557 */
558 public abstract AbstractTreeIterator createSubtreeIterator(
559 ObjectReader reader) throws IncorrectObjectTypeException,
560 IOException;
561
562 /**
563 * Create a new iterator as though the current entry were a subtree.
564 *
565 * @return a new empty tree iterator.
566 */
567 public EmptyTreeIterator createEmptyTreeIterator() {
568 return new EmptyTreeIterator(this);
569 }
570
571 /**
572 * Create a new iterator for the current entry's subtree.
573 * <p>
574 * The parent reference of the iterator must be <code>this</code>, otherwise
575 * the caller would not be able to exit out of the subtree iterator
576 * correctly and return to continue walking <code>this</code>.
577 *
578 * @param reader
579 * reader to load the tree data from.
580 * @param idBuffer
581 * temporary ObjectId buffer for use by this method.
582 * @return a new parser that walks over the current subtree.
583 * @throws org.eclipse.jgit.errors.IncorrectObjectTypeException
584 * the current entry is not actually a tree and cannot be parsed
585 * as though it were a tree.
586 * @throws java.io.IOException
587 * a loose object or pack file could not be read.
588 */
589 public AbstractTreeIterator createSubtreeIterator(
590 final ObjectReader reader, final MutableObjectId idBuffer)
591 throws IncorrectObjectTypeException, IOException {
592 return createSubtreeIterator(reader);
593 }
594
595 /**
596 * Position this iterator on the first entry.
597 *
598 * The default implementation of this method uses {@code back(1)} until
599 * {@code first()} is true. This is most likely not the most efficient
600 * method of repositioning the iterator to its first entry, so subclasses
601 * are strongly encouraged to override the method.
602 *
603 * @throws org.eclipse.jgit.errors.CorruptObjectException
604 * the tree is invalid.
605 */
606 public void reset() throws CorruptObjectException {
607 while (!first())
608 back(1);
609 }
610
611 /**
612 * Is this tree iterator positioned on its first entry?
613 * <p>
614 * An iterator is positioned on the first entry if <code>back(1)</code>
615 * would be an invalid request as there is no entry before the current one.
616 * <p>
617 * An empty iterator (one with no entries) will be
618 * <code>first() && eof()</code>.
619 *
620 * @return true if the iterator is positioned on the first entry.
621 */
622 public abstract boolean first();
623
624 /**
625 * Is this tree iterator at its EOF point (no more entries)?
626 * <p>
627 * An iterator is at EOF if there is no current entry.
628 *
629 * @return true if we have walked all entries and have none left.
630 */
631 public abstract boolean eof();
632
633 /**
634 * Move to next entry, populating this iterator with the entry data.
635 * <p>
636 * The delta indicates how many moves forward should occur. The most common
637 * delta is 1 to move to the next entry.
638 * <p>
639 * Implementations must populate the following members:
640 * <ul>
641 * <li>{@link #mode}</li>
642 * <li>{@link #path} (from {@link #pathOffset} to {@link #pathLen})</li>
643 * <li>{@link #pathLen}</li>
644 * </ul>
645 * as well as any implementation dependent information necessary to
646 * accurately return data from {@link #idBuffer()} and {@link #idOffset()}
647 * when demanded.
648 *
649 * @param delta
650 * number of entries to move the iterator by. Must be a positive,
651 * non-zero integer.
652 * @throws org.eclipse.jgit.errors.CorruptObjectException
653 * the tree is invalid.
654 */
655 public abstract void next(int delta) throws CorruptObjectException;
656
657 /**
658 * Move to prior entry, populating this iterator with the entry data.
659 * <p>
660 * The delta indicates how many moves backward should occur.The most common
661 * delta is 1 to move to the prior entry.
662 * <p>
663 * Implementations must populate the following members:
664 * <ul>
665 * <li>{@link #mode}</li>
666 * <li>{@link #path} (from {@link #pathOffset} to {@link #pathLen})</li>
667 * <li>{@link #pathLen}</li>
668 * </ul>
669 * as well as any implementation dependent information necessary to
670 * accurately return data from {@link #idBuffer()} and {@link #idOffset()}
671 * when demanded.
672 *
673 * @param delta
674 * number of entries to move the iterator by. Must be a positive,
675 * non-zero integer.
676 * @throws org.eclipse.jgit.errors.CorruptObjectException
677 * the tree is invalid.
678 */
679 public abstract void back(int delta) throws CorruptObjectException;
680
681 /**
682 * Advance to the next tree entry, populating this iterator with its data.
683 * <p>
684 * This method behaves like <code>seek(1)</code> but is called by
685 * {@link org.eclipse.jgit.treewalk.TreeWalk} only if a
686 * {@link org.eclipse.jgit.treewalk.filter.TreeFilter} was used and ruled
687 * out the current entry from the results. In such cases this tree iterator
688 * may perform special behavior.
689 *
690 * @throws org.eclipse.jgit.errors.CorruptObjectException
691 * the tree is invalid.
692 */
693 public void skip() throws CorruptObjectException {
694 next(1);
695 }
696
697 /**
698 * Indicates to the iterator that no more entries will be read.
699 * <p>
700 * This is only invoked by TreeWalk when the iteration is aborted early due
701 * to a {@link org.eclipse.jgit.errors.StopWalkException} being thrown from
702 * within a TreeFilter.
703 */
704 public void stopWalk() {
705 // Do nothing by default. Most iterators do not care.
706 }
707
708 /**
709 * Whether the iterator implements {@link #stopWalk()}.
710 *
711 * @return {@code true} if the iterator implements {@link #stopWalk()}.
712 * @since 4.2
713 */
714 protected boolean needsStopWalk() {
715 return false;
716 }
717
718 /**
719 * Get the length of the name component of the path for the current entry.
720 *
721 * @return the length of the name component of the path for the current
722 * entry.
723 */
724 public int getNameLength() {
725 return pathLen - pathOffset;
726 }
727
728 /**
729 * JGit internal API for use by
730 * {@link org.eclipse.jgit.dircache.DirCacheCheckout}
731 *
732 * @return start of name component part within {@link #getEntryPathBuffer()}
733 * @since 2.0
734 */
735 public int getNameOffset() {
736 return pathOffset;
737 }
738
739 /**
740 * Get the name component of the current entry path into the provided
741 * buffer.
742 *
743 * @param buffer
744 * the buffer to get the name into, it is assumed that buffer can
745 * hold the name
746 * @param offset
747 * the offset of the name in the buffer
748 * @see #getNameLength()
749 */
750 public void getName(byte[] buffer, int offset) {
751 System.arraycopy(path, pathOffset, buffer, offset, pathLen - pathOffset);
752 }
753
754 /** {@inheritDoc} */
755 @SuppressWarnings("nls")
756 @Override
757 public String toString() {
758 return getClass().getSimpleName() + "[" + getEntryPathString() + "]"; //$NON-NLS-1$
759 }
760
761 /**
762 * Whether or not this Iterator is iterating through the working tree.
763 *
764 * @return whether or not this Iterator is iterating through the working
765 * tree
766 * @since 4.3
767 */
768 public boolean isWorkTree() {
769 return false;
770 }
771 }