1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45 package org.eclipse.jgit.dircache;
46
47 import java.io.IOException;
48 import java.io.InputStream;
49 import java.util.Collections;
50
51 import org.eclipse.jgit.attributes.AttributesNode;
52 import org.eclipse.jgit.attributes.AttributesRule;
53 import org.eclipse.jgit.errors.IncorrectObjectTypeException;
54 import org.eclipse.jgit.lib.Constants;
55 import org.eclipse.jgit.lib.FileMode;
56 import org.eclipse.jgit.lib.ObjectId;
57 import org.eclipse.jgit.lib.ObjectLoader;
58 import org.eclipse.jgit.lib.ObjectReader;
59 import org.eclipse.jgit.treewalk.AbstractTreeIterator;
60 import org.eclipse.jgit.treewalk.EmptyTreeIterator;
61 import org.eclipse.jgit.util.RawParseUtils;
62
63
64
65
66
67
68
69
70
71
72
73
74 public class DirCacheIterator extends AbstractTreeIterator {
75
76 private static final byte[] DOT_GIT_ATTRIBUTES_BYTES = Constants.DOT_GIT_ATTRIBUTES
77 .getBytes();
78
79
80 protected final DirCache cache;
81
82
83 private final DirCacheTree tree;
84
85
86 private final int treeStart;
87
88
89 private final int treeEnd;
90
91
92 private final byte[] subtreeId;
93
94
95 protected int ptr;
96
97
98 private int nextSubtreePos;
99
100
101 protected DirCacheEntry currentEntry;
102
103
104 protected DirCacheTree currentSubtree;
105
106
107
108
109
110
111
112
113
114
115
116 public DirCacheIterator(final DirCache dc) {
117 cache = dc;
118 tree = dc.getCacheTree(true);
119 treeStart = 0;
120 treeEnd = tree.getEntrySpan();
121 subtreeId = new byte[Constants.OBJECT_ID_LENGTH];
122 if (!eof())
123 parseEntry();
124 }
125
126 DirCacheIterator(final DirCacheIterator p, final DirCacheTree dct) {
127 super(p, p.path, p.pathLen + 1);
128 cache = p.cache;
129 tree = dct;
130 treeStart = p.ptr;
131 treeEnd = treeStart + tree.getEntrySpan();
132 subtreeId = p.subtreeId;
133 ptr = p.ptr;
134 parseEntry();
135 }
136
137 @Override
138 public AbstractTreeIterator createSubtreeIterator(final ObjectReader reader)
139 throws IncorrectObjectTypeException, IOException {
140 if (currentSubtree == null)
141 throw new IncorrectObjectTypeException(getEntryObjectId(),
142 Constants.TYPE_TREE);
143 return new DirCacheIterator(this, currentSubtree);
144 }
145
146 @Override
147 public EmptyTreeIterator createEmptyTreeIterator() {
148 final byte[] n = new byte[Math.max(pathLen + 1, DEFAULT_PATH_SIZE)];
149 System.arraycopy(path, 0, n, 0, pathLen);
150 n[pathLen] = '/';
151 return new EmptyTreeIterator(this, n, pathLen + 1);
152 }
153
154 @Override
155 public boolean hasId() {
156 if (currentSubtree != null)
157 return currentSubtree.isValid();
158 return currentEntry != null;
159 }
160
161 @Override
162 public byte[] idBuffer() {
163 if (currentSubtree != null)
164 return currentSubtree.isValid() ? subtreeId : zeroid;
165 if (currentEntry != null)
166 return currentEntry.idBuffer();
167 return zeroid;
168 }
169
170 @Override
171 public int idOffset() {
172 if (currentSubtree != null)
173 return 0;
174 if (currentEntry != null)
175 return currentEntry.idOffset();
176 return 0;
177 }
178
179 @Override
180 public void reset() {
181 if (!first()) {
182 ptr = treeStart;
183 nextSubtreePos = 0;
184 currentEntry = null;
185 currentSubtree = null;
186 if (!eof())
187 parseEntry();
188 }
189 }
190
191 @Override
192 public boolean first() {
193 return ptr == treeStart;
194 }
195
196 @Override
197 public boolean eof() {
198 return ptr == treeEnd;
199 }
200
201 @Override
202 public void next(int delta) {
203 while (--delta >= 0) {
204 if (currentSubtree != null)
205 ptr += currentSubtree.getEntrySpan();
206 else
207 ptr++;
208 if (eof())
209 break;
210 parseEntry();
211 }
212 }
213
214 @Override
215 public void back(int delta) {
216 while (--delta >= 0) {
217 if (currentSubtree != null)
218 nextSubtreePos--;
219 ptr--;
220 parseEntry(false);
221 if (currentSubtree != null)
222 ptr -= currentSubtree.getEntrySpan() - 1;
223 }
224 }
225
226 private void parseEntry() {
227 parseEntry(true);
228 }
229
230 private void parseEntry(boolean forward) {
231 currentEntry = cache.getEntry(ptr);
232 final byte[] cep = currentEntry.path;
233
234 if (!forward) {
235 if (nextSubtreePos > 0) {
236 final DirCacheTree p = tree.getChild(nextSubtreePos - 1);
237 if (p.contains(cep, pathOffset, cep.length)) {
238 nextSubtreePos--;
239 currentSubtree = p;
240 }
241 }
242 }
243 if (nextSubtreePos != tree.getChildCount()) {
244 final DirCacheTree s = tree.getChild(nextSubtreePos);
245 if (s.contains(cep, pathOffset, cep.length)) {
246
247
248
249 currentSubtree = s;
250 nextSubtreePos++;
251
252 if (s.isValid())
253 s.getObjectId().copyRawTo(subtreeId, 0);
254 mode = FileMode.TREE.getBits();
255 path = cep;
256 pathLen = pathOffset + s.nameLength();
257 return;
258 }
259 }
260
261
262
263
264 mode = currentEntry.getRawMode();
265 path = cep;
266 pathLen = cep.length;
267 currentSubtree = null;
268
269 if (RawParseUtils.match(path, pathOffset, DOT_GIT_ATTRIBUTES_BYTES) == path.length)
270 attributesNode = new LazyLoadingAttributesNode(
271 currentEntry.getObjectId());
272 }
273
274
275
276
277
278
279
280 public DirCacheEntry getDirCacheEntry() {
281 return currentSubtree == null ? currentEntry : null;
282 }
283
284
285
286
287
288
289
290
291
292
293 public AttributesNode getEntryAttributesNode(ObjectReader reader)
294 throws IOException {
295 if (attributesNode instanceof LazyLoadingAttributesNode)
296 attributesNode = ((LazyLoadingAttributesNode) attributesNode)
297 .load(reader);
298 return attributesNode;
299 }
300
301
302
303
304
305 private static class LazyLoadingAttributesNode extends AttributesNode {
306 final ObjectId objectId;
307
308 LazyLoadingAttributesNode(ObjectId objectId) {
309 super(Collections.<AttributesRule> emptyList());
310 this.objectId = objectId;
311
312 }
313
314 AttributesNode load(ObjectReader reader) throws IOException {
315 AttributesNode r = new AttributesNode();
316 ObjectLoader loader = reader.open(objectId);
317 if (loader != null) {
318 InputStream in = loader.openStream();
319 try {
320 r.parse(in);
321 } finally {
322 in.close();
323 }
324 }
325 return r.getRules().isEmpty() ? null : r;
326 }
327 }
328
329 }