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