2 * Copyright (C) 2008, Shawn O. Pearce <spearce@spearce.org>
6 * Redistribution and use in source and binary forms, with or
7 * without modification, are permitted provided that the following
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
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
;
42 import org
.spearce
.jgit
.errors
.IncorrectObjectTypeException
;
43 import org
.spearce
.jgit
.errors
.MissingObjectException
;
44 import org
.spearce
.jgit
.lib
.Constants
;
45 import org
.spearce
.jgit
.lib
.FileMode
;
46 import org
.spearce
.jgit
.lib
.ObjectId
;
47 import org
.spearce
.jgit
.lib
.ObjectLoader
;
48 import org
.spearce
.jgit
.lib
.Repository
;
50 /** Parses raw Git trees from the canonical semi-text/semi-binary format. */
51 public class CanonicalTreeParser
extends AbstractTreeIterator
{
54 /** First offset within {@link #raw} of the current entry's data. */
57 /** Offset one past the current entry (first byte of next entry. */
60 /** Create a new parser. */
61 public CanonicalTreeParser() {
65 private CanonicalTreeParser(final CanonicalTreeParser p
) {
70 * Reset this parser to walk through the given tree data.
73 * the raw tree content.
75 public void reset(final byte[] treeData
) {
83 * Reset this parser to walk through the given tree.
86 * repository to load the tree data from.
88 * identity of the tree being parsed; used only in exception
89 * messages if data corruption is found.
90 * @throws MissingObjectException
91 * the object supplied is not available from the repository.
92 * @throws IncorrectObjectTypeException
93 * the object supplied as an argument is not actually a tree and
94 * cannot be parsed as though it were a tree.
96 * a loose object or pack file could not be read.
98 public void reset(final Repository repo
, final ObjectId id
)
99 throws IncorrectObjectTypeException
, IOException
{
100 final ObjectLoader ldr
= repo
.openObject(id
);
102 throw new MissingObjectException(id
, Constants
.TYPE_TREE
);
103 final byte[] subtreeData
= ldr
.getCachedBytes();
104 if (ldr
.getType() != Constants
.OBJ_TREE
)
105 throw new IncorrectObjectTypeException(id
, Constants
.TYPE_TREE
);
109 public CanonicalTreeParser
createSubtreeIterator(final Repository repo
)
110 throws IncorrectObjectTypeException
, IOException
{
111 final ObjectId id
= getEntryObjectId();
112 if (!FileMode
.TREE
.equals(mode
))
113 throw new IncorrectObjectTypeException(id
, Constants
.TYPE_TREE
);
114 final CanonicalTreeParser p
= new CanonicalTreeParser(this);
120 public byte[] idBuffer() {
125 public int idOffset() {
126 return nextPtr
- Constants
.OBJECT_ID_LENGTH
;
130 public boolean first() {
134 public boolean eof() {
135 return currPtr
== raw
.length
;
139 public void next(int delta
) {
141 // Moving forward one is the most common case.
149 // Fast skip over records, then parse the last one.
151 final int end
= raw
.length
;
153 while (--delta
> 0 && ptr
!= end
) {
154 while (raw
[ptr
] != 0)
156 ptr
+= Constants
.OBJECT_ID_LENGTH
+ 1;
159 throw new ArrayIndexOutOfBoundsException(delta
);
166 public void back(int delta
) {
168 while (--delta
>= 0) {
170 throw new ArrayIndexOutOfBoundsException(delta
);
172 // Rewind back beyond the id and the null byte. Find the
173 // last space, this _might_ be the split between the mode
174 // and the path. Most paths in most trees do not contain a
175 // space so this prunes our search more quickly.
177 ptr
-= Constants
.OBJECT_ID_LENGTH
;
178 while (raw
[--ptr
] != ' ')
180 if (--ptr
< Constants
.OBJECT_ID_LENGTH
) {
182 throw new ArrayIndexOutOfBoundsException(delta
);
187 // Locate a position that matches "\0.{20}[0-7]" such that
188 // the ptr will rest on the [0-7]. This must be the first
189 // byte of the mode. This search works because the path in
190 // the prior record must have a non-zero length and must not
191 // contain a null byte.
193 for (int n
;; ptr
= n
) {
195 final byte b
= raw
[n
];
196 if ('0' <= b
&& b
<= '7')
198 if (raw
[n
- Constants
.OBJECT_ID_LENGTH
] != 0)
207 private void parseEntry() {
227 } catch (ArrayIndexOutOfBoundsException e
) {
233 nextPtr
= ptr
+ Constants
.OBJECT_ID_LENGTH
;