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