Package org.eclipse.jgit.patch

Source Code of org.eclipse.jgit.patch.HunkHeader$OldImage

/*
* Copyright (C) 2008-2009, 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.util.RawParseUtils.match;
import static org.eclipse.jgit.util.RawParseUtils.nextLF;
import static org.eclipse.jgit.util.RawParseUtils.parseBase10;

import java.io.IOException;
import java.io.OutputStream;
import java.text.MessageFormat;

import org.eclipse.jgit.JGitText;
import org.eclipse.jgit.diff.Edit;
import org.eclipse.jgit.diff.EditList;
import org.eclipse.jgit.lib.AbbreviatedObjectId;
import org.eclipse.jgit.util.MutableInteger;

/** Hunk header describing the layout of a single block of lines */
public class HunkHeader {
  /** Details about an old image of the file. */
  public abstract static class OldImage {
    /** First line number the hunk starts on in this file. */
    int startLine;

    /** Total number of lines this hunk covers in this file. */
    int lineCount;

    /** Number of lines deleted by the post-image from this file. */
    int nDeleted;

    /** Number of lines added by the post-image not in this file. */
    int nAdded;

    /** @return first line number the hunk starts on in this file. */
    public int getStartLine() {
      return startLine;
    }

    /** @return total number of lines this hunk covers in this file. */
    public int getLineCount() {
      return lineCount;
    }

    /** @return number of lines deleted by the post-image from this file. */
    public int getLinesDeleted() {
      return nDeleted;
    }

    /** @return number of lines added by the post-image not in this file. */
    public int getLinesAdded() {
      return nAdded;
    }

    /** @return object id of the pre-image file. */
    public abstract AbbreviatedObjectId getId();
  }

  final FileHeader file;

  /** Offset within {@link #file}.buf to the "@@ -" line. */
  final int startOffset;

  /** Position 1 past the end of this hunk within {@link #file}'s buf. */
  int endOffset;

  private final OldImage old;

  /** First line number in the post-image file where the hunk starts */
  int newStartLine;

  /** Total number of post-image lines this hunk covers (context + inserted) */
  int newLineCount;

  /** Total number of lines of context appearing in this hunk */
  int nContext;

  private EditList editList;

  HunkHeader(final FileHeader fh, final int offset) {
    this(fh, offset, new OldImage() {
      @Override
      public AbbreviatedObjectId getId() {
        return fh.getOldId();
      }
    });
  }

  HunkHeader(final FileHeader fh, final int offset, final OldImage oi) {
    file = fh;
    startOffset = offset;
    old = oi;
  }

  HunkHeader(final FileHeader fh, final EditList editList) {
    this(fh, fh.buf.length);
    this.editList = editList;
    endOffset = startOffset;
    nContext = 0;
    if (editList.isEmpty()) {
      newStartLine = 0;
      newLineCount = 0;
    } else {
      newStartLine = editList.get(0).getBeginB();
      Edit last = editList.get(editList.size() - 1);
      newLineCount = last.getEndB() - newStartLine;
    }
  }

  /** @return header for the file this hunk applies to */
  public FileHeader getFileHeader() {
    return file;
  }

  /** @return the byte array holding this hunk's patch script. */
  public byte[] getBuffer() {
    return file.buf;
  }

  /** @return offset the start of this hunk in {@link #getBuffer()}. */
  public int getStartOffset() {
    return startOffset;
  }

  /** @return offset one past the end of the hunk in {@link #getBuffer()}. */
  public int getEndOffset() {
    return endOffset;
  }

  /** @return information about the old image mentioned in this hunk. */
  public OldImage getOldImage() {
    return old;
  }

  /** @return first line number in the post-image file where the hunk starts */
  public int getNewStartLine() {
    return newStartLine;
  }

  /** @return Total number of post-image lines this hunk covers */
  public int getNewLineCount() {
    return newLineCount;
  }

  /** @return total number of lines of context appearing in this hunk */
  public int getLinesContext() {
    return nContext;
  }

  /** @return a list describing the content edits performed within the hunk. */
  public EditList toEditList() {
    if (editList == null) {
      editList = new EditList();
      final byte[] buf = file.buf;
      int c = nextLF(buf, startOffset);
      int oLine = old.startLine;
      int nLine = newStartLine;
      Edit in = null;

      SCAN: for (; c < endOffset; c = nextLF(buf, c)) {
        switch (buf[c]) {
        case ' ':
        case '\n':
          in = null;
          oLine++;
          nLine++;
          continue;

        case '-':
          if (in == null) {
            in = new Edit(oLine - 1, nLine - 1);
            editList.add(in);
          }
          oLine++;
          in.extendA();
          continue;

        case '+':
          if (in == null) {
            in = new Edit(oLine - 1, nLine - 1);
            editList.add(in);
          }
          nLine++;
          in.extendB();
          continue;

        case '\\': // Matches "\ No newline at end of file"
          continue;

        default:
          break SCAN;
        }
      }
    }
    return editList;
  }

