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 (CombinedOldImage o : old) {
113 o.startLine = -parseBase10(buf, ptr.value, ptr);
114 if (buf[ptr.value] == ',') {
115 o.lineCount = parseBase10(buf, ptr.value + 1, ptr);
116 } else {
117 o.lineCount = 1;
118 }
119 }
120
121 newStartLine = parseBase10(buf, ptr.value + 1, ptr);
122 if (buf[ptr.value] == ',')
123 newLineCount = parseBase10(buf, ptr.value + 1, ptr);
124 else
125 newLineCount = 1;
126 }
127
128 @Override
129 int parseBody(Patch script, int end) {
130 final byte[] buf = file.buf;
131 int c = nextLF(buf, startOffset);
132
133 for (CombinedOldImage o : old) {
134 o.nDeleted = 0;
135 o.nAdded = 0;
136 o.nContext = 0;
137 }
138 nContext = 0;
139 int nAdded = 0;
140
141 SCAN: for (int eol; c < end; c = eol) {
142 eol = nextLF(buf, c);
143
144 if (eol - c < old.length + 1) {
145
146
147 break SCAN;
148 }
149
150 switch (buf[c]) {
151 case ' ':
152 case '-':
153 case '+':
154 break;
155
156 default:
157
158
159
160 break SCAN;
161 }
162
163 int localcontext = 0;
164 for (int ancestor = 0; ancestor < old.length; ancestor++) {
165 switch (buf[c + ancestor]) {
166 case ' ':
167 localcontext++;
168 old[ancestor].nContext++;
169 continue;
170
171 case '-':
172 old[ancestor].nDeleted++;
173 continue;
174
175 case '+':
176 old[ancestor].nAdded++;
177 nAdded++;
178 continue;
179
180 default:
181 break SCAN;
182 }
183 }
184 if (localcontext == old.length)
185 nContext++;
186 }
187
188 for (int ancestor = 0; ancestor < old.length; ancestor++) {
189 final CombinedOldImage o = old[ancestor];
190 final int cmp = o.nContext + o.nDeleted;
191 if (cmp < o.lineCount) {
192 final int missingCnt = o.lineCount - cmp;
193 script.error(buf, startOffset, MessageFormat.format(
194 JGitText.get().truncatedHunkLinesMissingForAncestor,
195 Integer.valueOf(missingCnt),
196 Integer.valueOf(ancestor + 1)));
197 }
198 }
199
200 if (nContext + nAdded < newLineCount) {
201 final int missingCount = newLineCount - (nContext + nAdded);
202 script.error(buf, startOffset, MessageFormat.format(
203 JGitText.get().truncatedHunkNewLinesMissing,
204 Integer.valueOf(missingCount)));
205 }
206
207 return c;
208 }
209
210 @Override
211 void extractFileLines(OutputStream[] out) throws IOException {
212 final byte[] buf = file.buf;
213 int ptr = startOffset;
214 int eol = nextLF(buf, ptr);
215 if (endOffset <= eol)
216 return;
217
218
219
220
221
222 out[0].write(buf, ptr, eol - ptr);
223
224 SCAN: for (ptr = eol; ptr < endOffset; ptr = eol) {
225 eol = nextLF(buf, ptr);
226
227 if (eol - ptr < old.length + 1) {
228
229
230 break SCAN;
231 }
232
233 switch (buf[ptr]) {
234 case ' ':
235 case '-':
236 case '+':
237 break;
238
239 default:
240
241
242
243 break SCAN;
244 }
245
246 int delcnt = 0;
247 for (int ancestor = 0; ancestor < old.length; ancestor++) {
248 switch (buf[ptr + ancestor]) {
249 case '-':
250 delcnt++;
251 out[ancestor].write(buf, ptr, eol - ptr);
252 continue;
253
254 case ' ':
255 out[ancestor].write(buf, ptr, eol - ptr);
256 continue;
257
258 case '+':
259 continue;
260
261 default:
262 break SCAN;
263 }
264 }
265 if (delcnt < old.length) {
266
267
268
269 out[old.length].write(buf, ptr, eol - ptr);
270 }
271 }
272 }
273
274 @Override
275 void extractFileLines(final StringBuilder sb, final String[] text,
276 final int[] offsets) {
277 final byte[] buf = file.buf;
278 int ptr = startOffset;
279 int eol = nextLF(buf, ptr);
280 if (endOffset <= eol)
281 return;
282 copyLine(sb, text, offsets, 0);
283 SCAN: for (ptr = eol; ptr < endOffset; ptr = eol) {
284 eol = nextLF(buf, ptr);
285
286 if (eol - ptr < old.length + 1) {
287
288
289 break SCAN;
290 }
291
292 switch (buf[ptr]) {
293 case ' ':
294 case '-':
295 case '+':
296 break;
297
298 default:
299
300
301
302 break SCAN;
303 }
304
305 boolean copied = false;
306 for (int ancestor = 0; ancestor < old.length; ancestor++) {
307 switch (buf[ptr + ancestor]) {
308 case ' ':
309 case '-':
310 if (copied)
311 skipLine(text, offsets, ancestor);
312 else {
313 copyLine(sb, text, offsets, ancestor);
314 copied = true;
315 }
316 continue;
317
318 case '+':
319 continue;
320
321 default:
322 break SCAN;
323 }
324 }
325 if (!copied) {
326
327
328
329
330 copyLine(sb, text, offsets, old.length);
331 }
332 }
333 }
334 }