View Javadoc
1   /*
2    * Copyright (C) 2008, Google Inc.
3    * and other copyright owners as documented in the project's IP log.
4    *
5    * This program and the accompanying materials are made available
6    * under the terms of the Eclipse Distribution License v1.0 which
7    * accompanies this distribution, is reproduced below, and is
8    * available at http://www.eclipse.org/org/documents/edl-v10.php
9    *
10   * All rights reserved.
11   *
12   * Redistribution and use in source and binary forms, with or
13   * without modification, are permitted provided that the following
14   * conditions are met:
15   *
16   * - Redistributions of source code must retain the above copyright
17   *   notice, this list of conditions and the following disclaimer.
18   *
19   * - Redistributions in binary form must reproduce the above
20   *   copyright notice, this list of conditions and the following
21   *   disclaimer in the documentation and/or other materials provided
22   *   with the distribution.
23   *
24   * - Neither the name of the Eclipse Foundation, Inc. nor the
25   *   names of its contributors may be used to endorse or promote
26   *   products derived from this software without specific prior
27   *   written permission.
28   *
29   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
30   * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
31   * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
32   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
33   * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
34   * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
35   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
36   * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
37   * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
38   * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
39   * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
40   * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
41   * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
42   */
43  
44  package org.eclipse.jgit.patch;
45  
46  import static org.eclipse.jgit.lib.Constants.encodeASCII;
47  import static org.eclipse.jgit.util.RawParseUtils.match;
48  import static org.eclipse.jgit.util.RawParseUtils.nextLF;
49  
50  import java.nio.charset.Charset;
51  import java.util.ArrayList;
52  import java.util.Arrays;
53  import java.util.List;
54  
55  import org.eclipse.jgit.lib.AbbreviatedObjectId;
56  import org.eclipse.jgit.lib.FileMode;
57  
58  /**
59   * A file in the Git "diff --cc" or "diff --combined" format.
60   * <p>
61   * A combined diff shows an n-way comparison between two or more ancestors and
62   * the final revision. Its primary function is to perform code reviews on a
63   * merge which introduces changes not in any ancestor.
64   */
65  public class CombinedFileHeader extends FileHeader {
66  	private static final byte[] MODE = encodeASCII("mode "); //$NON-NLS-1$
67  
68  	private AbbreviatedObjectId[] oldIds;
69  
70  	private FileMode[] oldModes;
71  
72  	CombinedFileHeader(byte[] b, int offset) {
73  		super(b, offset);
74  	}
75  
76  	/** {@inheritDoc} */
77  	@Override
78  	@SuppressWarnings("unchecked")
79  	public List<? extends CombinedHunkHeader> getHunks() {
80  		return (List<CombinedHunkHeader>) super.getHunks();
81  	}
82  
83  	/**
84  	 * {@inheritDoc}
85  	 * <p>
86  	 *
87  	 * @return number of ancestor revisions mentioned in this diff.
88  	 */
89  	@Override
90  	public int getParentCount() {
91  		return oldIds.length;
92  	}
93  
94  	/**
95  	 * {@inheritDoc}
96  	 * <p>
97  	 * @return get the file mode of the first parent.
98  	 */
99  	@Override
100 	public FileMode getOldMode() {
101 		return getOldMode(0);
102 	}
103 
104 	/**
105 	 * Get the file mode of the nth ancestor
106 	 *
107 	 * @param nthParent
108 	 *            the ancestor to get the mode of
109 	 * @return the mode of the requested ancestor.
110 	 */
111 	public FileMode getOldMode(int nthParent) {
112 		return oldModes[nthParent];
113 	}
114 
115 	/**
116 	 * {@inheritDoc}
117 	 * <p>
118 	 *
119 	 * @return get the object id of the first parent.
120 	 */
121 	@Override
122 	public AbbreviatedObjectId getOldId() {
123 		return getOldId(0);
124 	}
125 
126 	/**
127 	 * Get the ObjectId of the nth ancestor
128 	 *
129 	 * @param nthParent
130 	 *            the ancestor to get the object id of
131 	 * @return the id of the requested ancestor.
132 	 */
133 	public AbbreviatedObjectId getOldId(int nthParent) {
134 		return oldIds[nthParent];
135 	}
136 
137 	/** {@inheritDoc} */
138 	@Override
139 	public String getScriptText(Charset ocs, Charset ncs) {
140 		final Charset[] cs = new Charset[getParentCount() + 1];
141 		Arrays.fill(cs, ocs);
142 		cs[getParentCount()] = ncs;
143 		return getScriptText(cs);
144 	}
145 
146 	/**
147 	 * {@inheritDoc}
148 	 * <p>
149 	 * Convert the patch script for this file into a string.
150 	 */
151 	@Override
152 	public String getScriptText(Charset[] charsetGuess) {
153 		return super.getScriptText(charsetGuess);
154 	}
155 
156 	@Override
157 	int parseGitHeaders(int ptr, int end) {
158 		while (ptr < end) {
159 			final int eol = nextLF(buf, ptr);
160 			if (isHunkHdr(buf, ptr, end) >= 1) {
161 				// First hunk header; break out and parse them later.
162 				break;
163 
164 			} else if (match(buf, ptr, OLD_NAME) >= 0) {
165 				parseOldName(ptr, eol);
166 
167 			} else if (match(buf, ptr, NEW_NAME) >= 0) {
168 				parseNewName(ptr, eol);
169 
170 			} else if (match(buf, ptr, INDEX) >= 0) {
171 				parseIndexLine(ptr + INDEX.length, eol);
172 
173 			} else if (match(buf, ptr, MODE) >= 0) {
174 				parseModeLine(ptr + MODE.length, eol);
175 
176 			} else if (match(buf, ptr, NEW_FILE_MODE) >= 0) {
177 				parseNewFileMode(ptr, eol);
178 
179 			} else if (match(buf, ptr, DELETED_FILE_MODE) >= 0) {
180 				parseDeletedFileMode(ptr + DELETED_FILE_MODE.length, eol);
181 
182 			} else {
183 				// Probably an empty patch (stat dirty).
184 				break;
185 			}
186 
187 			ptr = eol;
188 		}
189 		return ptr;
190 	}
191 
192 	/** {@inheritDoc} */
193 	@Override
194 	protected void parseIndexLine(int ptr, int eol) {
195 		// "index $asha1,$bsha1..$csha1"
196 		//
197 		final List<AbbreviatedObjectId> ids = new ArrayList<>();
198 		while (ptr < eol) {
199 			final int comma = nextLF(buf, ptr, ',');
200 			if (eol <= comma)
201 				break;
202 			ids.add(AbbreviatedObjectId.fromString(buf, ptr, comma - 1));
203 			ptr = comma;
204 		}
205 
206 		oldIds = new AbbreviatedObjectId[ids.size() + 1];
207 		ids.toArray(oldIds);
208 		final int dot2 = nextLF(buf, ptr, '.');
209 		oldIds[ids.size()] = AbbreviatedObjectId.fromString(buf, ptr, dot2 - 1);
210 		newId = AbbreviatedObjectId.fromString(buf, dot2 + 1, eol - 1);
211 		oldModes = new FileMode[oldIds.length];
212 	}
213 
214 	/** {@inheritDoc} */
215 	@Override
216 	protected void parseNewFileMode(int ptr, int eol) {
217 		for (int i = 0; i < oldModes.length; i++)
218 			oldModes[i] = FileMode.MISSING;
219 		super.parseNewFileMode(ptr, eol);
220 	}
221 
222 	@Override
223 	HunkHeader newHunkHeader(int offset) {
224 		return new CombinedHunkHeader(this, offset);
225 	}
226 
227 	private void parseModeLine(int ptr, int eol) {
228 		// "mode $amode,$bmode..$cmode"
229 		//
230 		int n = 0;
231 		while (ptr < eol) {
232 			final int comma = nextLF(buf, ptr, ',');
233 			if (eol <= comma)
234 				break;
235 			oldModes[n++] = parseFileMode(ptr, comma);
236 			ptr = comma;
237 		}
238 		final int dot2 = nextLF(buf, ptr, '.');
239 		oldModes[n] = parseFileMode(ptr, dot2);
240 		newMode = parseFileMode(dot2 + 1, eol);
241 	}
242 
243 	private void parseDeletedFileMode(int ptr, int eol) {
244 		// "deleted file mode $amode,$bmode"
245 		//
246 		changeType = ChangeType.DELETE;
247 		int n = 0;
248 		while (ptr < eol) {
249 			final int comma = nextLF(buf, ptr, ',');
250 			if (eol <= comma)
251 				break;
252 			oldModes[n++] = parseFileMode(ptr, comma);
253 			ptr = comma;
254 		}
255 		oldModes[n] = parseFileMode(ptr, eol);
256 		newMode = FileMode.MISSING;
257 	}
258 }