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.patch;
45
46 import static org.eclipse.jgit.util.RawParseUtils.nextLF;
47 import static org.eclipse.jgit.util.RawParseUtils.parseBase10;
48
49 import java.io.IOException;
50 import java.io.OutputStream;
51 import java.text.MessageFormat;
52
53 import org.eclipse.jgit.internal.JGitText;
54 import org.eclipse.jgit.lib.AbbreviatedObjectId;
55 import org.eclipse.jgit.util.MutableInteger;
56
57
58
59
60 public class CombinedHunkHeader extends HunkHeader {
61 private static abstract class CombinedOldImage extends OldImage {
62 int nContext;
63 }
64
65 private CombinedOldImage[] old;
66
67 CombinedHunkHeader(CombinedFileHeader fh, int offset) {
68 super(fh, offset, null);
69 old = new CombinedOldImage[fh.getParentCount()];
70 for (int i = 0; i < old.length; i++) {
71 final int imagePos = i;
72 old[i] = new CombinedOldImage() {
73 @Override
74 public AbbreviatedObjectId getId() {
75 return fh.getOldId(imagePos);
76 }
77 };
78 }
79 }
80
81
82 @Override
83 public CombinedFileHeader getFileHeader() {
84 return (CombinedFileHeader) super.getFileHeader();
85 }
86
87
88 @Override
89 public OldImage getOldImage() {
90 return getOldImage(0);
91 }
92
93
94
95
96
97
98
99
100 public OldImage getOldImage(int nthParent) {
101 return old[nthParent];
102 }
103
104 @Override
105 void parseHeader() {
106
107
108 final byte[] buf = file.buf;
109 final MutableIntegerger.html#MutableInteger">MutableInteger ptr = new MutableInteger();
110 ptr.value = nextLF(buf, startOffset, ' ');
111
112 for (int n = 0; n < old.length; n++) {
113 old[n].startLine = -parseBase10(buf, ptr.value, ptr);
114 if (buf[ptr.value] == ',')
115 old[n].lineCount = parseBase10(buf, ptr.value + 1, ptr);
116 else
117 old[n].lineCount = 1;
118 }
119
120 newStartLine = parseBase10(buf, ptr.value + 1, ptr);
121 if (buf[ptr.value] == ',')
122 newLineCount = parseBase10(buf, ptr.value + 1, ptr);
123 else
124 newLineCount = 1;
125 }
126
127 @Override
128 int parseBody(Patch script, int end) {
129 final byte[] buf = file.buf;
130 int c = nextLF(buf, startOffset);
131
132 for (CombinedOldImage o : old) {
133 o.nDeleted = 0;
134 o.nAdded = 0;
135 o.nContext = 0;
136 }
137 nContext = 0;
138 int nAdded = 0;
139
140 SCAN: for (int eol; c < end; c = eol) {
141 eol = nextLF(buf, c);
142
143 if (eol - c < old.length + 1) {
144
145
146 break SCAN;
147 }
148
149 switch (buf[c]) {
150 case ' ':
151 case '-':
152 case '+':
153 break;
154
155 default:
156
157
158
159 break SCAN;
160 }
161
162 int localcontext = 0;
163 for (int ancestor = 0; ancestor < old.length; ancestor++) {
164 switch (buf[c + ancestor]) {
165 case ' ':
166 localcontext++;
167 old[ancestor].nContext++;
168 continue;
169
170 case '-':
171 old[ancestor].nDeleted++;
172 continue;
173
174 case '+':
175 old[ancestor].nAdded++;
176 nAdded++;
177 continue;
178
179 default:
180 break SCAN;
181 }
182 }
183 if (localcontext == old.length)
184 nContext++;
185 }
186
187 for (int ancestor = 0; ancestor < old.length; ancestor++) {
188 final CombinedOldImage o = old[ancestor];
189 final int cmp = o.nContext + o.nDeleted;
190 if (cmp < o.lineCount) {
191 final int missingCnt = o.lineCount - cmp;
192 script.error(buf, startOffset, MessageFormat.format(
193 JGitText.get().truncatedHunkLinesMissingForAncestor,
194 Integer.valueOf(missingCnt),
195 Integer.valueOf(ancestor + 1)));
196 }
197 }
198
199 if (nContext + nAdded < newLineCount) {
200 final int missingCount = newLineCount - (nContext + nAdded);
201 script.error(buf, startOffset, MessageFormat.format(
202 JGitText.get().truncatedHunkNewLinesMissing,
203 Integer.valueOf(missingCount)));
204 }
205
206 return c;
207 }
208
209 @Override
210 void extractFileLines(OutputStream[] out) throws IOException {
211 final byte[] buf = file.buf;
212 int ptr = startOffset;
213 int eol = nextLF(buf, ptr);
214 if (endOffset <= eol)
215 return;
216
217
218
219
220
221 out[0].write(buf, ptr, eol - ptr);
222
223 SCAN: for (ptr = eol; ptr < endOffset; ptr = eol) {
224 eol = nextLF(buf, ptr);
225
226 if (eol - ptr < old.length + 1) {
227
228
229 break SCAN;
230 }
231
232 switch (buf[ptr]) {
233 case ' ':
234 case '-':
235 case '+':
236 break;
237
238 default:
239
240
241
242 break SCAN;
243 }
244
245 int delcnt = 0;
246 for (int ancestor = 0; ancestor < old.length; ancestor++) {
247 switch (buf[ptr + ancestor]) {
248 case '-':
249 delcnt++;
250 out[ancestor].write(buf, ptr, eol - ptr);
251 continue;
252
253 case ' ':
254 out[ancestor].write(buf, ptr, eol - ptr);
255 continue;
256
257 case '+':
258 continue;
259
260 default:
261 break SCAN;
262 }
263 }
264 if (delcnt < old.length) {
265
266
267
268 out[old.length].write(buf, ptr, eol - ptr);
269 }
270 }
271 }
272
273 @Override
274 void extractFileLines(final StringBuilder sb, final String[] text,
275 final int[] offsets) {
276 final byte[] buf = file.buf;
277 int ptr = startOffset;
278 int eol = nextLF(buf, ptr);
279 if (endOffset <= eol)
280 return;
281 copyLine(sb, text, offsets, 0);
282 SCAN: for (ptr = eol; ptr < endOffset; ptr = eol) {
283 eol = nextLF(buf, ptr);
284
285 if (eol - ptr < old.length + 1) {
286
287
288 break SCAN;
289 }
290
291 switch (buf[ptr]) {
292 case ' ':
293 case '-':
294 case '+':
295 break;
296
297 default:
298
299
300
301 break SCAN;
302 }
303
304 boolean copied = false;
305 for (int ancestor = 0; ancestor < old.length; ancestor++) {
306 switch (buf[ptr + ancestor]) {
307 case ' ':
308 case '-':
309 if (copied)
310 skipLine(text, offsets, ancestor);
311 else {
312 copyLine(sb, text, offsets, ancestor);
313 copied = true;
314 }
315 continue;
316
317 case '+':
318 continue;
319
320 default:
321 break SCAN;
322 }
323 }
324 if (!copied) {
325
326
327
328
329 copyLine(sb, text, offsets, old.length);
330 }
331 }
332 }
333 }