2 * Copyright (C) 2008, Google Inc.
6 * Redistribution and use in source and binary forms, with or
7 * without modification, are permitted provided that the following
10 * - Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
13 * - Redistributions in binary form must reproduce the above
14 * copyright notice, this list of conditions and the following
15 * disclaimer in the documentation and/or other materials provided
16 * with the distribution.
18 * - Neither the name of the Git Development Community nor the
19 * names of its contributors may be used to endorse or promote
20 * products derived from this software without specific prior
23 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
24 * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
25 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
26 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
28 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
29 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
30 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
31 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
32 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
33 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
34 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
35 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
38 package org
.spearce
.jgit
.patch
;
40 import static org
.spearce
.jgit
.util
.RawParseUtils
.match
;
41 import static org
.spearce
.jgit
.util
.RawParseUtils
.nextLF
;
42 import static org
.spearce
.jgit
.util
.RawParseUtils
.parseBase10
;
44 import org
.spearce
.jgit
.lib
.AbbreviatedObjectId
;
45 import org
.spearce
.jgit
.util
.MutableInteger
;
47 /** Hunk header describing the layout of a single block of lines */
48 public class HunkHeader
{
49 /** Details about an old image of the file. */
50 public abstract static class OldImage
{
51 /** First line number the hunk starts on in this file. */
54 /** Total number of lines this hunk covers in this file. */
57 /** Number of lines deleted by the post-image from this file. */
60 /** Number of lines added by the post-image not in this file. */
63 /** @return first line number the hunk starts on in this file. */
64 public int getStartLine() {
68 /** @return total number of lines this hunk covers in this file. */
69 public int getLineCount() {
73 /** @return number of lines deleted by the post-image from this file. */
74 public int getLinesDeleted() {
78 /** @return number of lines added by the post-image not in this file. */
79 public int getLinesAdded() {
83 /** @return object id of the pre-image file. */
84 public abstract AbbreviatedObjectId
getId();
87 final FileHeader file
;
89 /** Offset within {@link #file}.buf to the "@@ -" line. */
90 final int startOffset
;
92 /** Position 1 past the end of this hunk within {@link #file}'s buf. */
95 private final OldImage old
;
97 /** First line number in the post-image file where the hunk starts */
100 /** Total number of post-image lines this hunk covers (context + inserted) */
103 /** Total number of lines of context appearing in this hunk */
106 HunkHeader(final FileHeader fh
, final int offset
) {
107 this(fh
, offset
, new OldImage() {
109 public AbbreviatedObjectId
getId() {
110 return fh
.getOldId();
115 HunkHeader(final FileHeader fh
, final int offset
, final OldImage oi
) {
117 startOffset
= offset
;
121 /** @return header for the file this hunk applies to */
122 public FileHeader
getFileHeader() {
126 /** @return the byte array holding this hunk's patch script. */
127 public byte[] getBuffer() {
131 /** @return offset the start of this hunk in {@link #getBuffer()}. */
132 public int getStartOffset() {
136 /** @return offset one past the end of the hunk in {@link #getBuffer()}. */
137 public int getEndOffset() {
141 /** @return information about the old image mentioned in this hunk. */
142 public OldImage
getOldImage() {
146 /** @return first line number in the post-image file where the hunk starts */
147 public int getNewStartLine() {
151 /** @return Total number of post-image lines this hunk covers */
152 public int getNewLineCount() {
156 /** @return total number of lines of context appearing in this hunk */
157 public int getLinesContext() {
161 void parseHeader(final int end
) {
162 // Parse "@@ -236,9 +236,9 @@ protected boolean"
164 final byte[] buf
= file
.buf
;
165 final MutableInteger ptr
= new MutableInteger();
166 ptr
.value
= nextLF(buf
, startOffset
, ' ');
167 old
.startLine
= -parseBase10(buf
, ptr
.value
, ptr
);
168 if (buf
[ptr
.value
] == ',')
169 old
.lineCount
= parseBase10(buf
, ptr
.value
+ 1, ptr
);
173 newStartLine
= parseBase10(buf
, ptr
.value
+ 1, ptr
);
174 if (buf
[ptr
.value
] == ',')
175 newLineCount
= parseBase10(buf
, ptr
.value
+ 1, ptr
);
180 int parseBody(final Patch script
, final int end
) {
181 final byte[] buf
= file
.buf
;
182 int c
= nextLF(buf
, startOffset
), last
= c
;
187 SCAN
: for (; c
< end
; last
= c
, c
= nextLF(buf
, c
)) {
202 case '\\': // Matches "\ No newline at end of file"
210 if (last
< end
&& nContext
+ old
.nDeleted
- 1 == old
.lineCount
211 && nContext
+ old
.nAdded
== newLineCount
212 && match(buf
, last
, Patch
.SIG_FOOTER
) >= 0) {
213 // This is an extremely common occurrence of "corruption".
214 // Users add footers with their signatures after this mark,
215 // and git diff adds the git executable version number.
216 // Let it slide; the hunk otherwise looked sound.
222 if (nContext
+ old
.nDeleted
< old
.lineCount
) {
223 final int missingCount
= old
.lineCount
- (nContext
+ old
.nDeleted
);
224 script
.error(buf
, startOffset
, "Truncated hunk, at least "
225 + missingCount
+ " old lines is missing");
227 } else if (nContext
+ old
.nAdded
< newLineCount
) {
228 final int missingCount
= newLineCount
- (nContext
+ old
.nAdded
);
229 script
.error(buf
, startOffset
, "Truncated hunk, at least "
230 + missingCount
+ " new lines is missing");
232 } else if (nContext
+ old
.nDeleted
> old
.lineCount
233 || nContext
+ old
.nAdded
> newLineCount
) {
234 final String oldcnt
= old
.lineCount
+ ":" + newLineCount
;
235 final String newcnt
= (nContext
+ old
.nDeleted
) + ":"
236 + (nContext
+ old
.nAdded
);
237 script
.warn(buf
, startOffset
, "Hunk header " + oldcnt
238 + " does not match body line count of " + newcnt
);