From ad9dc94eaefae9ab91e3a29f76a13d6e037547ca Mon Sep 17 00:00:00 2001 From: Tobias Hunger <tobias.hunger@theqtcompany.com> Date: Thu, 23 Apr 2015 17:48:32 +0200 Subject: [PATCH] DiffEditor: Parse git diffs properly Do not put filenames into a regular expression and then hope for the best... any file with any character in its name that has a special meaning for a regexp will break the parsing. Task-number: QTCREATORBUG-14322 Change-Id: Ifab513d675168aff041f20d2b3f06a8d27919aa7 Reviewed-by: Tobias Hunger <tobias.hunger@theqtcompany.com> --- src/plugins/diffeditor/diffutils.cpp | 56 ++++++++++++++-------------- 1 file changed, 27 insertions(+), 29 deletions(-) diff --git a/src/plugins/diffeditor/diffutils.cpp b/src/plugins/diffeditor/diffutils.cpp index 0e16becbdf6..9bc5d3a75e2 100644 --- a/src/plugins/diffeditor/diffutils.cpp +++ b/src/plugins/diffeditor/diffutils.cpp @@ -868,6 +868,11 @@ static QList<FileData> readDiffPatch(const QString &patch, return fileDataList; } +static bool fileNameEnd(const QChar &c) +{ + return c == QLatin1Char('\n') || c == QLatin1Char('\t'); +} + static FileData readGitHeaderAndChunks(const QString &headerAndChunks, const QString &fileName, bool *ok) @@ -909,34 +914,30 @@ static FileData readGitHeaderAndChunks(const QString &headerAndChunks, patch.remove(0, indexRegExp.matchedLength()); } - const QRegExp leftFileRegExp(QLatin1String("^-{3} ") // "--- " - + leftFileName // "a/fileName" or "/dev/null" - + QLatin1String("(?:\\t[^\\n]*)*\\n")); // optionally followed by: \t anything \t anything ...) - const QRegExp rightFileRegExp(QLatin1String("^\\+{3} ") // "+++ " - + rightFileName // "b/fileName" or "/dev/null" - + QLatin1String("(?:\\t[^\\n]*)*\\n")); // optionally followed by: \t anything \t anything ...) - const QRegExp binaryRegExp(QLatin1String("^Binary files ") - + leftFileName - + QLatin1String(" and ") - + rightFileName - + QLatin1String(" differ$")); + const QString binaryLine = QString::fromLatin1("Binary files ") + leftFileName + + QLatin1String(" and ") + rightFileName + QLatin1String(" differ"); + const QString leftStart = QString::fromLatin1("--- ") + leftFileName; + QChar leftFollow = patch.count() > leftStart.count() ? patch.at(leftStart.count()) : QLatin1Char('\n'); // empty or followed either by leftFileRegExp or by binaryRegExp if (patch.isEmpty() && (fileData.fileOperation == FileData::NewFile || fileData.fileOperation == FileData::DeleteFile)) { readOk = true; - } else if (leftFileRegExp.indexIn(patch) == 0) { - patch.remove(0, leftFileRegExp.matchedLength()); + } else if (patch.startsWith(leftStart) && fileNameEnd(leftFollow)) { + patch.remove(0, patch.indexOf(QLatin1Char('\n'), leftStart.count()) + 1); + + const QString rightStart = QString::fromLatin1("+++ ") + rightFileName; + QChar rightFollow = patch.count() > rightStart.count() ? patch.at(rightStart.count()) : QLatin1Char('\n'); // followed by rightFileRegExp - if (rightFileRegExp.indexIn(patch) == 0) { - patch.remove(0, rightFileRegExp.matchedLength()); + if (patch.startsWith(rightStart) && fileNameEnd(rightFollow)) { + patch.remove(0, patch.indexOf(QLatin1Char('\n'), rightStart.count()) + 1); fileData.chunks = readChunks(patch, &fileData.lastChunkAtTheEndOfFile, &readOk); } - } else if (binaryRegExp.indexIn(patch) == 0) { + } else if (patch == binaryLine) { readOk = true; fileData.binaryFiles = true; } @@ -966,9 +967,6 @@ static FileData readCopyRenameChunks(const QString ©RenameChunks, const QRegExp indexRegExp(QLatin1String("^index (\\w+)\\.{2}(\\w+)(?: \\d+)?(\\n|$)")); // index cap1..cap2(optionally: octal) - QString leftGitFileName = QLatin1String("a/") + leftFileName; - QString rightGitFileName = QLatin1String("b/") + rightFileName; - if (fileOperation == FileData::CopyFile || fileOperation == FileData::RenameFile) { if (indexRegExp.indexIn(patch) == 0) { fileData.leftFileInfo.typeInfo = indexRegExp.cap(1); @@ -976,20 +974,20 @@ static FileData readCopyRenameChunks(const QString ©RenameChunks, patch.remove(0, indexRegExp.matchedLength()); - const QRegExp leftFileRegExp(QLatin1String("^-{3} ") // "--- " - + leftGitFileName // "a/fileName" or "/dev/null" - + QLatin1String("(?:\\t[^\\n]*)*\\n")); // optionally followed by: \t anything \t anything ...) - const QRegExp rightFileRegExp(QLatin1String("^\\+{3} ") // "+++ " - + rightGitFileName // "b/fileName" or "/dev/null" - + QLatin1String("(?:\\t[^\\n]*)*\\n")); // optionally followed by: \t anything \t anything ...) + const QString leftStart = QString::fromLatin1("--- a/") + leftFileName; + QChar leftFollow = patch.count() > leftStart.count() ? patch.at(leftStart.count()) : QLatin1Char('\n'); // followed by leftFileRegExp - if (leftFileRegExp.indexIn(patch) == 0) { - patch.remove(0, leftFileRegExp.matchedLength()); + if (patch.startsWith(leftStart) && fileNameEnd(leftFollow)) { + patch.remove(0, patch.indexOf(QLatin1Char('\n'), leftStart.count()) + 1); + + // followed by rightFileRegExp + const QString rightStart = QString::fromLatin1("+++ b/") + rightFileName; + QChar rightFollow = patch.count() > rightStart.count() ? patch.at(rightStart.count()) : QLatin1Char('\n'); // followed by rightFileRegExp - if (rightFileRegExp.indexIn(patch) == 0) { - patch.remove(0, rightFileRegExp.matchedLength()); + if (patch.startsWith(rightStart) && fileNameEnd(rightFollow)) { + patch.remove(0, patch.indexOf(QLatin1Char('\n'), rightStart.count()) + 1); fileData.chunks = readChunks(patch, &fileData.lastChunkAtTheEndOfFile, -- GitLab