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
75 public class DirCacheIterator extends AbstractTreeIterator {
76
77 private static final byte[] DOT_GIT_ATTRIBUTES_BYTES = Constants.DOT_GIT_ATTRIBUTES
78 .getBytes();
79
80
81 protected final DirCache cache;
82
83
84 private final DirCacheTree tree;
85
86
87 private final int treeStart;
88
89
90 private final int treeEnd;
91
92
93 private final byte[] subtreeId;
94
95
96 protected int ptr;
97
98
99 private int nextSubtreePos;
100
101
102 protected DirCacheEntry currentEntry;
103
104
105 protected DirCacheTree currentSubtree;
106
107
108
109
110
111
112
113
114
115
116
117 public DirCacheIterator(DirCache dc) {
118 cache = dc;
119 tree = dc.getCacheTree(true);
120 treeStart = 0;
121 treeEnd = tree.getEntrySpan();
122 subtreeId = new byte[Constants.OBJECT_ID_LENGTH];
123 if (!eof())
124 parseEntry();
125 }
126
127 DirCacheIterator(DirCacheIterator p, DirCacheTree dct) {
128 super(p, p.path, p.pathLen + 1);
129 cache = p.cache;
130 tree = dct;
131 treeStart = p.ptr;
132 treeEnd = treeStart + tree.getEntrySpan();
133 subtreeId = p.subtreeId;
134 ptr = p.ptr;
135 parseEntry();
136 }
137
138
139 @Override
140 public AbstractTreeIterator createSubtreeIterator(ObjectReader reader)
141 throws IncorrectObjectTypeException, IOException {
142 if (currentSubtree == null)
143 throw new IncorrectObjectTypeException(getEntryObjectId(),
144 Constants.TYPE_TREE);
145 return new DirCacheIterator(this, currentSubtree);
146 }
147
148
149 @Override
150 public EmptyTreeIterator createEmptyTreeIterator() {
151 final byte[] n = new byte[Math.max(pathLen + 1, DEFAULT_PATH_SIZE)];
152 System.arraycopy(path, 0, n, 0, pathLen);
153 n[pathLen] = '/';
154 return new EmptyTreeIterator(this, n, pathLen + 1);
155 }
156
157
158 @Override
159 public boolean hasId() {
160 if (currentSubtree != null)
161 return currentSubtree.isValid();
162 return currentEntry != null;
163 }
164
165
166 @Override
167 public byte[] idBuffer() {
168 if (currentSubtree != null)
169 return currentSubtree.isValid() ? subtreeId : zeroid;
170 if (currentEntry != null)
171 return currentEntry.idBuffer();
172 return zeroid;
173 }
174
175
176 @Override
177 public int idOffset() {
178 if (currentSubtree != null)
179 return 0;
180 if (currentEntry != null)
181 return currentEntry.idOffset();
182 return 0;
183 }
184
185
186 @Override
187 public void reset() {
188 if (!first()) {
189 ptr = treeStart;
190 nextSubtreePos = 0;
191 currentEntry = null;
192 currentSubtree = null;
193 if (!eof())
194 parseEntry();
195 }
196 }
197
198
199 @Override
200 public boolean first() {
201 return ptr == treeStart;
202 }
203
204
205 @Override
206 public boolean eof() {
207 return ptr == treeEnd;
208 }
209
210
211 @Override
212 public void next(int delta) {
213 while (--delta >= 0) {
214 if (currentSubtree != null)
215 ptr += currentSubtree.getEntrySpan();
216 else
217 ptr++;
218 if (eof())
219 break;
220 parseEntry();
221 }
222 }
223
224
225 @Override
226 public void back(int delta) {
227 while (--delta >= 0) {
228 if (currentSubtree != null)
229 nextSubtreePos--;
230 ptr--;
231 parseEntry(false);
232 if (currentSubtree != null)
233 ptr -= currentSubtree.getEntrySpan() - 1;
234 }
235 }
236
237 private void parseEntry() {
238 parseEntry(true);
239 }
240
241 private void parseEntry(boolean forward) {
242 currentEntry = cache.getEntry(ptr);
243 final byte[] cep = currentEntry.path;
244
245 if (!forward) {
246 if (nextSubtreePos > 0) {
247 final DirCacheTree p = tree.getChild(nextSubtreePos - 1);
248 if (p.contains(cep, pathOffset, cep.length)) {
249 nextSubtreePos--;
250 currentSubtree = p;
251 }
252 }
253 }
254 if (nextSubtreePos != tree.getChildCount()) {
255 final DirCacheTree s = tree.getChild(nextSubtreePos);
256 if (s.contains(cep, pathOffset, cep.length)) {
257
258
259
260 currentSubtree = s;
261 nextSubtreePos++;
262
263 if (s.isValid())
264 s.getObjectId().copyRawTo(subtreeId, 0);
265 mode = FileMode.TREE.getBits();
266 path = cep;
267 pathLen = pathOffset + s.nameLength();
268 return;
269 }
270 }
271
272
273
274
275 mode = currentEntry.getRawMode();
276 path = cep;
277 pathLen = cep.length;
278 currentSubtree = null;
279
280 if (RawParseUtils.match(path, pathOffset, DOT_GIT_ATTRIBUTES_BYTES) == path.length)
281 attributesNode = new LazyLoadingAttributesNode(
282 currentEntry.getObjectId());
283 }
284
285
286
287
288
289
290
291 public DirCacheEntry getDirCacheEntry() {
292 return currentSubtree == null ? currentEntry : null;
293 }
294
295
296
297
298
299
300
301
302
303
304
305
306
307 public AttributesNode getEntryAttributesNode(ObjectReader reader)
308 throws IOException {
309 if (attributesNode instanceof LazyLoadingAttributesNode)
310 attributesNode = ((LazyLoadingAttributesNode) attributesNode)
311 .load(reader);
312 return attributesNode;
313 }
314
315
316
317
318
319 private static class LazyLoadingAttributesNode extends AttributesNode {
320 final ObjectId objectId;
321
322 LazyLoadingAttributesNode(ObjectId objectId) {
323 super(Collections.<AttributesRule> emptyList());
324 this.objectId = objectId;
325
326 }
327
328 AttributesNode load(ObjectReader reader) throws IOException {
329 AttributesNode r = new AttributesNode();
330 ObjectLoader loader = reader.open(objectId);
331 if (loader != null) {
332 try (InputStream in = loader.openStream()) {
333 r.parse(in);
334 }
335 }
336 return r.getRules().isEmpty() ? null : r;
337 }
338 }
339
340 }