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
.lib
.Constants
.encodeASCII
;
41 import static org
.spearce
.jgit
.util
.RawParseUtils
.match
;
42 import static org
.spearce
.jgit
.util
.RawParseUtils
.nextLF
;
44 import java
.nio
.charset
.Charset
;
45 import java
.util
.ArrayList
;
46 import java
.util
.Arrays
;
47 import java
.util
.List
;
49 import org
.spearce
.jgit
.lib
.AbbreviatedObjectId
;
50 import org
.spearce
.jgit
.lib
.FileMode
;
53 * A file in the Git "diff --cc" or "diff --combined" format.
55 * A combined diff shows an n-way comparison between two or more ancestors and
56 * the final revision. Its primary function is to perform code reviews on a
57 * merge which introduces changes not in any ancestor.
59 public class CombinedFileHeader
extends FileHeader
{
60 private static final byte[] MODE
= encodeASCII("mode ");
62 private AbbreviatedObjectId
[] oldIds
;
64 private FileMode
[] oldModes
;
66 CombinedFileHeader(final byte[] b
, final int offset
) {
71 @SuppressWarnings("unchecked")
72 public List
<?
extends CombinedHunkHeader
> getHunks() {
73 return (List
<CombinedHunkHeader
>) super.getHunks();
76 /** @return number of ancestor revisions mentioned in this diff. */
78 public int getParentCount() {
82 /** @return get the file mode of the first parent. */
84 public FileMode
getOldMode() {
89 * Get the file mode of the nth ancestor
92 * the ancestor to get the mode of
93 * @return the mode of the requested ancestor.
95 public FileMode
getOldMode(final int nthParent
) {
96 return oldModes
[nthParent
];
99 /** @return get the object id of the first parent. */
101 public AbbreviatedObjectId
getOldId() {
106 * Get the ObjectId of the nth ancestor
109 * the ancestor to get the object id of
110 * @return the id of the requested ancestor.
112 public AbbreviatedObjectId
getOldId(final int nthParent
) {
113 return oldIds
[nthParent
];
117 public String
getScriptText(final Charset ocs
, final Charset ncs
) {
118 final Charset
[] cs
= new Charset
[getParentCount() + 1];
119 Arrays
.fill(cs
, ocs
);
120 cs
[getParentCount()] = ncs
;
121 return getScriptText(cs
);
125 * Convert the patch script for this file into a string.
127 * @param charsetGuess
128 * optional array to suggest the character set to use when
129 * decoding each file's line. If supplied the array must have a
130 * length of <code>{@link #getParentCount()} + 1</code>
131 * representing the old revision character sets and the new
132 * revision character set.
133 * @return the patch script, as a Unicode string.
136 public String
getScriptText(final Charset
[] charsetGuess
) {
137 return super.getScriptText(charsetGuess
);
141 int parseGitHeaders(int ptr
, final int end
) {
143 final int eol
= nextLF(buf
, ptr
);
144 if (isHunkHdr(buf
, ptr
, end
) >= 1) {
145 // First hunk header; break out and parse them later.
148 } else if (match(buf
, ptr
, OLD_NAME
) >= 0) {
149 parseOldName(ptr
, eol
);
151 } else if (match(buf
, ptr
, NEW_NAME
) >= 0) {
152 parseNewName(ptr
, eol
);
154 } else if (match(buf
, ptr
, INDEX
) >= 0) {
155 parseIndexLine(ptr
+ INDEX
.length
, eol
);
157 } else if (match(buf
, ptr
, MODE
) >= 0) {
158 parseModeLine(ptr
+ MODE
.length
, eol
);
160 } else if (match(buf
, ptr
, NEW_FILE_MODE
) >= 0) {
161 parseNewFileMode(ptr
, eol
);
163 } else if (match(buf
, ptr
, DELETED_FILE_MODE
) >= 0) {
164 parseDeletedFileMode(ptr
+ DELETED_FILE_MODE
.length
, eol
);
167 // Probably an empty patch (stat dirty).
177 protected void parseIndexLine(int ptr
, final int eol
) {
178 // "index $asha1,$bsha1..$csha1"
180 final List
<AbbreviatedObjectId
> ids
= new ArrayList
<AbbreviatedObjectId
>();
182 final int comma
= nextLF(buf
, ptr
, ',');
185 ids
.add(AbbreviatedObjectId
.fromString(buf
, ptr
, comma
- 1));
189 oldIds
= new AbbreviatedObjectId
[ids
.size() + 1];
191 final int dot2
= nextLF(buf
, ptr
, '.');
192 oldIds
[ids
.size()] = AbbreviatedObjectId
.fromString(buf
, ptr
, dot2
- 1);
193 newId
= AbbreviatedObjectId
.fromString(buf
, dot2
+ 1, eol
- 1);
194 oldModes
= new FileMode
[oldIds
.length
];
198 protected void parseNewFileMode(final int ptr
, final int eol
) {
199 for (int i
= 0; i
< oldModes
.length
; i
++)
200 oldModes
[i
] = FileMode
.MISSING
;
201 super.parseNewFileMode(ptr
, eol
);
205 HunkHeader
newHunkHeader(final int offset
) {
206 return new CombinedHunkHeader(this, offset
);
209 private void parseModeLine(int ptr
, final int eol
) {
210 // "mode $amode,$bmode..$cmode"
214 final int comma
= nextLF(buf
, ptr
, ',');
217 oldModes
[n
++] = parseFileMode(ptr
, comma
);
220 final int dot2
= nextLF(buf
, ptr
, '.');
221 oldModes
[n
] = parseFileMode(ptr
, dot2
);
222 newMode
= parseFileMode(dot2
+ 1, eol
);
225 private void parseDeletedFileMode(int ptr
, final int eol
) {
226 // "deleted file mode $amode,$bmode"
228 changeType
= ChangeType
.DELETE
;
231 final int comma
= nextLF(buf
, ptr
, ',');
234 oldModes
[n
++] = parseFileMode(ptr
, comma
);
237 oldModes
[n
] = parseFileMode(ptr
, eol
);
238 newMode
= FileMode
.MISSING
;