Add raw buffer fetch methods to FileHeader, HunkHeader
[egit/qmx.git] / org.spearce.jgit / src / org / spearce / jgit / patch / HunkHeader.java
blob12c670d76dc271e17d87863ad4dd48ff111fffaf
1 /*
2 * Copyright (C) 2008, Google Inc.
4 * All rights reserved.
6 * Redistribution and use in source and binary forms, with or
7 * without modification, are permitted provided that the following
8 * conditions are met:
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
21 * written permission.
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. */
52 int startLine;
54 /** Total number of lines this hunk covers in this file. */
55 int lineCount;
57 /** Number of lines deleted by the post-image from this file. */
58 int nDeleted;
60 /** Number of lines added by the post-image not in this file. */
61 int nAdded;
63 /** @return first line number the hunk starts on in this file. */
64 public int getStartLine() {
65 return startLine;
68 /** @return total number of lines this hunk covers in this file. */
69 public int getLineCount() {
70 return lineCount;
73 /** @return number of lines deleted by the post-image from this file. */
74 public int getLinesDeleted() {
75 return nDeleted;
78 /** @return number of lines added by the post-image not in this file. */
79 public int getLinesAdded() {
80 return nAdded;
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. */
93 int endOffset;
95 private final OldImage old;
97 /** First line number in the post-image file where the hunk starts */
98 int newStartLine;
100 /** Total number of post-image lines this hunk covers (context + inserted) */
101 int newLineCount;
103 /** Total number of lines of context appearing in this hunk */
104 int nContext;
106 HunkHeader(final FileHeader fh, final int offset) {
107 this(fh, offset, new OldImage() {
108 @Override
109 public AbbreviatedObjectId getId() {
110 return fh.getOldId();
115 HunkHeader(final FileHeader fh, final int offset, final OldImage oi) {
116 file = fh;
117 startOffset = offset;
118 old = oi;
121 /** @return header for the file this hunk applies to */
122 public FileHeader getFileHeader() {
123 return file;
126 /** @return the byte array holding this hunk's patch script. */
127 public byte[] getBuffer() {
128 return file.buf;
131 /** @return offset the start of this hunk in {@link #getBuffer()}. */
132 public int getStartOffset() {
133 return startOffset;
136 /** @return offset one past the end of the hunk in {@link #getBuffer()}. */
137 public int getEndOffset() {
138 return endOffset;
141 /** @return information about the old image mentioned in this hunk. */
142 public OldImage getOldImage() {
143 return old;
146 /** @return first line number in the post-image file where the hunk starts */
147 public int getNewStartLine() {
148 return newStartLine;
151 /** @return Total number of post-image lines this hunk covers */
152 public int getNewLineCount() {
153 return newLineCount;
156 /** @return total number of lines of context appearing in this hunk */
157 public int getLinesContext() {
158 return nContext;
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);
170 else
171 old.lineCount = 1;
173 newStartLine = parseBase10(buf, ptr.value + 1, ptr);
174 if (buf[ptr.value] == ',')
175 newLineCount = parseBase10(buf, ptr.value + 1, ptr);
176 else
177 newLineCount = 1;
180 int parseBody(final Patch script, final int end) {
181 final byte[] buf = file.buf;
182 int c = nextLF(buf, startOffset), last = c;
184 old.nDeleted = 0;
185 old.nAdded = 0;
187 SCAN: for (; c < end; last = c, c = nextLF(buf, c)) {
188 switch (buf[c]) {
189 case ' ':
190 case '\n':
191 nContext++;
192 continue;
194 case '-':
195 old.nDeleted++;
196 continue;
198 case '+':
199 old.nAdded++;
200 continue;
202 case '\\': // Matches "\ No newline at end of file"
203 continue;
205 default:
206 break SCAN;
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.
218 old.nDeleted--;
219 return last;
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);
241 return c;