package org.tmatesoft.svn.core.internal.wc2.patch; import org.tmatesoft.svn.core.ISVNCanceller; import org.tmatesoft.svn.core.SVNException; import org.tmatesoft.svn.core.internal.util.SVNFormatUtil; import org.tmatesoft.svn.core.internal.wc.admin.SVNTranslator; import org.tmatesoft.svn.core.internal.wc17.SVNWCContext; import java.io.File; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; public class SvnTargetContent { boolean existed; int currentLine; private SVNWCContext.SVNEolStyle eolStyle; private String eolStr; private List<Long> lines; private List<SvnHunkInfo> hunkInfos; private boolean eof; private Map<String, byte[]> keywords; private Object readBaton; private Object writeBaton; private ISeekCallback seekCallback; private ITellCallback tellCallback; private IRealLineCallback readLineCallback; private IWriteCallback writeCallback; public SvnTargetContent() { this.hunkInfos = new ArrayList<SvnHunkInfo>(); this.lines = new ArrayList<Long>(); this.keywords = new HashMap<String, byte[]>(); this.eolStyle = SVNWCContext.SVNEolStyle.Unknown; } public String readLine() throws SVNException { int maxLine = getLines().size() + 1; if (isEof() || getReadLineCallback() == null) { return ""; } assert getCurrentLine() <= maxLine; if (getCurrentLine() == maxLine) { long offset = getTellCallback().tell(getReadBaton()); getLines().add(offset); } String[] eolStr = {null}; boolean[] eof = {false}; String line = getReadLineCallback().readLine(getReadBaton(), eolStr, eof); setEof(eof[0]); if (getEolStyle() == SVNWCContext.SVNEolStyle.None) { setEolStr(eolStr[0]); } if (line != null) { line = SVNTranslator.translateString(line, null, getKeywords(), false, false); } else { line = ""; } if ((line != null && line.length() > 0) || eolStr != null) { setCurrentLine(getCurrentLine() + 1); } assert getCurrentLine() > 0; return line; } protected void seekToLine(int line) throws SVNException { assert line > 0; if (line == getCurrentLine()) { return; } int savedLine = getCurrentLine(); boolean savedEof = isEof(); if (line <= getLines().size()) { long offset = (long) getLines().get(line - 1); getSeekCallback().seek(getReadBaton(), offset); setCurrentLine(line); } else { while (!isEof() && getCurrentLine() < line) { readLine(); } } if (savedEof && savedLine > getCurrentLine()) { setEof(false); } } protected int scanForMatch(SvnDiffHunk hunk, boolean matchFirst, int upperLine, int fuzz, boolean ignoreWhitespace, boolean matchModified, ISVNCanceller canceller) throws SVNException { int matchedLine = 0; while ((getCurrentLine() < upperLine || upperLine == 0) && !isEof()) { if (canceller != null) { canceller.checkCancelled(); } boolean matched = matchHunk(hunk, fuzz, ignoreWhitespace, matchModified); if (matched) { boolean taken = false; int length; List<SvnHunkInfo> hunks = getHunkInfos(); for (SvnHunkInfo hunkInfo : hunks) { if (matchModified) { length = hunkInfo.getHunk().getDirectedModifiedLength(); } else { length = hunkInfo.getHunk().getDirectedOriginalLength(); } taken = (!hunkInfo.isRejected() && getCurrentLine() >= hunkInfo.getMatchedLine() && getCurrentLine() < (hunkInfo.getMatchedLine() + length)); if (taken) { break; } } if (!taken) { matchedLine = getCurrentLine(); if (matchFirst) { break; } } } if (!isEof()) { seekToLine(getCurrentLine() + 1); } } return matchedLine; } private boolean matchHunk(SvnDiffHunk hunk, int fuzz, boolean ignoreWhitespace, boolean matchModified) throws SVNException { boolean matched = false; if (isEof()) { return matched; } int savedLine = getCurrentLine(); int linesRead = 0; boolean linesMatched = false; int leadingContext = hunk.getLeadingContext(); int trailingContext = hunk.getTrailingContext(); int hunkLength; if (matchModified) { hunk.resetModifiedText(); hunkLength = hunk.getDirectedModifiedLength(); } else { hunk.resetOriginalText(); hunkLength = hunk.getDirectedOriginalLength(); } boolean[] hunkEof; String hunkLine; do { String hunkLineTranslated; hunkEof = new boolean[1]; if (matchModified) { hunkLine = hunk.readLineModifiedText(null, hunkEof); } else { hunkLine = hunk.readLineOriginalText(null, hunkEof); } hunkLineTranslated = SVNTranslator.translateString(hunkLine, null, getKeywords(), false, false); String targetLine = readLine(); linesRead++; if ((hunkEof[0] && hunkLine.length() == 0) || (isEof() && targetLine.length() == 0)) { break; } if ((linesRead <= fuzz && leadingContext > fuzz) || linesRead > hunkLength - fuzz && trailingContext > fuzz) { linesMatched = true; } else { if (ignoreWhitespace) { String hunkLineTrimmed = hunkLineTranslated; String targetLineTrimmed = targetLine; hunkLineTrimmed = SVNFormatUtil.collapseSpaces(hunkLineTrimmed); targetLineTrimmed = SVNFormatUtil.collapseSpaces(targetLineTrimmed); linesMatched = hunkLineTrimmed.equals(targetLineTrimmed); } else { linesMatched = hunkLineTranslated.equals(targetLine); } } } while (linesMatched); boolean ret = linesMatched && hunkEof[0] && hunkLine.length() == 0; seekToLine(savedLine); return ret; } protected boolean matchExistingTarget(SvnDiffHunk hunk) throws SVNException { hunk.resetModifiedText(); boolean[] hunkEof = {false}; boolean linesMatched; int savedLine = getCurrentLine(); do { String line = readLine(); String hunkLine = hunk.readLineModifiedText(null, hunkEof); String lineTranslated = SVNTranslator.translateString(line, null, getKeywords(), false, false); String hunkLineTranslated = SVNTranslator.translateString(hunkLine, null, getKeywords(), false, false); linesMatched = lineTranslated.equals(hunkLineTranslated); if (isEof() != hunkEof[0]) { return false; } } while (linesMatched && !isEof() && !hunkEof[0]); boolean result = linesMatched && isEof() == hunkEof[0]; seekToLine(savedLine); return result; } public boolean isExisted() { return existed; } public int getCurrentLine() { return currentLine; } public SVNWCContext.SVNEolStyle getEolStyle() { return eolStyle; } public String getEolStr() { return eolStr; } public List<Long> getLines() { return lines; } public List<SvnHunkInfo> getHunkInfos() { return hunkInfos; } public boolean isEof() { return eof; } public Map<String, byte[]> getKeywords() { return keywords; } public Object getReadBaton() { return readBaton; } public ISeekCallback getSeekCallback() { return seekCallback; } public ITellCallback getTellCallback() { return tellCallback; } public IRealLineCallback getReadLineCallback() { return readLineCallback; } public IWriteCallback getWriteCallback() { return writeCallback; } public void setExisted(boolean existed) { this.existed = existed; } public void setCurrentLine(int currentLine) { this.currentLine = currentLine; } public void setEolStyle(SVNWCContext.SVNEolStyle eolStyle) { this.eolStyle = eolStyle; } public void setEolStr(String eolStr) { this.eolStr = eolStr; } public void setLines(List<Long> lines) { this.lines = lines; } public void addHunkInfo(SvnHunkInfo hunkInfo) { this.hunkInfos.add(hunkInfo); } public void setEof(boolean eof) { this.eof = eof; } public void setKeywords(Map<String, byte[]> keywords) { this.keywords = keywords; } public void setReadLineCallback(IRealLineCallback readLineCallback) { this.readLineCallback = readLineCallback; } public void setTellCallback(ITellCallback tellCallback) { this.tellCallback = tellCallback; } public void setSeekCallback(ISeekCallback seekCallback) { this.seekCallback = seekCallback; } public void setWriteCallback(IWriteCallback writeCallback) { this.writeCallback = writeCallback; } public void setReadBaton(Object readBaton) { this.readBaton = readBaton; } public void setWriteBaton(Object writeBaton) { this.writeBaton = writeBaton; } public Object getWriteBaton() { return writeBaton; } private static class SymlinkBaton { private final File localAbsPath; public SymlinkBaton(File absPath) { this.localAbsPath = absPath; } } public static interface ISeekCallback { void seek(Object object, long offset) throws SVNException; } public static interface ITellCallback { long tell(Object readBaton) throws SVNException; } public static interface IRealLineCallback { String readLine(Object baton, String[] eolStr, boolean[] eof) throws SVNException; } public static interface IWriteCallback { void write(Object writeBaton, String s) throws SVNException; } }