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 package org.eclipse.jgit.lib;
45
46 import static org.eclipse.jgit.lib.Constants.OBJECT_ID_LENGTH;
47 import static org.eclipse.jgit.lib.Constants.OBJ_TREE;
48 import static org.eclipse.jgit.lib.Constants.encode;
49 import static org.eclipse.jgit.lib.FileMode.GITLINK;
50 import static org.eclipse.jgit.lib.FileMode.REGULAR_FILE;
51 import static org.eclipse.jgit.lib.FileMode.TREE;
52
53 import java.io.IOException;
54
55 import org.eclipse.jgit.errors.CorruptObjectException;
56 import org.eclipse.jgit.revwalk.RevBlob;
57 import org.eclipse.jgit.revwalk.RevCommit;
58 import org.eclipse.jgit.revwalk.RevTree;
59 import org.eclipse.jgit.treewalk.CanonicalTreeParser;
60 import org.eclipse.jgit.util.TemporaryBuffer;
61
62
63
64
65
66
67
68
69
70
71
72 public class TreeFormatter {
73
74
75
76
77
78
79
80
81
82
83
84
85
86 public static int entrySize(FileMode mode, int nameLen) {
87 return mode.copyToLength() + nameLen + OBJECT_ID_LENGTH + 2;
88 }
89
90 private byte[] buf;
91
92 private int ptr;
93
94 private TemporaryBuffer.Heap overflowBuffer;
95
96
97 public TreeFormatter() {
98 this(8192);
99 }
100
101
102
103
104
105
106
107
108
109 public TreeFormatter(int size) {
110 buf = new byte[size];
111 }
112
113
114
115
116
117
118
119
120
121 public void append(String name, RevCommit commit) {
122 append(name, GITLINK, commit);
123 }
124
125
126
127
128
129
130
131
132
133 public void append(String name, RevTree tree) {
134 append(name, TREE, tree);
135 }
136
137
138
139
140
141
142
143
144
145 public void append(String name, RevBlob blob) {
146 append(name, REGULAR_FILE, blob);
147 }
148
149
150
151
152
153
154
155
156
157
158
159 public void append(String name, FileMode mode, AnyObjectId id) {
160 append(encode(name), mode, id);
161 }
162
163
164
165
166
167
168
169
170
171
172
173
174 public void append(byte[] name, FileMode mode, AnyObjectId id) {
175 append(name, 0, name.length, mode, id);
176 }
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194 public void append(byte[] nameBuf, int namePos, int nameLen, FileMode mode,
195 AnyObjectId id) {
196 if (fmtBuf(nameBuf, namePos, nameLen, mode)) {
197 id.copyRawTo(buf, ptr);
198 ptr += OBJECT_ID_LENGTH;
199
200 } else {
201 try {
202 fmtOverflowBuffer(nameBuf, namePos, nameLen, mode);
203 id.copyRawTo(overflowBuffer);
204 } catch (IOException badBuffer) {
205
206 throw new RuntimeException(badBuffer);
207 }
208 }
209 }
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229 public void append(byte[] nameBuf, int namePos, int nameLen, FileMode mode,
230 byte[] idBuf, int idPos) {
231 if (fmtBuf(nameBuf, namePos, nameLen, mode)) {
232 System.arraycopy(idBuf, idPos, buf, ptr, OBJECT_ID_LENGTH);
233 ptr += OBJECT_ID_LENGTH;
234
235 } else {
236 try {
237 fmtOverflowBuffer(nameBuf, namePos, nameLen, mode);
238 overflowBuffer.write(idBuf, idPos, OBJECT_ID_LENGTH);
239 } catch (IOException badBuffer) {
240
241 throw new RuntimeException(badBuffer);
242 }
243 }
244 }
245
246 private boolean fmtBuf(byte[] nameBuf, int namePos, int nameLen,
247 FileMode mode) {
248 if (buf == null || buf.length < ptr + entrySize(mode, nameLen))
249 return false;
250
251 mode.copyTo(buf, ptr);
252 ptr += mode.copyToLength();
253 buf[ptr++] = ' ';
254
255 System.arraycopy(nameBuf, namePos, buf, ptr, nameLen);
256 ptr += nameLen;
257 buf[ptr++] = 0;
258 return true;
259 }
260
261 private void fmtOverflowBuffer(byte[] nameBuf, int namePos, int nameLen,
262 FileMode mode) throws IOException {
263 if (buf != null) {
264 overflowBuffer = new TemporaryBuffer.Heap(Integer.MAX_VALUE);
265 overflowBuffer.write(buf, 0, ptr);
266 buf = null;
267 }
268
269 mode.copyTo(overflowBuffer);
270 overflowBuffer.write((byte) ' ');
271 overflowBuffer.write(nameBuf, namePos, nameLen);
272 overflowBuffer.write((byte) 0);
273 }
274
275
276
277
278
279
280
281
282
283
284 public ObjectId insertTo(ObjectInserter ins) throws IOException {
285 if (buf != null)
286 return ins.insert(OBJ_TREE, buf, 0, ptr);
287
288 final long len = overflowBuffer.length();
289 return ins.insert(OBJ_TREE, len, overflowBuffer.openInputStream());
290 }
291
292
293
294
295
296
297
298 public ObjectId computeId(ObjectInserter ins) {
299 if (buf != null)
300 return ins.idFor(OBJ_TREE, buf, 0, ptr);
301
302 final long len = overflowBuffer.length();
303 try {
304 return ins.idFor(OBJ_TREE, len, overflowBuffer.openInputStream());
305 } catch (IOException e) {
306
307 throw new RuntimeException(e);
308 }
309 }
310
311
312
313
314
315
316
317
318
319
320
321 public byte[] toByteArray() {
322 if (buf != null) {
323 byte[] r = new byte[ptr];
324 System.arraycopy(buf, 0, r, 0, ptr);
325 return r;
326 }
327
328 try {
329 return overflowBuffer.toByteArray();
330 } catch (IOException err) {
331
332 throw new RuntimeException(err);
333 }
334 }
335
336 @SuppressWarnings("nls")
337 @Override
338 public String toString() {
339 byte[] raw = toByteArray();
340
341 CanonicalTreeParser p = new CanonicalTreeParser();
342 p.reset(raw);
343
344 StringBuilder r = new StringBuilder();
345 r.append("Tree={");
346 if (!p.eof()) {
347 r.append('\n');
348 try {
349 new ObjectChecker().checkTree(raw);
350 } catch (CorruptObjectException error) {
351 r.append("*** ERROR: ").append(error.getMessage()).append("\n");
352 r.append('\n');
353 }
354 }
355 while (!p.eof()) {
356 final FileMode mode = p.getEntryFileMode();
357 r.append(mode);
358 r.append(' ');
359 r.append(Constants.typeString(mode.getObjectType()));
360 r.append(' ');
361 r.append(p.getEntryObjectId().name());
362 r.append(' ');
363 r.append(p.getEntryPathString());
364 r.append('\n');
365 p.next();
366 }
367 r.append("}");
368 return r.toString();
369 }
370 }