diff options
Diffstat (limited to 'org.eclipse.jgit/src/org/eclipse/jgit/patch/CombinedFileHeader.java')
-rw-r--r-- | org.eclipse.jgit/src/org/eclipse/jgit/patch/CombinedFileHeader.java | 246 |
1 files changed, 246 insertions, 0 deletions
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/patch/CombinedFileHeader.java b/org.eclipse.jgit/src/org/eclipse/jgit/patch/CombinedFileHeader.java new file mode 100644 index 0000000000..e95c026ddc --- /dev/null +++ b/org.eclipse.jgit/src/org/eclipse/jgit/patch/CombinedFileHeader.java @@ -0,0 +1,246 @@ +/* + * Copyright (C) 2008, Google Inc. + * and other copyright owners as documented in the project's IP log. + * + * This program and the accompanying materials are made available + * under the terms of the Eclipse Distribution License v1.0 which + * accompanies this distribution, is reproduced below, and is + * available at http://www.eclipse.org/org/documents/edl-v10.php + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * + * - Neither the name of the Eclipse Foundation, Inc. nor the + * names of its contributors may be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package org.eclipse.jgit.patch; + +import static org.eclipse.jgit.lib.Constants.encodeASCII; +import static org.eclipse.jgit.util.RawParseUtils.match; +import static org.eclipse.jgit.util.RawParseUtils.nextLF; + +import java.nio.charset.Charset; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import org.eclipse.jgit.lib.AbbreviatedObjectId; +import org.eclipse.jgit.lib.FileMode; + +/** + * A file in the Git "diff --cc" or "diff --combined" format. + * <p> + * A combined diff shows an n-way comparison between two or more ancestors and + * the final revision. Its primary function is to perform code reviews on a + * merge which introduces changes not in any ancestor. + */ +public class CombinedFileHeader extends FileHeader { + private static final byte[] MODE = encodeASCII("mode "); + + private AbbreviatedObjectId[] oldIds; + + private FileMode[] oldModes; + + CombinedFileHeader(final byte[] b, final int offset) { + super(b, offset); + } + + @Override + @SuppressWarnings("unchecked") + public List<? extends CombinedHunkHeader> getHunks() { + return (List<CombinedHunkHeader>) super.getHunks(); + } + + /** @return number of ancestor revisions mentioned in this diff. */ + @Override + public int getParentCount() { + return oldIds.length; + } + + /** @return get the file mode of the first parent. */ + @Override + public FileMode getOldMode() { + return getOldMode(0); + } + + /** + * Get the file mode of the nth ancestor + * + * @param nthParent + * the ancestor to get the mode of + * @return the mode of the requested ancestor. + */ + public FileMode getOldMode(final int nthParent) { + return oldModes[nthParent]; + } + + /** @return get the object id of the first parent. */ + @Override + public AbbreviatedObjectId getOldId() { + return getOldId(0); + } + + /** + * Get the ObjectId of the nth ancestor + * + * @param nthParent + * the ancestor to get the object id of + * @return the id of the requested ancestor. + */ + public AbbreviatedObjectId getOldId(final int nthParent) { + return oldIds[nthParent]; + } + + @Override + public String getScriptText(final Charset ocs, final Charset ncs) { + final Charset[] cs = new Charset[getParentCount() + 1]; + Arrays.fill(cs, ocs); + cs[getParentCount()] = ncs; + return getScriptText(cs); + } + + /** + * Convert the patch script for this file into a string. + * + * @param charsetGuess + * optional array to suggest the character set to use when + * decoding each file's line. If supplied the array must have a + * length of <code>{@link #getParentCount()} + 1</code> + * representing the old revision character sets and the new + * revision character set. + * @return the patch script, as a Unicode string. + */ + @Override + public String getScriptText(final Charset[] charsetGuess) { + return super.getScriptText(charsetGuess); + } + + @Override + int parseGitHeaders(int ptr, final int end) { + while (ptr < end) { + final int eol = nextLF(buf, ptr); + if (isHunkHdr(buf, ptr, end) >= 1) { + // First hunk header; break out and parse them later. + break; + + } else if (match(buf, ptr, OLD_NAME) >= 0) { + parseOldName(ptr, eol); + + } else if (match(buf, ptr, NEW_NAME) >= 0) { + parseNewName(ptr, eol); + + } else if (match(buf, ptr, INDEX) >= 0) { + parseIndexLine(ptr + INDEX.length, eol); + + } else if (match(buf, ptr, MODE) >= 0) { + parseModeLine(ptr + MODE.length, eol); + + } else if (match(buf, ptr, NEW_FILE_MODE) >= 0) { + parseNewFileMode(ptr, eol); + + } else if (match(buf, ptr, DELETED_FILE_MODE) >= 0) { + parseDeletedFileMode(ptr + DELETED_FILE_MODE.length, eol); + + } else { + // Probably an empty patch (stat dirty). + break; + } + + ptr = eol; + } + return ptr; + } + + @Override + protected void parseIndexLine(int ptr, final int eol) { + // "index $asha1,$bsha1..$csha1" + // + final List<AbbreviatedObjectId> ids = new ArrayList<AbbreviatedObjectId>(); + while (ptr < eol) { + final int comma = nextLF(buf, ptr, ','); + if (eol <= comma) + break; + ids.add(AbbreviatedObjectId.fromString(buf, ptr, comma - 1)); + ptr = comma; + } + + oldIds = new AbbreviatedObjectId[ids.size() + 1]; + ids.toArray(oldIds); + final int dot2 = nextLF(buf, ptr, '.'); + oldIds[ids.size()] = AbbreviatedObjectId.fromString(buf, ptr, dot2 - 1); + newId = AbbreviatedObjectId.fromString(buf, dot2 + 1, eol - 1); + oldModes = new FileMode[oldIds.length]; + } + + @Override + protected void parseNewFileMode(final int ptr, final int eol) { + for (int i = 0; i < oldModes.length; i++) + oldModes[i] = FileMode.MISSING; + super.parseNewFileMode(ptr, eol); + } + + @Override + HunkHeader newHunkHeader(final int offset) { + return new CombinedHunkHeader(this, offset); + } + + private void parseModeLine(int ptr, final int eol) { + // "mode $amode,$bmode..$cmode" + // + int n = 0; + while (ptr < eol) { + final int comma = nextLF(buf, ptr, ','); + if (eol <= comma) + break; + oldModes[n++] = parseFileMode(ptr, comma); + ptr = comma; + } + final int dot2 = nextLF(buf, ptr, '.'); + oldModes[n] = parseFileMode(ptr, dot2); + newMode = parseFileMode(dot2 + 1, eol); + } + + private void parseDeletedFileMode(int ptr, final int eol) { + // "deleted file mode $amode,$bmode" + // + changeType = ChangeType.DELETE; + int n = 0; + while (ptr < eol) { + final int comma = nextLF(buf, ptr, ','); + if (eol <= comma) + break; + oldModes[n++] = parseFileMode(ptr, comma); + ptr = comma; + } + oldModes[n] = parseFileMode(ptr, eol); + newMode = FileMode.MISSING; + } +} |