  void parseHeader() {
    // Parse "@@ -236,9 +236,9 @@ protected boolean"
    //
    final byte[] buf = file.buf;
    final MutableInteger ptr = new MutableInteger();
    ptr.value = nextLF(buf, startOffset, ' ');
    old.startLine = -parseBase10(buf, ptr.value, ptr);
    if (buf[ptr.value] == ',')
      old.lineCount = parseBase10(buf, ptr.value + 1, ptr);
    else
      old.lineCount = 1;

    newStartLine = parseBase10(buf, ptr.value + 1, ptr);
    if (buf[ptr.value] == ',')
      newLineCount = parseBase10(buf, ptr.value + 1, ptr);
    else
      newLineCount = 1;
  }

  int parseBody(final Patch script, final int end) {
    final byte[] buf = file.buf;
    int c = nextLF(buf, startOffset), last = c;

    old.nDeleted = 0;
    old.nAdded = 0;

    SCAN: for (; c < end; last = c, c = nextLF(buf, c)) {
      switch (buf[c]) {
      case ' ':
      case '\n':
        nContext++;
        continue;

      case '-':
        old.nDeleted++;
        continue;

      case '+':
        old.nAdded++;
        continue;

      case '\\': // Matches "\ No newline at end of file"
        continue;

      default:
        break SCAN;
      }
    }

    if (last < end && nContext + old.nDeleted - 1 == old.lineCount
        && nContext + old.nAdded == newLineCount
        && match(buf, last, Patch.SIG_FOOTER) >= 0) {
      // This is an extremely common occurrence of "corruption".
      // Users add footers with their signatures after this mark,
      // and git diff adds the git executable version number.
      // Let it slide; the hunk otherwise looked sound.
      //
      old.nDeleted--;
      return last;
    }

    if (nContext + old.nDeleted < old.lineCount) {
      final int missingCount = old.lineCount - (nContext + old.nDeleted);
      script.error(buf, startOffset, MessageFormat.format(
          JGitText.get().truncatedHunkOldLinesMissing, missingCount));

    } else if (nContext + old.nAdded < newLineCount) {
      final int missingCount = newLineCount - (nContext + old.nAdded);
      script.error(buf, startOffset, MessageFormat.format(
          JGitText.get().truncatedHunkNewLinesMissing, missingCount));

    } else if (nContext + old.nDeleted > old.lineCount
        || nContext + old.nAdded > newLineCount) {
      final String oldcnt = old.lineCount + ":" + newLineCount;
      final String newcnt = (nContext + old.nDeleted) + ":"
          + (nContext + old.nAdded);
      script.warn(buf, startOffset, MessageFormat.format(
          JGitText.get().hunkHeaderDoesNotMatchBodyLineCountOf, oldcnt, newcnt));
    }

    return c;
  }

  void extractFileLines(final OutputStream[] out) throws IOException {
    final byte[] buf = file.buf;
    int ptr = startOffset;
    int eol = nextLF(buf, ptr);
    if (endOffset <= eol)
      return;

    // Treat the hunk header as though it were from the ancestor,
    // as it may have a function header appearing after it which
    // was copied out of the ancestor file.
    //
    out[0].write(buf, ptr, eol - ptr);

    SCAN: for (ptr = eol; ptr < endOffset; ptr = eol) {
      eol = nextLF(buf, ptr);
      switch (buf[ptr]) {
      case ' ':
      case '\n':
      case '\\':
        out[0].write(buf, ptr, eol - ptr);
        out[1].write(buf, ptr, eol - ptr);
        break;
      case '-':
        out[0].write(buf, ptr, eol - ptr);
        break;
      case '+':
        out[1].write(buf, ptr, eol - ptr);
        break;
      default:
        break SCAN;
      }
    }
  }

  void extractFileLines(final StringBuilder sb, final String[] text,
      final int[] offsets) {
    final byte[] buf = file.buf;
    int ptr = startOffset;
    int eol = nextLF(buf, ptr);
    if (endOffset <= eol)
      return;
    copyLine(sb, text, offsets, 0);
    SCAN: for (ptr = eol; ptr < endOffset; ptr = eol) {
      eol = nextLF(buf, ptr);
      switch (buf[ptr]) {
      case ' ':
      case '\n':
      case '\\':
        copyLine(sb, text, offsets, 0);
        skipLine(text, offsets, 1);
        break;
      case '-':
        copyLine(sb, text, offsets, 0);
        break;
      case '+':
        copyLine(sb, text, offsets, 1);
        break;
      default:
        break SCAN;
      }
    }
  }

  void copyLine(final StringBuilder sb, final String[] text,
      final int[] offsets, final int fileIdx) {
    final String s = text[fileIdx];
    final int start = offsets[fileIdx];
    int end = s.indexOf('\n', start);
    if (end < 0)
      end = s.length();
    else
      end++;
    sb.append(s, start, end);
    offsets[fileIdx] = end;
  }

  void skipLine(final String[] text, final int[] offsets,
      final int fileIdx) {
    final String s = text[fileIdx];
    final int end = s.indexOf('\n', offsets[fileIdx]);
    offsets[fileIdx] = end < 0 ? s.length() : end + 1;
  }

  @Override
  public String toString() {
    StringBuilder buf = new StringBuilder();
    buf.append("HunkHeader[");
    buf.append(getOldImage().getStartLine());
    buf.append(',');
    buf.append(getOldImage().getLineCount());
    buf.append("->");
    buf.append(getNewStartLine()).append(',').append(getNewLineCount());
    buf.append(']');
    return buf.toString();
  }
}
TOP

Related Classes of org.eclipse.jgit.patch.HunkHeader$OldImage

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.