upload-pack: Force an fd flush after receiving flush pkt from client
[egit/qmx.git] / org.spearce.jgit / src / org / spearce / jgit / treewalk / TreeWalk.java
bloba41ca58714ccdf2829b50b059ed046ed2d22ffec
1 /*
2 * Copyright (C) 2008, Shawn O. Pearce <spearce@spearce.org>
4 * All rights reserved.
6 * Redistribution and use in source and binary forms, with or
7 * without modification, are permitted provided that the following
8 * conditions are met:
10 * - Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
13 * - Redistributions in binary form must reproduce the above
14 * copyright notice, this list of conditions and the following
15 * disclaimer in the documentation and/or other materials provided
16 * with the distribution.
18 * - Neither the name of the Git Development Community nor the
19 * names of its contributors may be used to endorse or promote
20 * products derived from this software without specific prior
21 * written permission.
23 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
24 * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
25 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
26 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
28 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
29 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
30 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
31 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
32 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
33 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
34 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
35 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
38 package org.spearce.jgit.treewalk;
40 import java.io.IOException;
41 import java.util.Collections;
43 import org.spearce.jgit.errors.CorruptObjectException;
44 import org.spearce.jgit.errors.IncorrectObjectTypeException;
45 import org.spearce.jgit.errors.MissingObjectException;
46 import org.spearce.jgit.errors.StopWalkException;
47 import org.spearce.jgit.lib.AnyObjectId;
48 import org.spearce.jgit.lib.Constants;
49 import org.spearce.jgit.lib.FileMode;
50 import org.spearce.jgit.lib.MutableObjectId;
51 import org.spearce.jgit.lib.ObjectId;
52 import org.spearce.jgit.lib.Repository;
53 import org.spearce.jgit.lib.WindowCursor;
54 import org.spearce.jgit.revwalk.RevTree;
55 import org.spearce.jgit.treewalk.filter.PathFilterGroup;
56 import org.spearce.jgit.treewalk.filter.TreeFilter;
57 import org.spearce.jgit.util.RawParseUtils;
59 /**
60 * Walks one or more {@link AbstractTreeIterator}s in parallel.
61 * <p>
62 * This class can perform n-way differences across as many trees as necessary.
63 * <p>
64 * Each tree added must have the same root as existing trees in the walk.
65 * <p>
66 * A TreeWalk instance can only be used once to generate results. Running a
67 * second time requires creating a new TreeWalk instance, or invoking
68 * {@link #reset()} and adding new trees before starting again. Resetting an
69 * existing instance may be faster for some applications as some internal
70 * buffers may be recycled.
71 * <p>
72 * TreeWalk instances are not thread-safe. Applications must either restrict
73 * usage of a TreeWalk instance to a single thread, or implement their own
74 * synchronization at a higher level.
75 * <p>
76 * Multiple simultaneous TreeWalk instances per {@link Repository} are
77 * permitted, even from concurrent threads.
79 public class TreeWalk {
80 /**
81 * Open a tree walk and filter to exactly one path.
82 * <p>
83 * The returned tree walk is already positioned on the requested path, so
84 * the caller should not need to invoke {@link #next()} unless they are
85 * looking for a possible directory/file name conflict.
87 * @param db
88 * repository to read tree object data from.
89 * @param path
90 * single path to advance the tree walk instance into.
91 * @param trees
92 * one or more trees to walk through, all with the same root.
93 * @return a new tree walk configured for exactly this one path; null if no
94 * path was found in any of the trees.
95 * @throws IOException
96 * reading a pack file or loose object failed.
97 * @throws CorruptObjectException
98 * an tree object could not be read as its data stream did not
99 * appear to be a tree, or could not be inflated.
100 * @throws IncorrectObjectTypeException
101 * an object we expected to be a tree was not a tree.
102 * @throws MissingObjectException
103 * a tree object was not found.
105 public static TreeWalk forPath(final Repository db, final String path,
106 final AnyObjectId[] trees) throws MissingObjectException,
107 IncorrectObjectTypeException, CorruptObjectException, IOException {
108 final TreeWalk r = new TreeWalk(db);
109 r.setFilter(PathFilterGroup.createFromStrings(Collections
110 .singleton(path)));
111 r.setRecursive(r.getFilter().shouldBeRecursive());
112 r.reset(trees);
113 return r.next() ? r : null;
117 * Open a tree walk and filter to exactly one path.
118 * <p>
119 * The returned tree walk is already positioned on the requested path, so
120 * the caller should not need to invoke {@link #next()} unless they are
121 * looking for a possible directory/file name conflict.
123 * @param db
124 * repository to read tree object data from.
125 * @param path
126 * single path to advance the tree walk instance into.
127 * @param tree
128 * the single tree to walk through.
129 * @return a new tree walk configured for exactly this one path; null if no
130 * path was found in any of the trees.
131 * @throws IOException
132 * reading a pack file or loose object failed.
133 * @throws CorruptObjectException
134 * an tree object could not be read as its data stream did not
135 * appear to be a tree, or could not be inflated.
136 * @throws IncorrectObjectTypeException
137 * an object we expected to be a tree was not a tree.
138 * @throws MissingObjectException
139 * a tree object was not found.
141 public static TreeWalk forPath(final Repository db, final String path,
142 final RevTree tree) throws MissingObjectException,
143 IncorrectObjectTypeException, CorruptObjectException, IOException {
144 return forPath(db, path, new ObjectId[] { tree });
147 private final Repository db;
149 private final MutableObjectId idBuffer = new MutableObjectId();
151 private final WindowCursor curs = new WindowCursor();
153 private TreeFilter filter;
155 AbstractTreeIterator[] trees;
157 private boolean recursive;
159 private boolean postOrderTraversal;
161 private int depth;
163 private boolean advance;
165 private boolean postChildren;
167 AbstractTreeIterator currentHead;
170 * Create a new tree walker for a given repository.
172 * @param repo
173 * the repository the walker will obtain data from.
175 public TreeWalk(final Repository repo) {
176 db = repo;
177 filter = TreeFilter.ALL;
178 trees = new AbstractTreeIterator[] { new EmptyTreeIterator() };
182 * Get the repository this tree walker is reading from.
184 * @return the repository configured when the walker was created.
186 public Repository getRepository() {
187 return db;
191 * Get the currently configured filter.
193 * @return the current filter. Never null as a filter is always needed.
195 public TreeFilter getFilter() {
196 return filter;
200 * Set the tree entry filter for this walker.
201 * <p>
202 * Multiple filters may be combined by constructing an arbitrary tree of
203 * <code>AndTreeFilter</code> or <code>OrTreeFilter</code> instances to
204 * describe the boolean expression required by the application. Custom
205 * filter implementations may also be constructed by applications.
206 * <p>
207 * Note that filters are not thread-safe and may not be shared by concurrent
208 * TreeWalk instances. Every TreeWalk must be supplied its own unique
209 * filter, unless the filter implementation specifically states it is (and
210 * always will be) thread-safe. Callers may use {@link TreeFilter#clone()}
211 * to create a unique filter tree for this TreeWalk instance.
213 * @param newFilter
214 * the new filter. If null the special {@link TreeFilter#ALL}
215 * filter will be used instead, as it matches every entry.
216 * @see org.spearce.jgit.treewalk.filter.AndTreeFilter
217 * @see org.spearce.jgit.treewalk.filter.OrTreeFilter
219 public void setFilter(final TreeFilter newFilter) {
220 filter = newFilter != null ? newFilter : TreeFilter.ALL;
224 * Is this walker automatically entering into subtrees?
225 * <p>
226 * If the walker is recursive then the caller will not see a subtree node
227 * and instead will only receive file nodes in all relevant subtrees.
229 * @return true if automatically entering subtrees is enabled.
231 public boolean isRecursive() {
232 return recursive;
236 * Set the walker to enter (or not enter) subtrees automatically.
237 * <p>
238 * If recursive mode is enabled the walker will hide subtree nodes from the
239 * calling application and will produce only file level nodes. If a tree
240 * (directory) is deleted then all of the file level nodes will appear to be
241 * deleted, recursively, through as many levels as necessary to account for
242 * all entries.
244 * @param b
245 * true to skip subtree nodes and only obtain files nodes.
247 public void setRecursive(final boolean b) {
248 recursive = b;
252 * Does this walker return a tree entry after it exits the subtree?
253 * <p>
254 * If post order traversal is enabled then the walker will return a subtree
255 * after it has returned the last entry within that subtree. This may cause
256 * a subtree to be seen by the application twice if {@link #isRecursive()}
257 * is false, as the application will see it once, call
258 * {@link #enterSubtree()}, and then see it again as it leaves the subtree.
259 * <p>
260 * If an application does not enable {@link #isRecursive()} and it does not
261 * call {@link #enterSubtree()} then the tree is returned only once as none
262 * of the children were processed.
264 * @return true if subtrees are returned after entries within the subtree.
266 public boolean isPostOrderTraversal() {
267 return postOrderTraversal;
271 * Set the walker to return trees after their children.
273 * @param b
274 * true to get trees after their children.
275 * @see #isPostOrderTraversal()
277 public void setPostOrderTraversal(final boolean b) {
278 postOrderTraversal = b;
281 /** Reset this walker so new tree iterators can be added to it. */
282 public void reset() {
283 trees = new AbstractTreeIterator[0];
284 advance = false;
285 depth = 0;
289 * Reset this walker to run over a single existing tree.
291 * @param id
292 * the tree we need to parse. The walker will execute over this
293 * single tree if the reset is successful.
294 * @throws MissingObjectException
295 * the given tree object does not exist in this repository.
296 * @throws IncorrectObjectTypeException
297 * the given object id does not denote a tree, but instead names
298 * some other non-tree type of object. Note that commits are not
299 * trees, even if they are sometimes called a "tree-ish".
300 * @throws CorruptObjectException
301 * the object claimed to be a tree, but its contents did not
302 * appear to be a tree. The repository may have data corruption.
303 * @throws IOException
304 * a loose object or pack file could not be read.
306 public void reset(final AnyObjectId id) throws MissingObjectException,
307 IncorrectObjectTypeException, CorruptObjectException, IOException {
308 if (trees.length == 1) {
309 AbstractTreeIterator o = trees[0];
310 while (o.parent != null)
311 o = o.parent;
312 if (o instanceof CanonicalTreeParser) {
313 o.matches = null;
314 o.matchShift = 0;
315 ((CanonicalTreeParser) o).reset(db, id, curs);
316 trees[0] = o;
317 } else {
318 trees[0] = parserFor(id);
320 } else {
321 trees = new AbstractTreeIterator[] { parserFor(id) };
324 advance = false;
325 depth = 0;
329 * Reset this walker to run over a set of existing trees.
331 * @param ids
332 * the trees we need to parse. The walker will execute over this
333 * many parallel trees if the reset is successful.
334 * @throws MissingObjectException
335 * the given tree object does not exist in this repository.
336 * @throws IncorrectObjectTypeException
337 * the given object id does not denote a tree, but instead names
338 * some other non-tree type of object. Note that commits are not
339 * trees, even if they are sometimes called a "tree-ish".
340 * @throws CorruptObjectException
341 * the object claimed to be a tree, but its contents did not
342 * appear to be a tree. The repository may have data corruption.
343 * @throws IOException
344 * a loose object or pack file could not be read.
346 public void reset(final AnyObjectId[] ids) throws MissingObjectException,
347 IncorrectObjectTypeException, CorruptObjectException, IOException {
348 final int oldLen = trees.length;
349 final int newLen = ids.length;
350 final AbstractTreeIterator[] r = newLen == oldLen ? trees
351 : new AbstractTreeIterator[newLen];
352 for (int i = 0; i < newLen; i++) {
353 AbstractTreeIterator o;
355 if (i < oldLen) {
356 o = trees[i];
357 while (o.parent != null)
358 o = o.parent;
359 if (o instanceof CanonicalTreeParser && o.pathOffset == 0) {
360 o.matches = null;
361 o.matchShift = 0;
362 ((CanonicalTreeParser) o).reset(db, ids[i], curs);
363 r[i] = o;
364 continue;
368 o = parserFor(ids[i]);
369 r[i] = o;
372 trees = r;
373 advance = false;
374 depth = 0;
378 * Add an already existing tree object for walking.
379 * <p>
380 * The position of this tree is returned to the caller, in case the caller
381 * has lost track of the order they added the trees into the walker.
382 * <p>
383 * The tree must have the same root as existing trees in the walk.
385 * @param id
386 * identity of the tree object the caller wants walked.
387 * @return position of this tree within the walker.
388 * @throws MissingObjectException
389 * the given tree object does not exist in this repository.
390 * @throws IncorrectObjectTypeException
391 * the given object id does not denote a tree, but instead names
392 * some other non-tree type of object. Note that commits are not
393 * trees, even if they are sometimes called a "tree-ish".
394 * @throws CorruptObjectException
395 * the object claimed to be a tree, but its contents did not
396 * appear to be a tree. The repository may have data corruption.
397 * @throws IOException
398 * a loose object or pack file could not be read.
400 public int addTree(final ObjectId id) throws MissingObjectException,
401 IncorrectObjectTypeException, CorruptObjectException, IOException {
402 return addTree(parserFor(id));
406 * Add an already created tree iterator for walking.
407 * <p>
408 * The position of this tree is returned to the caller, in case the caller
409 * has lost track of the order they added the trees into the walker.
410 * <p>
411 * The tree which the iterator operates on must have the same root as
412 * existing trees in the walk.
414 * @param p
415 * an iterator to walk over. The iterator should be new, with no
416 * parent, and should still be positioned before the first entry.
417 * The tree which the iterator operates on must have the same root
418 * as other trees in the walk.
420 * @return position of this tree within the walker.
421 * @throws CorruptObjectException
422 * the iterator was unable to obtain its first entry, due to
423 * possible data corruption within the backing data store.
425 public int addTree(final AbstractTreeIterator p)
426 throws CorruptObjectException {
427 final int n = trees.length;
428 final AbstractTreeIterator[] newTrees = new AbstractTreeIterator[n + 1];
430 System.arraycopy(trees, 0, newTrees, 0, n);
431 newTrees[n] = p;
432 p.matches = null;
433 p.matchShift = 0;
435 trees = newTrees;
436 return n;
440 * Get the number of trees known to this walker.
442 * @return the total number of trees this walker is iterating over.
444 public int getTreeCount() {
445 return trees.length;
449 * Advance this walker to the next relevant entry.
451 * @return true if there is an entry available; false if all entries have
452 * been walked and the walk of this set of tree iterators is over.
453 * @throws MissingObjectException
454 * {@link #isRecursive()} was enabled, a subtree was found, but
455 * the subtree object does not exist in this repository. The
456 * repository may be missing objects.
457 * @throws IncorrectObjectTypeException
458 * {@link #isRecursive()} was enabled, a subtree was found, and
459 * the subtree id does not denote a tree, but instead names some
460 * other non-tree type of object. The repository may have data
461 * corruption.
462 * @throws CorruptObjectException
463 * the contents of a tree did not appear to be a tree. The
464 * repository may have data corruption.
465 * @throws IOException
466 * a loose object or pack file could not be read.
468 public boolean next() throws MissingObjectException,
469 IncorrectObjectTypeException, CorruptObjectException, IOException {
470 try {
471 if (advance) {
472 advance = false;
473 postChildren = false;
474 popEntriesEqual();
477 for (;;) {
478 final AbstractTreeIterator t = min();
479 if (t.eof()) {
480 if (depth > 0) {
481 exitSubtree();
482 if (postOrderTraversal) {
483 advance = true;
484 postChildren = true;
485 return true;
487 popEntriesEqual();
488 continue;
490 return false;
493 currentHead = t;
494 if (!filter.include(this)) {
495 skipEntriesEqual();
496 continue;
499 if (recursive && FileMode.TREE.equals(t.mode)) {
500 enterSubtree();
501 continue;
504 advance = true;
505 return true;
507 } catch (StopWalkException stop) {
508 for (final AbstractTreeIterator t : trees)
509 t.stopWalk();
510 return false;
515 * Obtain the tree iterator for the current entry.
516 * <p>
517 * Entering into (or exiting out of) a subtree causes the current tree
518 * iterator instance to be changed for the nth tree. This allows the tree
519 * iterators to manage only one list of items, with the diving handled by
520 * recursive trees.
522 * @param <T>
523 * type of the tree iterator expected by the caller.
524 * @param nth
525 * tree to obtain the current iterator of.
526 * @param clazz
527 * type of the tree iterator expected by the caller.
528 * @return r the current iterator of the requested type; null if the tree
529 * has no entry to match the current path.
531 public <T extends AbstractTreeIterator> T getTree(final int nth,
532 final Class<T> clazz) {
533 final AbstractTreeIterator t = trees[nth];
534 return t.matches == currentHead ? (T) t : null;
538 * Obtain the raw {@link FileMode} bits for the current entry.
539 * <p>
540 * Every added tree supplies mode bits, even if the tree does not contain
541 * the current entry. In the latter case {@link FileMode#MISSING}'s mode
542 * bits (0) are returned.
544 * @param nth
545 * tree to obtain the mode bits from.
546 * @return mode bits for the current entry of the nth tree.
547 * @see FileMode#fromBits(int)
549 public int getRawMode(final int nth) {
550 final AbstractTreeIterator t = trees[nth];
551 return t.matches == currentHead ? t.mode : 0;
555 * Obtain the {@link FileMode} for the current entry.
556 * <p>
557 * Every added tree supplies a mode, even if the tree does not contain the
558 * current entry. In the latter case {@link FileMode#MISSING} is returned.
560 * @param nth
561 * tree to obtain the mode from.
562 * @return mode for the current entry of the nth tree.
564 public FileMode getFileMode(final int nth) {
565 return FileMode.fromBits(getRawMode(nth));
569 * Obtain the ObjectId for the current entry.
570 * <p>
571 * Using this method to compare ObjectId values between trees of this walker
572 * is very inefficient. Applications should try to use
573 * {@link #idEqual(int, int)} or {@link #getObjectId(MutableObjectId, int)}
574 * whenever possible.
575 * <p>
576 * Every tree supplies an object id, even if the tree does not contain the
577 * current entry. In the latter case {@link ObjectId#zeroId()} is returned.
579 * @param nth
580 * tree to obtain the object identifier from.
581 * @return object identifier for the current tree entry.
582 * @see #getObjectId(MutableObjectId, int)
583 * @see #idEqual(int, int)
585 public ObjectId getObjectId(final int nth) {
586 final AbstractTreeIterator t = trees[nth];
587 return t.matches == currentHead ? t.getEntryObjectId() : ObjectId
588 .zeroId();
592 * Obtain the ObjectId for the current entry.
593 * <p>
594 * Every tree supplies an object id, even if the tree does not contain the
595 * current entry. In the latter case {@link ObjectId#zeroId()} is supplied.
596 * <p>
597 * Applications should try to use {@link #idEqual(int, int)} when possible
598 * as it avoids conversion overheads.
600 * @param out
601 * buffer to copy the object id into.
602 * @param nth
603 * tree to obtain the object identifier from.
604 * @see #idEqual(int, int)
606 public void getObjectId(final MutableObjectId out, final int nth) {
607 final AbstractTreeIterator t = trees[nth];
608 if (t.matches == currentHead)
609 t.getEntryObjectId(out);
610 else
611 out.clear();
615 * Compare two tree's current ObjectId values for equality.
617 * @param nthA
618 * first tree to compare the object id from.
619 * @param nthB
620 * second tree to compare the object id from.
621 * @return result of
622 * <code>getObjectId(nthA).equals(getObjectId(nthB))</code>.
623 * @see #getObjectId(int)
625 public boolean idEqual(final int nthA, final int nthB) {
626 final AbstractTreeIterator ch = currentHead;
627 final AbstractTreeIterator a = trees[nthA];
628 final AbstractTreeIterator b = trees[nthB];
629 if (a.matches == ch && b.matches == ch)
630 return a.idEqual(b);
631 if (a.matches != ch && b.matches != ch) {
632 // If neither tree matches the current path node then neither
633 // tree has this entry. In such case the ObjectId is zero(),
634 // and zero() is always equal to zero().
636 return true;
638 return false;
642 * Get the current entry's name within its parent tree.
643 * <p>
644 * This method is not very efficient and is primarily meant for debugging
645 * and final output generation. Applications should try to avoid calling it,
646 * and if invoked do so only once per interesting entry, where the name is
647 * absolutely required for correct function.
649 * @return name of the current entry within the parent tree (or directory).
650 * The name never includes a '/'.
652 public String getNameString() {
653 final AbstractTreeIterator t = currentHead;
654 final int off = t.pathOffset;
655 final int end = t.pathLen;
656 return RawParseUtils.decode(Constants.CHARSET, t.path, off, end);
660 * Get the current entry's complete path.
661 * <p>
662 * This method is not very efficient and is primarily meant for debugging
663 * and final output generation. Applications should try to avoid calling it,
664 * and if invoked do so only once per interesting entry, where the name is
665 * absolutely required for correct function.
667 * @return complete path of the current entry, from the root of the
668 * repository. If the current entry is in a subtree there will be at
669 * least one '/' in the returned string.
671 public String getPathString() {
672 return pathOf(currentHead);
676 * Get the current entry's complete path as a UTF-8 byte array.
678 * @return complete path of the current entry, from the root of the
679 * repository. If the current entry is in a subtree there will be at
680 * least one '/' in the returned string.
682 public byte[] getRawPath() {
683 final AbstractTreeIterator t = currentHead;
684 final int n = t.pathLen;
685 final byte[] r = new byte[n];
686 System.arraycopy(t.path, 0, r, 0, n);
687 return r;
691 * Test if the supplied path matches the current entry's path.
692 * <p>
693 * This method tests that the supplied path is exactly equal to the current
694 * entry, or is one of its parent directories. It is faster to use this
695 * method then to use {@link #getPathString()} to first create a String
696 * object, then test <code>startsWith</code> or some other type of string
697 * match function.
699 * @param p
700 * path buffer to test. Callers should ensure the path does not
701 * end with '/' prior to invocation.
702 * @param pLen
703 * number of bytes from <code>buf</code> to test.
704 * @return < 0 if p is before the current path; 0 if p matches the current
705 * path; 1 if the current path is past p and p will never match
706 * again on this tree walk.
708 public int isPathPrefix(final byte[] p, final int pLen) {
709 final AbstractTreeIterator t = currentHead;
710 final byte[] c = t.path;
711 final int cLen = t.pathLen;
712 int ci;
714 for (ci = 0; ci < cLen && ci < pLen; ci++) {
715 final int c_value = (c[ci] & 0xff) - (p[ci] & 0xff);
716 if (c_value != 0)
717 return c_value;
720 if (ci < cLen) {
721 // Ran out of pattern but we still had current data.
722 // If c[ci] == '/' then pattern matches the subtree.
723 // Otherwise we cannot be certain so we return -1.
725 return c[ci] == '/' ? 0 : -1;
728 if (ci < pLen) {
729 // Ran out of current, but we still have pattern data.
730 // If p[ci] == '/' then pattern matches this subtree,
731 // otherwise we cannot be certain so we return -1.
733 return p[ci] == '/' ? 0 : -1;
736 // Both strings are identical.
738 return 0;
742 * Get the current subtree depth of this walker.
744 * @return the current subtree depth of this walker.
746 public int getDepth() {
747 return depth;
751 * Is the current entry a subtree?
752 * <p>
753 * This method is faster then testing the raw mode bits of all trees to see
754 * if any of them are a subtree. If at least one is a subtree then this
755 * method will return true.
757 * @return true if {@link #enterSubtree()} will work on the current node.
759 public boolean isSubtree() {
760 return FileMode.TREE.equals(currentHead.mode);
764 * Is the current entry a subtree returned after its children?
766 * @return true if the current node is a tree that has been returned after
767 * its children were already processed.
768 * @see #isPostOrderTraversal()
770 public boolean isPostChildren() {
771 return postChildren && isSubtree();
775 * Enter into the current subtree.
776 * <p>
777 * If the current entry is a subtree this method arranges for its children
778 * to be returned before the next sibling following the subtree is returned.
780 * @throws MissingObjectException
781 * a subtree was found, but the subtree object does not exist in
782 * this repository. The repository may be missing objects.
783 * @throws IncorrectObjectTypeException
784 * a subtree was found, and the subtree id does not denote a
785 * tree, but instead names some other non-tree type of object.
786 * The repository may have data corruption.
787 * @throws CorruptObjectException
788 * the contents of a tree did not appear to be a tree. The
789 * repository may have data corruption.
790 * @throws IOException
791 * a loose object or pack file could not be read.
793 public void enterSubtree() throws MissingObjectException,
794 IncorrectObjectTypeException, CorruptObjectException, IOException {
795 final AbstractTreeIterator ch = currentHead;
796 final AbstractTreeIterator[] tmp = new AbstractTreeIterator[trees.length];
797 for (int i = 0; i < trees.length; i++) {
798 final AbstractTreeIterator t = trees[i];
799 final AbstractTreeIterator n;
800 if (t.matches == ch && !t.eof() && FileMode.TREE.equals(t.mode))
801 n = t.createSubtreeIterator(db, idBuffer, curs);
802 else
803 n = new EmptyTreeIterator(t);
804 tmp[i] = n;
806 depth++;
807 advance = false;
808 System.arraycopy(tmp, 0, trees, 0, trees.length);
811 AbstractTreeIterator min() throws CorruptObjectException {
812 int i = 0;
813 AbstractTreeIterator minRef = trees[i];
814 while (minRef.eof() && ++i < trees.length)
815 minRef = trees[i];
816 if (minRef.eof())
817 return minRef;
819 minRef.matches = minRef;
820 while (++i < trees.length) {
821 final AbstractTreeIterator t = trees[i];
822 if (t.eof())
823 continue;
824 final int cmp = t.pathCompare(minRef);
825 if (cmp < 0) {
826 t.matches = t;
827 minRef = t;
828 } else if (cmp == 0) {
829 t.matches = minRef;
833 return minRef;
836 void popEntriesEqual() throws CorruptObjectException {
837 final AbstractTreeIterator ch = currentHead;
838 for (int i = 0; i < trees.length; i++) {
839 final AbstractTreeIterator t = trees[i];
840 if (t.matches == ch) {
841 t.next(1);
842 t.matches = null;
847 void skipEntriesEqual() throws CorruptObjectException {
848 final AbstractTreeIterator ch = currentHead;
849 for (int i = 0; i < trees.length; i++) {
850 final AbstractTreeIterator t = trees[i];
851 if (t.matches == ch) {
852 t.skip();
853 t.matches = null;
858 private void exitSubtree() {
859 depth--;
860 for (int i = 0; i < trees.length; i++)
861 trees[i] = trees[i].parent;
863 AbstractTreeIterator minRef = null;
864 for (final AbstractTreeIterator t : trees) {
865 if (t.matches != t)
866 continue;
867 if (minRef == null || t.pathCompare(minRef) < 0)
868 minRef = t;
870 currentHead = minRef;
873 private CanonicalTreeParser parserFor(final AnyObjectId id)
874 throws IncorrectObjectTypeException, IOException {
875 final CanonicalTreeParser p = new CanonicalTreeParser();
876 p.reset(db, id, curs);
877 return p;
880 static String pathOf(final AbstractTreeIterator t) {
881 return RawParseUtils.decode(Constants.CHARSET, t.path, 0, t.pathLen);