kdiff3/0001-Collected-fixes-from-master.patch
Christophe Giboudeaux df2e03d319 Accepting request 902836 from home:tivo:branches:openSUSE:Factory
The latest kdiff3 currently shipped with Tumbleweed is unsuitable for everyday use. I, for example, use it as my go-to `git mergetool` and I need that a lot. And it must be reliable and not messing up merge-output. Since the upgrade from 1.8.4 to 1.9.2, many regressions have to be experienced, please see the list of fixed issues below. 

From a distribution point of view, I see two options: Fix-up 1.9.2 like proposed here, or (really!) downgrade to 1.8.5 until a new reliable 1.9 release comes out. I have contributed many fixes to upstream meanwhile.

- Remove GCC 11 build fix:
  * 0001-Explicitly-include-limits-for-compatibility-with-gcc.patch
    now contained in squashed patch
- Add collected fixes from upstream master:
  * 0001-Collected-fixes-from-master.patch
    contains the original and many more fixes:
    + misalignment and wrong conflict resolutions when using manual
      alignment markers
    + uninitialized variables causing crashes
    + hangs and crashes due to wrong loop conditions
    + wrong handling of new-line at end-of-file
    + spurious insertion of empty lines in merge result
    + access of uninitialized iterators causing crashes
    + wrong buffer length calculations causing out-of-bounds access
    + wrong bit-logic causing comments to always be treated as white-space
    + crashes when hitting a key on empty merge results
    + technical details allowing fixes to be cherry-picked

OBS-URL: https://build.opensuse.org/request/show/902836
OBS-URL: https://build.opensuse.org/package/show/KDE:Extra/kdiff3?expand=0&rev=31
2021-06-29 06:37:21 +00:00

1370 lines
50 KiB
Diff

