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