/*
 * 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.

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.

/** * 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 "); //$NON-NLS-1$ private AbbreviatedObjectId[] oldIds; private FileMode[] oldModes; CombinedFileHeader(byte[] b, int offset) { super(b, offset); }
{@inheritDoc}
/** {@inheritDoc} */
@Override @SuppressWarnings("unchecked") public List<? extends CombinedHunkHeader> getHunks() { return (List<CombinedHunkHeader>) super.getHunks(); }
{@inheritDoc}

Returns:number of ancestor revisions mentioned in this diff.
/** * {@inheritDoc} * <p> * * @return number of ancestor revisions mentioned in this diff. */
@Override public int getParentCount() { return oldIds.length; }
{@inheritDoc}

Returns:get the file mode of the first parent.
/** * {@inheritDoc} * <p> * @return get the file mode of the first parent. */
@Override public FileMode getOldMode() { return getOldMode(0); }
Get the file mode of the nth ancestor
Params:
  • nthParent – the ancestor to get the mode of
Returns:the mode of the requested ancestor.
/** * 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(int nthParent) { return oldModes[nthParent]; }
{@inheritDoc}

Returns:get the object id of the first parent.
/** * {@inheritDoc} * <p> * * @return get the object id of the first parent. */
@Override public AbbreviatedObjectId getOldId() { return getOldId(0); }
Get the ObjectId of the nth ancestor
Params:
  • nthParent – the ancestor to get the object id of
Returns:the id of the requested ancestor.
/** * 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(int nthParent) { return oldIds[nthParent]; }
{@inheritDoc}
/** {@inheritDoc} */
@Override public String getScriptText(Charset ocs, Charset ncs) { final Charset[] cs = new Charset[getParentCount() + 1]; Arrays.fill(cs, ocs); cs[getParentCount()] = ncs; return getScriptText(cs); }
{@inheritDoc}

Convert the patch script for this file into a string.

/** * {@inheritDoc} * <p> * Convert the patch script for this file into a string. */
@Override public String getScriptText(Charset[] charsetGuess) { return super.getScriptText(charsetGuess); } @Override int parseGitHeaders(int ptr, 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; }
{@inheritDoc}
/** {@inheritDoc} */
@Override protected void parseIndexLine(int ptr, int eol) { // "index $asha1,$bsha1..$csha1" // final List<AbbreviatedObjectId> ids = new ArrayList<>(); 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]; }
{@inheritDoc}
/** {@inheritDoc} */
@Override protected void parseNewFileMode(int ptr, int eol) { for (int i = 0; i < oldModes.length; i++) oldModes[i] = FileMode.MISSING; super.parseNewFileMode(ptr, eol); } @Override HunkHeader newHunkHeader(int offset) { return new CombinedHunkHeader(this, offset); } private void parseModeLine(int ptr, 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, 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; } }