From 8605cc11f667c95d0253378f10855ed6d214da84 Mon Sep 17 00:00:00 2001
From: Michael Reeves <reeves.87@gmail.com>
Date: Wed, 28 Apr 2021 18:02:32 -0400
Subject: [PATCH] Collected fixes from master
Issues fixed:
- misalignment and wrong conflict resolutions when using manual
alignment markers
- uninitialized variables causing crashes
- hangs and crashes due to wrong loop conditions
- wrong handling of new-line at end-of-file
- spurious insertion of empty lines in merge result
- access of uninitialized iterators causing crashes
- wrong buffer length calculations causing out-of-bounds access
- wrong bit-logic causing comments to always be treated as white-space
- crashes when hitting a key on empty merge results
- technical details allowing fixes to be cherry-picked
> This is a combination of 32 commits.
> This is the 1st commit message:
Switch to 'using' syntax, add QtSizeType for Qt6 transition.
> This is the commit message #2:
Imporove checking for overflow when converting 64 bit to 32 bit.
Oversized diff lists will now generate an error.
Created SafeInt32 template class as an additional protection against undefined behavoir on 64 to 32 conversion.
> This is the commit message #3:
Drop uneeded member variable
> This is the commit message #4:
Drop old gcc support and force exception handling on
> This is the commit message #5:
Blacklist boost::safe_numerics on MSVC
MSVC is not compatiable with boost::safe_numerics it creates duplicate symbols as this is specfic to MSCV blacklist it
I don't have time to deal with wierd link-time wonkyness.
> This is the commit message #6:
Don't bring boost name space into global scope.]
This avoids name collisions in CommentParser.
> This is the commit message #7:
Cleanup
> This is the commit message #8:
Revert "Blacklist boost::safe_numerics on MSVC"
This reverts commit 13b9dcaff946be0ae373d8bff940d2d3171bacf7.
> This is the commit message #9:
Update to require boost 1.71 due to bug in earlier headers.
The bug only affects MSCV compiles as it is over zealous about creating additional function definitions.
When the function is writen inline but as no inline keyword.
> This is the commit message #10:
fix typo
> This is the commit message #11:
Work aroung link-time bug on MSVC
Don't use safe numerics on windows until boost 1.71 is part of craft.
> This is the commit message #12:
Revert "Work aroung link-time bug on MSVC"
This reverts commit fbd9c64a36193d32b2f6c0047894c3011b9a06e7.
> This is the commit message #13:
By pass boost::safe_numerics on windows.
> This is the commit message #14:
Change boost version back to 1.66
> This is the commit message #15:
QtGlobal should be first header if its included explicitly
Q_OS_WIN is not defined until this header is read. This creates an incorrect OS dectection in TypeUtils.h
> This is the commit message #16:
Cleanup: Remove unneeded file.
> This is the commit message #17:
Only swap lines in column under consideration
This fixes a regression caused by 0806d2a28dd70df5255b7e5ee26477dab321acdd
> This is the commit message #18:
Add missing initialization
> This is the commit message #19:
Fix broken loop end condition
Regression by enum refactoring
> This is the commit message #20:
Add link to download binaries in README
This is useful to help prospective users quickly find where to download
and install the application instead of doing several searches on the
web.
> This is the commit message #21:
Make dependency on KI18n explicit
It already pulled in by KParts, but we better not rely on that
> This is the commit message #22:
Refactor CMakeLists.txt find all depedancies at root level.
This does not affect the Contextual Menu plugins these are different between linux and windows.
> This is the commit message #23:
Exposes EOL termination in SourceData.
> This is the commit message #24:
Fix EOL handling in SourceData::FileData::preprocess
This resolves the striping of the trailing EOLs.
CCBUG:437570
> This is the commit message #25:
Factor out line feed when writing output.
The line feed sequence (CRLF or LF) is constant in the file, so calculate
it once, before starting writing. Don't modify the string that is being
written, just dump the line feed to the output text stream.
(cherry picked from commit 93c8c07b925eb55bcdfd597fbef824c11d84160b)
> This is the commit message #26:
Do not put line feed between removed lines
If a line is removed in a merge, then there should be no
line feed before it -- that will come from a subsequent
**non**-deleted line. This avoids double-newlines when a
line is removed.
(cherry picked from commit 942325c58a922b0297861ad3c2b1832248b1bf14)
BUG:437570
FIXED-IN:1.9.3
> This is the commit message #27:
Fix more enum refactoring regressions
> This is the commit message #28:
Prevent accessing uninitialized iterators
MergeResultWindow:
calcIteratorFromLineNr():
add documentation;
return success status to make checking validity of out-iterators
easy;
keyPressEvent():
check for failure to look up line (may happen on empty merge
window);
remove duplicated handling for bCtrl;
remove "else" after "return": allows less indentation;
deleteSelection2():
make guarantee of always succeeding lookup explicit;
pasteClipboard():
check for failure to look up line (may happen on empty merge
window);
getString():
(slightly) simplify handling of empty merge window using return
code from calcIteratorFromLineNr();
> This is the commit message #29:
Fix wrong buffer length calculation and out-of-bounds access
This fixes regressions caused by
29042af9a3d7bd424d123457bfb76e47a59107e8
DiffList::runDiff() fix number 1:
In the original code, the test for a present but empty initial line in
p1 or p2 was testing for a null line buffer pointer. Due to the
regression, the new getLine() method returning a QString was tested
against nullptr which surprisingly compiles because with
QT_RESTRICTED_CAST_FROM_ASCII, that comparison boils down to
comparing the QString vs. a QStringRef(nullptr) which is the same
as a check for an empty string. This is of course very different
from the original check for allocated data.
So, now check getBuffer() against nullptr instead.
DiffList::runDiff() fix number 2:
The calculation of the comparisonInput buffer sizes was wrong, different
from the original and risky: The new code was using (*p1)[size1]
which in general may well access the first past-end element of *p1.
The original code only used beginning of first and end of last
line. Also, the new code ignored the new index1 which needs to
be used because lines are not of equal length.
So, reverting to the original logic of calculating the buffer length.
This bug actually caused crashes when using manual alignment:
assert(d.numberOfEquals() >= 0);
> This is the commit message #30:
Also treat CR like LF
This also moves the lineCount increment close to the push_back - why is a
separate count needed anyway?
And move comment (back) to right place.
> This is the commit message #31:
Use CMAKE_CXX_STANDARD for setting the required C++ version
Use the CMAKE_CXX_STANDARD variable for setting the required C++ version
as this is the official way of controlling this and it propagates
correctly to the autotests projects as well.
> This is the commit message #32:
Fix wrong bit-logic operator to check set bit
Also, make it easier to read by using separate line for each flag.
Problem introduced in 8d4fdeaf742d47942882e2453fdc28c1d0a2e2c1 .
---
.gitlab-nonkde.yml | 35 -----------
CMakeLists.txt | 19 +++---
README | 2 +
src/CMakeLists.txt | 10 +--
src/SourceData.cpp | 55 +++++++++++++----
src/SourceData.h | 8 ++-
src/TypeUtils.h | 29 +++++++--
src/diff.cpp | 37 ++++++------
src/diff.h | 35 ++++-------
src/difftextwindow.cpp | 22 +++----
src/gnudiff_diff.h | 3 +-
src/kdiff3.h | 5 +-
src/mergeresultwindow.cpp | 124 +++++++++++++++++++++-----------------
src/mergeresultwindow.h | 2 +-
src/pdiff.cpp | 29 +++++----
src/selection.cpp | 4 +-
16 files changed, 224 insertions(+), 195 deletions(-)
delete mode 100644 .gitlab-nonkde.yml
diff --git a/.gitlab-nonkde.yml b/.gitlab-nonkde.yml
deleted file mode 100644
index 5c500e1c..00000000
--- a/.gitlab-nonkde.yml
+++ /dev/null
@@ -1,35 +0,0 @@
-stages:
- - build
- - test
-
-build_ubuntu_20_04:
- stage: build
- image: reporter123/kdiff3env:groovy
- #before_script:
- # - apt-get update
- # - apt-get install -y libqt5test5 gettext qtbase5-dev extra-cmake-modules libkf5i18n-dev libkf5coreaddons-dev libkf5iconthemes-dev libkf5parts-dev libkf5doctools-dev libkf5crash-dev libboost-dev
- script:
- - cmake -DBUILD_TESTING=YES .
- - make
- artifacts:
- untracked: true
- retry:
- max: 2
- when:
- - runner_system_failure
- - stuck_or_timeout_failure
-
-ubuntu_20_04_test:
- stage: test
- needs: ["build_ubuntu_20_04"]
- image: reporter123/kdiff3env:groovy
-# before_script:
-# - apt-get update
-# - apt-get install -y libqt5test5
- script:
- - make ARGS="-V -E appstreamtest" test #exclude appstreamtest this does not run properly in my #image
- retry:
- max: 2
- when:
- - runner_system_failure
- - stuck_or_timeout_failure
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 98237ace..96686df4 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -36,6 +36,9 @@ ecm_setup_version(1.9.2 VARIABLE_PREFIX KDIFF3 VERSION_HEADER ${CMAKE_BINARY_DIR
# Some older versions on boost contain a bug that prevents compiling gcc offers a built-in workaround
# but that isn't enough to ship as clang has no such workaround. 1.65 is known to be affected.
+#
+# 1.71 or later is required for safe_numerics to work on MSVC otherwise we get a link-time error.
+# A work around is in place since craft has not yet updated.
find_package(Boost 1.66 REQUIRED)
#needed on craft and possiablely other custom setups.
@@ -58,6 +61,9 @@ find_package(
COMPONENTS
I18n
CoreAddons
+ Parts
+ WidgetsAddons
+ Config
Crash
OPTIONAL_COMPONENTS
DocTools
@@ -68,11 +74,11 @@ set_package_properties(KF5DocTools PROPERTIES PURPOSE "Allows generating and ins
option(ENABLE_AUTO "Enable kdiff3's '--auto' flag" ON)
option(ENABLE_CLANG_TIDY "Run clang-tidy if available and cmake version >=3.6" OFF)
-set(KDiff3_LIBRARIES ${Qt5PrintSupport_LIBRARIES} KF5::I18n KF5::CoreAddons )
+set(CMAKE_CXX_STANDARD 17)
if (CMAKE_CXX_COMPILER_ID MATCHES "Clang")
#Adjust clang specific warnings
- set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wshadow")
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wshadow -fexceptions")
set(CLANG_WARNING_FLAGS "-Wno-undef -Wno-trigraphs -Wno-invalid-pp-token -Wno-comment -Wshorten-64-to-32 -Wstring-conversion -Wc++11-narrowing -fstack-protector-all")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${CLANG_WARNING_FLAGS}")
elseif(CMAKE_CXX_COMPILER_ID MATCHES "MSVC")
@@ -82,9 +88,7 @@ elseif(CMAKE_CXX_COMPILER_ID MATCHES "GNU")
if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS 8.0)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fstack-check")
endif()
- if(CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 7.0)
- set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wno-trigraphs -Wduplicated-cond -Wduplicated-branches -Wshadow")
- endif()
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wno-trigraphs -Wduplicated-cond -Wduplicated-branches -Wshadow -fexceptions")
endif()
#new in cmake 3.6+ integrate clang-tidy
@@ -100,11 +104,6 @@ endif()
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${CMAKE_CXX_FLAGS}")
-set(
- needed_features
- cxx_std_11
-)
-
if(ENABLE_AUTO)
add_definitions(
-DENABLE_AUTO
diff --git a/README b/README
index 971338fd..ae926f22 100644
--- a/README
+++ b/README
@@ -20,6 +20,8 @@ Known Issues:
The current reprository is at https://invent.kde.org/kde/kdiff3
+Binaries can be downloaded at https://download.kde.org/stable/kdiff3/?C=M;O=D
+
Bugs can be reported at https://bugs.kde.org
The original pre KF5/Qt5 Readme follows old build instructions have been removed to avoid confusion:
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 3190160a..249dbd75 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -3,7 +3,7 @@
# SPDX-License-Identifier: GPL-2.0-or-later
########### kdiff3 KPart ###############
-find_package(KF5 ${KF5_MIN_VERSION} REQUIRED COMPONENTS Parts WidgetsAddons)
+
set(kdiff3part_PART_SRCS
kdiff3_part.cpp
@@ -45,14 +45,12 @@ ki18n_wrap_ui(kdiff3part_PART_SRCS
add_library(kdiff3part MODULE ${kdiff3part_PART_SRCS})
set_target_properties(kdiff3part PROPERTIES DEFINE_SYMBOL KDIFF3_PART)
-target_compile_features(kdiff3part PRIVATE ${needed_features})
-target_link_libraries(kdiff3part ${KDiff3_LIBRARIES} KF5::Parts KF5::Crash)
+target_link_libraries(kdiff3part ${Qt5PrintSupport_LIBRARIES} KF5::I18n KF5::CoreAddons KF5::Parts KF5::Crash)
target_compile_definitions(kdiff3part PRIVATE -DTRANSLATION_DOMAIN=\"kdiff3\")
install(TARGETS kdiff3part DESTINATION ${KDE_INSTALL_PLUGINDIR}/kf5/parts )
########### kdiff3 executable ###############
-find_package(KF5 ${KF5_MIN_VERSION} REQUIRED COMPONENTS Parts WidgetsAddons Config)
set(kdiff3_SRCS
main.cpp
@@ -67,8 +65,7 @@ endif()
include(icons/CMakeLists.txt)
add_executable(kdiff3 ${kdiff3_SRCS})
-target_link_libraries(kdiff3 KF5::ConfigCore KF5::ConfigGui KF5::Parts KF5::Crash ${KDiff3_LIBRARIES} )
-target_compile_features(kdiff3 PRIVATE ${needed_features})
+target_link_libraries(kdiff3 KF5::ConfigCore KF5::ConfigGui KF5::Parts KF5::Crash ${Qt5PrintSupport_LIBRARIES} KF5::I18n KF5::CoreAddons )
# See https://cmake.org/cmake/help/v3.15/prop_tgt/MACOSX_BUNDLE_INFO_PLIST.html
if(APPLE)
@@ -99,4 +96,3 @@ install( FILES kdiff3_shell.rc DESTINATION ${KDE_INSTALL_KXMLGUI5DIR}/kdiff3 )
#install( PROGRAMS kdiff3.desktop DESTINATION ${XDG_APPS_INSTALL_DIR} )
install( PROGRAMS org.kde.kdiff3.desktop DESTINATION ${XDG_APPS_INSTALL_DIR} )
install( FILES org.kde.kdiff3.appdata.xml DESTINATION ${KDE_INSTALL_METAINFODIR} )
-
diff --git a/src/SourceData.cpp b/src/SourceData.cpp
index 72738c7b..161e2510 100644
--- a/src/SourceData.cpp
+++ b/src/SourceData.cpp
@@ -33,9 +33,11 @@ Optimizations: Skip unneeded steps.
#include "CommentParser.h"
#include "diff.h"
#include "kdiff3.h"
+#include "LineRef.h"
#include "Logging.h"
#include "Utils.h"
+#include <qglobal.h>
#include <QProcess>
#include <QScopedPointer>
#include <QString>
@@ -176,9 +178,9 @@ const QVector<LineData>* SourceData::getLineDataForDisplay() const
return m_normalData.m_v.size() > 0 ? &m_normalData.m_v : nullptr;
}
-LineRef SourceData::getSizeLines() const
+LineCount SourceData::getSizeLines() const
{
- return m_normalData.lineCount();
+ return SafeInt32<LineCount>(m_normalData.lineCount());
}
qint64 SourceData::getSizeBytes() const
@@ -601,14 +603,20 @@ bool SourceData::FileData::preprocess(QTextCodec* pEncoding, bool removeComments
return false;
const QByteArray ba = QByteArray::fromRawData(m_pBuf + skipBytes, (int)(mDataSize - skipBytes));
- QTextStream ts(ba, QIODevice::ReadOnly); //Don't use text mode we need to see the actual line ending.
+ QTextStream ts(ba, QIODevice::ReadOnly); // Don't use text mode we need to see the actual line ending.
+ QTextStream ts2(ba, QIODevice::ReadOnly);
ts.setCodec(pEncoding);
ts.setAutoDetectUnicode(false);
-
+ ts2.setCodec(pEncoding);
+ ts2.setAutoDetectUnicode(false);
+ QString s = ts2.readAll();
m_bIncompleteConversion = false;
m_unicodeBuf->clear();
+ //*m_unicodeBuf = ts.readAll();
Q_ASSERT(m_unicodeBuf->length() == 0);
+ mHasEOLTermination = false;
+
while(!ts.atEnd())
{
line.clear();
@@ -618,7 +626,7 @@ bool SourceData::FileData::preprocess(QTextCodec* pEncoding, bool removeComments
return false;
}
- ts >> curChar;
+ curChar = ts.read(1).unicode()[0];
quint32 firstNonwhite = 0;
bool foundNonWhite = false;
@@ -645,10 +653,9 @@ bool SourceData::FileData::preprocess(QTextCodec* pEncoding, bool removeComments
if(ts.atEnd())
break;
- ts >> curChar;
+ curChar = ts.read(1).unicode()[0];
}
- ++lineCount;
switch(curChar.unicode())
{
@@ -668,7 +675,7 @@ bool SourceData::FileData::preprocess(QTextCodec* pEncoding, bool removeComments
if(m_pBuf[lastOffset + j] == '\n')
{
- ts >> curChar;
+ curChar = ts.read(1).unicode()[0];
vOrigDataLineEndStyle.push_back(eLineEndStyleDos);
lastOffset = ts.pos();
break;
@@ -683,15 +690,39 @@ bool SourceData::FileData::preprocess(QTextCodec* pEncoding, bool removeComments
if(removeComments)
parser->removeComment(line);
- //kdiff3 internally uses only unix style endings for simplicity.
+ ++lineCount;
m_v.push_back(LineData(m_unicodeBuf, lastOffset, line.length(), firstNonwhite, parser->isSkipable(), parser->isPureComment()));
- m_unicodeBuf->append(line).append('\n');
+ //The last line may not have an EOL mark. In that case don't add one to our buffer.
+ m_unicodeBuf->append(line);
+ if(curChar == '\n' || curChar == '\r')
+ {
+ //kdiff3 internally uses only unix style endings for simplicity.
+ m_unicodeBuf->append('\n');
+ }
lastOffset = m_unicodeBuf->length();
}
+ /*
+ Process trailing new line as if there were a blank non-terminated line after it.
+ But do nothing to the data buffer since this a phantom line needed for internal purposes.
+ */
+ if(curChar == '\n' || curChar == '\r')
+ {
+ mHasEOLTermination = true;
+ ++lineCount;
+
+ parser->processLine("");
+ m_v.push_back(LineData(m_unicodeBuf, lastOffset, 0, 0, parser->isSkipable(), parser->isPureComment()));
+ }
+ //Check if we have two identical offsets at the end. Indicates a bug in the read loop.
+ assert(m_v.size() < 2 || m_v[m_v.size() - 1].getOffset() != m_v[m_v.size() - 2].getOffset());
+
m_v.push_back(LineData(m_unicodeBuf, lastOffset));
- Q_ASSERT(m_v.size() < 2 || m_v[m_v.size() - 1].getOffset() != m_v[m_v.size() - 2].getOffset());
+ //TODO: Fix this properly we should not be sending GNU:Diff invalid offsets.
+ //m_unicodeBuf->append('\u0000');
+ //Validate
+ //assert(m_v->size() < 1 || (quint64)(*m_v)[m_v->size() - 2].getOffset() == lastOffset);
m_bIsText = true;
@@ -782,7 +813,7 @@ QTextCodec* SourceData::detectEncoding(const char* buf, qint64 size, qint64& ski
QByteArray s;
/*
We don't need the whole file here just the header.
-] */
+ */
if(size <= 5000)
s = QByteArray(buf, (int)size);
else
diff --git a/src/SourceData.h b/src/SourceData.h
index d72d7d84..d42dcf6d 100644
--- a/src/SourceData.h
+++ b/src/SourceData.h
@@ -27,7 +27,7 @@ class SourceData
void setupConnections();
void setOptions(const QSharedPointer<Options> &pOptions);
- Q_REQUIRED_RESULT LineRef getSizeLines() const;
+ Q_REQUIRED_RESULT LineCount getSizeLines() const;
Q_REQUIRED_RESULT qint64 getSizeBytes() const;
Q_REQUIRED_RESULT const char* getBuf() const;
Q_REQUIRED_RESULT const QString& getText() const;
@@ -59,12 +59,14 @@ class SourceData
Q_REQUIRED_RESULT QTextCodec* getEncoding() const { return m_pEncoding; }
Q_REQUIRED_RESULT e_LineEndStyle getLineEndStyle() const { return m_normalData.m_eLineEndStyle; }
+ [[nodiscard]] inline bool hasEOLTermiantion() { return m_normalData.hasEOLTermiantion(); }
+
Q_REQUIRED_RESULT const QStringList& getErrors() const { return mErrors; }
void setEncoding(QTextCodec* pEncoding);
- private:
+ protected:
bool convertFileEncoding(const QString& fileNameIn, QTextCodec* pCodecIn,
const QString& fileNameOut, QTextCodec* pCodecOut);
@@ -94,6 +96,7 @@ class SourceData
bool m_bIsText = false;
bool m_bIncompleteConversion = false;
e_LineEndStyle m_eLineEndStyle = eLineEndStyleUndefined;
+ bool mHasEOLTermination = false;
public:
~FileData() { reset(); }
@@ -109,6 +112,7 @@ class SourceData
bool isEmpty() const { return mDataSize == 0; }
bool isText() const { return m_bIsText || isEmpty(); }
+ [[nodiscard]] inline bool hasEOLTermiantion() { return m_bIsText && mHasEOLTermination; }
inline qint64 lineCount() const { return mLineCount; }
inline qint64 byteCount() const { return mDataSize; }
diff --git a/src/TypeUtils.h b/src/TypeUtils.h
index a3b4be08..a2c5ec76 100644
--- a/src/TypeUtils.h
+++ b/src/TypeUtils.h
@@ -1,23 +1,42 @@
/*
* KDiff3 - Text Diff And Merge Tool
- *
+ *
* SPDX-FileCopyrightText: 2018-2020 Michael Reeves reeves.87@gmail.com
* SPDX-License-Identifier: GPL-2.0-or-later
*/
#ifndef TYPEUTILS_H
#define TYPEUTILS_H
+#include <QtGlobal>
+
#include <stdlib.h>
#include <type_traits>
+#include <boost/version.hpp>
+/*
+ MSVC is not compatiable with boost::safe_numerics it creates duplicate symbols as this is specfic to MSCV blacklist it
+*/
+#if !defined(Q_OS_WIN) && BOOST_VERSION >= 106900
+#include <boost/safe_numerics/safe_integer.hpp>
+#endif
+
+#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0))
+using QtSizeType = qint32;
+#else
+using QtSizeType = qsizetype;
+#endif
+using QtNumberType = qint32;//Qt insists on one type for all but does not create a typedef for it.
+
+using PtrDiffRef = size_t;
-#include <QtGlobal>
+#if !defined(Q_OS_WIN) && (BOOST_VERSION >= 106900)
+template<typename T> using SafeInt32 = boost::safe_numerics::safe<T, boost::safe_numerics::native>;
+#else
+template<typename T> using SafeInt32 = T;
+#endif
#define TYPE_MAX(x) std::numeric_limits<x>::max()
#define TYPE_MIN(x) std::numeric_limits<x>::min()
-typedef size_t PtrDiffRef;
-typedef qint32 QtNumberType;//Qt insists on one type for all but does not create a typedef for it.
-
static_assert(sizeof(int) >= sizeof(qint32), "Legacy LP32 systems/compilers not supported"); // e.g. Windows 16-bit
#endif
diff --git a/src/diff.cpp b/src/diff.cpp
index 50c2ab85..778e4d86 100644
--- a/src/diff.cpp
+++ b/src/diff.cpp
@@ -7,6 +7,7 @@
*/
#include "diff.h"
+#include <QtGlobal>
#include "gnudiff_diff.h"
#include "merger.h"
@@ -19,7 +20,6 @@
#include <KLocalizedString>
#include <KMessageBox>
-#include <QtGlobal>
#include <QSharedPointer>
constexpr bool g_bIgnoreWhiteSpace = true;
@@ -543,7 +543,8 @@ void ManualDiffHelpList::insertEntry(e_SrcSelector winIdx, LineRef firstLine, Li
}
if(i->firstLine(wIdx).isValid()) // Current item is not empty -> move it to the empty place
{
- std::swap(iEmpty, i);
+ std::swap(iEmpty->firstLine(wIdx), i->firstLine(wIdx));
+ std::swap(iEmpty->lastLine(wIdx), i->lastLine(wIdx));
++iEmpty;
}
}
@@ -574,14 +575,14 @@ bool ManualDiffHelpEntry::isValidMove(int line1, int line2, e_SrcSelector winIdx
int ManualDiffHelpEntry::calcManualDiffFirstDiff3LineIdx(const Diff3LineVector& d3lv)
{
- int i;
+ QtSizeType i;
for(i = 0; i < d3lv.size(); ++i)
{
const Diff3Line& d3l = *d3lv[i];
if((lineA1.isValid() && lineA1 == d3l.getLineA()) ||
(lineB1.isValid() && lineB1 == d3l.getLineB()) ||
(lineC1.isValid() && lineC1 == d3l.getLineC()))
- return i;
+ return SafeInt32<int>(i);
}
return -1;
}
@@ -595,9 +596,9 @@ void DiffList::runDiff(const QVector<LineData>* p1, const qint32 index1, LineRef
pp.setCurrent(0);
clear();
- if(p1 == nullptr || (*p1)[index1].getLine() == nullptr || p2 == nullptr || (*p2)[index2].getLine() == nullptr || size1 == 0 || size2 == 0)
+ if(p1 == nullptr || (*p1)[index1].getBuffer() == nullptr || p2 == nullptr || (*p2)[index2].getBuffer() == nullptr || size1 == 0 || size2 == 0)
{
- if(p1 != nullptr && p2 != nullptr && (*p1)[index1].getLine() == nullptr && (*p2)[index2].getLine() == nullptr && size1 == size2)
+ if(p1 != nullptr && p2 != nullptr && (*p1)[index1].getBuffer() == nullptr && (*p2)[index2].getBuffer() == nullptr && size1 == size2)
push_back(Diff(size1, 0, 0));
else
{
@@ -606,13 +607,15 @@ void DiffList::runDiff(const QVector<LineData>* p1, const qint32 index1, LineRef
}
else
{
+ assert((size_t)size1 < p1->size() && (size_t)size2 < p2->size());
+
GnuDiff::comparison comparisonInput;
memset(&comparisonInput, 0, sizeof(comparisonInput));
comparisonInput.parent = nullptr;
comparisonInput.file[0].buffer = (*p1)[index1].getBuffer()->unicode() + (*p1)[index1].getOffset(); //ptr to buffer
- comparisonInput.file[0].buffered = ((*p1)[size1].getOffset() - 1); // size of buffer
+ comparisonInput.file[0].buffered = ((*p1)[index1 + size1 - 1].getOffset() + (*p1)[index1 + size1 - 1].size() - (*p1)[index1].getOffset()); // size of buffer
comparisonInput.file[1].buffer = (*p2)[index2].getBuffer()->unicode() + (*p2)[index2].getOffset(); //ptr to buffer
- comparisonInput.file[1].buffered = ((*p2)[size2].getOffset() - 1); // size of buffer
+ comparisonInput.file[1].buffered = ((*p2)[index2 + size2 - 1].getOffset() + (*p2)[index2 + size2 - 1].size() - (*p2)[index2].getOffset()); // size of buffer
gnuDiff.ignore_white_space = GnuDiff::IGNORE_ALL_SPACE; // I think nobody needs anything else ...
gnuDiff.bIgnoreWhiteSpace = true;
@@ -754,7 +757,7 @@ void Diff3LineList::correctManualDiffAlignment(ManualDiffHelpList* pManualDiffHe
e_SrcSelector wi = e_SrcSelector::None;
for(; i3 != end(); ++i3)
{
- for(wi = e_SrcSelector::A; wi <= e_SrcSelector::Max; wi=nextSelector(wi))
+ for(wi = e_SrcSelector::A; wi != e_SrcSelector::Invalid; wi=nextSelector(wi))
{
if(i3->getLineInFile(wi).isValid() && iMDHL->firstLine(wi) == i3->getLineInFile(wi))
break;
@@ -772,12 +775,12 @@ void Diff3LineList::correctManualDiffAlignment(ManualDiffHelpList* pManualDiffHe
e_SrcSelector wi2 = e_SrcSelector::None;
for(; i3 != end(); ++i3)
{
- for(wi2 = e_SrcSelector::A; wi2 <= e_SrcSelector::C; wi2 = nextSelector(wi2))
+ for(wi2 = e_SrcSelector::A; wi2 != e_SrcSelector::Invalid; wi2 = nextSelector(wi2))
{
if(wi != wi2 && i3->getLineInFile(wi2).isValid() && iMDHL->firstLine(wi2) == i3->getLineInFile(wi2))
break;
}
- if(wi2 > e_SrcSelector::C)
+ if(wi2 == e_SrcSelector::Invalid)
{ // Not yet found
// Move both others up
Diff3Line d3l;
@@ -1167,11 +1170,10 @@ void Diff3LineList::calcDiff3LineListTrim(
*/
}
-void DiffBufferInfo::init(Diff3LineList* pD3ll, const Diff3LineVector* pD3lv,
+void DiffBufferInfo::init(Diff3LineList* pD3ll,
const QVector<LineData>* pldA, LineCount sizeA, const QVector<LineData>* pldB, LineCount sizeB, const QVector<LineData>* pldC, LineCount sizeC)
{
m_pDiff3LineList = pD3ll;
- m_pDiff3LineVector = pD3lv;
mLineDataA = pldA;
mLineDataB = pldB;
mLineDataC = pldC;
@@ -1366,8 +1368,9 @@ bool Diff3Line::fineDiff(bool inBTextsTotalEqual, const e_SrcSelector selector,
LineRef k1 = 0;
LineRef k2 = 0;
int maxSearchLength = 500;
- bool bTextsTotalEqual = inBTextsTotalEqual, bIgnoreComments = eIgnoreFlags | IgnoreFlag::ignoreComments;
- bool bIgnoreWhiteSpace = eIgnoreFlags | IgnoreFlag::ignoreWhiteSpace;
+ bool bTextsTotalEqual = inBTextsTotalEqual;
+ bool bIgnoreComments = eIgnoreFlags & IgnoreFlag::ignoreComments;
+ bool bIgnoreWhiteSpace = eIgnoreFlags & IgnoreFlag::ignoreWhiteSpace;
Q_ASSERT(selector == e_SrcSelector::A || selector == e_SrcSelector::B || selector == e_SrcSelector::C);
@@ -1491,7 +1494,7 @@ bool Diff3LineList::fineDiff(const e_SrcSelector selector, const QVector<LineDat
ProgressProxy pp;
Diff3LineList::iterator i;
bool bTextsTotalEqual = true;
- int listSize = size();
+ size_t listSize = size();
pp.setMaxNofSteps(listSize);
int listIdx = 0;
for(i = begin(); i != end(); ++i)
@@ -1506,7 +1509,7 @@ bool Diff3LineList::fineDiff(const e_SrcSelector selector, const QVector<LineDat
// Convert the list to a vector of pointers
void Diff3LineList::calcDiff3LineVector(Diff3LineVector& d3lv)
{
- d3lv.resize(size());
+ d3lv.resize(SafeInt32<QtSizeType>(size()));
Diff3LineList::iterator i;
int j = 0;
for(i = begin(); i != end(); ++i, ++j)
diff --git a/src/diff.h b/src/diff.h
index 414caf85..fcca7c2d 100644
--- a/src/diff.h
+++ b/src/diff.h
@@ -163,8 +163,10 @@ class LineData
class ManualDiffHelpList; // A list of corresponding ranges
+class Diff3Line;
class Diff3LineList;
-class Diff3LineVector;
+
+using Diff3LineVector = QVector<Diff3Line*>;
class DiffBufferInfo
{
@@ -179,7 +181,7 @@ class DiffBufferInfo
const Diff3LineList* m_pDiff3LineList;
const Diff3LineVector* m_pDiff3LineVector;
public:
- void init(Diff3LineList* d3ll, const Diff3LineVector* d3lv,
+ void init(Diff3LineList* d3ll,
const QVector<LineData>* pldA, LineCount sizeA, const QVector<LineData>* pldB, LineCount sizeB, const QVector<LineData>* pldC, LineCount sizeC);
inline const QVector<LineData>* getLineData(e_SrcSelector srcIndex) const
@@ -379,25 +381,13 @@ class Diff3LineList : public std::list<Diff3Line>
return sumOfLines;
}
- //TODO: Add safety guards to prevent list from getting too large. Same problem as with QLinkedList.
- qint32 size() const
- {
- if(std::list<Diff3Line>::size() > (size_t)TYPE_MAX(qint32))//explicit cast to silence gcc
- {
- qCDebug(kdiffMain) << "Diff3Line: List too large. size=" << std::list<Diff3Line>::size();
- Q_ASSERT(false); //Unsupported size
- return 0;
- }
- return (qint32)std::list<Diff3Line>::size();
- } //safe for small files same limit as exited with QLinkedList. This should ultimatly be removed.
-
void debugLineCheck(const LineCount size, const e_SrcSelector srcSelector) const;
- qint32 numberOfLines(bool bWordWrap) const
+ [[nodiscard]] LineCount numberOfLines(bool bWordWrap) const
{
if(bWordWrap)
{
- qint32 lines;
+ LineCount lines;
lines = 0;
Diff3LineList::const_iterator i;
@@ -410,21 +400,18 @@ class Diff3LineList : public std::list<Diff3Line>
}
else
{
- return size();
+ return SafeInt32<LineCount>(size());
}
}
};
-class Diff3LineVector : public QVector<Diff3Line*>
-{
-};
struct Diff3WrapLine
{
- Diff3Line* pD3L;
- int diff3LineIndex;
- int wrapLineOffset;
- int wrapLineLength;
+ Diff3Line* pD3L = nullptr;
+ int diff3LineIndex = 0;
+ int wrapLineOffset = 0;
+ int wrapLineLength = 0;
};
typedef QVector<Diff3WrapLine> Diff3WrapLineVector;
diff --git a/src/difftextwindow.cpp b/src/difftextwindow.cpp
index 3ffb85be..dbe01c29 100644
--- a/src/difftextwindow.cpp
+++ b/src/difftextwindow.cpp
@@ -132,7 +132,7 @@ class DiffTextWindowData
bool isThreeWay() const { return KDiff3App::isTripleDiff(); };
const QString& getFileName() { return m_filename; }
- const Diff3LineVector* getDiff3LineVector() { return m_pDiff3LineVector; }
+ const Diff3LineVector* getDiff3LineVector() { return mDiff3LineVector; }
const QSharedPointer<Options>& getOptions() { return m_pOptions; }
@@ -149,7 +149,7 @@ class DiffTextWindowData
bool m_bWordWrap = false;
int m_delayedDrawTimer = 0;
- const Diff3LineVector* m_pDiff3LineVector = nullptr;
+ const Diff3LineVector* mDiff3LineVector = nullptr;
Diff3WrapLineVector m_diff3WrapLineVector;
const ManualDiffHelpList* m_pManualDiffHelpList = nullptr;
QList<QVector<WrapLineCacheData>> m_wrapLineCacheList;
@@ -241,7 +241,7 @@ void DiffTextWindow::init(
d->m_filename = filename;
d->m_pLineData = pLineData;
d->m_size = size;
- d->m_pDiff3LineVector = pDiff3LineVector;
+ d->mDiff3LineVector = pDiff3LineVector;
d->m_diff3WrapLineVector.clear();
d->m_pManualDiffHelpList = pManualDiffHelpList;
@@ -290,7 +290,7 @@ void DiffTextWindow::reset()
{
d->m_pLineData = nullptr;
d->m_size = 0;
- d->m_pDiff3LineVector = nullptr;
+ d->mDiff3LineVector = nullptr;
d->m_filename = "";
d->m_diff3WrapLineVector.clear();
}
@@ -1246,7 +1246,7 @@ void DiffTextWindowData::draw(RLPainter& p, const QRect& invalidRect, int beginL
}
else
{
- d3l = (*m_pDiff3LineVector)[line];
+ d3l = (*mDiff3LineVector)[line];
}
DiffList* pFineDiff1;
DiffList* pFineDiff2;
@@ -1276,10 +1276,10 @@ QString DiffTextWindowData::getString(int d3lIdx)
{
Q_ASSERT(!(m_pLineData != nullptr && m_pLineData->isEmpty() && m_size != 0));
- if(m_pLineData == nullptr || m_pLineData->isEmpty() || d3lIdx < 0 || d3lIdx >= m_pDiff3LineVector->size())
+ if(m_pLineData == nullptr || m_pLineData->isEmpty() || d3lIdx < 0 || d3lIdx >= mDiff3LineVector->size())
return QString();
- const Diff3Line* d3l = (*m_pDiff3LineVector)[d3lIdx];
+ const Diff3Line* d3l = (*mDiff3LineVector)[d3lIdx];
DiffList* pFineDiff1;
DiffList* pFineDiff2;
ChangeFlags changed = NoChange;
@@ -1535,12 +1535,12 @@ int DiffTextWindowData::convertLineOnScreenToLineInSource(int lineOnScreen, e_Co
{
if(coordType == eWrapCoords) return lineOnScreen;
int d3lIdx = m_pDiffTextWindow->convertLineToDiff3LineIdx(lineOnScreen);
- if(!bFirstLine && d3lIdx >= m_pDiff3LineVector->size())
- d3lIdx = m_pDiff3LineVector->size() - 1;
+ if(!bFirstLine && d3lIdx >= mDiff3LineVector->size())
+ d3lIdx = mDiff3LineVector->size() - 1;
if(coordType == eD3LLineCoords) return d3lIdx;
- while(!line.isValid() && d3lIdx < m_pDiff3LineVector->size() && d3lIdx >= 0)
+ while(!line.isValid() && d3lIdx < mDiff3LineVector->size() && d3lIdx >= 0)
{
- const Diff3Line* d3l = (*m_pDiff3LineVector)[d3lIdx];
+ const Diff3Line* d3l = (*mDiff3LineVector)[d3lIdx];
if(m_winIdx == e_SrcSelector::A) line = d3l->getLineA();
if(m_winIdx == e_SrcSelector::B) line = d3l->getLineB();
if(m_winIdx == e_SrcSelector::C) line = d3l->getLineC();
diff --git a/src/gnudiff_diff.h b/src/gnudiff_diff.h
index 1d2b92fc..79aeb8c3 100644
--- a/src/gnudiff_diff.h
+++ b/src/gnudiff_diff.h
@@ -17,6 +17,8 @@
#include "LineRef.h"
#include "Utils.h"
+#include <QtGlobal>
+
#include <stdint.h>
#include <sys/stat.h>
#include <sys/types.h>
@@ -30,7 +32,6 @@
#include <stdio.h>
#include <QString>
-#include <QtGlobal>
/* The integer type of a line number. */
typedef qint64 GNULineRef;
diff --git a/src/kdiff3.h b/src/kdiff3.h
index f504f597..adcd5eb1 100644
--- a/src/kdiff3.h
+++ b/src/kdiff3.h
@@ -12,6 +12,7 @@
#include "diff.h"
#include "defmac.h"
#include "combiners.h"
+#include "TypeUtils.h"
#include <boost/signals2.hpp>
@@ -442,11 +443,11 @@ public Q_SLOTS:
QSharedPointer<DiffBufferInfo> m_diffBufferInfo = QSharedPointer<DiffBufferInfo>::create();
Diff3LineList m_diff3LineList;
- Diff3LineVector m_diff3LineVector;
+ Diff3LineVector mDiff3LineVector;
//ManualDiffHelpDialog* m_pManualDiffHelpDialog;
ManualDiffHelpList m_manualDiffHelpList;
- int m_neededLines;
+ SafeInt32<QtNumberType> m_neededLines;
int m_DTWHeight;
bool m_bOutputModified = false;
bool m_bFileSaved = false;
diff --git a/src/mergeresultwindow.cpp b/src/mergeresultwindow.cpp
index 3ebfcd21..c384fb12 100644
--- a/src/mergeresultwindow.cpp
+++ b/src/mergeresultwindow.cpp
@@ -2269,7 +2269,12 @@ void MergeResultWindow::keyPressEvent(QKeyEvent* e)
int y = m_cursorYPos;
MergeLineList::iterator mlIt;
MergeEditLineList::iterator melIt;
- calcIteratorFromLineNr(y, mlIt, melIt);
+ if(!calcIteratorFromLineNr(y, mlIt, melIt))
+ {
+ // no data loaded or y out of bounds
+ e->ignore();
+ return;
+ }
QString str = melIt->getString(m_pldA, m_pldB, m_pldC);
int x = m_cursorXPos;
@@ -2306,8 +2311,7 @@ void MergeResultWindow::keyPressEvent(QKeyEvent* e)
setModified();
MergeLineList::iterator mlIt1;
MergeEditLineList::iterator melIt1;
- calcIteratorFromLineNr(y + 1, mlIt1, melIt1);
- if(melIt1->isEditableText())
+ if(calcIteratorFromLineNr(y + 1, mlIt1, melIt1) && melIt1->isEditableText())
{
QString s2 = melIt1->getString(m_pldA, m_pldB, m_pldC);
melIt->setString(str + s2);
@@ -2339,8 +2343,7 @@ void MergeResultWindow::keyPressEvent(QKeyEvent* e)
setModified();
MergeLineList::iterator mlIt1;
MergeEditLineList::iterator melIt1;
- calcIteratorFromLineNr(y - 1, mlIt1, melIt1);
- if(melIt1->isEditableText())
+ if(calcIteratorFromLineNr(y - 1, mlIt1, melIt1) && melIt1->isEditableText())
{
QString s1 = melIt1->getString(m_pldA, m_pldB, m_pldC);
melIt1->setString(s1 + str);
@@ -2543,43 +2546,34 @@ void MergeResultWindow::keyPressEvent(QKeyEvent* e)
e->ignore();
return;
}
- else
+ if(!melIt->isEditableText()) break;
+ deleteSelection2(str, x, y, mlIt, melIt);
+
+ setModified();
+ // Characters to insert
+ QString s = str;
+ if(t[0] == '\t' && m_pOptions->m_bReplaceTabs)
{
- if(bCtrl)
- {
- e->ignore();
- return;
- }
- else
- {
- if(!melIt->isEditableText()) break;
- deleteSelection2(str, x, y, mlIt, melIt);
+ int spaces = (m_cursorXPos / m_pOptions->m_tabSize + 1) * m_pOptions->m_tabSize - m_cursorXPos;
+ t.fill(' ', spaces);
+ }
+ if(m_bInsertMode)
+ s.insert(x, t);
+ else
+ s.replace(x, t.length(), t);
- setModified();
- // Characters to insert
- QString s = str;
- if(t[0] == '\t' && m_pOptions->m_bReplaceTabs)
- {
- int spaces = (m_cursorXPos / m_pOptions->m_tabSize + 1) * m_pOptions->m_tabSize - m_cursorXPos;
- t.fill(' ', spaces);
- }
- if(m_bInsertMode)
- s.insert(x, t);
- else
- s.replace(x, t.length(), t);
+ melIt->setString(s);
+ x += t.length();
+ bShift = false;
+ } // default case
+ } // switch(e->key())
- melIt->setString(s);
- x += t.length();
- bShift = false;
- }
- }
- }
- }
y = qBound(0, y, m_nofLines - 1);
- calcIteratorFromLineNr(y, mlIt, melIt);
- str = melIt->getString(m_pldA, m_pldB, m_pldC);
+ str = calcIteratorFromLineNr(y, mlIt, melIt)
+ ? melIt->getString(m_pldA, m_pldB, m_pldC)
+ : QString();
x = qBound(0, x, (int)str.length());
@@ -2651,7 +2645,22 @@ void MergeResultWindow::keyPressEvent(QKeyEvent* e)
}
}
-void MergeResultWindow::calcIteratorFromLineNr(
+/**
+ * Determine MergeLine and MergeEditLine from line number
+ *
+ * @param line
+ * line number to look up
+ * @param[out] mlIt
+ * iterator to merge-line
+ * or m_mergeLineList.end() if not available
+ * @param[out] melIt
+ * iterator to MergeEditLine
+ * or mlIt->mergeEditLineList.end() if not available
+ * @warning uninitialized if mlIt is not available!
+ * @return whether line is available;
+ * when true, @p mlIt and @p melIt are set to valid iterators
+ */
+bool MergeResultWindow::calcIteratorFromLineNr(
int line,
MergeLineList::iterator& mlIt,
MergeEditLineList::iterator& melIt)
@@ -2668,10 +2677,11 @@ void MergeResultWindow::calcIteratorFromLineNr(
for(melIt = ml.mergeEditLineList.begin(); melIt != ml.mergeEditLineList.end(); ++melIt)
{
--line;
- if(line < 0) return;
+ if(line < 0) return true;
}
}
}
+ return false;
}
QString MergeResultWindow::getSelection()
@@ -2742,7 +2752,13 @@ bool MergeResultWindow::deleteSelection2(QString& s, int& x, int& y,
Q_ASSERT(m_selection.isValidFirstLine());
deleteSelection();
y = m_cursorYPos;
- calcIteratorFromLineNr(y, mlIt, melIt);
+ if(!calcIteratorFromLineNr(y, mlIt, melIt))
+ {
+ // deleteSelection() should never remove or empty the first line, so
+ // resolving m_cursorYPos shall always succeed
+ Q_ASSERT(false);
+ }
+
s = melIt->getString(m_pldA, m_pldB, m_pldC);
x = m_cursorXPos;
return true;
@@ -2860,7 +2876,10 @@ void MergeResultWindow::pasteClipboard(bool bFromSelection)
int y = m_cursorYPos;
MergeLineList::iterator mlIt;
MergeEditLineList::iterator melIt, melItAfter;
- calcIteratorFromLineNr(y, mlIt, melIt);
+ if (!calcIteratorFromLineNr(y, mlIt, melIt))
+ {
+ return;
+ }
melItAfter = melIt;
++melItAfter;
QString str = melIt->getString(m_pldA, m_pldB, m_pldC);
@@ -2964,6 +2983,9 @@ bool MergeResultWindow::saveDocument(const QString& fileName, QTextCodec* pEncod
textOutStream.setGenerateByteOrderMark(true); // Only for UTF-16
textOutStream.setCodec(pEncoding);
+ // Determine the line feed for this file
+ const QString lineFeed(eLineEndStyle == eLineEndStyleDos ? QString("\r\n") : QString("\n"));
+
int line = 0;
MergeLineList::iterator mlIt = m_mergeLineList.begin();
for(mlIt = m_mergeLineList.begin(); mlIt != m_mergeLineList.end(); ++mlIt)
@@ -2976,18 +2998,14 @@ bool MergeResultWindow::saveDocument(const QString& fileName, QTextCodec* pEncod
if(mel.isEditableText())
{
- QString str = mel.getString(m_pldA, m_pldB, m_pldC);
+ const QString str = mel.getString(m_pldA, m_pldB, m_pldC);
- if(line > 0) // Prepend line feed, but not for first line
+ if(line > 0 && !mel.isRemoved())
{
- if(eLineEndStyle == eLineEndStyleDos)
- {
- str.prepend("\r\n");
- }
- else
- {
- str.prepend("\n");
- }
+ // Put line feed between lines, but not for the first line
+ // or between lines that have been removed (because there
+ // isn't a line there).
+ textOutStream << lineFeed;
}
textOutStream << str;
@@ -3013,13 +3031,11 @@ QString MergeResultWindow::getString(int lineIdx)
{
MergeLineList::iterator mlIt;
MergeEditLineList::iterator melIt;
- if(m_mergeLineList.empty())
+ if(!calcIteratorFromLineNr(lineIdx, mlIt, melIt))
{
return QString();
}
- calcIteratorFromLineNr(lineIdx, mlIt, melIt);
- QString s = melIt->getString(m_pldA, m_pldB, m_pldC);
- return s;
+ return melIt->getString(m_pldA, m_pldB, m_pldC);
}
bool MergeResultWindow::findString(const QString& s, LineRef& d3vLine, int& posInLine, bool bDirDown, bool bCaseSensitive)
diff --git a/src/mergeresultwindow.h b/src/mergeresultwindow.h
index ad16db1e..91136d1e 100644
--- a/src/mergeresultwindow.h
+++ b/src/mergeresultwindow.h
@@ -216,7 +216,7 @@ class MergeResultWindow: public QWidget
eEnd
};
void go(e_Direction eDir, e_EndPoint eEndPoint);
- void calcIteratorFromLineNr(
+ bool calcIteratorFromLineNr(
int line,
MergeLineList::iterator& mlIt,
MergeEditLineList::iterator& melIt);
diff --git a/src/pdiff.cpp b/src/pdiff.cpp
index 389b69ec..ed1cc2fd 100644
--- a/src/pdiff.cpp
+++ b/src/pdiff.cpp
@@ -112,7 +112,7 @@ void KDiff3App::mainInit(TotalDiffStatus* pTotalDiffStatus, const InitFlags inFl
//insure merge result window never has stale iterators.
if(m_pMergeResultWindow) m_pMergeResultWindow->clearMergeList();
m_diff3LineList.clear();
- m_diff3LineVector.clear();
+ mDiff3LineVector.clear();
if(bLoadFiles)
{
@@ -309,18 +309,23 @@ void KDiff3App::mainInit(TotalDiffStatus* pTotalDiffStatus, const InitFlags inFl
if(errors.isEmpty() && m_sd1->isText() && m_sd2->isText())
{
- m_diffBufferInfo->init(&m_diff3LineList, &m_diff3LineVector,
+ m_diffBufferInfo->init(&m_diff3LineList,
m_sd1->getLineDataForDiff(), m_sd1->getSizeLines(),
m_sd2->getLineDataForDiff(), m_sd2->getSizeLines(),
m_sd3->getLineDataForDiff(), m_sd3->getSizeLines());
Diff3Line::m_pDiffBufferInfo = m_diffBufferInfo;
m_diff3LineList.calcWhiteDiff3Lines(m_sd1->getLineDataForDiff(), m_sd2->getLineDataForDiff(), m_sd3->getLineDataForDiff(), m_pOptions->ignoreComments());
- m_diff3LineList.calcDiff3LineVector(m_diff3LineVector);
+ m_diff3LineList.calcDiff3LineVector(mDiff3LineVector);
}
// Calc needed lines for display
- m_neededLines = m_diff3LineList.size();
+ if(m_diff3LineList.size() <= TYPE_MAX(QtNumberType))
+ m_neededLines = SafeInt32<QtNumberType>(m_diff3LineList.size());
+ else
+ {
+ errors.append("Too many lines in diff. Skiping file.");
+ }
QList<int> oldHeights;
if(m_pDirectoryMergeSplitter->isVisible())
@@ -360,15 +365,15 @@ void KDiff3App::mainInit(TotalDiffStatus* pTotalDiffStatus, const InitFlags inFl
{
const ManualDiffHelpList* pMDHL = &m_manualDiffHelpList;
m_pDiffTextWindow1->init(m_sd1->getAliasName(), m_sd1->getEncoding(), m_sd1->getLineEndStyle(),
- m_sd1->getLineDataForDisplay(), m_sd1->getSizeLines(), &m_diff3LineVector, pMDHL);
+ m_sd1->getLineDataForDisplay(), m_sd1->getSizeLines(), &mDiff3LineVector, pMDHL);
m_pDiffTextWindowFrame1->init();
m_pDiffTextWindow2->init(m_sd2->getAliasName(), m_sd2->getEncoding(), m_sd2->getLineEndStyle(),
- m_sd2->getLineDataForDisplay(), m_sd2->getSizeLines(), &m_diff3LineVector, pMDHL);
+ m_sd2->getLineDataForDisplay(), m_sd2->getSizeLines(), &mDiff3LineVector, pMDHL);
m_pDiffTextWindowFrame2->init();
m_pDiffTextWindow3->init(m_sd3->getAliasName(), m_sd3->getEncoding(), m_sd3->getLineEndStyle(),
- m_sd3->getLineDataForDisplay(), m_sd3->getSizeLines(), &m_diff3LineVector, pMDHL);
+ m_sd3->getLineDataForDisplay(), m_sd3->getSizeLines(), &mDiff3LineVector, pMDHL);
m_pDiffTextWindowFrame3->init();
m_pDiffTextWindowFrame3->setVisible(m_bTripleDiff);
@@ -501,7 +506,7 @@ void KDiff3App::resizeDiffTextWindowHeight(int newHeight)
{
m_DTWHeight = newHeight;
- DiffTextWindow::mVScrollBar->setRange(0, std::max(0, m_neededLines + 1 - newHeight));
+ DiffTextWindow::mVScrollBar->setRange(0, std::max(0, QtNumberType(m_neededLines + 1 - newHeight)));
DiffTextWindow::mVScrollBar->setPageStep(newHeight);
m_pOverview->setRange(DiffTextWindow::mVScrollBar->value(), DiffTextWindow::mVScrollBar->pageStep());
@@ -704,13 +709,13 @@ void KDiff3App::slotFinishMainInit()
/*int newWidth = m_pDiffTextWindow1->getNofVisibleColumns();*/
m_DTWHeight = newHeight;
- DiffTextWindow::mVScrollBar->setRange(0, std::max(0, m_neededLines + 1 - newHeight));
+ DiffTextWindow::mVScrollBar->setRange(0, std::max(0, QtNumberType(m_neededLines + 1 - newHeight)));
DiffTextWindow::mVScrollBar->setPageStep(newHeight);
m_pOverview->setRange(DiffTextWindow::mVScrollBar->value(), DiffTextWindow::mVScrollBar->pageStep());
int d3l = -1;
if(!m_manualDiffHelpList.empty())
- d3l = m_manualDiffHelpList.front().calcManualDiffFirstDiff3LineIdx(m_diff3LineVector);
+ d3l = m_manualDiffHelpList.front().calcManualDiffFirstDiff3LineIdx(mDiff3LineVector);
if(d3l >= 0 && m_pDiffTextWindow1)
{
int line = m_pDiffTextWindow1->convertDiff3LineIdxToLine(d3l);
@@ -1454,7 +1459,7 @@ void KDiff3App::recalcWordWrap(int visibleTextWidthForPrinting)
}
else
{
- m_neededLines = m_diff3LineVector.size();
+ m_neededLines = m_diff3LineList.size();
if(m_pDiffTextWindow1)
m_pDiffTextWindow1->recalcWordWrap(false, 0, 0);
if(m_pDiffTextWindow2)
@@ -1537,7 +1542,7 @@ void KDiff3App::slotFinishRecalcWordWrap(int visibleTextWidthForPrinting)
if(m_pOverview)
m_pOverview->slotRedraw();
if(DiffTextWindow::mVScrollBar)
- DiffTextWindow::mVScrollBar->setRange(0, std::max(0, m_neededLines + 1 - m_DTWHeight));
+ DiffTextWindow::mVScrollBar->setRange(0, std::max(0, QtNumberType(m_neededLines + 1 - m_DTWHeight)));
if(m_pDiffTextWindow1)
{
if(DiffTextWindow::mVScrollBar)
diff --git a/src/selection.cpp b/src/selection.cpp
index 5c4b8d99..20796340 100644
--- a/src/selection.cpp
+++ b/src/selection.cpp
@@ -7,12 +7,12 @@
*/
#include "selection.h"
-
#include "TypeUtils.h"
+#include <QtGlobal>
+
#include <utility> // for swap
-#include <QtGlobal>
int Selection::firstPosInLine(LineRef l) const
{
--
2.31.1