Full Code of google/diff-match-patch for AI

master 62f2e689f498 cached
80 files
1.6 MB
465.1k tokens
558 symbols
1 requests
Download .txt
Showing preview only (1,672K chars total). Download the full file or copy to clipboard to get everything.
Repository: google/diff-match-patch
Branch: master
Commit: 62f2e689f498
Files: 80
Total size: 1.6 MB

Directory structure:
gitextract_e25j56v0/

├── .gitignore
├── AUTHORS
├── CONTRIBUTING.md
├── LICENSE
├── README.md
├── cpp/
│   ├── diff_match_patch.cpp
│   ├── diff_match_patch.h
│   ├── diff_match_patch.pro
│   ├── diff_match_patch_test.cpp
│   └── diff_match_patch_test.h
├── csharp/
│   ├── DiffMatchPatch.cs
│   └── tests/
│       ├── DiffMatchPatchTest.cs
│       ├── Speedtest.cs
│       ├── Speedtest1.txt
│       └── Speedtest2.txt
├── dart/
│   ├── DMPClass.dart
│   ├── DiffClass.dart
│   ├── DiffMatchPatch.dart
│   ├── PatchClass.dart
│   └── tests/
│       ├── DiffMatchPatchTest.dart
│       ├── Speedtest.dart
│       ├── Speedtest.dart.js
│       ├── Speedtest.html
│       └── SpeedtestVM.dart
├── demos/
│   ├── diff.html
│   ├── match.html
│   └── patch.html
├── java/
│   ├── src/
│   │   └── name/
│   │       └── fraser/
│   │           └── neil/
│   │               └── plaintext/
│   │                   └── diff_match_patch.java
│   └── tests/
│       └── name/
│           └── fraser/
│               └── neil/
│                   └── plaintext/
│                       ├── Speedtest.java
│                       ├── Speedtest1.txt
│                       ├── Speedtest2.txt
│                       └── diff_match_patch_test.java
├── javascript/
│   ├── diff_match_patch.js
│   ├── diff_match_patch_uncompressed.js
│   └── tests/
│       ├── diff_match_patch_test.html
│       ├── diff_match_patch_test.js
│       └── speedtest.html
├── lua/
│   ├── diff_match_patch.lua
│   └── tests/
│       ├── diff_match_patch_test.lua
│       ├── speedtest.lua
│       ├── speedtest1.txt
│       └── speedtest2.txt
├── objectivec/
│   ├── DiffMatchPatch.h
│   ├── DiffMatchPatch.m
│   ├── DiffMatchPatch.xcodeproj/
│   │   ├── project.pbxproj
│   │   └── project.xcworkspace/
│   │       ├── contents.xcworkspacedata
│   │       └── xcshareddata/
│   │           └── WorkspaceSettings.xcsettings
│   ├── DiffMatchPatchCFUtilities.c
│   ├── DiffMatchPatchCFUtilities.h
│   ├── DiffMatchPatch_Prefix.pch
│   ├── English.lproj/
│   │   └── InfoPlist.strings
│   ├── Info.plist
│   ├── MinMaxMacros.h
│   ├── NSMutableDictionary+DMPExtensions.h
│   ├── NSMutableDictionary+DMPExtensions.m
│   ├── NSString+JavaSubstring.h
│   ├── NSString+JavaSubstring.m
│   ├── NSString+UnicharUtilities.h
│   ├── NSString+UnicharUtilities.m
│   ├── NSString+UriCompatibility.h
│   ├── NSString+UriCompatibility.m
│   ├── Tests/
│   │   ├── DiffMatchPatchTest-Info.plist
│   │   ├── DiffMatchPatchTest.h
│   │   ├── DiffMatchPatchTest.m
│   │   ├── Speedtest1.txt
│   │   ├── Speedtest2.txt
│   │   └── speedtest.m
│   └── speedtest_Prefix.pch
├── python2/
│   ├── __init__.py
│   ├── diff_match_patch.py
│   └── tests/
│       ├── diff_match_patch_test.py
│       ├── speedtest.py
│       ├── speedtest1.txt
│       └── speedtest2.txt
└── python3/
    ├── __init__.py
    ├── diff_match_patch.py
    └── tests/
        ├── diff_match_patch_test.py
        ├── speedtest.py
        ├── speedtest1.txt
        └── speedtest2.txt

================================================
FILE CONTENTS
================================================

================================================
FILE: .gitignore
================================================

*.class
*.exe
*.pyc
*.komodoproject

.DS_STORE
xcuserdata

dart/tests/Speedtest.dart.js.deps
dart/tests/Speedtest.dart.js.map


================================================
FILE: AUTHORS
================================================
# Below is a list of people and organizations that have contributed
# to the Diff Match Patch project.

Google Inc.

Duncan Cross <duncan.cross@gmail.com> (Lua port)
Jan Weiß <jan@geheimwerk.de> (Objective C port)
Matthaeus G. Chajdas <anteru@developer.shelter13.net> (C# port)
Mike Slemmer <mikeslemmer@gmail.com> (C++ port)



================================================
FILE: CONTRIBUTING.md
================================================
# How to Contribute

We'd love to accept your patches and contributions to this project. There are
just a few small guidelines you need to follow.

## Contributor License Agreement

Contributions to this project must be accompanied by a Contributor License
Agreement. You (or your employer) retain the copyright to your contribution,
this simply gives us permission to use and redistribute your contributions as
part of the project. Head over to <https://cla.developers.google.com/> to see
your current agreements on file or to sign a new one.

You generally only need to submit a CLA once, so if you've already submitted one
(even if it was for a different project), you probably don't need to do it
again.

## Code reviews

All submissions, including submissions by project members, require review. We
use GitHub pull requests for this purpose. Consult
[GitHub Help](https://help.github.com/articles/about-pull-requests/) for more
information on using pull requests.


================================================
FILE: LICENSE
================================================

                                 Apache License
                           Version 2.0, January 2004
                        http://www.apache.org/licenses/

   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION

   1. Definitions.

      "License" shall mean the terms and conditions for use, reproduction,
      and distribution as defined by Sections 1 through 9 of this document.

      "Licensor" shall mean the copyright owner or entity authorized by
      the copyright owner that is granting the License.

      "Legal Entity" shall mean the union of the acting entity and all
      other entities that control, are controlled by, or are under common
      control with that entity. For the purposes of this definition,
      "control" means (i) the power, direct or indirect, to cause the
      direction or management of such entity, whether by contract or
      otherwise, or (ii) ownership of fifty percent (50%) or more of the
      outstanding shares, or (iii) beneficial ownership of such entity.

      "You" (or "Your") shall mean an individual or Legal Entity
      exercising permissions granted by this License.

      "Source" form shall mean the preferred form for making modifications,
      including but not limited to software source code, documentation
      source, and configuration files.

      "Object" form shall mean any form resulting from mechanical
      transformation or translation of a Source form, including but
      not limited to compiled object code, generated documentation,
      and conversions to other media types.

      "Work" shall mean the work of authorship, whether in Source or
      Object form, made available under the License, as indicated by a
      copyright notice that is included in or attached to the work
      (an example is provided in the Appendix below).

      "Derivative Works" shall mean any work, whether in Source or Object
      form, that is based on (or derived from) the Work and for which the
      editorial revisions, annotations, elaborations, or other modifications
      represent, as a whole, an original work of authorship. For the purposes
      of this License, Derivative Works shall not include works that remain
      separable from, or merely link (or bind by name) to the interfaces of,
      the Work and Derivative Works thereof.

      "Contribution" shall mean any work of authorship, including
      the original version of the Work and any modifications or additions
      to that Work or Derivative Works thereof, that is intentionally
      submitted to Licensor for inclusion in the Work by the copyright owner
      or by an individual or Legal Entity authorized to submit on behalf of
      the copyright owner. For the purposes of this definition, "submitted"
      means any form of electronic, verbal, or written communication sent
      to the Licensor or its representatives, including but not limited to
      communication on electronic mailing lists, source code control systems,
      and issue tracking systems that are managed by, or on behalf of, the
      Licensor for the purpose of discussing and improving the Work, but
      excluding communication that is conspicuously marked or otherwise
      designated in writing by the copyright owner as "Not a Contribution."

      "Contributor" shall mean Licensor and any individual or Legal Entity
      on behalf of whom a Contribution has been received by Licensor and
      subsequently incorporated within the Work.

   2. Grant of Copyright License. Subject to the terms and conditions of
      this License, each Contributor hereby grants to You a perpetual,
      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
      copyright license to reproduce, prepare Derivative Works of,
      publicly display, publicly perform, sublicense, and distribute the
      Work and such Derivative Works in Source or Object form.

   3. Grant of Patent License. Subject to the terms and conditions of
      this License, each Contributor hereby grants to You a perpetual,
      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
      (except as stated in this section) patent license to make, have made,
      use, offer to sell, sell, import, and otherwise transfer the Work,
      where such license applies only to those patent claims licensable
      by such Contributor that are necessarily infringed by their
      Contribution(s) alone or by combination of their Contribution(s)
      with the Work to which such Contribution(s) was submitted. If You
      institute patent litigation against any entity (including a
      cross-claim or counterclaim in a lawsuit) alleging that the Work
      or a Contribution incorporated within the Work constitutes direct
      or contributory patent infringement, then any patent licenses
      granted to You under this License for that Work shall terminate
      as of the date such litigation is filed.

   4. Redistribution. You may reproduce and distribute copies of the
      Work or Derivative Works thereof in any medium, with or without
      modifications, and in Source or Object form, provided that You
      meet the following conditions:

      (a) You must give any other recipients of the Work or
          Derivative Works a copy of this License; and

      (b) You must cause any modified files to carry prominent notices
          stating that You changed the files; and

      (c) You must retain, in the Source form of any Derivative Works
          that You distribute, all copyright, patent, trademark, and
          attribution notices from the Source form of the Work,
          excluding those notices that do not pertain to any part of
          the Derivative Works; and

      (d) If the Work includes a "NOTICE" text file as part of its
          distribution, then any Derivative Works that You distribute must
          include a readable copy of the attribution notices contained
          within such NOTICE file, excluding those notices that do not
          pertain to any part of the Derivative Works, in at least one
          of the following places: within a NOTICE text file distributed
          as part of the Derivative Works; within the Source form or
          documentation, if provided along with the Derivative Works; or,
          within a display generated by the Derivative Works, if and
          wherever such third-party notices normally appear. The contents
          of the NOTICE file are for informational purposes only and
          do not modify the License. You may add Your own attribution
          notices within Derivative Works that You distribute, alongside
          or as an addendum to the NOTICE text from the Work, provided
          that such additional attribution notices cannot be construed
          as modifying the License.

      You may add Your own copyright statement to Your modifications and
      may provide additional or different license terms and conditions
      for use, reproduction, or distribution of Your modifications, or
      for any such Derivative Works as a whole, provided Your use,
      reproduction, and distribution of the Work otherwise complies with
      the conditions stated in this License.

   5. Submission of Contributions. Unless You explicitly state otherwise,
      any Contribution intentionally submitted for inclusion in the Work
      by You to the Licensor shall be under the terms and conditions of
      this License, without any additional terms or conditions.
      Notwithstanding the above, nothing herein shall supersede or modify
      the terms of any separate license agreement you may have executed
      with Licensor regarding such Contributions.

   6. Trademarks. This License does not grant permission to use the trade
      names, trademarks, service marks, or product names of the Licensor,
      except as required for reasonable and customary use in describing the
      origin of the Work and reproducing the content of the NOTICE file.

   7. Disclaimer of Warranty. Unless required by applicable law or
      agreed to in writing, Licensor provides the Work (and each
      Contributor provides its Contributions) on an "AS IS" BASIS,
      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
      implied, including, without limitation, any warranties or conditions
      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
      PARTICULAR PURPOSE. You are solely responsible for determining the
      appropriateness of using or redistributing the Work and assume any
      risks associated with Your exercise of permissions under this License.

   8. Limitation of Liability. In no event and under no legal theory,
      whether in tort (including negligence), contract, or otherwise,
      unless required by applicable law (such as deliberate and grossly
      negligent acts) or agreed to in writing, shall any Contributor be
      liable to You for damages, including any direct, indirect, special,
      incidental, or consequential damages of any character arising as a
      result of this License or out of the use or inability to use the
      Work (including but not limited to damages for loss of goodwill,
      work stoppage, computer failure or malfunction, or any and all
      other commercial damages or losses), even if such Contributor
      has been advised of the possibility of such damages.

   9. Accepting Warranty or Additional Liability. While redistributing
      the Work or Derivative Works thereof, You may choose to offer,
      and charge a fee for, acceptance of support, warranty, indemnity,
      or other liability obligations and/or rights consistent with this
      License. However, in accepting such obligations, You may act only
      on Your own behalf and on Your sole responsibility, not on behalf
      of any other Contributor, and only if You agree to indemnify,
      defend, and hold each Contributor harmless for any liability
      incurred by, or claims asserted against, such Contributor by reason
      of your accepting any such warranty or additional liability.

   END OF TERMS AND CONDITIONS

   APPENDIX: How to apply the Apache License to your work.

      To apply the Apache License to your work, attach the following
      boilerplate notice, with the fields enclosed by brackets "[]"
      replaced with your own identifying information. (Don't include
      the brackets!)  The text should be enclosed in the appropriate
      comment syntax for the file format. We also recommend that a
      file or class name and description of purpose be included on the
      same "printed page" as the copyright notice for easier
      identification within third-party archives.

   Copyright [yyyy] [name of copyright owner]

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.


================================================
FILE: README.md
================================================
The Diff Match and Patch libraries offer robust algorithms to perform the
operations required for synchronizing plain text.

1. Diff:
   * Compare two blocks of plain text and efficiently return a list of differences.
   * [Diff Demo](https://neil.fraser.name/software/diff_match_patch/demos/diff.html)
2. Match:
   * Given a search string, find its best fuzzy match in a block of plain text. Weighted for both accuracy and location.
   * [Match Demo](https://neil.fraser.name/software/diff_match_patch/demos/match.html)
3. Patch:
   * Apply a list of patches onto plain text. Use best-effort to apply patch even when the underlying text doesn't match.
   * [Patch Demo](https://neil.fraser.name/software/diff_match_patch/demos/patch.html)

Originally built in 2006 to power Google Docs, this library is now available in C++, C#, Dart, Java, JavaScript, Lua, Objective C, and Python.

### Reference

* [API](https://github.com/google/diff-match-patch/wiki/API) - Common API across all languages.
* [Line or Word Diffs](https://github.com/google/diff-match-patch/wiki/Line-or-Word-Diffs) - Less detailed diffs.
* [Plain Text vs. Structured Content](https://github.com/google/diff-match-patch/wiki/Plain-Text-vs.-Structured-Content) - How to deal with data like XML.
* [Unidiff](https://github.com/google/diff-match-patch/wiki/Unidiff) - The patch serialization format.
* [Support](https://groups.google.com/forum/#!forum/diff-match-patch) - Newsgroup for developers.

### Languages
Although each language port of Diff Match Patch uses the same API, there are some language-specific notes.

* [C++](https://github.com/google/diff-match-patch/wiki/Language:-Cpp)
* [C#](https://github.com/google/diff-match-patch/wiki/Language:-C%23)
* [Dart](https://github.com/google/diff-match-patch/wiki/Language:-Dart)
* [Java](https://github.com/google/diff-match-patch/wiki/Language:-Java)
* [JavaScript](https://github.com/google/diff-match-patch/wiki/Language:-JavaScript)
* [Lua](https://github.com/google/diff-match-patch/wiki/Language:-Lua)
* [Objective-C](https://github.com/google/diff-match-patch/wiki/Language:-Objective-C)
* [Python](https://github.com/google/diff-match-patch/wiki/Language:-Python)

A standardized speed test tracks the [relative performance of diffs](https://docs.google.com/spreadsheets/d/1zpZccuBpjMZTvL1nGDMKJc7rWL_m_drF4XKOJvB27Kc/edit#gid=0) in each language.

### Algorithms
This library implements [Myer's diff algorithm](https://neil.fraser.name/writing/diff/myers.pdf) which is generally considered to be the best general-purpose diff. A layer of [pre-diff speedups and post-diff cleanups](https://neil.fraser.name/writing/diff/) surround the diff algorithm, improving both performance and output quality.

This library also implements a [Bitap matching algorithm](https://neil.fraser.name/writing/patch/bitap.ps) at the heart of a [flexible matching and patching strategy](https://neil.fraser.name/writing/patch/).


================================================
FILE: cpp/diff_match_patch.cpp
================================================
/*
 * Diff Match and Patch
 * Copyright 2018 The diff-match-patch Authors.
 * https://github.com/google/diff-match-patch
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <algorithm>
#include <limits>
// Code known to compile and run with Qt 4.3 through Qt 4.7.
#include <QtCore>
#include <time.h>
#include "diff_match_patch.h"


//////////////////////////
//
// Diff Class
//
//////////////////////////


/**
 * Constructor.  Initializes the diff with the provided values.
 * @param operation One of INSERT, DELETE or EQUAL
 * @param text The text being applied
 */
Diff::Diff(Operation _operation, const QString &_text) :
  operation(_operation), text(_text) {
  // Construct a diff with the specified operation and text.
}

Diff::Diff() {
}


QString Diff::strOperation(Operation op) {
  switch (op) {
    case INSERT:
      return "INSERT";
    case DELETE:
      return "DELETE";
    case EQUAL:
      return "EQUAL";
  }
  throw "Invalid operation.";
}

/**
 * Display a human-readable version of this Diff.
 * @return text version
 */
QString Diff::toString() const {
  QString prettyText = text;
  // Replace linebreaks with Pilcrow signs.
  prettyText.replace('\n', L'\u00b6');
  return QString("Diff(") + strOperation(operation) + QString(",\"")
      + prettyText + QString("\")");
}

/**
 * Is this Diff equivalent to another Diff?
 * @param d Another Diff to compare against
 * @return true or false
 */
bool Diff::operator==(const Diff &d) const {
  return (d.operation == this->operation) && (d.text == this->text);
}

bool Diff::operator!=(const Diff &d) const {
  return !(operator == (d));
}


/////////////////////////////////////////////
//
// Patch Class
//
/////////////////////////////////////////////


/**
 * Constructor.  Initializes with an empty list of diffs.
 */
Patch::Patch() :
  start1(0), start2(0),
  length1(0), length2(0) {
}

bool Patch::isNull() const {
  if (start1 == 0 && start2 == 0 && length1 == 0 && length2 == 0
      && diffs.size() == 0) {
    return true;
  }
  return false;
}


/**
 * Emulate GNU diff's format.
 * Header: @@ -382,8 +481,9 @@
 * Indices are printed as 1-based, not 0-based.
 * @return The GNU diff string
 */
QString Patch::toString() {
  QString coords1, coords2;
  if (length1 == 0) {
    coords1 = QString::number(start1) + QString(",0");
  } else if (length1 == 1) {
    coords1 = QString::number(start1 + 1);
  } else {
    coords1 = QString::number(start1 + 1) + QString(",")
        + QString::number(length1);
  }
  if (length2 == 0) {
    coords2 = QString::number(start2) + QString(",0");
  } else if (length2 == 1) {
    coords2 = QString::number(start2 + 1);
  } else {
    coords2 = QString::number(start2 + 1) + QString(",")
        + QString::number(length2);
  }
  QString text;
  text = QString("@@ -") + coords1 + QString(" +") + coords2
      + QString(" @@\n");
  // Escape the body of the patch with %xx notation.
  foreach (Diff aDiff, diffs) {
    switch (aDiff.operation) {
      case INSERT:
        text += QString('+');
        break;
      case DELETE:
        text += QString('-');
        break;
      case EQUAL:
        text += QString(' ');
        break;
    }
    text += QString(QUrl::toPercentEncoding(aDiff.text, " !~*'();/?:@&=+$,#"))
        + QString("\n");
  }

  return text;
}


/////////////////////////////////////////////
//
// diff_match_patch Class
//
/////////////////////////////////////////////

diff_match_patch::diff_match_patch() :
  Diff_Timeout(1.0f),
  Diff_EditCost(4),
  Match_Threshold(0.5f),
  Match_Distance(1000),
  Patch_DeleteThreshold(0.5f),
  Patch_Margin(4),
  Match_MaxBits(32) {
}


QList<Diff> diff_match_patch::diff_main(const QString &text1,
                                        const QString &text2) {
  return diff_main(text1, text2, true);
}

QList<Diff> diff_match_patch::diff_main(const QString &text1,
    const QString &text2, bool checklines) {
  // Set a deadline by which time the diff must be complete.
  clock_t deadline;
  if (Diff_Timeout <= 0) {
    deadline = std::numeric_limits<clock_t>::max();
  } else {
    deadline = clock() + (clock_t)(Diff_Timeout * CLOCKS_PER_SEC);
  }
  return diff_main(text1, text2, checklines, deadline);
}

QList<Diff> diff_match_patch::diff_main(const QString &text1,
    const QString &text2, bool checklines, clock_t deadline) {
  // Check for null inputs.
  if (text1.isNull() || text2.isNull()) {
    throw "Null inputs. (diff_main)";
  }

  // Check for equality (speedup).
  QList<Diff> diffs;
  if (text1 == text2) {
    if (!text1.isEmpty()) {
      diffs.append(Diff(EQUAL, text1));
    }
    return diffs;
  }

  // Trim off common prefix (speedup).
  int commonlength = diff_commonPrefix(text1, text2);
  const QString &commonprefix = text1.left(commonlength);
  QString textChopped1 = text1.mid(commonlength);
  QString textChopped2 = text2.mid(commonlength);

  // Trim off common suffix (speedup).
  commonlength = diff_commonSuffix(textChopped1, textChopped2);
  const QString &commonsuffix = textChopped1.right(commonlength);
  textChopped1 = textChopped1.left(textChopped1.length() - commonlength);
  textChopped2 = textChopped2.left(textChopped2.length() - commonlength);

  // Compute the diff on the middle block.
  diffs = diff_compute(textChopped1, textChopped2, checklines, deadline);

  // Restore the prefix and suffix.
  if (!commonprefix.isEmpty()) {
    diffs.prepend(Diff(EQUAL, commonprefix));
  }
  if (!commonsuffix.isEmpty()) {
    diffs.append(Diff(EQUAL, commonsuffix));
  }

  diff_cleanupMerge(diffs);

  return diffs;
}


QList<Diff> diff_match_patch::diff_compute(QString text1, QString text2,
    bool checklines, clock_t deadline) {
  QList<Diff> diffs;

  if (text1.isEmpty()) {
    // Just add some text (speedup).
    diffs.append(Diff(INSERT, text2));
    return diffs;
  }

  if (text2.isEmpty()) {
    // Just delete some text (speedup).
    diffs.append(Diff(DELETE, text1));
    return diffs;
  }

  {
    const QString longtext = text1.length() > text2.length() ? text1 : text2;
    const QString shorttext = text1.length() > text2.length() ? text2 : text1;
    const int i = longtext.indexOf(shorttext);
    if (i != -1) {
      // Shorter text is inside the longer text (speedup).
      const Operation op = (text1.length() > text2.length()) ? DELETE : INSERT;
      diffs.append(Diff(op, longtext.left(i)));
      diffs.append(Diff(EQUAL, shorttext));
      diffs.append(Diff(op, safeMid(longtext, i + shorttext.length())));
      return diffs;
    }

    if (shorttext.length() == 1) {
      // Single character string.
      // After the previous speedup, the character can't be an equality.
      diffs.append(Diff(DELETE, text1));
      diffs.append(Diff(INSERT, text2));
      return diffs;
    }
    // Garbage collect longtext and shorttext by scoping out.
  }

  // Check to see if the problem can be split in two.
  const QStringList hm = diff_halfMatch(text1, text2);
  if (hm.count() > 0) {
    // A half-match was found, sort out the return data.
    const QString text1_a = hm[0];
    const QString text1_b = hm[1];
    const QString text2_a = hm[2];
    const QString text2_b = hm[3];
    const QString mid_common = hm[4];
    // Send both pairs off for separate processing.
    const QList<Diff> diffs_a = diff_main(text1_a, text2_a,
                                          checklines, deadline);
    const QList<Diff> diffs_b = diff_main(text1_b, text2_b,
                                          checklines, deadline);
    // Merge the results.
    diffs = diffs_a;
    diffs.append(Diff(EQUAL, mid_common));
    diffs += diffs_b;
    return diffs;
  }

  // Perform a real diff.
  if (checklines && text1.length() > 100 && text2.length() > 100) {
    return diff_lineMode(text1, text2, deadline);
  }

  return diff_bisect(text1, text2, deadline);
}


QList<Diff> diff_match_patch::diff_lineMode(QString text1, QString text2,
    clock_t deadline) {
  // Scan the text on a line-by-line basis first.
  const QList<QVariant> b = diff_linesToChars(text1, text2);
  text1 = b[0].toString();
  text2 = b[1].toString();
  QStringList linearray = b[2].toStringList();

  QList<Diff> diffs = diff_main(text1, text2, false, deadline);

  // Convert the diff back to original text.
  diff_charsToLines(diffs, linearray);
  // Eliminate freak matches (e.g. blank lines)
  diff_cleanupSemantic(diffs);

  // Rediff any replacement blocks, this time character-by-character.
  // Add a dummy entry at the end.
  diffs.append(Diff(EQUAL, ""));
  int count_delete = 0;
  int count_insert = 0;
  QString text_delete = "";
  QString text_insert = "";

  QMutableListIterator<Diff> pointer(diffs);
  Diff *thisDiff = pointer.hasNext() ? &pointer.next() : NULL;
  while (thisDiff != NULL) {
    switch (thisDiff->operation) {
      case INSERT:
        count_insert++;
        text_insert += thisDiff->text;
        break;
      case DELETE:
        count_delete++;
        text_delete += thisDiff->text;
        break;
      case EQUAL:
        // Upon reaching an equality, check for prior redundancies.
        if (count_delete >= 1 && count_insert >= 1) {
          // Delete the offending records and add the merged ones.
          pointer.previous();
          for (int j = 0; j < count_delete + count_insert; j++) {
            pointer.previous();
            pointer.remove();
          }
          foreach(Diff newDiff,
              diff_main(text_delete, text_insert, false, deadline)) {
            pointer.insert(newDiff);
          }
        }
        count_insert = 0;
        count_delete = 0;
        text_delete = "";
        text_insert = "";
        break;
    }
    thisDiff = pointer.hasNext() ? &pointer.next() : NULL;
  }
  diffs.removeLast();  // Remove the dummy entry at the end.

  return diffs;
}


QList<Diff> diff_match_patch::diff_bisect(const QString &text1,
    const QString &text2, clock_t deadline) {
  // Cache the text lengths to prevent multiple calls.
  const int text1_length = text1.length();
  const int text2_length = text2.length();
  const int max_d = (text1_length + text2_length + 1) / 2;
  const int v_offset = max_d;
  const int v_length = 2 * max_d;
  int *v1 = new int[v_length];
  int *v2 = new int[v_length];
  for (int x = 0; x < v_length; x++) {
    v1[x] = -1;
    v2[x] = -1;
  }
  v1[v_offset + 1] = 0;
  v2[v_offset + 1] = 0;
  const int delta = text1_length - text2_length;
  // If the total number of characters is odd, then the front path will
  // collide with the reverse path.
  const bool front = (delta % 2 != 0);
  // Offsets for start and end of k loop.
  // Prevents mapping of space beyond the grid.
  int k1start = 0;
  int k1end = 0;
  int k2start = 0;
  int k2end = 0;
  for (int d = 0; d < max_d; d++) {
    // Bail out if deadline is reached.
    if (clock() > deadline) {
      break;
    }

    // Walk the front path one step.
    for (int k1 = -d + k1start; k1 <= d - k1end; k1 += 2) {
      const int k1_offset = v_offset + k1;
      int x1;
      if (k1 == -d || (k1 != d && v1[k1_offset - 1] < v1[k1_offset + 1])) {
        x1 = v1[k1_offset + 1];
      } else {
        x1 = v1[k1_offset - 1] + 1;
      }
      int y1 = x1 - k1;
      while (x1 < text1_length && y1 < text2_length
          && text1[x1] == text2[y1]) {
        x1++;
        y1++;
      }
      v1[k1_offset] = x1;
      if (x1 > text1_length) {
        // Ran off the right of the graph.
        k1end += 2;
      } else if (y1 > text2_length) {
        // Ran off the bottom of the graph.
        k1start += 2;
      } else if (front) {
        int k2_offset = v_offset + delta - k1;
        if (k2_offset >= 0 && k2_offset < v_length && v2[k2_offset] != -1) {
          // Mirror x2 onto top-left coordinate system.
          int x2 = text1_length - v2[k2_offset];
          if (x1 >= x2) {
            // Overlap detected.
            delete [] v1;
            delete [] v2;
            return diff_bisectSplit(text1, text2, x1, y1, deadline);
          }
        }
      }
    }

    // Walk the reverse path one step.
    for (int k2 = -d + k2start; k2 <= d - k2end; k2 += 2) {
      const int k2_offset = v_offset + k2;
      int x2;
      if (k2 == -d || (k2 != d && v2[k2_offset - 1] < v2[k2_offset + 1])) {
        x2 = v2[k2_offset + 1];
      } else {
        x2 = v2[k2_offset - 1] + 1;
      }
      int y2 = x2 - k2;
      while (x2 < text1_length && y2 < text2_length
          && text1[text1_length - x2 - 1] == text2[text2_length - y2 - 1]) {
        x2++;
        y2++;
      }
      v2[k2_offset] = x2;
      if (x2 > text1_length) {
        // Ran off the left of the graph.
        k2end += 2;
      } else if (y2 > text2_length) {
        // Ran off the top of the graph.
        k2start += 2;
      } else if (!front) {
        int k1_offset = v_offset + delta - k2;
        if (k1_offset >= 0 && k1_offset < v_length && v1[k1_offset] != -1) {
          int x1 = v1[k1_offset];
          int y1 = v_offset + x1 - k1_offset;
          // Mirror x2 onto top-left coordinate system.
          x2 = text1_length - x2;
          if (x1 >= x2) {
            // Overlap detected.
            delete [] v1;
            delete [] v2;
            return diff_bisectSplit(text1, text2, x1, y1, deadline);
          }
        }
      }
    }
  }
  delete [] v1;
  delete [] v2;
  // Diff took too long and hit the deadline or
  // number of diffs equals number of characters, no commonality at all.
  QList<Diff> diffs;
  diffs.append(Diff(DELETE, text1));
  diffs.append(Diff(INSERT, text2));
  return diffs;
}

QList<Diff> diff_match_patch::diff_bisectSplit(const QString &text1,
    const QString &text2, int x, int y, clock_t deadline) {
  QString text1a = text1.left(x);
  QString text2a = text2.left(y);
  QString text1b = safeMid(text1, x);
  QString text2b = safeMid(text2, y);

  // Compute both diffs serially.
  QList<Diff> diffs = diff_main(text1a, text2a, false, deadline);
  QList<Diff> diffsb = diff_main(text1b, text2b, false, deadline);

  return diffs + diffsb;
}

QList<QVariant> diff_match_patch::diff_linesToChars(const QString &text1,
                                                    const QString &text2) {
  QStringList lineArray;
  QMap<QString, int> lineHash;
  // e.g. linearray[4] == "Hello\n"
  // e.g. linehash.get("Hello\n") == 4

  // "\x00" is a valid character, but various debuggers don't like it.
  // So we'll insert a junk entry to avoid generating a null character.
  lineArray.append("");

  const QString chars1 = diff_linesToCharsMunge(text1, lineArray, lineHash);
  const QString chars2 = diff_linesToCharsMunge(text2, lineArray, lineHash);

  QList<QVariant> listRet;
  listRet.append(QVariant::fromValue(chars1));
  listRet.append(QVariant::fromValue(chars2));
  listRet.append(QVariant::fromValue(lineArray));
  return listRet;
}


QString diff_match_patch::diff_linesToCharsMunge(const QString &text,
                                                 QStringList &lineArray,
                                                 QMap<QString, int> &lineHash) {
  int lineStart = 0;
  int lineEnd = -1;
  QString line;
  QString chars;
  // Walk the text, pulling out a substring for each line.
  // text.split('\n') would would temporarily double our memory footprint.
  // Modifying text would create many large strings to garbage collect.
  while (lineEnd < text.length() - 1) {
    lineEnd = text.indexOf('\n', lineStart);
    if (lineEnd == -1) {
      lineEnd = text.length() - 1;
    }
    line = safeMid(text, lineStart, lineEnd + 1 - lineStart);
    lineStart = lineEnd + 1;

    if (lineHash.contains(line)) {
      chars += QChar(static_cast<ushort>(lineHash.value(line)));
    } else {
      lineArray.append(line);
      lineHash.insert(line, lineArray.size() - 1);
      chars += QChar(static_cast<ushort>(lineArray.size() - 1));
    }
  }
  return chars;
}



void diff_match_patch::diff_charsToLines(QList<Diff> &diffs,
                                         const QStringList &lineArray) {
  // Qt has no mutable foreach construct.
  QMutableListIterator<Diff> i(diffs);
  while (i.hasNext()) {
    Diff &diff = i.next();
    QString text;
    for (int y = 0; y < diff.text.length(); y++) {
      text += lineArray.value(static_cast<ushort>(diff.text[y].unicode()));
    }
    diff.text = text;
  }
}


int diff_match_patch::diff_commonPrefix(const QString &text1,
                                        const QString &text2) {
  // Performance analysis: http://neil.fraser.name/news/2007/10/09/
  const int n = std::min(text1.length(), text2.length());
  for (int i = 0; i < n; i++) {
    if (text1[i] != text2[i]) {
      return i;
    }
  }
  return n;
}


int diff_match_patch::diff_commonSuffix(const QString &text1,
                                        const QString &text2) {
  // Performance analysis: http://neil.fraser.name/news/2007/10/09/
  const int text1_length = text1.length();
  const int text2_length = text2.length();
  const int n = std::min(text1_length, text2_length);
  for (int i = 1; i <= n; i++) {
    if (text1[text1_length - i] != text2[text2_length - i]) {
      return i - 1;
    }
  }
  return n;
}

int diff_match_patch::diff_commonOverlap(const QString &text1,
                                         const QString &text2) {
  // Cache the text lengths to prevent multiple calls.
  const int text1_length = text1.length();
  const int text2_length = text2.length();
  // Eliminate the null case.
  if (text1_length == 0 || text2_length == 0) {
    return 0;
  }
  // Truncate the longer string.
  QString text1_trunc = text1;
  QString text2_trunc = text2;
  if (text1_length > text2_length) {
    text1_trunc = text1.right(text2_length);
  } else if (text1_length < text2_length) {
    text2_trunc = text2.left(text1_length);
  }
  const int text_length = std::min(text1_length, text2_length);
  // Quick check for the worst case.
  if (text1_trunc == text2_trunc) {
    return text_length;
  }

  // Start by looking for a single character match
  // and increase length until no match is found.
  // Performance analysis: http://neil.fraser.name/news/2010/11/04/
  int best = 0;
  int length = 1;
  while (true) {
    QString pattern = text1_trunc.right(length);
    int found = text2_trunc.indexOf(pattern);
    if (found == -1) {
      return best;
    }
    length += found;
    if (found == 0 || text1_trunc.right(length) == text2_trunc.left(length)) {
      best = length;
      length++;
    }
  }
}

QStringList diff_match_patch::diff_halfMatch(const QString &text1,
                                             const QString &text2) {
  if (Diff_Timeout <= 0) {
    // Don't risk returning a non-optimal diff if we have unlimited time.
    return QStringList();
  }
  const QString longtext = text1.length() > text2.length() ? text1 : text2;
  const QString shorttext = text1.length() > text2.length() ? text2 : text1;
  if (longtext.length() < 4 || shorttext.length() * 2 < longtext.length()) {
    return QStringList();  // Pointless.
  }

  // First check if the second quarter is the seed for a half-match.
  const QStringList hm1 = diff_halfMatchI(longtext, shorttext,
      (longtext.length() + 3) / 4);
  // Check again based on the third quarter.
  const QStringList hm2 = diff_halfMatchI(longtext, shorttext,
      (longtext.length() + 1) / 2);
  QStringList hm;
  if (hm1.isEmpty() && hm2.isEmpty()) {
    return QStringList();
  } else if (hm2.isEmpty()) {
    hm = hm1;
  } else if (hm1.isEmpty()) {
    hm = hm2;
  } else {
    // Both matched.  Select the longest.
    hm = hm1[4].length() > hm2[4].length() ? hm1 : hm2;
  }

  // A half-match was found, sort out the return data.
  if (text1.length() > text2.length()) {
    return hm;
  } else {
    QStringList listRet;
    listRet << hm[2] << hm[3] << hm[0] << hm[1] << hm[4];
    return listRet;
  }
}


QStringList diff_match_patch::diff_halfMatchI(const QString &longtext,
                                              const QString &shorttext,
                                              int i) {
  // Start with a 1/4 length substring at position i as a seed.
  const QString seed = safeMid(longtext, i, longtext.length() / 4);
  int j = -1;
  QString best_common;
  QString best_longtext_a, best_longtext_b;
  QString best_shorttext_a, best_shorttext_b;
  while ((j = shorttext.indexOf(seed, j + 1)) != -1) {
    const int prefixLength = diff_commonPrefix(safeMid(longtext, i),
        safeMid(shorttext, j));
    const int suffixLength = diff_commonSuffix(longtext.left(i),
        shorttext.left(j));
    if (best_common.length() < suffixLength + prefixLength) {
      best_common = safeMid(shorttext, j - suffixLength, suffixLength)
          + safeMid(shorttext, j, prefixLength);
      best_longtext_a = longtext.left(i - suffixLength);
      best_longtext_b = safeMid(longtext, i + prefixLength);
      best_shorttext_a = shorttext.left(j - suffixLength);
      best_shorttext_b = safeMid(shorttext, j + prefixLength);
    }
  }
  if (best_common.length() * 2 >= longtext.length()) {
    QStringList listRet;
    listRet << best_longtext_a << best_longtext_b << best_shorttext_a
        << best_shorttext_b << best_common;
    return listRet;
  } else {
    return QStringList();
  }
}


void diff_match_patch::diff_cleanupSemantic(QList<Diff> &diffs) {
  if (diffs.isEmpty()) {
    return;
  }
  bool changes = false;
  QStack<Diff> equalities;  // Stack of equalities.
  QString lastequality;  // Always equal to equalities.lastElement().text
  QMutableListIterator<Diff> pointer(diffs);
  // Number of characters that changed prior to the equality.
  int length_insertions1 = 0;
  int length_deletions1 = 0;
  // Number of characters that changed after the equality.
  int length_insertions2 = 0;
  int length_deletions2 = 0;
  Diff *thisDiff = pointer.hasNext() ? &pointer.next() : NULL;
  while (thisDiff != NULL) {
    if (thisDiff->operation == EQUAL) {
      // Equality found.
      equalities.push(*thisDiff);
      length_insertions1 = length_insertions2;
      length_deletions1 = length_deletions2;
      length_insertions2 = 0;
      length_deletions2 = 0;
      lastequality = thisDiff->text;
    } else {
      // An insertion or deletion.
      if (thisDiff->operation == INSERT) {
        length_insertions2 += thisDiff->text.length();
      } else {
        length_deletions2 += thisDiff->text.length();
      }
      // Eliminate an equality that is smaller or equal to the edits on both
      // sides of it.
      if (!lastequality.isNull()
          && (lastequality.length()
              <= std::max(length_insertions1, length_deletions1))
          && (lastequality.length()
              <= std::max(length_insertions2, length_deletions2))) {
        // printf("Splitting: '%s'\n", qPrintable(lastequality));
        // Walk back to offending equality.
        while (*thisDiff != equalities.top()) {
          thisDiff = &pointer.previous();
        }
        pointer.next();

        // Replace equality with a delete.
        pointer.setValue(Diff(DELETE, lastequality));
        // Insert a corresponding an insert.
        pointer.insert(Diff(INSERT, lastequality));

        equalities.pop();  // Throw away the equality we just deleted.
        if (!equalities.isEmpty()) {
          // Throw away the previous equality (it needs to be reevaluated).
          equalities.pop();
        }
        if (equalities.isEmpty()) {
          // There are no previous equalities, walk back to the start.
          while (pointer.hasPrevious()) {
            pointer.previous();
          }
        } else {
          // There is a safe equality we can fall back to.
          thisDiff = &equalities.top();
          while (*thisDiff != pointer.previous()) {
            // Intentionally empty loop.
          }
        }

        length_insertions1 = 0;  // Reset the counters.
        length_deletions1 = 0;
        length_insertions2 = 0;
        length_deletions2 = 0;
        lastequality = QString();
        changes = true;
      }
    }
    thisDiff = pointer.hasNext() ? &pointer.next() : NULL;
  }

  // Normalize the diff.
  if (changes) {
    diff_cleanupMerge(diffs);
  }
  diff_cleanupSemanticLossless(diffs);

  // Find any overlaps between deletions and insertions.
  // e.g: <del>abcxxx</del><ins>xxxdef</ins>
  //   -> <del>abc</del>xxx<ins>def</ins>
  // e.g: <del>xxxabc</del><ins>defxxx</ins>
  //   -> <ins>def</ins>xxx<del>abc</del>
  // Only extract an overlap if it is as big as the edit ahead or behind it.
  pointer.toFront();
  Diff *prevDiff = NULL;
  thisDiff = NULL;
  if (pointer.hasNext()) {
    prevDiff = &pointer.next();
    if (pointer.hasNext()) {
      thisDiff = &pointer.next();
    }
  }
  while (thisDiff != NULL) {
    if (prevDiff->operation == DELETE &&
        thisDiff->operation == INSERT) {
      QString deletion = prevDiff->text;
      QString insertion = thisDiff->text;
      int overlap_length1 = diff_commonOverlap(deletion, insertion);
      int overlap_length2 = diff_commonOverlap(insertion, deletion);
      if (overlap_length1 >= overlap_length2) {
        if (overlap_length1 >= deletion.length() / 2.0 ||
            overlap_length1 >= insertion.length() / 2.0) {
          // Overlap found.  Insert an equality and trim the surrounding edits.
          pointer.previous();
          pointer.insert(Diff(EQUAL, insertion.left(overlap_length1)));
          prevDiff->text =
              deletion.left(deletion.length() - overlap_length1);
          thisDiff->text = safeMid(insertion, overlap_length1);
          // pointer.insert inserts the element before the cursor, so there is
          // no need to step past the new element.
        }
      } else {
        if (overlap_length2 >= deletion.length() / 2.0 ||
            overlap_length2 >= insertion.length() / 2.0) {
          // Reverse overlap found.
          // Insert an equality and swap and trim the surrounding edits.
          pointer.previous();
          pointer.insert(Diff(EQUAL, deletion.left(overlap_length2)));
          prevDiff->operation = INSERT;
          prevDiff->text =
              insertion.left(insertion.length() - overlap_length2);
          thisDiff->operation = DELETE;
          thisDiff->text = safeMid(deletion, overlap_length2);
          // pointer.insert inserts the element before the cursor, so there is
          // no need to step past the new element.
        }
      }
      thisDiff = pointer.hasNext() ? &pointer.next() : NULL;
    }
    prevDiff = thisDiff;
    thisDiff = pointer.hasNext() ? &pointer.next() : NULL;
  }
}


void diff_match_patch::diff_cleanupSemanticLossless(QList<Diff> &diffs) {
  QString equality1, edit, equality2;
  QString commonString;
  int commonOffset;
  int score, bestScore;
  QString bestEquality1, bestEdit, bestEquality2;
  // Create a new iterator at the start.
  QMutableListIterator<Diff> pointer(diffs);
  Diff *prevDiff = pointer.hasNext() ? &pointer.next() : NULL;
  Diff *thisDiff = pointer.hasNext() ? &pointer.next() : NULL;
  Diff *nextDiff = pointer.hasNext() ? &pointer.next() : NULL;

  // Intentionally ignore the first and last element (don't need checking).
  while (nextDiff != NULL) {
    if (prevDiff->operation == EQUAL &&
      nextDiff->operation == EQUAL) {
        // This is a single edit surrounded by equalities.
        equality1 = prevDiff->text;
        edit = thisDiff->text;
        equality2 = nextDiff->text;

        // First, shift the edit as far left as possible.
        commonOffset = diff_commonSuffix(equality1, edit);
        if (commonOffset != 0) {
          commonString = safeMid(edit, edit.length() - commonOffset);
          equality1 = equality1.left(equality1.length() - commonOffset);
          edit = commonString + edit.left(edit.length() - commonOffset);
          equality2 = commonString + equality2;
        }

        // Second, step character by character right, looking for the best fit.
        bestEquality1 = equality1;
        bestEdit = edit;
        bestEquality2 = equality2;
        bestScore = diff_cleanupSemanticScore(equality1, edit)
            + diff_cleanupSemanticScore(edit, equality2);
        while (!edit.isEmpty() && !equality2.isEmpty()
            && edit[0] == equality2[0]) {
          equality1 += edit[0];
          edit = safeMid(edit, 1) + equality2[0];
          equality2 = safeMid(equality2, 1);
          score = diff_cleanupSemanticScore(equality1, edit)
              + diff_cleanupSemanticScore(edit, equality2);
          // The >= encourages trailing rather than leading whitespace on edits.
          if (score >= bestScore) {
            bestScore = score;
            bestEquality1 = equality1;
            bestEdit = edit;
            bestEquality2 = equality2;
          }
        }

        if (prevDiff->text != bestEquality1) {
          // We have an improvement, save it back to the diff.
          if (!bestEquality1.isEmpty()) {
            prevDiff->text = bestEquality1;
          } else {
            pointer.previous();  // Walk past nextDiff.
            pointer.previous();  // Walk past thisDiff.
            pointer.previous();  // Walk past prevDiff.
            pointer.remove();  // Delete prevDiff.
            pointer.next();  // Walk past thisDiff.
            pointer.next();  // Walk past nextDiff.
          }
          thisDiff->text = bestEdit;
          if (!bestEquality2.isEmpty()) {
            nextDiff->text = bestEquality2;
          } else {
            pointer.remove(); // Delete nextDiff.
            nextDiff = thisDiff;
            thisDiff = prevDiff;
          }
        }
    }
    prevDiff = thisDiff;
    thisDiff = nextDiff;
    nextDiff = pointer.hasNext() ? &pointer.next() : NULL;
  }
}


int diff_match_patch::diff_cleanupSemanticScore(const QString &one,
                                                const QString &two) {
  if (one.isEmpty() || two.isEmpty()) {
    // Edges are the best.
    return 6;
  }

  // Each port of this function behaves slightly differently due to
  // subtle differences in each language's definition of things like
  // 'whitespace'.  Since this function's purpose is largely cosmetic,
  // the choice has been made to use each language's native features
  // rather than force total conformity.
  QChar char1 = one[one.length() - 1];
  QChar char2 = two[0];
  bool nonAlphaNumeric1 = !char1.isLetterOrNumber();
  bool nonAlphaNumeric2 = !char2.isLetterOrNumber();
  bool whitespace1 = nonAlphaNumeric1 && char1.isSpace();
  bool whitespace2 = nonAlphaNumeric2 && char2.isSpace();
  bool lineBreak1 = whitespace1 && char1.category() == QChar::Other_Control;
  bool lineBreak2 = whitespace2 && char2.category() == QChar::Other_Control;
  bool blankLine1 = lineBreak1 && BLANKLINEEND.indexIn(one) != -1;
  bool blankLine2 = lineBreak2 && BLANKLINESTART.indexIn(two) != -1;

  if (blankLine1 || blankLine2) {
    // Five points for blank lines.
    return 5;
  } else if (lineBreak1 || lineBreak2) {
    // Four points for line breaks.
    return 4;
  } else if (nonAlphaNumeric1 && !whitespace1 && whitespace2) {
    // Three points for end of sentences.
    return 3;
  } else if (whitespace1 || whitespace2) {
    // Two points for whitespace.
    return 2;
  } else if (nonAlphaNumeric1 || nonAlphaNumeric2) {
    // One point for non-alphanumeric.
    return 1;
  }
  return 0;
}


// Define some regex patterns for matching boundaries.
QRegExp diff_match_patch::BLANKLINEEND = QRegExp("\\n\\r?\\n$");
QRegExp diff_match_patch::BLANKLINESTART = QRegExp("^\\r?\\n\\r?\\n");


void diff_match_patch::diff_cleanupEfficiency(QList<Diff> &diffs) {
  if (diffs.isEmpty()) {
    return;
  }
  bool changes = false;
  QStack<Diff> equalities;  // Stack of equalities.
  QString lastequality;  // Always equal to equalities.lastElement().text
  QMutableListIterator<Diff> pointer(diffs);
  // Is there an insertion operation before the last equality.
  bool pre_ins = false;
  // Is there a deletion operation before the last equality.
  bool pre_del = false;
  // Is there an insertion operation after the last equality.
  bool post_ins = false;
  // Is there a deletion operation after the last equality.
  bool post_del = false;

  Diff *thisDiff = pointer.hasNext() ? &pointer.next() : NULL;
  Diff *safeDiff = thisDiff;

  while (thisDiff != NULL) {
    if (thisDiff->operation == EQUAL) {
      // Equality found.
      if (thisDiff->text.length() < Diff_EditCost && (post_ins || post_del)) {
        // Candidate found.
        equalities.push(*thisDiff);
        pre_ins = post_ins;
        pre_del = post_del;
        lastequality = thisDiff->text;
      } else {
        // Not a candidate, and can never become one.
        equalities.clear();
        lastequality = QString();
        safeDiff = thisDiff;
      }
      post_ins = post_del = false;
    } else {
      // An insertion or deletion.
      if (thisDiff->operation == DELETE) {
        post_del = true;
      } else {
        post_ins = true;
      }
      /*
      * Five types to be split:
      * <ins>A</ins><del>B</del>XY<ins>C</ins><del>D</del>
      * <ins>A</ins>X<ins>C</ins><del>D</del>
      * <ins>A</ins><del>B</del>X<ins>C</ins>
      * <ins>A</del>X<ins>C</ins><del>D</del>
      * <ins>A</ins><del>B</del>X<del>C</del>
      */
      if (!lastequality.isNull()
          && ((pre_ins && pre_del && post_ins && post_del)
          || ((lastequality.length() < Diff_EditCost / 2)
          && ((pre_ins ? 1 : 0) + (pre_del ? 1 : 0)
          + (post_ins ? 1 : 0) + (post_del ? 1 : 0)) == 3))) {
        // printf("Splitting: '%s'\n", qPrintable(lastequality));
        // Walk back to offending equality.
        while (*thisDiff != equalities.top()) {
          thisDiff = &pointer.previous();
        }
        pointer.next();

        // Replace equality with a delete.
        pointer.setValue(Diff(DELETE, lastequality));
        // Insert a corresponding an insert.
        pointer.insert(Diff(INSERT, lastequality));
        thisDiff = &pointer.previous();
        pointer.next();

        equalities.pop();  // Throw away the equality we just deleted.
        lastequality = QString();
        if (pre_ins && pre_del) {
          // No changes made which could affect previous entry, keep going.
          post_ins = post_del = true;
          equalities.clear();
          safeDiff = thisDiff;
        } else {
          if (!equalities.isEmpty()) {
            // Throw away the previous equality (it needs to be reevaluated).
            equalities.pop();
          }
          if (equalities.isEmpty()) {
            // There are no previous questionable equalities,
            // walk back to the last known safe diff.
            thisDiff = safeDiff;
          } else {
            // There is an equality we can fall back to.
            thisDiff = &equalities.top();
          }
          while (*thisDiff != pointer.previous()) {
            // Intentionally empty loop.
          }
          post_ins = post_del = false;
        }

        changes = true;
      }
    }
    thisDiff = pointer.hasNext() ? &pointer.next() : NULL;
  }

  if (changes) {
    diff_cleanupMerge(diffs);
  }
}


void diff_match_patch::diff_cleanupMerge(QList<Diff> &diffs) {
  diffs.append(Diff(EQUAL, ""));  // Add a dummy entry at the end.
  QMutableListIterator<Diff> pointer(diffs);
  int count_delete = 0;
  int count_insert = 0;
  QString text_delete = "";
  QString text_insert = "";
  Diff *thisDiff = pointer.hasNext() ? &pointer.next() : NULL;
  Diff *prevEqual = NULL;
  int commonlength;
  while (thisDiff != NULL) {
    switch (thisDiff->operation) {
      case INSERT:
        count_insert++;
        text_insert += thisDiff->text;
        prevEqual = NULL;
        break;
      case DELETE:
        count_delete++;
        text_delete += thisDiff->text;
        prevEqual = NULL;
        break;
      case EQUAL:
        if (count_delete + count_insert > 1) {
          bool both_types = count_delete != 0 && count_insert != 0;
          // Delete the offending records.
          pointer.previous();  // Reverse direction.
          while (count_delete-- > 0) {
            pointer.previous();
            pointer.remove();
          }
          while (count_insert-- > 0) {
            pointer.previous();
            pointer.remove();
          }
          if (both_types) {
            // Factor out any common prefixies.
            commonlength = diff_commonPrefix(text_insert, text_delete);
            if (commonlength != 0) {
              if (pointer.hasPrevious()) {
                thisDiff = &pointer.previous();
                if (thisDiff->operation != EQUAL) {
                  throw "Previous diff should have been an equality.";
                }
                thisDiff->text += text_insert.left(commonlength);
                pointer.next();
              } else {
                pointer.insert(Diff(EQUAL, text_insert.left(commonlength)));
              }
              text_insert = safeMid(text_insert, commonlength);
              text_delete = safeMid(text_delete, commonlength);
            }
            // Factor out any common suffixies.
            commonlength = diff_commonSuffix(text_insert, text_delete);
            if (commonlength != 0) {
              thisDiff = &pointer.next();
              thisDiff->text = safeMid(text_insert, text_insert.length()
                  - commonlength) + thisDiff->text;
              text_insert = text_insert.left(text_insert.length()
                  - commonlength);
              text_delete = text_delete.left(text_delete.length()
                  - commonlength);
              pointer.previous();
            }
          }
          // Insert the merged records.
          if (!text_delete.isEmpty()) {
            pointer.insert(Diff(DELETE, text_delete));
          }
          if (!text_insert.isEmpty()) {
            pointer.insert(Diff(INSERT, text_insert));
          }
          // Step forward to the equality.
          thisDiff = pointer.hasNext() ? &pointer.next() : NULL;

        } else if (prevEqual != NULL) {
          // Merge this equality with the previous one.
          prevEqual->text += thisDiff->text;
          pointer.remove();
          thisDiff = &pointer.previous();
          pointer.next();  // Forward direction
        }
        count_insert = 0;
        count_delete = 0;
        text_delete = "";
        text_insert = "";
        prevEqual = thisDiff;
        break;
      }
      thisDiff = pointer.hasNext() ? &pointer.next() : NULL;
  }
  if (diffs.back().text.isEmpty()) {
    diffs.removeLast();  // Remove the dummy entry at the end.
  }

  /*
  * Second pass: look for single edits surrounded on both sides by equalities
  * which can be shifted sideways to eliminate an equality.
  * e.g: A<ins>BA</ins>C -> <ins>AB</ins>AC
  */
  bool changes = false;
  // Create a new iterator at the start.
  // (As opposed to walking the current one back.)
  pointer.toFront();
  Diff *prevDiff = pointer.hasNext() ? &pointer.next() : NULL;
  thisDiff = pointer.hasNext() ? &pointer.next() : NULL;
  Diff *nextDiff = pointer.hasNext() ? &pointer.next() : NULL;

  // Intentionally ignore the first and last element (don't need checking).
  while (nextDiff != NULL) {
    if (prevDiff->operation == EQUAL &&
      nextDiff->operation == EQUAL) {
        // This is a single edit surrounded by equalities.
        if (thisDiff->text.endsWith(prevDiff->text)) {
          // Shift the edit over the previous equality.
          thisDiff->text = prevDiff->text
              + thisDiff->text.left(thisDiff->text.length()
              - prevDiff->text.length());
          nextDiff->text = prevDiff->text + nextDiff->text;
          pointer.previous();  // Walk past nextDiff.
          pointer.previous();  // Walk past thisDiff.
          pointer.previous();  // Walk past prevDiff.
          pointer.remove();  // Delete prevDiff.
          pointer.next();  // Walk past thisDiff.
          thisDiff = &pointer.next();  // Walk past nextDiff.
          nextDiff = pointer.hasNext() ? &pointer.next() : NULL;
          changes = true;
        } else if (thisDiff->text.startsWith(nextDiff->text)) {
          // Shift the edit over the next equality.
          prevDiff->text += nextDiff->text;
          thisDiff->text = safeMid(thisDiff->text, nextDiff->text.length())
              + nextDiff->text;
          pointer.remove(); // Delete nextDiff.
          nextDiff = pointer.hasNext() ? &pointer.next() : NULL;
          changes = true;
        }
    }
    prevDiff = thisDiff;
    thisDiff = nextDiff;
    nextDiff = pointer.hasNext() ? &pointer.next() : NULL;
  }
  // If shifts were made, the diff needs reordering and another shift sweep.
  if (changes) {
    diff_cleanupMerge(diffs);
  }
}


int diff_match_patch::diff_xIndex(const QList<Diff> &diffs, int loc) {
  int chars1 = 0;
  int chars2 = 0;
  int last_chars1 = 0;
  int last_chars2 = 0;
  Diff lastDiff;
  foreach(Diff aDiff, diffs) {
    if (aDiff.operation != INSERT) {
      // Equality or deletion.
      chars1 += aDiff.text.length();
    }
    if (aDiff.operation != DELETE) {
      // Equality or insertion.
      chars2 += aDiff.text.length();
    }
    if (chars1 > loc) {
      // Overshot the location.
      lastDiff = aDiff;
      break;
    }
    last_chars1 = chars1;
    last_chars2 = chars2;
  }
  if (lastDiff.operation == DELETE) {
    // The location was deleted.
    return last_chars2;
  }
  // Add the remaining character length.
  return last_chars2 + (loc - last_chars1);
}


QString diff_match_patch::diff_prettyHtml(const QList<Diff> &diffs) {
  QString html;
  QString text;
  foreach(Diff aDiff, diffs) {
    text = aDiff.text;
    text.replace("&", "&amp;").replace("<", "&lt;")
        .replace(">", "&gt;").replace("\n", "&para;<br>");
    switch (aDiff.operation) {
      case INSERT:
        html += QString("<ins style=\"background:#e6ffe6;\">") + text
            + QString("</ins>");
        break;
      case DELETE:
        html += QString("<del style=\"background:#ffe6e6;\">") + text
            + QString("</del>");
        break;
      case EQUAL:
        html += QString("<span>") + text + QString("</span>");
        break;
    }
  }
  return html;
}


QString diff_match_patch::diff_text1(const QList<Diff> &diffs) {
  QString text;
  foreach(Diff aDiff, diffs) {
    if (aDiff.operation != INSERT) {
      text += aDiff.text;
    }
  }
  return text;
}


QString diff_match_patch::diff_text2(const QList<Diff> &diffs) {
  QString text;
  foreach(Diff aDiff, diffs) {
    if (aDiff.operation != DELETE) {
      text += aDiff.text;
    }
  }
  return text;
}


int diff_match_patch::diff_levenshtein(const QList<Diff> &diffs) {
  int levenshtein = 0;
  int insertions = 0;
  int deletions = 0;
  foreach(Diff aDiff, diffs) {
    switch (aDiff.operation) {
      case INSERT:
        insertions += aDiff.text.length();
        break;
      case DELETE:
        deletions += aDiff.text.length();
        break;
      case EQUAL:
        // A deletion and an insertion is one substitution.
        levenshtein += std::max(insertions, deletions);
        insertions = 0;
        deletions = 0;
        break;
    }
  }
  levenshtein += std::max(insertions, deletions);
  return levenshtein;
}


QString diff_match_patch::diff_toDelta(const QList<Diff> &diffs) {
  QString text;
  foreach(Diff aDiff, diffs) {
    switch (aDiff.operation) {
      case INSERT: {
        QString encoded = QString(QUrl::toPercentEncoding(aDiff.text,
            " !~*'();/?:@&=+$,#"));
        text += QString("+") + encoded + QString("\t");
        break;
      }
      case DELETE:
        text += QString("-") + QString::number(aDiff.text.length())
            + QString("\t");
        break;
      case EQUAL:
        text += QString("=") + QString::number(aDiff.text.length())
            + QString("\t");
        break;
    }
  }
  if (!text.isEmpty()) {
    // Strip off trailing tab character.
    text = text.left(text.length() - 1);
  }
  return text;
}


QList<Diff> diff_match_patch::diff_fromDelta(const QString &text1,
                                             const QString &delta) {
  QList<Diff> diffs;
  int pointer = 0;  // Cursor in text1
  QStringList tokens = delta.split("\t");
  foreach(QString token, tokens) {
    if (token.isEmpty()) {
      // Blank tokens are ok (from a trailing \t).
      continue;
    }
    // Each token begins with a one character parameter which specifies the
    // operation of this token (delete, insert, equality).
    QString param = safeMid(token, 1);
    switch (token[0].toAscii()) {
      case '+':
        param = QUrl::fromPercentEncoding(qPrintable(param));
        diffs.append(Diff(INSERT, param));
        break;
      case '-':
        // Fall through.
      case '=': {
        int n;
        n = param.toInt();
        if (n < 0) {
          throw QString("Negative number in diff_fromDelta: %1").arg(param);
        }
        QString text;
        text = safeMid(text1, pointer, n);
        pointer += n;
        if (token[0] == QChar('=')) {
          diffs.append(Diff(EQUAL, text));
        } else {
          diffs.append(Diff(DELETE, text));
        }
        break;
      }
      default:
        throw QString("Invalid diff operation in diff_fromDelta: %1")
            .arg(token[0]);
    }
  }
  if (pointer != text1.length()) {
    throw QString("Delta length (%1) smaller than source text length (%2)")
        .arg(pointer).arg(text1.length());
  }
  return diffs;
}


  //  MATCH FUNCTIONS


int diff_match_patch::match_main(const QString &text, const QString &pattern,
                                 int loc) {
  // Check for null inputs.
  if (text.isNull() || pattern.isNull()) {
    throw "Null inputs. (match_main)";
  }

  loc = std::max(0, std::min(loc, text.length()));
  if (text == pattern) {
    // Shortcut (potentially not guaranteed by the algorithm)
    return 0;
  } else if (text.isEmpty()) {
    // Nothing to match.
    return -1;
  } else if (loc + pattern.length() <= text.length()
      && safeMid(text, loc, pattern.length()) == pattern) {
    // Perfect match at the perfect spot!  (Includes case of null pattern)
    return loc;
  } else {
    // Do a fuzzy compare.
    return match_bitap(text, pattern, loc);
  }
}


int diff_match_patch::match_bitap(const QString &text, const QString &pattern,
                                  int loc) {
  if (!(Match_MaxBits == 0 || pattern.length() <= Match_MaxBits)) {
    throw "Pattern too long for this application.";
  }

  // Initialise the alphabet.
  QMap<QChar, int> s = match_alphabet(pattern);

  // Highest score beyond which we give up.
  double score_threshold = Match_Threshold;
  // Is there a nearby exact match? (speedup)
  int best_loc = text.indexOf(pattern, loc);
  if (best_loc != -1) {
    score_threshold = std::min(match_bitapScore(0, best_loc, loc, pattern),
        score_threshold);
    // What about in the other direction? (speedup)
    best_loc = text.lastIndexOf(pattern, loc + pattern.length());
    if (best_loc != -1) {
      score_threshold = std::min(match_bitapScore(0, best_loc, loc, pattern),
          score_threshold);
    }
  }

  // Initialise the bit arrays.
  int matchmask = 1 << (pattern.length() - 1);
  best_loc = -1;

  int bin_min, bin_mid;
  int bin_max = pattern.length() + text.length();
  int *rd;
  int *last_rd = NULL;
  for (int d = 0; d < pattern.length(); d++) {
    // Scan for the best match; each iteration allows for one more error.
    // Run a binary search to determine how far from 'loc' we can stray at
    // this error level.
    bin_min = 0;
    bin_mid = bin_max;
    while (bin_min < bin_mid) {
      if (match_bitapScore(d, loc + bin_mid, loc, pattern)
          <= score_threshold) {
        bin_min = bin_mid;
      } else {
        bin_max = bin_mid;
      }
      bin_mid = (bin_max - bin_min) / 2 + bin_min;
    }
    // Use the result from this iteration as the maximum for the next.
    bin_max = bin_mid;
    int start = std::max(1, loc - bin_mid + 1);
    int finish = std::min(loc + bin_mid, text.length()) + pattern.length();

    rd = new int[finish + 2];
    rd[finish + 1] = (1 << d) - 1;
    for (int j = finish; j >= start; j--) {
      int charMatch;
      if (text.length() <= j - 1) {
        // Out of range.
        charMatch = 0;
      } else {
        charMatch = s.value(text[j - 1], 0);
      }
      if (d == 0) {
        // First pass: exact match.
        rd[j] = ((rd[j + 1] << 1) | 1) & charMatch;
      } else {
        // Subsequent passes: fuzzy match.
        rd[j] = ((rd[j + 1] << 1) | 1) & charMatch
            | (((last_rd[j + 1] | last_rd[j]) << 1) | 1)
            | last_rd[j + 1];
      }
      if ((rd[j] & matchmask) != 0) {
        double score = match_bitapScore(d, j - 1, loc, pattern);
        // This match will almost certainly be better than any existing
        // match.  But check anyway.
        if (score <= score_threshold) {
          // Told you so.
          score_threshold = score;
          best_loc = j - 1;
          if (best_loc > loc) {
            // When passing loc, don't exceed our current distance from loc.
            start = std::max(1, 2 * loc - best_loc);
          } else {
            // Already passed loc, downhill from here on in.
            break;
          }
        }
      }
    }
    if (match_bitapScore(d + 1, loc, loc, pattern) > score_threshold) {
      // No hope for a (better) match at greater error levels.
      break;
    }
    delete [] last_rd;
    last_rd = rd;
  }
  delete [] last_rd;
  delete [] rd;
  return best_loc;
}


double diff_match_patch::match_bitapScore(int e, int x, int loc,
                                          const QString &pattern) {
  const float accuracy = static_cast<float> (e) / pattern.length();
  const int proximity = qAbs(loc - x);
  if (Match_Distance == 0) {
    // Dodge divide by zero error.
    return proximity == 0 ? accuracy : 1.0;
  }
  return accuracy + (proximity / static_cast<float> (Match_Distance));
}


QMap<QChar, int> diff_match_patch::match_alphabet(const QString &pattern) {
  QMap<QChar, int> s;
  int i;
  for (i = 0; i < pattern.length(); i++) {
    QChar c = pattern[i];
    s.insert(c, 0);
  }
  for (i = 0; i < pattern.length(); i++) {
    QChar c = pattern[i];
    s.insert(c, s.value(c) | (1 << (pattern.length() - i - 1)));
  }
  return s;
}


//  PATCH FUNCTIONS


void diff_match_patch::patch_addContext(Patch &patch, const QString &text) {
  if (text.isEmpty()) {
    return;
  }
  QString pattern = safeMid(text, patch.start2, patch.length1);
  int padding = 0;

  // Look for the first and last matches of pattern in text.  If two different
  // matches are found, increase the pattern length.
  while (text.indexOf(pattern) != text.lastIndexOf(pattern)
      && pattern.length() < Match_MaxBits - Patch_Margin - Patch_Margin) {
    padding += Patch_Margin;
    pattern = safeMid(text, std::max(0, patch.start2 - padding),
        std::min(text.length(), patch.start2 + patch.length1 + padding)
        - std::max(0, patch.start2 - padding));
  }
  // Add one chunk for good luck.
  padding += Patch_Margin;

  // Add the prefix.
  QString prefix = safeMid(text, std::max(0, patch.start2 - padding),
      patch.start2 - std::max(0, patch.start2 - padding));
  if (!prefix.isEmpty()) {
    patch.diffs.prepend(Diff(EQUAL, prefix));
  }
  // Add the suffix.
  QString suffix = safeMid(text, patch.start2 + patch.length1,
      std::min(text.length(), patch.start2 + patch.length1 + padding)
      - (patch.start2 + patch.length1));
  if (!suffix.isEmpty()) {
    patch.diffs.append(Diff(EQUAL, suffix));
  }

  // Roll back the start points.
  patch.start1 -= prefix.length();
  patch.start2 -= prefix.length();
  // Extend the lengths.
  patch.length1 += prefix.length() + suffix.length();
  patch.length2 += prefix.length() + suffix.length();
}


QList<Patch> diff_match_patch::patch_make(const QString &text1,
                                          const QString &text2) {
  // Check for null inputs.
  if (text1.isNull() || text2.isNull()) {
    throw "Null inputs. (patch_make)";
  }

  // No diffs provided, compute our own.
  QList<Diff> diffs = diff_main(text1, text2, true);
  if (diffs.size() > 2) {
    diff_cleanupSemantic(diffs);
    diff_cleanupEfficiency(diffs);
  }

  return patch_make(text1, diffs);
}


QList<Patch> diff_match_patch::patch_make(const QList<Diff> &diffs) {
  // No origin string provided, compute our own.
  const QString text1 = diff_text1(diffs);
  return patch_make(text1, diffs);
}


QList<Patch> diff_match_patch::patch_make(const QString &text1,
                                          const QString &text2,
                                          const QList<Diff> &diffs) {
  // text2 is entirely unused.
  return patch_make(text1, diffs);

  Q_UNUSED(text2)
}


QList<Patch> diff_match_patch::patch_make(const QString &text1,
                                          const QList<Diff> &diffs) {
  // Check for null inputs.
  if (text1.isNull()) {
    throw "Null inputs. (patch_make)";
  }

  QList<Patch> patches;
  if (diffs.isEmpty()) {
    return patches;  // Get rid of the null case.
  }
  Patch patch;
  int char_count1 = 0;  // Number of characters into the text1 string.
  int char_count2 = 0;  // Number of characters into the text2 string.
  // Start with text1 (prepatch_text) and apply the diffs until we arrive at
  // text2 (postpatch_text).  We recreate the patches one by one to determine
  // context info.
  QString prepatch_text = text1;
  QString postpatch_text = text1;
  foreach(Diff aDiff, diffs) {
    if (patch.diffs.isEmpty() && aDiff.operation != EQUAL) {
      // A new patch starts here.
      patch.start1 = char_count1;
      patch.start2 = char_count2;
    }

    switch (aDiff.operation) {
      case INSERT:
        patch.diffs.append(aDiff);
        patch.length2 += aDiff.text.length();
        postpatch_text = postpatch_text.left(char_count2)
            + aDiff.text + safeMid(postpatch_text, char_count2);
        break;
      case DELETE:
        patch.length1 += aDiff.text.length();
        patch.diffs.append(aDiff);
        postpatch_text = postpatch_text.left(char_count2)
            + safeMid(postpatch_text, char_count2 + aDiff.text.length());
        break;
      case EQUAL:
        if (aDiff.text.length() <= 2 * Patch_Margin
            && !patch.diffs.isEmpty() && !(aDiff == diffs.back())) {
          // Small equality inside a patch.
          patch.diffs.append(aDiff);
          patch.length1 += aDiff.text.length();
          patch.length2 += aDiff.text.length();
        }

        if (aDiff.text.length() >= 2 * Patch_Margin) {
          // Time for a new patch.
          if (!patch.diffs.isEmpty()) {
            patch_addContext(patch, prepatch_text);
            patches.append(patch);
            patch = Patch();
            // Unlike Unidiff, our patch lists have a rolling context.
            // http://code.google.com/p/google-diff-match-patch/wiki/Unidiff
            // Update prepatch text & pos to reflect the application of the
            // just completed patch.
            prepatch_text = postpatch_text;
            char_count1 = char_count2;
          }
        }
        break;
    }

    // Update the current character count.
    if (aDiff.operation != INSERT) {
      char_count1 += aDiff.text.length();
    }
    if (aDiff.operation != DELETE) {
      char_count2 += aDiff.text.length();
    }
  }
  // Pick up the leftover patch if not empty.
  if (!patch.diffs.isEmpty()) {
    patch_addContext(patch, prepatch_text);
    patches.append(patch);
  }

  return patches;
}


QList<Patch> diff_match_patch::patch_deepCopy(QList<Patch> &patches) {
  QList<Patch> patchesCopy;
  foreach(Patch aPatch, patches) {
    Patch patchCopy = Patch();
    foreach(Diff aDiff, aPatch.diffs) {
      Diff diffCopy = Diff(aDiff.operation, aDiff.text);
      patchCopy.diffs.append(diffCopy);
    }
    patchCopy.start1 = aPatch.start1;
    patchCopy.start2 = aPatch.start2;
    patchCopy.length1 = aPatch.length1;
    patchCopy.length2 = aPatch.length2;
    patchesCopy.append(patchCopy);
  }
  return patchesCopy;
}


QPair<QString, QVector<bool> > diff_match_patch::patch_apply(
    QList<Patch> &patches, const QString &sourceText) {
  QString text = sourceText;  // Copy to preserve original.
  if (patches.isEmpty()) {
    return QPair<QString,QVector<bool> >(text, QVector<bool>(0));
  }

  // Deep copy the patches so that no changes are made to originals.
  QList<Patch> patchesCopy = patch_deepCopy(patches);

  QString nullPadding = patch_addPadding(patchesCopy);
  text = nullPadding + text + nullPadding;
  patch_splitMax(patchesCopy);

  int x = 0;
  // delta keeps track of the offset between the expected and actual location
  // of the previous patch.  If there are patches expected at positions 10 and
  // 20, but the first patch was found at 12, delta is 2 and the second patch
  // has an effective expected position of 22.
  int delta = 0;
  QVector<bool> results(patchesCopy.size());
  foreach(Patch aPatch, patchesCopy) {
    int expected_loc = aPatch.start2 + delta;
    QString text1 = diff_text1(aPatch.diffs);
    int start_loc;
    int end_loc = -1;
    if (text1.length() > Match_MaxBits) {
      // patch_splitMax will only provide an oversized pattern in the case of
      // a monster delete.
      start_loc = match_main(text, text1.left(Match_MaxBits), expected_loc);
      if (start_loc != -1) {
        end_loc = match_main(text, text1.right(Match_MaxBits),
            expected_loc + text1.length() - Match_MaxBits);
        if (end_loc == -1 || start_loc >= end_loc) {
          // Can't find valid trailing context.  Drop this patch.
          start_loc = -1;
        }
      }
    } else {
      start_loc = match_main(text, text1, expected_loc);
    }
    if (start_loc == -1) {
      // No match found.  :(
      results[x] = false;
      // Subtract the delta for this failed patch from subsequent patches.
      delta -= aPatch.length2 - aPatch.length1;
    } else {
      // Found a match.  :)
      results[x] = true;
      delta = start_loc - expected_loc;
      QString text2;
      if (end_loc == -1) {
        text2 = safeMid(text, start_loc, text1.length());
      } else {
        text2 = safeMid(text, start_loc, end_loc + Match_MaxBits - start_loc);
      }
      if (text1 == text2) {
        // Perfect match, just shove the replacement text in.
        text = text.left(start_loc) + diff_text2(aPatch.diffs)
            + safeMid(text, start_loc + text1.length());
      } else {
        // Imperfect match.  Run a diff to get a framework of equivalent
        // indices.
        QList<Diff> diffs = diff_main(text1, text2, false);
        if (text1.length() > Match_MaxBits
            && diff_levenshtein(diffs) / static_cast<float> (text1.length())
            > Patch_DeleteThreshold) {
          // The end points match, but the content is unacceptably bad.
          results[x] = false;
        } else {
          diff_cleanupSemanticLossless(diffs);
          int index1 = 0;
          foreach(Diff aDiff, aPatch.diffs) {
            if (aDiff.operation != EQUAL) {
              int index2 = diff_xIndex(diffs, index1);
              if (aDiff.operation == INSERT) {
                // Insertion
                text = text.left(start_loc + index2) + aDiff.text
                    + safeMid(text, start_loc + index2);
              } else if (aDiff.operation == DELETE) {
                // Deletion
                text = text.left(start_loc + index2)
                    + safeMid(text, start_loc + diff_xIndex(diffs,
                    index1 + aDiff.text.length()));
              }
            }
            if (aDiff.operation != DELETE) {
              index1 += aDiff.text.length();
            }
          }
        }
      }
    }
    x++;
  }
  // Strip the padding off.
  text = safeMid(text, nullPadding.length(), text.length()
      - 2 * nullPadding.length());
  return QPair<QString, QVector<bool> >(text, results);
}


QString diff_match_patch::patch_addPadding(QList<Patch> &patches) {
  short paddingLength = Patch_Margin;
  QString nullPadding = "";
  for (short x = 1; x <= paddingLength; x++) {
    nullPadding += QChar((ushort)x);
  }

  // Bump all the patches forward.
  QMutableListIterator<Patch> pointer(patches);
  while (pointer.hasNext()) {
    Patch &aPatch = pointer.next();
    aPatch.start1 += paddingLength;
    aPatch.start2 += paddingLength;
  }

  // Add some padding on start of first diff.
  Patch &firstPatch = patches.first();
  QList<Diff> &firstPatchDiffs = firstPatch.diffs;
  if (firstPatchDiffs.empty() || firstPatchDiffs.first().operation != EQUAL) {
    // Add nullPadding equality.
    firstPatchDiffs.prepend(Diff(EQUAL, nullPadding));
    firstPatch.start1 -= paddingLength;  // Should be 0.
    firstPatch.start2 -= paddingLength;  // Should be 0.
    firstPatch.length1 += paddingLength;
    firstPatch.length2 += paddingLength;
  } else if (paddingLength > firstPatchDiffs.first().text.length()) {
    // Grow first equality.
    Diff &firstDiff = firstPatchDiffs.first();
    int extraLength = paddingLength - firstDiff.text.length();
    firstDiff.text = safeMid(nullPadding, firstDiff.text.length(),
        paddingLength - firstDiff.text.length()) + firstDiff.text;
    firstPatch.start1 -= extraLength;
    firstPatch.start2 -= extraLength;
    firstPatch.length1 += extraLength;
    firstPatch.length2 += extraLength;
  }

  // Add some padding on end of last diff.
  Patch &lastPatch = patches.first();
  QList<Diff> &lastPatchDiffs = lastPatch.diffs;
  if (lastPatchDiffs.empty() || lastPatchDiffs.last().operation != EQUAL) {
    // Add nullPadding equality.
    lastPatchDiffs.append(Diff(EQUAL, nullPadding));
    lastPatch.length1 += paddingLength;
    lastPatch.length2 += paddingLength;
  } else if (paddingLength > lastPatchDiffs.last().text.length()) {
    // Grow last equality.
    Diff &lastDiff = lastPatchDiffs.last();
    int extraLength = paddingLength - lastDiff.text.length();
    lastDiff.text += nullPadding.left(extraLength);
    lastPatch.length1 += extraLength;
    lastPatch.length2 += extraLength;
  }

  return nullPadding;
}


void diff_match_patch::patch_splitMax(QList<Patch> &patches) {
  short patch_size = Match_MaxBits;
  QString precontext, postcontext;
  Patch patch;
  int start1, start2;
  bool empty;
  Operation diff_type;
  QString diff_text;
  QMutableListIterator<Patch> pointer(patches);
  Patch bigpatch;

  if (pointer.hasNext()) {
    bigpatch = pointer.next();
  }

  while (!bigpatch.isNull()) {
    if (bigpatch.length1 <= patch_size) {
      bigpatch = pointer.hasNext() ? pointer.next() : Patch();
      continue;
    }
    // Remove the big old patch.
    pointer.remove();
    start1 = bigpatch.start1;
    start2 = bigpatch.start2;
    precontext = "";
    while (!bigpatch.diffs.isEmpty()) {
      // Create one of several smaller patches.
      patch = Patch();
      empty = true;
      patch.start1 = start1 - precontext.length();
      patch.start2 = start2 - precontext.length();
      if (!precontext.isEmpty()) {
        patch.length1 = patch.length2 = precontext.length();
        patch.diffs.append(Diff(EQUAL, precontext));
      }
      while (!bigpatch.diffs.isEmpty()
          && patch.length1 < patch_size - Patch_Margin) {
        diff_type = bigpatch.diffs.front().operation;
        diff_text = bigpatch.diffs.front().text;
        if (diff_type == INSERT) {
          // Insertions are harmless.
          patch.length2 += diff_text.length();
          start2 += diff_text.length();
          patch.diffs.append(bigpatch.diffs.front());
          bigpatch.diffs.removeFirst();
          empty = false;
        } else if (diff_type == DELETE && patch.diffs.size() == 1
            && patch.diffs.front().operation == EQUAL
            && diff_text.length() > 2 * patch_size) {
          // This is a large deletion.  Let it pass in one chunk.
          patch.length1 += diff_text.length();
          start1 += diff_text.length();
          empty = false;
          patch.diffs.append(Diff(diff_type, diff_text));
          bigpatch.diffs.removeFirst();
        } else {
          // Deletion or equality.  Only take as much as we can stomach.
          diff_text = diff_text.left(std::min(diff_text.length(),
              patch_size - patch.length1 - Patch_Margin));
          patch.length1 += diff_text.length();
          start1 += diff_text.length();
          if (diff_type == EQUAL) {
            patch.length2 += diff_text.length();
            start2 += diff_text.length();
          } else {
            empty = false;
          }
          patch.diffs.append(Diff(diff_type, diff_text));
          if (diff_text == bigpatch.diffs.front().text) {
            bigpatch.diffs.removeFirst();
          } else {
            bigpatch.diffs.front().text = safeMid(bigpatch.diffs.front().text,
                diff_text.length());
          }
        }
      }
      // Compute the head context for the next patch.
      precontext = diff_text2(patch.diffs);
      precontext = safeMid(precontext, precontext.length() - Patch_Margin);
      // Append the end context for this patch.
      if (diff_text1(bigpatch.diffs).length() > Patch_Margin) {
        postcontext = diff_text1(bigpatch.diffs).left(Patch_Margin);
      } else {
        postcontext = diff_text1(bigpatch.diffs);
      }
      if (!postcontext.isEmpty()) {
        patch.length1 += postcontext.length();
        patch.length2 += postcontext.length();
        if (!patch.diffs.isEmpty()
            && patch.diffs.back().operation == EQUAL) {
          patch.diffs.back().text += postcontext;
        } else {
          patch.diffs.append(Diff(EQUAL, postcontext));
        }
      }
      if (!empty) {
        pointer.insert(patch);
      }
    }
    bigpatch = pointer.hasNext() ? pointer.next() : Patch();
  }
}


QString diff_match_patch::patch_toText(const QList<Patch> &patches) {
  QString text;
  foreach(Patch aPatch, patches) {
    text.append(aPatch.toString());
  }
  return text;
}


QList<Patch> diff_match_patch::patch_fromText(const QString &textline) {
  QList<Patch> patches;
  if (textline.isEmpty()) {
    return patches;
  }
  QStringList text = textline.split("\n", QString::SkipEmptyParts);
  Patch patch;
  QRegExp patchHeader("^@@ -(\\d+),?(\\d*) \\+(\\d+),?(\\d*) @@$");
  char sign;
  QString line;
  while (!text.isEmpty()) {
    if (!patchHeader.exactMatch(text.front())) {
      throw QString("Invalid patch string: %1").arg(text.front());
    }

    patch = Patch();
    patch.start1 = patchHeader.cap(1).toInt();
    if (patchHeader.cap(2).isEmpty()) {
      patch.start1--;
      patch.length1 = 1;
    } else if (patchHeader.cap(2) == "0") {
      patch.length1 = 0;
    } else {
      patch.start1--;
      patch.length1 = patchHeader.cap(2).toInt();
    }

    patch.start2 = patchHeader.cap(3).toInt();
    if (patchHeader.cap(4).isEmpty()) {
      patch.start2--;
      patch.length2 = 1;
    } else if (patchHeader.cap(4) == "0") {
      patch.length2 = 0;
    } else {
      patch.start2--;
      patch.length2 = patchHeader.cap(4).toInt();
    }
    text.removeFirst();

    while (!text.isEmpty()) {
      if (text.front().isEmpty()) {
        text.removeFirst();
        continue;
      }
      sign = text.front()[0].toAscii();
      line = safeMid(text.front(), 1);
      line = line.replace("+", "%2B");  // decode would change all "+" to " "
      line = QUrl::fromPercentEncoding(qPrintable(line));
      if (sign == '-') {
        // Deletion.
        patch.diffs.append(Diff(DELETE, line));
      } else if (sign == '+') {
        // Insertion.
        patch.diffs.append(Diff(INSERT, line));
      } else if (sign == ' ') {
        // Minor equality.
        patch.diffs.append(Diff(EQUAL, line));
      } else if (sign == '@') {
        // Start of next patch.
        break;
      } else {
        // WTF?
        throw QString("Invalid patch mode '%1' in: %2").arg(sign).arg(line);
        return QList<Patch>();
      }
      text.removeFirst();
    }

    patches.append(patch);

  }
  return patches;
}


================================================
FILE: cpp/diff_match_patch.h
================================================
/*
 * Diff Match and Patch
 * Copyright 2018 The diff-match-patch Authors.
 * https://github.com/google/diff-match-patch
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#ifndef DIFF_MATCH_PATCH_H
#define DIFF_MATCH_PATCH_H

/*
 * Functions for diff, match and patch.
 * Computes the difference between two texts to create a patch.
 * Applies the patch onto another text, allowing for errors.
 *
 * @author fraser@google.com (Neil Fraser)
 *
 * Qt/C++ port by mikeslemmer@gmail.com (Mike Slemmer):
 *
 * Code known to compile and run with Qt 4.3 through Qt 4.7.
 *
 * Here is a trivial sample program which works properly when linked with this
 * library:
 *

 #include <QtCore>
 #include <QString>
 #include <QList>
 #include <QMap>
 #include <QVariant>
 #include "diff_match_patch.h"
 int main(int argc, char **argv) {
   diff_match_patch dmp;
   QString str1 = QString("First string in diff");
   QString str2 = QString("Second string in diff");

   QString strPatch = dmp.patch_toText(dmp.patch_make(str1, str2));
   QPair<QString, QVector<bool> > out
       = dmp.patch_apply(dmp.patch_fromText(strPatch), str1);
   QString strResult = out.first;

   // here, strResult will equal str2 above.
   return 0;
 }

 */


/**-
* The data structure representing a diff is a Linked list of Diff objects:
* {Diff(Operation.DELETE, "Hello"), Diff(Operation.INSERT, "Goodbye"),
*  Diff(Operation.EQUAL, " world.")}
* which means: delete "Hello", add "Goodbye" and keep " world."
*/
enum Operation {
  DELETE, INSERT, EQUAL
};


/**
* Class representing one diff operation.
*/
class Diff {
 public:
  Operation operation;
  // One of: INSERT, DELETE or EQUAL.
  QString text;
  // The text associated with this diff operation.

  /**
   * Constructor.  Initializes the diff with the provided values.
   * @param operation One of INSERT, DELETE or EQUAL.
   * @param text The text being applied.
   */
  Diff(Operation _operation, const QString &_text);
  Diff();
  inline bool isNull() const;
  QString toString() const;
  bool operator==(const Diff &d) const;
  bool operator!=(const Diff &d) const;

  static QString strOperation(Operation op);
};


/**
* Class representing one patch operation.
*/
class Patch {
 public:
  QList<Diff> diffs;
  int start1;
  int start2;
  int length1;
  int length2;

  /**
   * Constructor.  Initializes with an empty list of diffs.
   */
  Patch();
  bool isNull() const;
  QString toString();
};


/**
 * Class containing the diff, match and patch methods.
 * Also contains the behaviour settings.
 */
class diff_match_patch {

  friend class diff_match_patch_test;

 public:
  // Defaults.
  // Set these on your diff_match_patch instance to override the defaults.

  // Number of seconds to map a diff before giving up (0 for infinity).
  float Diff_Timeout;
  // Cost of an empty edit operation in terms of edit characters.
  short Diff_EditCost;
  // At what point is no match declared (0.0 = perfection, 1.0 = very loose).
  float Match_Threshold;
  // How far to search for a match (0 = exact location, 1000+ = broad match).
  // A match this many characters away from the expected location will add
  // 1.0 to the score (0.0 is a perfect match).
  int Match_Distance;
  // When deleting a large block of text (over ~64 characters), how close does
  // the contents have to match the expected contents. (0.0 = perfection,
  // 1.0 = very loose).  Note that Match_Threshold controls how closely the
  // end points of a delete need to match.
  float Patch_DeleteThreshold;
  // Chunk size for context length.
  short Patch_Margin;

  // The number of bits in an int.
  short Match_MaxBits;

 private:
  // Define some regex patterns for matching boundaries.
  static QRegExp BLANKLINEEND;
  static QRegExp BLANKLINESTART;


 public:

  diff_match_patch();

  //  DIFF FUNCTIONS


  /**
   * Find the differences between two texts.
   * Run a faster slightly less optimal diff.
   * This method allows the 'checklines' of diff_main() to be optional.
   * Most of the time checklines is wanted, so default to true.
   * @param text1 Old string to be diffed.
   * @param text2 New string to be diffed.
   * @return Linked List of Diff objects.
   */
  QList<Diff> diff_main(const QString &text1, const QString &text2);

  /**
   * Find the differences between two texts.
   * @param text1 Old string to be diffed.
   * @param text2 New string to be diffed.
   * @param checklines Speedup flag.  If false, then don't run a
   *     line-level diff first to identify the changed areas.
   *     If true, then run a faster slightly less optimal diff.
   * @return Linked List of Diff objects.
   */
  QList<Diff> diff_main(const QString &text1, const QString &text2, bool checklines);

  /**
   * Find the differences between two texts.  Simplifies the problem by
   * stripping any common prefix or suffix off the texts before diffing.
   * @param text1 Old string to be diffed.
   * @param text2 New string to be diffed.
   * @param checklines Speedup flag.  If false, then don't run a
   *     line-level diff first to identify the changed areas.
   *     If true, then run a faster slightly less optimal diff.
   * @param deadline Time when the diff should be complete by.  Used
   *     internally for recursive calls.  Users should set DiffTimeout instead.
   * @return Linked List of Diff objects.
   */
 private:
  QList<Diff> diff_main(const QString &text1, const QString &text2, bool checklines, clock_t deadline);

  /**
   * Find the differences between two texts.  Assumes that the texts do not
   * have any common prefix or suffix.
   * @param text1 Old string to be diffed.
   * @param text2 New string to be diffed.
   * @param checklines Speedup flag.  If false, then don't run a
   *     line-level diff first to identify the changed areas.
   *     If true, then run a faster slightly less optimal diff.
   * @param deadline Time when the diff should be complete by.
   * @return Linked List of Diff objects.
   */
 private:
  QList<Diff> diff_compute(QString text1, QString text2, bool checklines, clock_t deadline);

  /**
   * Do a quick line-level diff on both strings, then rediff the parts for
   * greater accuracy.
   * This speedup can produce non-minimal diffs.
   * @param text1 Old string to be diffed.
   * @param text2 New string to be diffed.
   * @param deadline Time when the diff should be complete by.
   * @return Linked List of Diff objects.
   */
 private:
  QList<Diff> diff_lineMode(QString text1, QString text2, clock_t deadline);

  /**
   * Find the 'middle snake' of a diff, split the problem in two
   * and return the recursively constructed diff.
   * See Myers 1986 paper: An O(ND) Difference Algorithm and Its Variations.
   * @param text1 Old string to be diffed.
   * @param text2 New string to be diffed.
   * @return Linked List of Diff objects.
   */
 protected:
  QList<Diff> diff_bisect(const QString &text1, const QString &text2, clock_t deadline);

  /**
   * Given the location of the 'middle snake', split the diff in two parts
   * and recurse.
   * @param text1 Old string to be diffed.
   * @param text2 New string to be diffed.
   * @param x Index of split point in text1.
   * @param y Index of split point in text2.
   * @param deadline Time at which to bail if not yet complete.
   * @return LinkedList of Diff objects.
   */
 private:
  QList<Diff> diff_bisectSplit(const QString &text1, const QString &text2, int x, int y, clock_t deadline);

  /**
   * Split two texts into a list of strings.  Reduce the texts to a string of
   * hashes where each Unicode character represents one line.
   * @param text1 First string.
   * @param text2 Second string.
   * @return Three element Object array, containing the encoded text1, the
   *     encoded text2 and the List of unique strings.  The zeroth element
   *     of the List of unique strings is intentionally blank.
   */
 protected:
  QList<QVariant> diff_linesToChars(const QString &text1, const QString &text2); // return elems 0 and 1 are QString, elem 2 is QStringList

  /**
   * Split a text into a list of strings.  Reduce the texts to a string of
   * hashes where each Unicode character represents one line.
   * @param text String to encode.
   * @param lineArray List of unique strings.
   * @param lineHash Map of strings to indices.
   * @return Encoded string.
   */
 private:
  QString diff_linesToCharsMunge(const QString &text, QStringList &lineArray,
                                 QMap<QString, int> &lineHash);

  /**
   * Rehydrate the text in a diff from a string of line hashes to real lines of
   * text.
   * @param diffs LinkedList of Diff objects.
   * @param lineArray List of unique strings.
   */
 private:
  void diff_charsToLines(QList<Diff> &diffs, const QStringList &lineArray);

  /**
   * Determine the common prefix of two strings.
   * @param text1 First string.
   * @param text2 Second string.
   * @return The number of characters common to the start of each string.
   */
 public:
  int diff_commonPrefix(const QString &text1, const QString &text2);

  /**
   * Determine the common suffix of two strings.
   * @param text1 First string.
   * @param text2 Second string.
   * @return The number of characters common to the end of each string.
   */
 public:
  int diff_commonSuffix(const QString &text1, const QString &text2);

  /**
   * Determine if the suffix of one string is the prefix of another.
   * @param text1 First string.
   * @param text2 Second string.
   * @return The number of characters common to the end of the first
   *     string and the start of the second string.
   */
 protected:
  int diff_commonOverlap(const QString &text1, const QString &text2);

  /**
   * Do the two texts share a substring which is at least half the length of
   * the longer text?
   * This speedup can produce non-minimal diffs.
   * @param text1 First string.
   * @param text2 Second string.
   * @return Five element String array, containing the prefix of text1, the
   *     suffix of text1, the prefix of text2, the suffix of text2 and the
   *     common middle.  Or null if there was no match.
   */
 protected:
  QStringList diff_halfMatch(const QString &text1, const QString &text2);

  /**
   * Does a substring of shorttext exist within longtext such that the
   * substring is at least half the length of longtext?
   * @param longtext Longer string.
   * @param shorttext Shorter string.
   * @param i Start index of quarter length substring within longtext.
   * @return Five element String array, containing the prefix of longtext, the
   *     suffix of longtext, the prefix of shorttext, the suffix of shorttext
   *     and the common middle.  Or null if there was no match.
   */
 private:
  QStringList diff_halfMatchI(const QString &longtext, const QString &shorttext, int i);

  /**
   * Reduce the number of edits by eliminating semantically trivial equalities.
   * @param diffs LinkedList of Diff objects.
   */
 public:
  void diff_cleanupSemantic(QList<Diff> &diffs);

  /**
   * Look for single edits surrounded on both sides by equalities
   * which can be shifted sideways to align the edit to a word boundary.
   * e.g: The c<ins>at c</ins>ame. -> The <ins>cat </ins>came.
   * @param diffs LinkedList of Diff objects.
   */
 public:
  void diff_cleanupSemanticLossless(QList<Diff> &diffs);

  /**
   * Given two strings, compute a score representing whether the internal
   * boundary falls on logical boundaries.
   * Scores range from 6 (best) to 0 (worst).
   * @param one First string.
   * @param two Second string.
   * @return The score.
   */
 private:
  int diff_cleanupSemanticScore(const QString &one, const QString &two);

  /**
   * Reduce the number of edits by eliminating operationally trivial equalities.
   * @param diffs LinkedList of Diff objects.
   */
 public:
  void diff_cleanupEfficiency(QList<Diff> &diffs);

  /**
   * Reorder and merge like edit sections.  Merge equalities.
   * Any edit section can move as long as it doesn't cross an equality.
   * @param diffs LinkedList of Diff objects.
   */
 public:
  void diff_cleanupMerge(QList<Diff> &diffs);

  /**
   * loc is a location in text1, compute and return the equivalent location in
   * text2.
   * e.g. "The cat" vs "The big cat", 1->1, 5->8
   * @param diffs LinkedList of Diff objects.
   * @param loc Location within text1.
   * @return Location within text2.
   */
 public:
  int diff_xIndex(const QList<Diff> &diffs, int loc);

  /**
   * Convert a Diff list into a pretty HTML report.
   * @param diffs LinkedList of Diff objects.
   * @return HTML representation.
   */
 public:
  QString diff_prettyHtml(const QList<Diff> &diffs);

  /**
   * Compute and return the source text (all equalities and deletions).
   * @param diffs LinkedList of Diff objects.
   * @return Source text.
   */
 public:
  QString diff_text1(const QList<Diff> &diffs);

  /**
   * Compute and return the destination text (all equalities and insertions).
   * @param diffs LinkedList of Diff objects.
   * @return Destination text.
   */
 public:
  QString diff_text2(const QList<Diff> &diffs);

  /**
   * Compute the Levenshtein distance; the number of inserted, deleted or
   * substituted characters.
   * @param diffs LinkedList of Diff objects.
   * @return Number of changes.
   */
 public:
  int diff_levenshtein(const QList<Diff> &diffs);

  /**
   * Crush the diff into an encoded string which describes the operations
   * required to transform text1 into text2.
   * E.g. =3\t-2\t+ing  -> Keep 3 chars, delete 2 chars, insert 'ing'.
   * Operations are tab-separated.  Inserted text is escaped using %xx notation.
   * @param diffs Array of diff tuples.
   * @return Delta text.
   */
 public:
  QString diff_toDelta(const QList<Diff> &diffs);

  /**
   * Given the original text1, and an encoded string which describes the
   * operations required to transform text1 into text2, compute the full diff.
   * @param text1 Source string for the diff.
   * @param delta Delta text.
   * @return Array of diff tuples or null if invalid.
   * @throws QString If invalid input.
   */
 public:
  QList<Diff> diff_fromDelta(const QString &text1, const QString &delta);


  //  MATCH FUNCTIONS


  /**
   * Locate the best instance of 'pattern' in 'text' near 'loc'.
   * Returns -1 if no match found.
   * @param text The text to search.
   * @param pattern The pattern to search for.
   * @param loc The location to search around.
   * @return Best match index or -1.
   */
 public:
  int match_main(const QString &text, const QString &pattern, int loc);

  /**
   * Locate the best instance of 'pattern' in 'text' near 'loc' using the
   * Bitap algorithm.  Returns -1 if no match found.
   * @param text The text to search.
   * @param pattern The pattern to search for.
   * @param loc The location to search around.
   * @return Best match index or -1.
   */
 protected:
  int match_bitap(const QString &text, const QString &pattern, int loc);

  /**
   * Compute and return the score for a match with e errors and x location.
   * @param e Number of errors in match.
   * @param x Location of match.
   * @param loc Expected location of match.
   * @param pattern Pattern being sought.
   * @return Overall score for match (0.0 = good, 1.0 = bad).
   */
 private:
  double match_bitapScore(int e, int x, int loc, const QString &pattern);

  /**
   * Initialise the alphabet for the Bitap algorithm.
   * @param pattern The text to encode.
   * @return Hash of character locations.
   */
 protected:
  QMap<QChar, int> match_alphabet(const QString &pattern);


 //  PATCH FUNCTIONS


  /**
   * Increase the context until it is unique,
   * but don't let the pattern expand beyond Match_MaxBits.
   * @param patch The patch to grow.
   * @param text Source text.
   */
 protected:
  void patch_addContext(Patch &patch, const QString &text);

  /**
   * Compute a list of patches to turn text1 into text2.
   * A set of diffs will be computed.
   * @param text1 Old text.
   * @param text2 New text.
   * @return LinkedList of Patch objects.
   */
 public:
  QList<Patch> patch_make(const QString &text1, const QString &text2);

  /**
   * Compute a list of patches to turn text1 into text2.
   * text1 will be derived from the provided diffs.
   * @param diffs Array of diff tuples for text1 to text2.
   * @return LinkedList of Patch objects.
   */
 public:
  QList<Patch> patch_make(const QList<Diff> &diffs);

  /**
   * Compute a list of patches to turn text1 into text2.
   * text2 is ignored, diffs are the delta between text1 and text2.
   * @param text1 Old text.
   * @param text2 Ignored.
   * @param diffs Array of diff tuples for text1 to text2.
   * @return LinkedList of Patch objects.
   * @deprecated Prefer patch_make(const QString &text1, const QList<Diff> &diffs).
   */
 public:
  QList<Patch> patch_make(const QString &text1, const QString &text2, const QList<Diff> &diffs);

  /**
   * Compute a list of patches to turn text1 into text2.
   * text2 is not provided, diffs are the delta between text1 and text2.
   * @param text1 Old text.
   * @param diffs Array of diff tuples for text1 to text2.
   * @return LinkedList of Patch objects.
   */
 public:
  QList<Patch> patch_make(const QString &text1, const QList<Diff> &diffs);

  /**
   * Given an array of patches, return another array that is identical.
   * @param patches Array of patch objects.
   * @return Array of patch objects.
   */
 public:
  QList<Patch> patch_deepCopy(QList<Patch> &patches);

  /**
   * Merge a set of patches onto the text.  Return a patched text, as well
   * as an array of true/false values indicating which patches were applied.
   * @param patches Array of patch objects.
   * @param text Old text.
   * @return Two element Object array, containing the new text and an array of
   *      boolean values.
   */
 public:
  QPair<QString,QVector<bool> > patch_apply(QList<Patch> &patches, const QString &text);

  /**
   * Add some padding on text start and end so that edges can match something.
   * Intended to be called only from within patch_apply.
   * @param patches Array of patch objects.
   * @return The padding string added to each side.
   */
 public:
  QString patch_addPadding(QList<Patch> &patches);

  /**
   * Look through the patches and break up any which are longer than the
   * maximum limit of the match algorithm.
   * Intended to be called only from within patch_apply.
   * @param patches LinkedList of Patch objects.
   */
 public:
  void patch_splitMax(QList<Patch> &patches);

  /**
   * Take a list of patches and return a textual representation.
   * @param patches List of Patch objects.
   * @return Text representation of patches.
   */
 public:
  QString patch_toText(const QList<Patch> &patches);

  /**
   * Parse a textual representation of patches and return a List of Patch
   * objects.
   * @param textline Text representation of patches.
   * @return List of Patch objects.
   * @throws QString If invalid input.
   */
 public:
  QList<Patch> patch_fromText(const QString &textline);

  /**
   * A safer version of QString.mid(pos).  This one returns "" instead of
   * null when the postion equals the string length.
   * @param str String to take a substring from.
   * @param pos Position to start the substring from.
   * @return Substring.
   */
 private:
  static inline QString safeMid(const QString &str, int pos) {
    return (pos == str.length()) ? QString("") : str.mid(pos);
  }

  /**
   * A safer version of QString.mid(pos, len).  This one returns "" instead of
   * null when the postion equals the string length.
   * @param str String to take a substring from.
   * @param pos Position to start the substring from.
   * @param len Length of substring.
   * @return Substring.
   */
 private:
  static inline QString safeMid(const QString &str, int pos, int len) {
    return (pos == str.length()) ? QString("") : str.mid(pos, len);
  }
};

#endif // DIFF_MATCH_PATCH_H


================================================
FILE: cpp/diff_match_patch.pro
================================================
#QT += sql xml network
TEMPLATE = app
CONFIG += qt debug_and_release

mac {
  CONFIG -= app_bundle
}

# don't embed the manifest for now (doesn't work :( )
#CONFIG -= embed_manifest_exe 

FORMS =

HEADERS = diff_match_patch.h diff_match_patch_test.h

SOURCES = diff_match_patch.cpp diff_match_patch_test.cpp

RESOURCES = 



================================================
FILE: cpp/diff_match_patch_test.cpp
================================================
/*
 * Diff Match and Patch -- Test Harness
 * Copyright 2018 The diff-match-patch Authors.
 * https://github.com/google/diff-match-patch
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

// Code known to compile and run with Qt 4.3 through Qt 4.7.
#include <QtCore>
#include "diff_match_patch.h"
#include "diff_match_patch_test.h"

int main(int argc, char **argv) {
  diff_match_patch_test dmp_test;
  qDebug("Starting diff_match_patch unit tests.");
  dmp_test.run_all_tests();
  qDebug("Done.");
  return 0;
  Q_UNUSED(argc)
  Q_UNUSED(argv)
}


diff_match_patch_test::diff_match_patch_test() {
}

void diff_match_patch_test::run_all_tests() {
  QTime t;
  t.start();
  try {
    testDiffCommonPrefix();
    testDiffCommonSuffix();
    testDiffCommonOverlap();
    testDiffHalfmatch();
    testDiffLinesToChars();
    testDiffCharsToLines();
    testDiffCleanupMerge();
    testDiffCleanupSemanticLossless();
    testDiffCleanupSemantic();
    testDiffCleanupEfficiency();
    testDiffPrettyHtml();
    testDiffText();
    testDiffDelta();
    testDiffXIndex();
    testDiffLevenshtein();
    testDiffBisect();
    testDiffMain();

    testMatchAlphabet();
    testMatchBitap();
    testMatchMain();

    testPatchObj();
    testPatchFromText();
    testPatchToText();
    testPatchAddContext();
    testPatchMake();
    testPatchSplitMax();
    testPatchAddPadding();
    testPatchApply();
    qDebug("All tests passed.");
  } catch (QString strCase) {
    qDebug("Test failed: %s", qPrintable(strCase));
  }
  qDebug("Total time: %d ms", t.elapsed());
}

//  DIFF TEST FUNCTIONS

void diff_match_patch_test::testDiffCommonPrefix() {
  // Detect any common prefix.
  assertEquals("diff_commonPrefix: Null case.", 0, dmp.diff_commonPrefix("abc", "xyz"));

  assertEquals("diff_commonPrefix: Non-null case.", 4, dmp.diff_commonPrefix("1234abcdef", "1234xyz"));

  assertEquals("diff_commonPrefix: Whole case.", 4, dmp.diff_commonPrefix("1234", "1234xyz"));
}

void diff_match_patch_test::testDiffCommonSuffix() {
  // Detect any common suffix.
  assertEquals("diff_commonSuffix: Null case.", 0, dmp.diff_commonSuffix("abc", "xyz"));

  assertEquals("diff_commonSuffix: Non-null case.", 4, dmp.diff_commonSuffix("abcdef1234", "xyz1234"));

  assertEquals("diff_commonSuffix: Whole case.", 4, dmp.diff_commonSuffix("1234", "xyz1234"));
}

void diff_match_patch_test::testDiffCommonOverlap() {
  // Detect any suffix/prefix overlap.
  assertEquals("diff_commonOverlap: Null case.", 0, dmp.diff_commonOverlap("", "abcd"));

  assertEquals("diff_commonOverlap: Whole case.", 3, dmp.diff_commonOverlap("abc", "abcd"));

  assertEquals("diff_commonOverlap: No overlap.", 0, dmp.diff_commonOverlap("123456", "abcd"));

  assertEquals("diff_commonOverlap: Overlap.", 3, dmp.diff_commonOverlap("123456xxx", "xxxabcd"));

  // Some overly clever languages (C#) may treat ligatures as equal to their
  // component letters.  E.g. U+FB01 == 'fi'
  assertEquals("diff_commonOverlap: Unicode.", 0, dmp.diff_commonOverlap("fi", QString::fromWCharArray((const wchar_t*) L"\ufb01i", 2)));
}

void diff_match_patch_test::testDiffHalfmatch() {
  // Detect a halfmatch.
  dmp.Diff_Timeout = 1;
  assertEmpty("diff_halfMatch: No match #1.", dmp.diff_halfMatch("1234567890", "abcdef"));

  assertEmpty("diff_halfMatch: No match #2.", dmp.diff_halfMatch("12345", "23"));

  assertEquals("diff_halfMatch: Single Match #1.", QString("12,90,a,z,345678").split(","), dmp.diff_halfMatch("1234567890", "a345678z"));

  assertEquals("diff_halfMatch: Single Match #2.", QString("a,z,12,90,345678").split(","), dmp.diff_halfMatch("a345678z", "1234567890"));

  assertEquals("diff_halfMatch: Single Match #3.", QString("abc,z,1234,0,56789").split(","), dmp.diff_halfMatch("abc56789z", "1234567890"));

  assertEquals("diff_halfMatch: Single Match #4.", QString("a,xyz,1,7890,23456").split(","), dmp.diff_halfMatch("a23456xyz", "1234567890"));

  assertEquals("diff_halfMatch: Multiple Matches #1.", QString("12123,123121,a,z,1234123451234").split(","), dmp.diff_halfMatch("121231234123451234123121", "a1234123451234z"));

  assertEquals("diff_halfMatch: Multiple Matches #2.", QString(",-=-=-=-=-=,x,,x-=-=-=-=-=-=-=").split(","), dmp.diff_halfMatch("x-=-=-=-=-=-=-=-=-=-=-=-=", "xx-=-=-=-=-=-=-="));

  assertEquals("diff_halfMatch: Multiple Matches #3.", QString("-=-=-=-=-=,,,y,-=-=-=-=-=-=-=y").split(","), dmp.diff_halfMatch("-=-=-=-=-=-=-=-=-=-=-=-=y", "-=-=-=-=-=-=-=yy"));

  // Optimal diff would be -q+x=H-i+e=lloHe+Hu=llo-Hew+y not -qHillo+x=HelloHe-w+Hulloy
  assertEquals("diff_halfMatch: Non-optimal halfmatch.", QString("qHillo,w,x,Hulloy,HelloHe").split(","), dmp.diff_halfMatch("qHilloHelloHew", "xHelloHeHulloy"));

  dmp.Diff_Timeout = 0;
  assertEmpty("diff_halfMatch: Optimal no halfmatch.", dmp.diff_halfMatch("qHilloHelloHew", "xHelloHeHulloy"));
}

void diff_match_patch_test::testDiffLinesToChars() {
  // Convert lines down to characters.
  QStringList tmpVector;
  QList<QVariant> tmpVarList;
  tmpVector.append("");
  tmpVector.append("alpha\n");
  tmpVector.append("beta\n");
  tmpVarList << QVariant::fromValue(QString() + QChar((ushort)1) + QChar((ushort)2) + QChar((ushort)1));  //(("\u0001\u0002\u0001"));
  tmpVarList << QVariant::fromValue(QString() + QChar((ushort)2) + QChar((ushort)1) + QChar((ushort)2));  // (("\u0002\u0001\u0002"));
  tmpVarList << QVariant::fromValue(tmpVector);
  assertEquals("diff_linesToChars:", tmpVarList, dmp.diff_linesToChars("alpha\nbeta\nalpha\n", "beta\nalpha\nbeta\n"));

  tmpVector.clear();
  tmpVarList.clear();
  tmpVector.append("");
  tmpVector.append("alpha\r\n");
  tmpVector.append("beta\r\n");
  tmpVector.append("\r\n");
  tmpVarList << QVariant::fromValue(QString(""));
  tmpVarList << QVariant::fromValue(QString() + QChar((ushort)1) + QChar((ushort)2) + QChar((ushort)3) + QChar((ushort)3));  // (("\u0001\u0002\u0003\u0003"));
  tmpVarList << QVariant::fromValue(tmpVector);
  assertEquals("diff_linesToChars:", tmpVarList, dmp.diff_linesToChars("", "alpha\r\nbeta\r\n\r\n\r\n"));

  tmpVector.clear();
  tmpVarList.clear();
  tmpVector.append("");
  tmpVector.append("a");
  tmpVector.append("b");
  tmpVarList << QVariant::fromValue(QString() + QChar((ushort)1));  // (("\u0001"));
  tmpVarList << QVariant::fromValue(QString() + QChar((ushort)2));  // (("\u0002"));
  tmpVarList << QVariant::fromValue(tmpVector);
  assertEquals("diff_linesToChars:", tmpVarList, dmp.diff_linesToChars("a", "b"));

  // More than 256 to reveal any 8-bit limitations.
  int n = 300;
  tmpVector.clear();
  tmpVarList.clear();
  QString lines;
  QString chars;
  for (int x = 1; x < n + 1; x++) {
    tmpVector.append(QString::number(x) + "\n");
    lines += QString::number(x) + "\n";
    chars += QChar(static_cast<ushort>(x));
  }
  assertEquals("diff_linesToChars: More than 256 (setup).", n, tmpVector.size());
  assertEquals("diff_linesToChars: More than 256 (setup).", n, chars.length());
  tmpVector.prepend("");
  tmpVarList << QVariant::fromValue(chars);
  tmpVarList << QVariant::fromValue(QString(""));
  tmpVarList << QVariant::fromValue(tmpVector);
  assertEquals("diff_linesToChars: More than 256.", tmpVarList, dmp.diff_linesToChars(lines, ""));
}

void diff_match_patch_test::testDiffCharsToLines() {
  // First check that Diff equality works.
  assertTrue("diff_charsToLines:", Diff(EQUAL, "a") == Diff(EQUAL, "a"));

  assertEquals("diff_charsToLines:", Diff(EQUAL, "a"), Diff(EQUAL, "a"));

  // Convert chars up to lines.
  QList<Diff> diffs;
  diffs << Diff(EQUAL, QString() + QChar((ushort)1) + QChar((ushort)2) + QChar((ushort)1));  // ("\u0001\u0002\u0001");
  diffs << Diff(INSERT, QString() + QChar((ushort)2) + QChar((ushort)1) + QChar((ushort)2));  // ("\u0002\u0001\u0002");
  QStringList tmpVector;
  tmpVector.append("");
  tmpVector.append("alpha\n");
  tmpVector.append("beta\n");
  dmp.diff_charsToLines(diffs, tmpVector);
  assertEquals("diff_charsToLines:", diffList(Diff(EQUAL, "alpha\nbeta\nalpha\n"), Diff(INSERT, "beta\nalpha\nbeta\n")), diffs);

  // More than 256 to reveal any 8-bit limitations.
  int n = 300;
  tmpVector.clear();
  QList<QVariant> tmpVarList;
  QString lines;
  QString chars;
  for (int x = 1; x < n + 1; x++) {
    tmpVector.append(QString::number(x) + "\n");
    lines += QString::number(x) + "\n";
    chars += QChar(static_cast<ushort>(x));
  }
  assertEquals("diff_linesToChars: More than 256 (setup).", n, tmpVector.size());
  assertEquals("diff_linesToChars: More than 256 (setup).", n, chars.length());
  tmpVector.prepend("");
  diffs = diffList(Diff(DELETE, chars));
  dmp.diff_charsToLines(diffs, tmpVector);
  assertEquals("diff_charsToLines: More than 256.", diffList(Diff(DELETE, lines)), diffs);
}

void diff_match_patch_test::testDiffCleanupMerge() {
  // Cleanup a messy diff.
  QList<Diff> diffs;
  dmp.diff_cleanupMerge(diffs);
  assertEquals("diff_cleanupMerge: Null case.", diffList(), diffs);

  diffs = diffList(Diff(EQUAL, "a"), Diff(DELETE, "b"), Diff(INSERT, "c"));
  dmp.diff_cleanupMerge(diffs);
  assertEquals("diff_cleanupMerge: No change case.", diffList(Diff(EQUAL, "a"), Diff(DELETE, "b"), Diff(INSERT, "c")), diffs);

  diffs = diffList(Diff(EQUAL, "a"), Diff(EQUAL, "b"), Diff(EQUAL, "c"));
  dmp.diff_cleanupMerge(diffs);
  assertEquals("diff_cleanupMerge: Merge equalities.", diffList(Diff(EQUAL, "abc")), diffs);

  diffs = diffList(Diff(DELETE, "a"), Diff(DELETE, "b"), Diff(DELETE, "c"));
  dmp.diff_cleanupMerge(diffs);
  assertEquals("diff_cleanupMerge: Merge deletions.", diffList(Diff(DELETE, "abc")), diffs);

  diffs = diffList(Diff(INSERT, "a"), Diff(INSERT, "b"), Diff(INSERT, "c"));
  dmp.diff_cleanupMerge(diffs);
  assertEquals("diff_cleanupMerge: Merge insertions.", diffList(Diff(INSERT, "abc")), diffs);

  diffs = diffList(Diff(DELETE, "a"), Diff(INSERT, "b"), Diff(DELETE, "c"), Diff(INSERT, "d"), Diff(EQUAL, "e"), Diff(EQUAL, "f"));
  dmp.diff_cleanupMerge(diffs);
  assertEquals("diff_cleanupMerge: Merge interweave.", diffList(Diff(DELETE, "ac"), Diff(INSERT, "bd"), Diff(EQUAL, "ef")), diffs);

  diffs = diffList(Diff(DELETE, "a"), Diff(INSERT, "abc"), Diff(DELETE, "dc"));
  dmp.diff_cleanupMerge(diffs);
  assertEquals("diff_cleanupMerge: Prefix and suffix detection.", diffList(Diff(EQUAL, "a"), Diff(DELETE, "d"), Diff(INSERT, "b"), Diff(EQUAL, "c")), diffs);

  diffs = diffList(Diff(EQUAL, "x"), Diff(DELETE, "a"), Diff(INSERT, "abc"), Diff(DELETE, "dc"), Diff(EQUAL, "y"));
  dmp.diff_cleanupMerge(diffs);
  assertEquals("diff_cleanupMerge: Prefix and suffix detection with equalities.", diffList(Diff(EQUAL, "xa"), Diff(DELETE, "d"), Diff(INSERT, "b"), Diff(EQUAL, "cy")), diffs);

  diffs = diffList(Diff(EQUAL, "a"), Diff(INSERT, "ba"), Diff(EQUAL, "c"));
  dmp.diff_cleanupMerge(diffs);
  assertEquals("diff_cleanupMerge: Slide edit left.", diffList(Diff(INSERT, "ab"), Diff(EQUAL, "ac")), diffs);

  diffs = diffList(Diff(EQUAL, "c"), Diff(INSERT, "ab"), Diff(EQUAL, "a"));
  dmp.diff_cleanupMerge(diffs);
  assertEquals("diff_cleanupMerge: Slide edit right.", diffList(Diff(EQUAL, "ca"), Diff(INSERT, "ba")), diffs);

  diffs = diffList(Diff(EQUAL, "a"), Diff(DELETE, "b"), Diff(EQUAL, "c"), Diff(DELETE, "ac"), Diff(EQUAL, "x"));
  dmp.diff_cleanupMerge(diffs);
  assertEquals("diff_cleanupMerge: Slide edit left recursive.", diffList(Diff(DELETE, "abc"), Diff(EQUAL, "acx")), diffs);

  diffs = diffList(Diff(EQUAL, "x"), Diff(DELETE, "ca"), Diff(EQUAL, "c"), Diff(DELETE, "b"), Diff(EQUAL, "a"));
  dmp.diff_cleanupMerge(diffs);
  assertEquals("diff_cleanupMerge: Slide edit right recursive.", diffList(Diff(EQUAL, "xca"), Diff(DELETE, "cba")), diffs);
}

void diff_match_patch_test::testDiffCleanupSemanticLossless() {
  // Slide diffs to match logical boundaries.
  QList<Diff> diffs = diffList();
  dmp.diff_cleanupSemanticLossless(diffs);
  assertEquals("diff_cleanupSemantic: Null case.", diffList(), diffs);

  diffs = diffList(Diff(EQUAL, "AAA\r\n\r\nBBB"), Diff(INSERT, "\r\nDDD\r\n\r\nBBB"), Diff(EQUAL, "\r\nEEE"));
  dmp.diff_cleanupSemanticLossless(diffs);
  assertEquals("diff_cleanupSemanticLossless: Blank lines.", diffList(Diff(EQUAL, "AAA\r\n\r\n"), Diff(INSERT, "BBB\r\nDDD\r\n\r\n"), Diff(EQUAL, "BBB\r\nEEE")), diffs);

  diffs = diffList(Diff(EQUAL, "AAA\r\nBBB"), Diff(INSERT, " DDD\r\nBBB"), Diff(EQUAL, " EEE"));
  dmp.diff_cleanupSemanticLossless(diffs);
  assertEquals("diff_cleanupSemanticLossless: Line boundaries.", diffList(Diff(EQUAL, "AAA\r\n"), Diff(INSERT, "BBB DDD\r\n"), Diff(EQUAL, "BBB EEE")), diffs);

  diffs = diffList(Diff(EQUAL, "The c"), Diff(INSERT, "ow and the c"), Diff(EQUAL, "at."));
  dmp.diff_cleanupSemanticLossless(diffs);
  assertEquals("diff_cleanupSemantic: Word boundaries.", diffList(Diff(EQUAL, "The "), Diff(INSERT, "cow and the "), Diff(EQUAL, "cat.")), diffs);

  diffs = diffList(Diff(EQUAL, "The-c"), Diff(INSERT, "ow-and-the-c"), Diff(EQUAL, "at."));
  dmp.diff_cleanupSemanticLossless(diffs);
  assertEquals("diff_cleanupSemantic: Alphanumeric boundaries.", diffList(Diff(EQUAL, "The-"), Diff(INSERT, "cow-and-the-"), Diff(EQUAL, "cat.")), diffs);

  diffs = diffList(Diff(EQUAL, "a"), Diff(DELETE, "a"), Diff(EQUAL, "ax"));
  dmp.diff_cleanupSemanticLossless(diffs);
  assertEquals("diff_cleanupSemantic: Hitting the start.", diffList(Diff(DELETE, "a"), Diff(EQUAL, "aax")), diffs);

  diffs = diffList(Diff(EQUAL, "xa"), Diff(DELETE, "a"), Diff(EQUAL, "a"));
  dmp.diff_cleanupSemanticLossless(diffs);
  assertEquals("diff_cleanupSemantic: Hitting the end.", diffList(Diff(EQUAL, "xaa"), Diff(DELETE, "a")), diffs);

  diffs = diffList(Diff(EQUAL, "The xxx. The "), Diff(INSERT, "zzz. The "), Diff(EQUAL, "yyy."));
  dmp.diff_cleanupSemanticLossless(diffs);
  assertEquals("diff_cleanupSemantic: Sentence boundaries.", diffList(Diff(EQUAL, "The xxx."), Diff(INSERT, " The zzz."), Diff(EQUAL, " The yyy.")), diffs);
}

void diff_match_patch_test::testDiffCleanupSemantic() {
  // Cleanup semantically trivial equalities.
  QList<Diff> diffs = diffList();
  dmp.diff_cleanupSemantic(diffs);
  assertEquals("diff_cleanupSemantic: Null case.", diffList(), diffs);

  diffs = diffList(Diff(DELETE, "ab"), Diff(INSERT, "cd"), Diff(EQUAL, "12"), Diff(DELETE, "e"));
  dmp.diff_cleanupSemantic(diffs);
  assertEquals("diff_cleanupSemantic: No elimination #1.", diffList(Diff(DELETE, "ab"), Diff(INSERT, "cd"), Diff(EQUAL, "12"), Diff(DELETE, "e")), diffs);

  diffs = diffList(Diff(DELETE, "abc"), Diff(INSERT, "ABC"), Diff(EQUAL, "1234"), Diff(DELETE, "wxyz"));
  dmp.diff_cleanupSemantic(diffs);
  assertEquals("diff_cleanupSemantic: No elimination #2.", diffList(Diff(DELETE, "abc"), Diff(INSERT, "ABC"), Diff(EQUAL, "1234"), Diff(DELETE, "wxyz")), diffs);

  diffs = diffList(Diff(DELETE, "a"), Diff(EQUAL, "b"), Diff(DELETE, "c"));
  dmp.diff_cleanupSemantic(diffs);
  assertEquals("diff_cleanupSemantic: Simple elimination.", diffList(Diff(DELETE, "abc"), Diff(INSERT, "b")), diffs);

  diffs = diffList(Diff(DELETE, "ab"), Diff(EQUAL, "cd"), Diff(DELETE, "e"), Diff(EQUAL, "f"), Diff(INSERT, "g"));
  dmp.diff_cleanupSemantic(diffs);
  assertEquals("diff_cleanupSemantic: Backpass elimination.", diffList(Diff(DELETE, "abcdef"), Diff(INSERT, "cdfg")), diffs);

  diffs = diffList(Diff(INSERT, "1"), Diff(EQUAL, "A"), Diff(DELETE, "B"), Diff(INSERT, "2"), Diff(EQUAL, "_"), Diff(INSERT, "1"), Diff(EQUAL, "A"), Diff(DELETE, "B"), Diff(INSERT, "2"));
  dmp.diff_cleanupSemantic(diffs);
  assertEquals("diff_cleanupSemantic: Multiple elimination.", diffList(Diff(DELETE, "AB_AB"), Diff(INSERT, "1A2_1A2")), diffs);

  diffs = diffList(Diff(EQUAL, "The c"), Diff(DELETE, "ow and the c"), Diff(EQUAL, "at."));
  dmp.diff_cleanupSemantic(diffs);
  assertEquals("diff_cleanupSemantic: Word boundaries.", diffList(Diff(EQUAL, "The "), Diff(DELETE, "cow and the "), Diff(EQUAL, "cat.")), diffs);

  diffs = diffList(Diff(DELETE, "abcxx"), Diff(INSERT, "xxdef"));
  dmp.diff_cleanupSemantic(diffs);
  assertEquals("diff_cleanupSemantic: No overlap elimination.", diffList(Diff(DELETE, "abcxx"), Diff(INSERT, "xxdef")), diffs);

  diffs = diffList(Diff(DELETE, "abcxxx"), Diff(INSERT, "xxxdef"));
  dmp.diff_cleanupSemantic(diffs);
  assertEquals("diff_cleanupSemantic: Overlap elimination.", diffList(Diff(DELETE, "abc"), Diff(EQUAL, "xxx"), Diff(INSERT, "def")), diffs);

  diffs = diffList(Diff(DELETE, "xxxabc"), Diff(INSERT, "defxxx"));
  dmp.diff_cleanupSemantic(diffs);
  assertEquals("diff_cleanupSemantic: Reverse overlap elimination.", diffList(Diff(INSERT, "def"), Diff(EQUAL, "xxx"), Diff(DELETE, "abc")), diffs);

  diffs = diffList(Diff(DELETE, "abcd1212"), Diff(INSERT, "1212efghi"), Diff(EQUAL, "----"), Diff(DELETE, "A3"), Diff(INSERT, "3BC"));
  dmp.diff_cleanupSemantic(diffs);
  assertEquals("diff_cleanupSemantic: Two overlap eliminations.", diffList(Diff(DELETE, "abcd"), Diff(EQUAL, "1212"), Diff(INSERT, "efghi"), Diff(EQUAL, "----"), Diff(DELETE, "A"), Diff(EQUAL, "3"), Diff(INSERT, "BC")), diffs);
}

void diff_match_patch_test::testDiffCleanupEfficiency() {
  // Cleanup operationally trivial equalities.
  dmp.Diff_EditCost = 4;
  QList<Diff> diffs = diffList();
  dmp.diff_cleanupEfficiency(diffs);
  assertEquals("diff_cleanupEfficiency: Null case.", diffList(), diffs);

  diffs = diffList(Diff(DELETE, "ab"), Diff(INSERT, "12"), Diff(EQUAL, "wxyz"), Diff(DELETE, "cd"), Diff(INSERT, "34"));
  dmp.diff_cleanupEfficiency(diffs);
  assertEquals("diff_cleanupEfficiency: No elimination.", diffList(Diff(DELETE, "ab"), Diff(INSERT, "12"), Diff(EQUAL, "wxyz"), Diff(DELETE, "cd"), Diff(INSERT, "34")), diffs);

  diffs = diffList(Diff(DELETE, "ab"), Diff(INSERT, "12"), Diff(EQUAL, "xyz"), Diff(DELETE, "cd"), Diff(INSERT, "34"));
  dmp.diff_cleanupEfficiency(diffs);
  assertEquals("diff_cleanupEfficiency: Four-edit elimination.", diffList(Diff(DELETE, "abxyzcd"), Diff(INSERT, "12xyz34")), diffs);

  diffs = diffList(Diff(INSERT, "12"), Diff(EQUAL, "x"), Diff(DELETE, "cd"), Diff(INSERT, "34"));
  dmp.diff_cleanupEfficiency(diffs);
  assertEquals("diff_cleanupEfficiency: Three-edit elimination.", diffList(Diff(DELETE, "xcd"), Diff(INSERT, "12x34")), diffs);

  diffs = diffList(Diff(DELETE, "ab"), Diff(INSERT, "12"), Diff(EQUAL, "xy"), Diff(INSERT, "34"), Diff(EQUAL, "z"), Diff(DELETE, "cd"), Diff(INSERT, "56"));
  dmp.diff_cleanupEfficiency(diffs);
  assertEquals("diff_cleanupEfficiency: Backpass elimination.", diffList(Diff(DELETE, "abxyzcd"), Diff(INSERT, "12xy34z56")), diffs);

  dmp.Diff_EditCost = 5;
  diffs = diffList(Diff(DELETE, "ab"), Diff(INSERT, "12"), Diff(EQUAL, "wxyz"), Diff(DELETE, "cd"), Diff(INSERT, "34"));
  dmp.diff_cleanupEfficiency(diffs);
  assertEquals("diff_cleanupEfficiency: High cost elimination.", diffList(Diff(DELETE, "abwxyzcd"), Diff(INSERT, "12wxyz34")), diffs);
  dmp.Diff_EditCost = 4;
}

void diff_match_patch_test::testDiffPrettyHtml() {
  // Pretty print.
  QList<Diff> diffs = diffList(Diff(EQUAL, "a\n"), Diff(DELETE, "<B>b</B>"), Diff(INSERT, "c&d"));
  assertEquals("diff_prettyHtml:", "<span>a&para;<br></span><del style=\"background:#ffe6e6;\">&lt;B&gt;b&lt;/B&gt;</del><ins style=\"background:#e6ffe6;\">c&amp;d</ins>", dmp.diff_prettyHtml(diffs));
}

void diff_match_patch_test::testDiffText() {
  // Compute the source and destination texts.
  QList<Diff> diffs = diffList(Diff(EQUAL, "jump"), Diff(DELETE, "s"), Diff(INSERT, "ed"), Diff(EQUAL, " over "), Diff(DELETE, "the"), Diff(INSERT, "a"), Diff(EQUAL, " lazy"));
  assertEquals("diff_text1:", "jumps over the lazy", dmp.diff_text1(diffs));
  assertEquals("diff_text2:", "jumped over a lazy", dmp.diff_text2(diffs));
}

void diff_match_patch_test::testDiffDelta() {
  // Convert a diff into delta string.
  QList<Diff> diffs = diffList(Diff(EQUAL, "jump"), Diff(DELETE, "s"), Diff(INSERT, "ed"), Diff(EQUAL, " over "), Diff(DELETE, "the"), Diff(INSERT, "a"), Diff(EQUAL, " lazy"), Diff(INSERT, "old dog"));
  QString text1 = dmp.diff_text1(diffs);
  assertEquals("diff_text1: Base text.", "jumps over the lazy", text1);

  QString delta = dmp.diff_toDelta(diffs);
  assertEquals("diff_toDelta:", "=4\t-1\t+ed\t=6\t-3\t+a\t=5\t+old dog", delta);

  // Convert delta string into a diff.
  assertEquals("diff_fromDelta: Normal.", diffs, dmp.diff_fromDelta(text1, delta));

  // Generates error (19 < 20).
  try {
    dmp.diff_fromDelta(text1 + "x", delta);
    assertFalse("diff_fromDelta: Too long.", true);
  } catch (QString ex) {
    // Exception expected.
  }

  // Generates error (19 > 18).
  try {
    dmp.diff_fromDelta(text1.mid(1), delta);
    assertFalse("diff_fromDelta: Too short.", true);
  } catch (QString ex) {
    // Exception expected.
  }

  // Generates error (%c3%xy invalid Unicode).
  /* This test does not work because QUrl::fromPercentEncoding("%xy") -> "?"
  try {
    dmp.diff_fromDelta("", "+%c3%xy");
    assertFalse("diff_fromDelta: Invalid character.", true);
  } catch (QString ex) {
    // Exception expected.
  }
  */

  // Test deltas with special characters.
  diffs = diffList(Diff(EQUAL, QString::fromWCharArray((const wchar_t*) L"\u0680 \000 \t %", 7)), Diff(DELETE, QString::fromWCharArray((const wchar_t*) L"\u0681 \001 \n ^", 7)), Diff(INSERT, QString::fromWCharArray((const wchar_t*) L"\u0682 \002 \\ |", 7)));
  text1 = dmp.diff_text1(diffs);
  assertEquals("diff_text1: Unicode text.", QString::fromWCharArray((const wchar_t*) L"\u0680 \000 \t %\u0681 \001 \n ^", 14), text1);

  delta = dmp.diff_toDelta(diffs);
  assertEquals("diff_toDelta: Unicode.", "=7\t-7\t+%DA%82 %02 %5C %7C", delta);

  assertEquals("diff_fromDelta: Unicode.", diffs, dmp.diff_fromDelta(text1, delta));

  // Verify pool of unchanged characters.
  diffs = diffList(Diff(INSERT, "A-Z a-z 0-9 - _ . ! ~ * ' ( ) ; / ? : @ & = + $ , # "));
  QString text2 = dmp.diff_text2(diffs);
  assertEquals("diff_text2: Unchanged characters.", "A-Z a-z 0-9 - _ . ! ~ * \' ( ) ; / ? : @ & = + $ , # ", text2);

  delta = dmp.diff_toDelta(diffs);
  assertEquals("diff_toDelta: Unchanged characters.", "+A-Z a-z 0-9 - _ . ! ~ * \' ( ) ; / ? : @ & = + $ , # ", delta);

  // Convert delta string into a diff.
  assertEquals("diff_fromDelta: Unchanged characters.", diffs, dmp.diff_fromDelta("", delta));
}

void diff_match_patch_test::testDiffXIndex() {
  // Translate a location in text1 to text2.
  QList<Diff> diffs = diffList(Diff(DELETE, "a"), Diff(INSERT, "1234"), Diff(EQUAL, "xyz"));
  assertEquals("diff_xIndex: Translation on equality.", 5, dmp.diff_xIndex(diffs, 2));

  diffs = diffList(Diff(EQUAL, "a"), Diff(DELETE, "1234"), Diff(EQUAL, "xyz"));
  assertEquals("diff_xIndex: Translation on deletion.", 1, dmp.diff_xIndex(diffs, 3));
}

void diff_match_patch_test::testDiffLevenshtein() {
  QList<Diff> diffs = diffList(Diff(DELETE, "abc"), Diff(INSERT, "1234"), Diff(EQUAL, "xyz"));
  assertEquals("diff_levenshtein: Trailing equality.", 4, dmp.diff_levenshtein(diffs));

  diffs = diffList(Diff(EQUAL, "xyz"), Diff(DELETE, "abc"), Diff(INSERT, "1234"));
  assertEquals("diff_levenshtein: Leading equality.", 4, dmp.diff_levenshtein(diffs));

  diffs = diffList(Diff(DELETE, "abc"), Diff(EQUAL, "xyz"), Diff(INSERT, "1234"));
  assertEquals("diff_levenshtein: Middle equality.", 7, dmp.diff_levenshtein(diffs));
}

void diff_match_patch_test::testDiffBisect() {
  // Normal.
  QString a = "cat";
  QString b = "map";
  // Since the resulting diff hasn't been normalized, it would be ok if
  // the insertion and deletion pairs are swapped.
  // If the order changes, tweak this test as required.
  QList<Diff> diffs = diffList(Diff(DELETE, "c"), Diff(INSERT, "m"), Diff(EQUAL, "a"), Diff(DELETE, "t"), Diff(INSERT, "p"));
  assertEquals("diff_bisect: Normal.", diffs, dmp.diff_bisect(a, b, std::numeric_limits<clock_t>::max()));

  // Timeout.
  diffs = diffList(Diff(DELETE, "cat"), Diff(INSERT, "map"));
  assertEquals("diff_bisect: Timeout.", diffs, dmp.diff_bisect(a, b, 0));
}

void diff_match_patch_test::testDiffMain() {
  // Perform a trivial diff.
  QList<Diff> diffs = diffList();
  assertEquals("diff_main: Null case.", diffs, dmp.diff_main("", "", false));

  diffs = diffList(Diff(EQUAL, "abc"));
  assertEquals("diff_main: Equality.", diffs, dmp.diff_main("abc", "abc", false));

  diffs = diffList(Diff(EQUAL, "ab"), Diff(INSERT, "123"), Diff(EQUAL, "c"));
  assertEquals("diff_main: Simple insertion.", diffs, dmp.diff_main("abc", "ab123c", false));

  diffs = diffList(Diff(EQUAL, "a"), Diff(DELETE, "123"), Diff(EQUAL, "bc"));
  assertEquals("diff_main: Simple deletion.", diffs, dmp.diff_main("a123bc", "abc", false));

  diffs = diffList(Diff(EQUAL, "a"), Diff(INSERT, "123"), Diff(EQUAL, "b"), Diff(INSERT, "456"), Diff(EQUAL, "c"));
  assertEquals("diff_main: Two insertions.", diffs, dmp.diff_main("abc", "a123b456c", false));

  diffs = diffList(Diff(EQUAL, "a"), Diff(DELETE, "123"), Diff(EQUAL, "b"), Diff(DELETE, "456"), Diff(EQUAL, "c"));
  assertEquals("diff_main: Two deletions.", diffs, dmp.diff_main("a123b456c", "abc", false));

  // Perform a real diff.
  // Switch off the timeout.
  dmp.Diff_Timeout = 0;
  diffs = diffList(Diff(DELETE, "a"), Diff(INSERT, "b"));
  assertEquals("diff_main: Simple case #1.", diffs, dmp.diff_main("a", "b", false));

  diffs = diffList(Diff(DELETE, "Apple"), Diff(INSERT, "Banana"), Diff(EQUAL, "s are a"), Diff(INSERT, "lso"), Diff(EQUAL, " fruit."));
  assertEquals("diff_main: Simple case #2.", diffs, dmp.diff_main("Apples are a fruit.", "Bananas are also fruit.", false));

  diffs = diffList(Diff(DELETE, "a"), Diff(INSERT, QString::fromWCharArray((const wchar_t*) L"\u0680", 1)), Diff(EQUAL, "x"), Diff(DELETE, "\t"), Diff(INSERT, QString::fromWCharArray((const wchar_t*) L"\000", 1)));
  assertEquals("diff_main: Simple case #3.", diffs, dmp.diff_main("ax\t", QString::fromWCharArray((const wchar_t*) L"\u0680x\000", 3), false));

  diffs = diffList(Diff(DELETE, "1"), Diff(EQUAL, "a"), Diff(DELETE, "y"), Diff(EQUAL, "b"), Diff(DELETE, "2"), Diff(INSERT, "xab"));
  assertEquals("diff_main: Overlap #1.", diffs, dmp.diff_main("1ayb2", "abxab", false));

  diffs = diffList(Diff(INSERT, "xaxcx"), Diff(EQUAL, "abc"), Diff(DELETE, "y"));
  assertEquals("diff_main: Overlap #2.", diffs, dmp.diff_main("abcy", "xaxcxabc", false));

  diffs = diffList(Diff(DELETE, "ABCD"), Diff(EQUAL, "a"), Diff(DELETE, "="), Diff(INSERT, "-"), Diff(EQUAL, "bcd"), Diff(DELETE, "="), Diff(INSERT, "-"), Diff(EQUAL, "efghijklmnopqrs"), Diff(DELETE, "EFGHIJKLMNOefg"));
  assertEquals("diff_main: Overlap #3.", diffs, dmp.diff_main("ABCDa=bcd=efghijklmnopqrsEFGHIJKLMNOefg", "a-bcd-efghijklmnopqrs", false));

  diffs = diffList(Diff(INSERT, " "), Diff(EQUAL, "a"), Diff(INSERT, "nd"), Diff(EQUAL, " [[Pennsylvania]]"), Diff(DELETE, " and [[New"));
  assertEquals("diff_main: Large equality.", diffs, dmp.diff_main("a [[Pennsylvania]] and [[New", " and [[Pennsylvania]]", false));

  dmp.Diff_Timeout = 0.1f;  // 100ms
  // This test may 'fail' on extremely fast computers.  If so, just increase the text lengths.
  QString a = "`Twas brillig, and the slithy toves\nDid gyre and gimble in the wabe:\nAll mimsy were the borogoves,\nAnd the mome raths outgrabe.\n";
  QString b = "I am the very model of a modern major general,\nI've information vegetable, animal, and mineral,\nI know the kings of England, and I quote the fights historical,\nFrom Marathon to Waterloo, in order categorical.\n";
  // Increase the text lengths by 1024 times to ensure a timeout.
  for (int x = 0; x < 10; x++) {
    a = a + a;
    b = b + b;
  }
  clock_t startTime = clock();
  dmp.diff_main(a, b);
  clock_t endTime = clock();
  // Test that we took at least the timeout period.
  assertTrue("diff_main: Timeout min.", dmp.Diff_Timeout * CLOCKS_PER_SEC <= endTime - startTime);
  // Test that we didn't take forever (be forgiving).
  // Theoretically this test could fail very occasionally if the
  // OS task swaps or locks up for a second at the wrong moment.
  // Java seems to overrun by ~80% (compared with 10% for other languages).
  // Therefore use an upper limit of 0.5s instead of 0.2s.
  assertTrue("diff_main: Timeout max.", dmp.Diff_Timeout * CLOCKS_PER_SEC * 2 > endTime - startTime);
  dmp.Diff_Timeout = 0;

  // Test the linemode speedup.
  // Must be long to pass the 100 char cutoff.
  a = "1234567890\n1234567890\n1234567890\n1234567890\n1234567890\n1234567890\n1234567890\n1234567890\n1234567890\n1234567890\n1234567890\n1234567890\n1234567890\n";
  b = "abcdefghij\nabcdefghij\nabcdefghij\nabcdefghij\nabcdefghij\nabcdefghij\nabcdefghij\nabcdefghij\nabcdefghij\nabcdefghij\nabcdefghij\nabcdefghij\nabcdefghij\n";
  assertEquals("diff_main: Simple line-mode.", dmp.diff_main(a, b, true), dmp.diff_main(a, b, false));

  a = "1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890";
  b = "abcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghij";
  assertEquals("diff_main: Single line-mode.", dmp.diff_main(a, b, true), dmp.diff_main(a, b, false));

  a = "1234567890\n1234567890\n1234567890\n1234567890\n1234567890\n1234567890\n1234567890\n1234567890\n1234567890\n1234567890\n1234567890\n1234567890\n1234567890\n";
  b = "abcdefghij\n1234567890\n1234567890\n1234567890\nabcdefghij\n1234567890\n1234567890\n1234567890\nabcdefghij\n1234567890\n1234567890\n1234567890\nabcdefghij\n";
  QStringList texts_linemode = diff_rebuildtexts(dmp.diff_main(a, b, true));
  QStringList texts_textmode = diff_rebuildtexts(dmp.diff_main(a, b, false));
  assertEquals("diff_main: Overlap line-mode.", texts_textmode, texts_linemode);

  // Test null inputs.
  try {
    dmp.diff_main(NULL, NULL);
    assertFalse("diff_main: Null inputs.", true);
  } catch (const char* ex) {
    // Exception expected.
  }
}


//  MATCH TEST FUNCTIONS


void diff_match_patch_test::testMatchAlphabet() {
  // Initialise the bitmasks for Bitap.
  QMap<QChar, int> bitmask;
  bitmask.insert('a', 4);
  bitmask.insert('b', 2);
  bitmask.insert('c', 1);
  assertEquals("match_alphabet: Unique.", bitmask, dmp.match_alphabet("abc"));

  bitmask = QMap<QChar, int>();
  bitmask.insert('a', 37);
  bitmask.insert('b', 18);
  bitmask.insert('c', 8);
  assertEquals("match_alphabet: Duplicates.", bitmask, dmp.match_alphabet("abcaba"));
}

void diff_match_patch_test::testMatchBitap() {
  // Bitap algorithm.
  dmp.Match_Distance = 100;
  dmp.Match_Threshold = 0.5f;
  assertEquals("match_bitap: Exact match #1.", 5, dmp.match_bitap("abcdefghijk", "fgh", 5));

  assertEquals("match_bitap: Exact match #2.", 5, dmp.match_bitap("abcdefghijk", "fgh", 0));

  assertEquals("match_bitap: Fuzzy match #1.", 4, dmp.match_bitap("abcdefghijk", "efxhi", 0));

  assertEquals("match_bitap: Fuzzy match #2.", 2, dmp.match_bitap("abcdefghijk", "cdefxyhijk", 5));

  assertEquals("match_bitap: Fuzzy match #3.", -1, dmp.match_bitap("abcdefghijk", "bxy", 1));

  assertEquals("match_bitap: Overflow.", 2, dmp.match_bitap("123456789xx0", "3456789x0", 2));

  assertEquals("match_bitap: Before start match.", 0, dmp.match_bitap("abcdef", "xxabc", 4));

  assertEquals("match_bitap: Beyond end match.", 3, dmp.match_bitap("abcdef", "defyy", 4));

  assertEquals("match_bitap: Oversized pattern.", 0, dmp.match_bitap("abcdef", "xabcdefy", 0));

  dmp.Match_Threshold = 0.4f;
  assertEquals("match_bitap: Threshold #1.", 4, dmp.match_bitap("abcdefghijk", "efxyhi", 1));

  dmp.Match_Threshold = 0.3f;
  assertEquals("match_bitap: Threshold #2.", -1, dmp.match_bitap("abcdefghijk", "efxyhi", 1));

  dmp.Match_Threshold = 0.0f;
  assertEquals("match_bitap: Threshold #3.", 1, dmp.match_bitap("abcdefghijk", "bcdef", 1));

  dmp.Match_Threshold = 0.5f;
  assertEquals("match_bitap: Multiple select #1.", 0, dmp.match_bitap("abcdexyzabcde", "abccde", 3));

  assertEquals("match_bitap: Multiple select #2.", 8, dmp.match_bitap("abcdexyzabcde", "abccde", 5));

  dmp.Match_Distance = 10;  // Strict location.
  assertEquals("match_bitap: Distance test #1.", -1, dmp.match_bitap("abcdefghijklmnopqrstuvwxyz", "abcdefg", 24));

  assertEquals("match_bitap: Distance test #2.", 0, dmp.match_bitap("abcdefghijklmnopqrstuvwxyz", "abcdxxefg", 1));

  dmp.Match_Distance = 1000;  // Loose location.
  assertEquals("match_bitap: Distance test #3.", 0, dmp.match_bitap("abcdefghijklmnopqrstuvwxyz", "abcdefg", 24));
}

void diff_match_patch_test::testMatchMain() {
  // Full match.
  assertEquals("match_main: Equality.", 0, dmp.match_main("abcdef", "abcdef", 1000));

  assertEquals("match_main: Null text.", -1, dmp.match_main("", "abcdef", 1));

  assertEquals("match_main: Null pattern.", 3, dmp.match_main("abcdef", "", 3));

  assertEquals("match_main: Exact match.", 3, dmp.match_main("abcdef", "de", 3));

  dmp.Match_Threshold = 0.7f;
  assertEquals("match_main: Complex match.", 4, dmp.match_main("I am the very model of a modern major general.", " that berry ", 5));
  dmp.Match_Threshold = 0.5f;

  // Test null inputs.
  try {
    dmp.match_main(NULL, NULL, 0);
    assertFalse("match_main: Null inputs.", true);
  } catch (const char* ex) {
    // Exception expected.
  }
}


//  PATCH TEST FUNCTIONS


void diff_match_patch_test::testPatchObj() {
  // Patch Object.
  Patch p;
  p.start1 = 20;
  p.start2 = 21;
  p.length1 = 18;
  p.length2 = 17;
  p.diffs = diffList(Diff(EQUAL, "jump"), Diff(DELETE, "s"), Diff(INSERT, "ed"), Diff(EQUAL, " over "), Diff(DELETE, "the"), Diff(INSERT, "a"), Diff(EQUAL, "\nlaz"));
  QString strp = "@@ -21,18 +22,17 @@\n jump\n-s\n+ed\n  over \n-the\n+a\n %0Alaz\n";
  assertEquals("Patch: toString.", strp, p.toString());
}

void diff_match_patch_test::testPatchFromText() {
  assertTrue("patch_fromText: #0.", dmp.patch_fromText("").isEmpty());

  QString strp = "@@ -21,18 +22,17 @@\n jump\n-s\n+ed\n  over \n-the\n+a\n %0Alaz\n";
  assertEquals("patch_fromText: #1.", strp, dmp.patch_fromText(strp).value(0).toString());

  assertEquals("patch_fromText: #2.", "@@ -1 +1 @@\n-a\n+b\n", dmp.patch_fromText("@@ -1 +1 @@\n-a\n+b\n").value(0).toString());

  assertEquals("patch_fromText: #3.", "@@ -1,3 +0,0 @@\n-abc\n", dmp.patch_fromText("@@ -1,3 +0,0 @@\n-abc\n").value(0).toString());

  assertEquals("patch_fromText: #4.", "@@ -0,0 +1,3 @@\n+abc\n", dmp.patch_fromText("@@ -0,0 +1,3 @@\n+abc\n").value(0).toString());

  // Generates error.
  try {
    dmp.patch_fromText("Bad\nPatch\n");
    assertFalse("patch_fromText: #5.", true);
  } catch (QString ex) {
    // Exception expected.
  }
}

void diff_match_patch_test::testPatchToText() {
  QString strp = "@@ -21,18 +22,17 @@\n jump\n-s\n+ed\n  over \n-the\n+a\n  laz\n";
  QList<Patch> patches;
  patches = dmp.patch_fromText(strp);
  assertEquals("patch_toText: Single", strp, dmp.patch_toText(patches));

  strp = "@@ -1,9 +1,9 @@\n-f\n+F\n oo+fooba\n@@ -7,9 +7,9 @@\n obar\n-,\n+.\n  tes\n";
  patches = dmp.patch_fromText(strp);
  assertEquals("patch_toText: Dual", strp, dmp.patch_toText(patches));
}

void diff_match_patch_test::testPatchAddContext() {
  dmp.Patch_Margin = 4;
  Patch p;
  p = dmp.patch_fromText("@@ -21,4 +21,10 @@\n-jump\n+somersault\n").value(0);
  dmp.patch_addContext(p, "The quick brown fox jumps over the lazy dog.");
  assertEquals("patch_addContext: Simple case.", "@@ -17,12 +17,18 @@\n fox \n-jump\n+somersault\n s ov\n", p.toString());

  p = dmp.patch_fromText("@@ -21,4 +21,10 @@\n-jump\n+somersault\n").value(0);
  dmp.patch_addContext(p, "The quick brown fox jumps.");
  assertEquals("patch_addContext: Not enough trailing context.", "@@ -17,10 +17,16 @@\n fox \n-jump\n+somersault\n s.\n", p.toString());

  p = dmp.patch_fromText("@@ -3 +3,2 @@\n-e\n+at\n").value(0);
  dmp.patch_addContext(p, "The quick brown fox jumps.");
  assertEquals("patch_addContext: Not enough leading context.", "@@ -1,7 +1,8 @@\n Th\n-e\n+at\n  qui\n", p.toString());

  p = dmp.patch_fromText("@@ -3 +3,2 @@\n-e\n+at\n").value(0);
  dmp.patch_addContext(p, "The quick brown fox jumps.  The quick brown fox crashes.");
  assertEquals("patch_addContext: Ambiguity.", "@@ -1,27 +1,28 @@\n Th\n-e\n+at\n  quick brown fox jumps. \n", p.toString());
}

void diff_match_patch_test::testPatchMake() {
  QList<Patch> patches;
  patches = dmp.patch_make("", "");
  assertEquals("patch_make: Null case", "", dmp.patch_toText(patches));

  QString text1 = "The quick brown fox jumps over the lazy dog.";
  QString text2 = "That quick brown fox jumped over a lazy dog.";
  QString expectedPatch = "@@ -1,8 +1,7 @@\n Th\n-at\n+e\n  qui\n@@ -21,17 +21,18 @@\n jump\n-ed\n+s\n  over \n-a\n+the\n  laz\n";
  // The second patch must be "-21,17 +21,18", not "-22,17 +21,18" due to rolling context.
  patches = dmp.patch_make(text2, text1);
  assertEquals("patch_make: Text2+Text1 inputs", expectedPatch, dmp.patch_toText(patches));

  expectedPatch = "@@ -1,11 +1,12 @@\n Th\n-e\n+at\n  quick b\n@@ -22,18 +22,17 @@\n jump\n-s\n+ed\n  over \n-the\n+a\n  laz\n";
  patches = dmp.patch_make(text1, text2);
  assertEquals("patch_make: Text1+Text2 inputs", expectedPatch, dmp.patch_toText(patches));

  QList<Diff> diffs = dmp.diff_main(text1, text2, false);
  patches = dmp.patch_make(diffs);
  assertEquals("patch_make: Diff input", expectedPatch, dmp.patch_toText(patches));

  patches = dmp.patch_make(text1, diffs);
  assertEquals("patch_make: Text1+Diff inputs", expectedPatch, dmp.patch_toText(patches));

  patches = dmp.patch_make(text1, text2, diffs);
  assertEquals("patch_make: Text1+Text2+Diff inputs (deprecated)", expectedPatch, dmp.patch_toText(patches));

  patches = dmp.patch_make("`1234567890-=[]\\;',./", "~!@#$%^&*()_+{}|:\"<>?");
  assertEquals("patch_toText: Character encoding.", "@@ -1,21 +1,21 @@\n-%601234567890-=%5B%5D%5C;',./\n+~!@#$%25%5E&*()_+%7B%7D%7C:%22%3C%3E?\n", dmp.patch_toText(patches));

  diffs = diffList(Diff(DELETE, "`1234567890-=[]\\;',./"), Diff(INSERT, "~!@#$%^&*()_+{}|:\"<>?"));
  assertEquals("patch_fromText: Character decoding.", diffs, dmp.patch_fromText("@@ -1,21 +1,21 @@\n-%601234567890-=%5B%5D%5C;',./\n+~!@#$%25%5E&*()_+%7B%7D%7C:%22%3C%3E?\n").value(0).diffs);

  text1 = "";
  for (int x = 0; x < 100; x++) {
    text1 += "abcdef";
  }
  text2 = text1 + "123";
  expectedPatch = "@@ -573,28 +573,31 @@\n cdefabcdefabcdefabcdefabcdef\n+123\n";
  patches = dmp.patch_make(text1, text2);
  assertEquals("patch_make: Long string with repeats.", expectedPatch, dmp.patch_toText(patches));

  // Test null inputs.
  try {
    dmp.patch_make(NULL, NULL);
    assertFalse("patch_make: Null inputs.", true);
  } catch (const char* ex) {
    // Exception expected.
  }
}

void diff_match_patch_test::testPatchSplitMax() {
  // Assumes that Match_MaxBits is 32.
  QList<Patch> patches;
  patches = dmp.patch_make("abcdefghijklmnopqrstuvwxyz01234567890", "XabXcdXefXghXijXklXmnXopXqrXstXuvXwxXyzX01X23X45X67X89X0");
  dmp.patch_splitMax(patches);
  assertEquals("patch_splitMax: #1.", "@@ -1,32 +1,46 @@\n+X\n ab\n+X\n cd\n+X\n ef\n+X\n gh\n+X\n ij\n+X\n kl\n+X\n mn\n+X\n op\n+X\n qr\n+X\n st\n+X\n uv\n+X\n wx\n+X\n yz\n+X\n 012345\n@@ -25,13 +39,18 @@\n zX01\n+X\n 23\n+X\n 45\n+X\n 67\n+X\n 89\n+X\n 0\n", dmp.patch_toText(patches));

  patches = dmp.patch_make("abcdef1234567890123456789012345678901234567890123456789012345678901234567890uvwxyz", "abcdefuvwxyz");
  QString oldToText = dmp.patch_toText(patches);
  dmp.patch_splitMax(patches);
  assertEquals("patch_splitMax: #2.", oldToText, dmp.patch_toText(patches));

  patches = dmp.patch_make("1234567890123456789012345678901234567890123456789012345678901234567890", "abc");
  dmp.patch_splitMax(patches);
  assertEquals("patch_splitMax: #3.", "@@ -1,32 +1,4 @@\n-1234567890123456789012345678\n 9012\n@@ -29,32 +1,4 @@\n-9012345678901234567890123456\n 7890\n@@ -57,14 +1,3 @@\n-78901234567890\n+abc\n", dmp.patch_toText(patches));

  patches = dmp.patch_make("abcdefghij , h : 0 , t : 1 abcdefghij , h : 0 , t : 1 abcdefghij , h : 0 , t : 1", "abcdefghij , h : 1 , t : 1 abcdefghij , h : 1 , t : 1 abcdefghij , h : 0 , t : 1");
  dmp.patch_splitMax(patches);
  assertEquals("patch_splitMax: #4.", "@@ -2,32 +2,32 @@\n bcdefghij , h : \n-0\n+1\n  , t : 1 abcdef\n@@ -29,32 +29,32 @@\n bcdefghij , h : \n-0\n+1\n  , t : 1 abcdef\n", dmp.patch_toText(patches));
}

void diff_match_patch_test::testPatchAddPadding() {
  QList<Patch> patches;
  patches = dmp.patch_make("", "test");
  assertEquals("patch_addPadding: Both edges full.", "@@ -0,0 +1,4 @@\n+test\n", dmp.patch_toText(patches));
  dmp.patch_addPadding(patches);
  assertEquals("patch_addPadding: Both edges full.", "@@ -1,8 +1,12 @@\n %01%02%03%04\n+test\n %01%02%03%04\n", dmp.patch_toText(patches));

  patches = dmp.patch_make("XY", "XtestY");
  assertEquals("patch_addPadding: Both edges partial.", "@@ -1,2 +1,6 @@\n X\n+test\n Y\n", dmp.patch_toText(patches));
  dmp.patch_addPadding(patches);
  assertEquals("patch_addPadding: Both edges partial.", "@@ -2,8 +2,12 @@\n %02%03%04X\n+test\n Y%01%02%03\n", dmp.patch_toText(patches));

  patches = dmp.patch_make("XXXXYYYY", "XXXXtestYYYY");
  assertEquals("patch_addPadding: Both edges none.", "@@ -1,8 +1,12 @@\n XXXX\n+test\n YYYY\n", dmp.patch_toText(patches));
  dmp.patch_addPadding(patches);
  assertEquals("patch_addPadding: Both edges none.", "@@ -5,8 +5,12 @@\n XXXX\n+test\n YYYY\n", dmp.patch_toText(patches));
}

void diff_match_patch_test::testPatchApply() {
  dmp.Match_Distance = 1000;
  dmp.Match_Threshold = 0.5f;
  dmp.Patch_DeleteThreshold = 0.5f;
  QList<Patch> patches;
  patches = dmp.patch_make("", "");
  QPair<QString, QVector<bool> > results = dmp.patch_apply(patches, "Hello world.");
  QVector<bool> boolArray = results.second;

  QString resultStr = QString("%1\t%2").arg(results.first).arg(boolArray.count());
  assertEquals("patch_apply: Null case.", "Hello world.\t0", resultStr);

  patches = dmp.patch_make("The quick brown fox jumps over the lazy dog.", "That quick brown fox jumped over a lazy dog.");
  results = dmp.patch_apply(patches, "The quick brown fox jumps over the lazy dog.");
  boolArray = results.second;
  resultStr = results.first + "\t" + (boolArray[0] ? "true" : "false") + "\t" + (boolArray[1] ? "true" : "false");
  assertEquals("patch_apply: Exact match.", "That quick brown fox jumped over a lazy dog.\ttrue\ttrue", resultStr);

  results = dmp.patch_apply(patches, "The quick red rabbit jumps over the tired tiger.");
  boolArray = results.second;
  resultStr = results.first + "\t" + (boolArray[0] ? "true" : "false") + "\t" + (boolArray[1] ? "true" : "false");
  assertEquals("patch_apply: Partial match.", "That quick red rabbit jumped over a tired tiger.\ttrue\ttrue", resultStr);

  results = dmp.patch_apply(patches, "I am the very model of a modern major general.");
  boolArray = results.second;
  resultStr = results.first + "\t" + (boolArray[0] ? "true" : "false") + "\t" + (boolArray[1] ? "true" : "false");
  assertEquals("patch_apply: Failed match.", "I am the very model of a modern major general.\tfalse\tfalse", resultStr);

  patches = dmp.patch_make("x1234567890123456789012345678901234567890123456789012345678901234567890y", "xabcy");
  results = dmp.patch_apply(patches, "x123456789012345678901234567890-----++++++++++-----123456789012345678901234567890y");
  boolArray = results.second;
  resultStr = results.first + "\t" + (boolArray[0] ? "true" : "false") + "\t" + (boolArray[1] ? "true" : "false");
  assertEquals("patch_apply: Big delete, small change.", "xabcy\ttrue\ttrue", resultStr);

  patches = dmp.patch_make("x1234567890123456789012345678901234567890123456789012345678901234567890y", "xabcy");
  results = dmp.patch_apply(patches, "x12345678901234567890---------------++++++++++---------------12345678901234567890y");
  boolArray = results.second;
  resultStr = results.first + "\t" + (boolArray[0] ? "true" : "false") + "\t" + (boolArray[1] ? "true" : "false");
  assertEquals("patch_apply: Big delete, large change 1.", "xabc12345678901234567890---------------++++++++++---------------12345678901234567890y\tfalse\ttrue", resultStr);

  dmp.Patch_DeleteThreshold = 0.6f;
  patches = dmp.patch_make("x1234567890123456789012345678901234567890123456789012345678901234567890y", "xabcy");
  results = dmp.patch_apply(patches, "x12345678901234567890---------------++++++++++---------------12345678901234567890y");
  boolArray = results.second;
  resultStr = results.first + "\t" + (boolArray[0] ? "true" : "false") + "\t" + (boolArray[1] ? "true" : "false");
  assertEquals("patch_apply: Big delete, large change 2.", "xabcy\ttrue\ttrue", resultStr);
  dmp.Patch_DeleteThreshold = 0.5f;

  dmp.Match_Threshold = 0.0f;
  dmp.Match_Distance = 0;
  patches = dmp.patch_make("abcdefghijklmnopqrstuvwxyz--------------------1234567890", "abcXXXXXXXXXXdefghijklmnopqrstuvwxyz--------------------1234567YYYYYYYYYY890");
  results = dmp.patch_apply(patches, "ABCDEFGHIJKLMNOPQRSTUVWXYZ--------------------1234567890");
  boolArray = results.second;
  resultStr = results.first + "\t" + (boolArray[0] ? "true" : "false") + "\t" + (boolArray[1] ? "true" : "false");
  assertEquals("patch_apply: Compensate for failed patch.", "ABCDEFGHIJKLMNOPQRSTUVWXYZ--------------------1234567YYYYYYYYYY890\tfalse\ttrue", resultStr);
  dmp.Match_Threshold = 0.5f;
  dmp.Match_Distance = 1000;

  patches = dmp.patch_make("", "test");
  QString patchStr = dmp.patch_toText(patches);
  dmp.patch_apply(patches, "");
  assertEquals("patch_apply: No side effects.", patchStr, dmp.patch_toText(patches));

  patches = dmp.patch_make("The quick brown fox jumps over the lazy dog.", "Woof");
  patchStr = dmp.patch_toText(patches);
  dmp.patch_apply(patches, "The quick brown fox jumps over the lazy dog.");
  assertEquals("patch_apply: No side effects with major delete.", patchStr, dmp.patch_toText(patches));

  patches = dmp.patch_make("", "test");
  results = dmp.patch_apply(patches, "");
  boolArray = results.second;
  resultStr = results.first + "\t" + (boolArray[0] ? "true" : "false");
  assertEquals("patch_apply: Edge exact match.", "test\ttrue", resultStr);

  patches = dmp.patch_make("XY", "XtestY");
  results = dmp.patch_apply(patches, "XY");
  boolArray = results.second;
  resultStr = results.first + "\t" + (boolArray[0] ? "true" : "false");
  assertEquals("patch_apply: Near edge exact match.", "XtestY\ttrue", resultStr);

  patches = dmp.patch_make("y", "y123");
  results = dmp.patch_apply(patches, "x");
  boolArray = results.second;
  resultStr = results.first + "\t" + (boolArray[0] ? "true" : "false");
  assertEquals("patch_apply: Edge partial match.", "x123\ttrue", resultStr);
}


void diff_match_patch_test::assertEquals(const QString &strCase, int n1, int n2) {
  if (n1 != n2) {
    qDebug("%s FAIL\nExpected: %d\nActual: %d", qPrintable(strCase), n1, n2);
    throw strCase;
  }
  qDebug("%s OK", qPrintable(strCase));
}

void diff_match_patch_test::assertEquals(const QString &strCase, const QString &s1, const QString &s2) {
  if (s1 != s2) {
    qDebug("%s FAIL\nExpected: %s\nActual: %s",
           qPrintable(strCase), qPrintable(s1), qPrintable(s2));
    throw strCase;
  }
  qDebug("%s OK", qPrintable(strCase));
}

void diff_match_patch_test::assertEquals(const QString &strCase, const Diff &d1, const Diff &d2) {
  if (d1 != d2) {
    qDebug("%s FAIL\nExpected: %s\nActual: %s", qPrintable(strCase),
        qPrintable(d1.toString()), qPrintable(d2.toString()));
    throw strCase;
  }
  qDebug("%s OK", qPrintable(strCase));
}

void diff_match_patch_test::assertEquals(const QString &strCase, const QList<Diff> &list1, const QList<Diff> &list2) {
  bool fail = false;
  if (list1.count() == list2.count()) {
    int i = 0;
    foreach(Diff d1, list1) {
      Diff d2 = list2.value(i);
      if (d1 != d2) {
        fail = true;
        break;
      }
      i++;
    }
  } else {
    fail = true;
  }

  if (fail) {
    // Build human readable description of both lists.
    QString listString1 = "(";
    bool first = true;
    foreach(Diff d1, list1) {
      if (!first) {
        listString1 += ", ";
      }
      listString1 += d1.toString();
      first = false;
    }
    listString1 += ")";
    QString listString2 = "(";
    first = true;
    foreach(Diff d2, list2) {
      if (!first) {
        listString2 += ", ";
      }
      listString2 += d2.toString();
      first = false;
    }
    listString2 += ")";
    qDebug("%s FAIL\nExpected: %s\nActual: %s",
        qPrintable(strCase), qPrintable(listString1), qPrintable(listString2));
    throw strCase;
  }
  qDebug("%s OK", qPrintable(strCase));
}

void diff_match_patch_test::assertEquals(const QString &strCase, const QList<QVariant> &list1, const QList<QVariant> &list2) {
  bool fail = false;
  if (list1.count() == list2.count()) {
    int i = 0;
    foreach(QVariant q1, list1) {
      QVariant q2 = list2.value(i);
      if (q1 != q2) {
        fail = true;
        break;
      }
      i++;
    }
  } else {
    fail = true;
  }

  if (fail) {
    // Build human readable description of both lists.
    QString listString1 = "(";
    bool first = true;
    foreach(QVariant q1, list1) {
      if (!first) {
        listString1 += ", ";
      }
      listString1 += q1.toString();
      first = false;
    }
    listString1 += ")";
    QString listString2 = "(";
    first = true;
    foreach(QVariant q2, list2) {
      if (!first) {
        listString2 += ", ";
      }
      listString2 += q2.toString();
      first = false;
    }
    listString2 += ")";
    qDebug("%s FAIL\nExpected: %s\nActual: %s",
        qPrintable(strCase), qPrintable(listString1), qPrintable(listString2));
    throw strCase;
  }
  qDebug("%s OK", qPrintable(strCase));
}

void diff_match_patch_test::assertEquals(const QString &strCase, const QVariant &var1, const QVariant &var2) {
  if (var1 != var2) {
    qDebug("%s FAIL\nExpected: %s\nActual: %s", qPrintable(strCase),
        qPrintable(var1.toString()), qPrintable(var2.toString()));
    throw strCase;
  }
  qDebug("%s OK", qPrintable(strCase));
}

void diff_match_patch_test::assertEquals(const QString &strCase, const QMap<QChar, int> &m1, const QMap<QChar, int> &m2) {
  QMapIterator<QChar, int> i1(m1), i2(m2);

  while (i1.hasNext() && i2.hasNext()) {
    i1.next();
    i2.next();
    if (i1.key() != i2.key() || i1.value() != i2.value()) {
      qDebug("%s FAIL\nExpected: (%c, %d)\nActual: (%c, %d)", qPrintable(strCase),
          i1.key().toAscii(), i1.value(), i2.key().toAscii(), i2.value());
      throw strCase;
    }
  }

  if (i1.hasNext()) {
    i1.next();
    qDebug("%s FAIL\nExpected: (%c, %d)\nActual: none",
        qPrintable(strCase), i1.key().toAscii(), i1.value());
    throw strCase;
  }
  if (i2.hasNext()) {
    i2.next();
    qDebug("%s FAIL\nExpected: none\nActual: (%c, %d)",
        qPrintable(strCase), i2.key().toAscii(), i2.value());
    throw strCase;
  }
  qDebug("%s OK", qPrintable(strCase));
}

void diff_match_patch_test::assertEquals(const QString &strCase, const QStringList &list1, const QStringList &list2) {
  if (list1 != list2) {
    qDebug("%s FAIL\nExpected: %s\nActual: %s", qPrintable(strCase),
        qPrintable(list1.join(",")), qPrintable(list2.join(",")));
    throw strCase;
  }
  qDebug("%s OK", qPrintable(strCase));
}

void diff_match_patch_test::assertTrue(const QString &strCase, bool value) {
  if (!value) {
    qDebug("%s FAIL\nExpected: true\nActual: false", qPrintable(strCase));
    throw strCase;
  }
  qDebug("%s OK", qPrintable(strCase));
}

void diff_match_patch_test::assertFalse(const QString &strCase, bool value) {
  if (value) {
    qDebug("%s FAIL\nExpected: false\nActual: true", qPrintable(strCase));
    throw strCase;
  }
  qDebug("%s OK", qPrintable(strCase));
}


// Construct the two texts which made up the diff originally.
QStringList diff_match_patch_test::diff_rebuildtexts(QList<Diff> diffs) {
  QStringList text;
  text << QString("") << QString("");
  foreach (Diff myDiff, diffs) {
    if (myDiff.operation != INSERT) {
      text[0] += myDiff.text;
    }
    if (myDiff.operation != DELETE) {
      text[1] += myDiff.text;
    }
  }
  return text;
}

void diff_match_patch_test::assertEmpty(const QString &strCase, const QStringList &list) {
  if (!list.isEmpty()) {
    throw strCase;
  }
}


// Private function for quickly building lists of diffs.
QList<Diff> diff_match_patch_test::diffList(Diff d1, Diff d2, Diff d3, Diff d4, Diff d5,
  Diff d6, Diff d7, Diff d8, Diff d9, Diff d10) {
  // Diff(INSERT, NULL) is invalid and thus is used as the default argument.
  QList<Diff> listRet;
  if (d1.operation == INSERT && d1.text == NULL) {
    return listRet;
  }
  listRet << d1;

  if (d2.operation == INSERT && d2.text == NULL) {
    return listRet;
  }
  listRet << d2;

  if (d3.operation == INSERT && d3.text == NULL) {
    return listRet;
  }
  listRet << d3;

  if (d4.operation == INSERT && d4.text == NULL) {
    return listRet;
  }
  listRet << d4;

  if (d5.operation == INSERT && d5.text == NULL) {
    return listRet;
  }
  listRet << d5;

  if (d6.operation == INSERT && d6.text == NULL) {
    return listRet;
  }
  listRet << d6;

  if (d7.operation == INSERT && d7.text == NULL) {
    return listRet;
  }
  listRet << d7;

  if (d8.operation == INSERT && d8.text == NULL) {
    return listRet;
  }
  listRet << d8;

  if (d9.operation == INSERT && d9.text == NULL) {
    return listRet;
  }
  listRet << d9;

  if (d10.operation == INSERT && d10.text == NULL) {
    return listRet;
  }
  listRet << d10;

  return listRet;
}


/*
Compile instructions for MinGW and QT4 on Windows:
qmake -project
qmake
mingw32-make
g++ -o diff_match_patch_test debug\diff_match_patch_test.o debug\diff_match_patch.o \qt4\lib\libQtCore4.a
diff_match_patch_test.exe

Compile insructions for OS X:
qmake -spec macx-g++
make
./diff_match_patch
*/


================================================
FILE: cpp/diff_match_patch_test.h
================================================
/*
 * Diff Match and Patch -- Test Harness
 * Copyright 2018 The diff-match-patch Authors.
 * https://github.com/google/diff-match-patch
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#ifndef DIFF_MATCH_PATCH_TEST_H
#define DIFF_MATCH_PATCH_TEST_H

class diff_match_patch_test {
 public:
  diff_match_patch_test();
  void run_all_tests();

  //  DIFF TEST FUNCTIONS
  void testDiffCommonPrefix();
  void testDiffCommonSuffix();
  void testDiffCommonOverlap();
  void testDiffHalfmatch();
  void testDiffLinesToChars();
  void testDiffCharsToLines();
  void testDiffCleanupMerge();
  void testDiffCleanupSemanticLossless();
  void testDiffCleanupSemantic();
  void testDiffCleanupEfficiency();
  void testDiffPrettyHtml();
  void testDiffText();
  void testDiffDelta();
  void testDiffXIndex();
  void testDiffLevenshtein();
  void testDiffBisect();
  void testDiffMain();

  //  MATCH TEST FUNCTIONS
  void testMatchAlphabet();
  void testMatchBitap();
  void testMatchMain();

  //  PATCH TEST FUNCTIONS
  void testPatchObj();
  void testPatchFromText();
  void testPatchToText();
  void testPatchAddContext();
  void testPatchMake();
  void testPatchSplitMax();
  void testPatchAddPadding();
  void testPatchApply();

 private:
  diff_match_patch dmp;

  // Define equality.
  void assertEquals(const QString &strCase, int n1, int n2);
  void assertEquals(const QString &strCase, const QString &s1, const QString &s2);
  void assertEquals(const QString &strCase, const Diff &d1, const Diff &d2);
  void assertEquals(const QString &strCase, const QList<Diff> &list1, const QList<Diff> &list2);
  void assertEquals(const QString &strCase, const QList<QVariant> &list1, const QList<QVariant> &list2);
  void assertEquals(const QString &strCase, const QVariant &var1, const QVariant &var2);
  void assertEquals(const QString &strCase, const QMap<QChar, int> &m1, const QMap<QChar, int> &m2);
  void assertEquals(const QString &strCase, const QStringList &list1, const QStringList &list2);
  void assertTrue(const QString &strCase, bool value);
  void assertFalse(const QString &strCase, bool value);
  void assertEmpty(const QString &strCase, const QStringList &list);

  // Construct the two texts which made up the diff originally.
  QStringList diff_rebuildtexts(QList<Diff> diffs);
  // Private function for quickly building lists of diffs.
  QList<Diff> diffList(
      // Diff(INSERT, NULL) is invalid and thus is used as the default argument.
      Diff d1 = Diff(INSERT, NULL), Diff d2 = Diff(INSERT, NULL),
      Diff d3 = Diff(INSERT, NULL), Diff d4 = Diff(INSERT, NULL),
      Diff d5 = Diff(INSERT, NULL), Diff d6 = Diff(INSERT, NULL),
      Diff d7 = Diff(INSERT, NULL), Diff d8 = Diff(INSERT, NULL),
      Diff d9 = Diff(INSERT, NULL), Diff d10 = Diff(INSERT, NULL));
};

#endif // DIFF_MATCH_PATCH_TEST_H


================================================
FILE: csharp/DiffMatchPatch.cs
================================================
/*
 * Diff Match and Patch
 * Copyright 2018 The diff-match-patch Authors.
 * https://github.com/google/diff-match-patch
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Web;

namespace DiffMatchPatch {
  internal static class CompatibilityExtensions {
    // JScript splice function
    public static List<T> Splice<T>(this List<T> input, int start, int count,
        params T[] objects) {
      List<T> deletedRange = input.GetRange(start, count);
      input.RemoveRange(start, count);
      input.InsertRange(start, objects);

      return deletedRange;
    }

    // Java substring function
    public static string JavaSubstring(this string s, int begin, int end) {
      return s.Substring(begin, end - begin);
    }
  }

  /**-
   * The data structure representing a diff is a List of Diff objects:
   * {Diff(Operation.DELETE, "Hello"), Diff(Operation.INSERT, "Goodbye"),
   *  Diff(Operation.EQUAL, " world.")}
   * which means: delete "Hello", add "Goodbye" and keep " world."
   */
  public enum Operation {
    DELETE, INSERT, EQUAL
  }


  /**
   * Class representing one diff operation.
   */
  public class Diff {
    public Operation operation;
    // One of: INSERT, DELETE or EQUAL.
    public string text;
    // The text associated with this diff operation.

    /**
     * Constructor.  Initializes the diff with the provided values.
     * @param operation One of INSERT, DELETE or EQUAL.
     * @param text The text being applied.
     */
    public Diff(Operation operation, string text) {
      // Construct a diff with the specified operation and text.
      this.operation = operation;
      this.text = text;
    }

    /**
     * Display a human-readable version of this Diff.
     * @return text version.
     */
    public override string ToString() {
      string prettyText = this.text.Replace('\n', '\u00b6');
      return "Diff(" + this.operation + ",\"" + prettyText + "\")";
    }

    /**
     * Is this Diff equivalent to another Diff?
     * @param d Another Diff to compare against.
     * @return true or false.
     */
    public override bool Equals(Object obj) {
      // If parameter is null return false.
      if (obj == null) {
        return false;
      }

      // If parameter cannot be cast to Diff return false.
      Diff p = obj as Diff;
      if ((System.Object)p == null) {
        return false;
      }

      // Return true if the fields match.
      return p.operation == this.operation && p.text == this.text;
    }

    public bool Equals(Diff obj) {
      // If parameter is null return false.
      if (obj == null) {
        return false;
      }

      // Return true if the fields match.
      return obj.operation == this.operation && obj.text == this.text;
    }

    public override int GetHashCode() {
      return text.GetHashCode() ^ operation.GetHashCode();
    }
  }


  /**
   * Class representing one patch operation.
   */
  public class Patch {
    public List<Diff> diffs = new List<Diff>();
    public int start1;
    public int start2;
    public int length1;
    public int length2;

    /**
     * Emulate GNU diff's format.
     * Header: @@ -382,8 +481,9 @@
     * Indices are printed as 1-based, not 0-based.
     * @return The GNU diff string.
     */
    public override string ToString() {
      string coords1, coords2;
      if (this.length1 == 0) {
        coords1 = this.start1 + ",0";
      } else if (this.length1 == 1) {
        coords1 = Convert.ToString(this.start1 + 1);
      } else {
        coords1 = (this.start1 + 1) + "," + this.length1;
      }
      if (this.length2 == 0) {
        coords2 = this.start2 + ",0";
      } else if (this.length2 == 1) {
        coords2 = Convert.ToString(this.start2 + 1);
      } else {
        coords2 = (this.start2 + 1) + "," + this.length2;
      }
      StringBuilder text = new StringBuilder();
      text.Append("@@ -").Append(coords1).Append(" +").Append(coords2)
          .Append(" @@\n");
      // Escape the body of the patch with %xx notation.
      foreach (Diff aDiff in this.diffs) {
        switch (aDiff.operation) {
          case Operation.INSERT:
            text.Append('+');
            break;
          case Operation.DELETE:
            text.Append('-');
            break;
          case Operation.EQUAL:
            text.Append(' ');
            break;
        }

        text.Append(diff_match_patch.encodeURI(aDiff.text)).Append("\n");
      }
      return text.ToString();
    }
  }


  /**
   * Class containing the diff, match and patch methods.
   * Also Contains the behaviour settings.
   */
  public class diff_match_patch {
    // Defaults.
    // Set these on your diff_match_patch instance to override the defaults.

    // Number of seconds to map a diff before giving up (0 for infinity).
    public float Diff_Timeout = 1.0f;
    // Cost of an empty edit operation in terms of edit characters.
    public short Diff_EditCost = 4;
    // At what point is no match declared (0.0 = perfection, 1.0 = very loose).
    public float Match_Threshold = 0.5f;
    // How far to search for a match (0 = exact location, 1000+ = broad match).
    // A match this many characters away from the expected location will add
    // 1.0 to the score (0.0 is a perfect match).
    public int Match_Distance = 1000;
    // When deleting a large block of text (over ~64 characters), how close
    // do the contents have to be to match the expected contents. (0.0 =
    // perfection, 1.0 = very loose).  Note that Match_Threshold controls
    // how closely the end points of a delete need to match.
    public float Patch_DeleteThreshold = 0.5f;
    // Chunk size for context length.
    public short Patch_Margin = 4;

    // The number of bits in an int.
    private short Match_MaxBits = 32;


    //  DIFF FUNCTIONS


    /**
     * Find the differences between two texts.
     * Run a faster, slightly less optimal diff.
     * This method allows the 'checklines' of diff_main() to be optional.
     * Most of the time checklines is wanted, so default to true.
     * @param text1 Old string to be diffed.
     * @param text2 New string to be diffed.
     * @return List of Diff objects.
     */
    public List<Diff> diff_main(string text1, string text2) {
      return diff_main(text1, text2, true);
    }

    /**
     * Find the differences between two texts.
     * @param text1 Old string to be diffed.
     * @param text2 New string to be diffed.
     * @param checklines Speedup flag.  If false, then don't run a
     *     line-level diff first to identify the changed areas.
     *     If true, then run a faster slightly less optimal diff.
     * @return List of Diff objects.
     */
    public List<Diff> diff_main(string text1, string text2, bool checklines) {
      // Set a deadline by which time the diff must be complete.
      DateTime deadline;
      if (this.Diff_Timeout <= 0) {
        deadline = DateTime.MaxValue;
      } else {
        deadline = DateTime.Now +
            new TimeSpan(((long)(Diff_Timeout * 1000)) * 10000);
      }
      return diff_main(text1, text2, checklines, deadline);
    }

    /**
     * Find the differences between two texts.  Simplifies the problem by
     * stripping any common prefix or suffix off the texts before diffing.
     * @param text1 Old string to be diffed.
     * @param text2 New string to be diffed.
     * @param checklines Speedup flag.  If false, then don't run a
     *     line-level diff first to identify the changed areas.
     *     If true, then run a faster slightly less optimal diff.
     * @param deadline Time when the diff should be complete by.  Used
     *     internally for recursive calls.  Users should set DiffTimeout
     *     instead.
     * @return List of Diff objects.
     */
    private List<Diff> diff_main(string text1, string text2, bool checklines,
        DateTime deadline) {
      // Check for null inputs not needed since null can't be passed in C#.

      // Check for equality (speedup).
      List<Diff> diffs;
      if (text1 == text2) {
        diffs = new List<Diff>();
        if (text1.Length != 0) {
          diffs.Add(new Diff(Operation.EQUAL, text1));
        }
        return diffs;
      }

      // Trim off common prefix (speedup).
      int commonlength = diff_commonPrefix(text1, text2);
      string commonprefix = text1.Substring(0, commonlength);
      text1 = text1.Substring(commonlength);
      text2 = text2.Substring(commonlength);

      // Trim off common suffix (speedup).
      commonlength = diff_commonSuffix(text1, text2);
      string commonsuffix = text1.Substring(text1.Length - commonlength);
      text1 = text1.Substring(0, text1.Length - commonlength);
      text2 = text2.Substring(0, text2.Length - commonlength);

      // Compute the diff on the middle block.
      diffs = diff_compute(text1, text2, checklines, deadline);

      // Restore the prefix and suffix.
      if (commonprefix.Length != 0) {
        diffs.Insert(0, (new Diff(Operation.EQUAL, commonprefix)));
      }
      if (commonsuffix.Length != 0) {
        diffs.Add(new Diff(Operation.EQUAL, commonsuffix));
      }

      diff_cleanupMerge(diffs);
      return diffs;
    }

    /**
     * Find the differences between two texts.  Assumes that the texts do not
     * have any common prefix or suffix.
     * @param text1 Old string to be diffed.
     * @param text2 New string to be diffed.
     * @param checklines Speedup flag.  If false, then don't run a
     *     line-level diff first to identify the changed areas.
     *     If true, then run a faster slightly less optimal diff.
     * @param deadline Time when the diff should be complete by.
     * @return List of Diff objects.
     */
    private List<Diff> diff_compute(string text1, string text2,
                                    bool checklines, DateTime deadline) {
      List<Diff> diffs = new List<Diff>();

      if (text1.Length == 0) {
        // Just add some text (speedup).
        diffs.Add(new Diff(Operation.INSERT, text2));
        return diffs;
      }

      if (text2.Length == 0) {
        // Just delete some text (speedup).
        diffs.Add(new Diff(Operation.DELETE, text1));
        return diffs;
      }

      string longtext = text1.Length > text2.Length ? text1 : text2;
      string shorttext = text1.Length > text2.Length ? text2 : text1;
      int i = longtext.IndexOf(shorttext, StringComparison.Ordinal);
      if (i != -1) {
        // Shorter text is inside the longer text (speedup).
        Operation op = (text1.Length > text2.Length) ?
            Operation.DELETE : Operation.INSERT;
        diffs.Add(new Diff(op, longtext.Substring(0, i)));
        diffs.Add(new Diff(Operation.EQUAL, shorttext));
        diffs.Add(new Diff(op, longtext.Substring(i + shorttext.Length)));
        return diffs;
      }

      if (shorttext.Length == 1) {
        // Single character string.
        // After the previous speedup, the character can't be an equality.
        diffs.Add(new Diff(Operation.DELETE, text1));
        diffs.Add(new Diff(Operation.INSERT, text2));
        return diffs;
      }

      // Check to see if the problem can be split in two.
      string[] hm = diff_halfMatch(text1, text2);
      if (hm != null) {
        // A half-match was found, sort out the return data.
        string text1_a = hm[0];
        string text1_b = hm[1];
        string text2_a = hm[2];
        string text2_b = hm[3];
        string mid_common = hm[4];
        // Send both pairs off for separate processing.
        List<Diff> diffs_a = diff_main(text1_a, text2_a, checklines, deadline);
        List<Diff> diffs_b = diff_main(text1_b, text2_b, checklines, deadline);
        // Merge the results.
        diffs = diffs_a;
        diffs.Add(new Diff(Operation.EQUAL, mid_common));
        diffs.AddRange(diffs_b);
        return diffs;
      }

      if (checklines && text1.Length > 100 && text2.Length > 100) {
        return diff_lineMode(text1, text2, deadline);
      }

      return diff_bisect(text1, text2, deadline);
    }

    /**
     * Do a quick line-level diff on both strings, then rediff the parts for
     * greater accuracy.
     * This speedup can produce non-minimal diffs.
     * @param text1 Old string to be diffed.
     * @param text2 New string to be diffed.
     * @param deadline Time when the diff should be complete by.
     * @return List of Diff objects.
     */
    private List<Diff> diff_lineMode(string text1, string text2,
                                     DateTime deadline) {
      // Scan the text on a line-by-line basis first.
      Object[] a = diff_linesToChars(text1, text2);
      text1 = (string)a[0];
      text2 = (string)a[1];
      List<string> linearray = (List<string>)a[2];

      List<Diff> diffs = diff_main(text1, text2, false, deadline);

      // Convert the diff back to original text.
      diff_charsToLines(diffs, linearray);
      // Eliminate freak matches (e.g. blank lines)
      diff_cleanupSemantic(diffs);

      // Rediff any replacement blocks, this time character-by-character.
      // Add a dummy entry at the end.
      diffs.Add(new Diff(Operation.EQUAL, string.Empty));
      int pointer = 0;
      int count_delete = 0;
      int count_insert = 0;
      string text_delete = string.Empty;
      string text_insert = string.Empty;
      while (pointer < diffs.Count) {
        switch (diffs[pointer].operation) {
          case Operation.INSERT:
            count_insert++;
            text_insert += diffs[pointer].text;
            break;
          case Operation.DELETE:
            count_delete++;
            text_delete += diffs[pointer].text;
            break;
          case Operation.EQUAL:
            // Upon reaching an equality, check for prior redundancies.
            if (count_delete >= 1 && count_insert >= 1) {
              // Delete the offending records and add the merged ones.
              diffs.RemoveRange(pointer - count_delete - count_insert,
                  count_delete + count_insert);
              pointer = pointer - count_delete - count_insert;
              List<Diff> subDiff =
                  this.diff_main(text_delete, text_insert, false, deadline);
              diffs.InsertRange(pointer, subDiff);
              pointer = pointer + subDiff.Count;
            }
            count_insert = 0;
            count_delete = 0;
            text_delete = string.Empty;
            text_insert = string.Empty;
            break;
        }
        pointer++;
      }
      diffs.RemoveAt(diffs.Count - 1);  // Remove the dummy entry at the end.

      return diffs;
    }

    /**
     * Find the 'middle snake' of a diff, split the problem in two
     * and return the recursively constructed diff.
     * See Myers 1986 paper: An O(ND) Difference Algorithm and Its Variations.
     * @param text1 Old string to be diffed.
     * @param text2 New string to be diffed.
     * @param deadline Time at which to bail if not yet complete.
     * @return List of Diff objects.
     */
    protected List<Diff> diff_bisect(string text1, string text2,
        DateTime deadline) {
      // Cache the text lengths to prevent multiple calls.
      int text1_length = text1.Length;
      int text2_length = text2.Length;
      int max_d = (text1_length + text2_length + 1) / 2;
      int v_offset = max_d;
      int v_length = 2 * max_d;
      int[] v1 = new int[v_length];
      int[] v2 = new int[v_length];
      for (int x = 0; x < v_length; x++) {
        v1[x] = -1;
        v2[x] = -1;
      }
      v1[v_offset + 1] = 0;
      v2[v_offset + 1] = 0;
      int delta = text1_length - text2_length;
      // If the total number of characters is odd, then the front path will
      // collide with the reverse path.
      bool front = (delta % 2 != 0);
      // Offsets for start and end of k loop.
      // Prevents mapping of space beyond the grid.
      int k1start = 0;
      int k1end = 0;
      int k2start = 0;
      int k2end = 0;
      for (int d = 0; d < max_d; d++) {
        // Bail out if deadline is reached.
        if (DateTime.Now > deadline) {
          break;
        }

        // Walk the front path one step.
        for (int k1 = -d + k1start; k1 <= d - k1end; k1 += 2) {
          int k1_offset = v_offset + k1;
          int x1;
          if (k1 == -d || k1 != d && v1[k1_offset - 1] < v1[k1_offset + 1]) {
            x1 = v1[k1_offset + 1];
          } else {
            x1 = v1[k1_offset - 1] + 1;
          }
          int y1 = x1 - k1;
          while (x1 < text1_length && y1 < text2_length
                && text1[x1] == text2[y1]) {
            x1++;
            y1++;
          }
          v1[k1_offset] = x1;
          if (x1 > text1_length) {
            // Ran off the right of the graph.
            k1end += 2;
          } else if (y1 > text2_length) {
            // Ran off the bottom of the graph.
            k1start += 2;
          } else if (front) {
            int k2_offset = v_offset + delta - k1;
            if (k2_offset >= 0 && k2_offset < v_length && v2[k2_offset] != -1) {
              // Mirror x2 onto top-left coordinate system.
              int x2 = text1_length - v2[k2_offset];
              if (x1 >= x2) {
                // Overlap detected.
                return diff_bisectSplit(text1, text2, x1, y1, deadline);
              }
            }
          }
        }

        // Walk the reverse path one step.
        for (int k2 = -d + k2start; k2 <= d - k2end; k2 += 2) {
          int k2_offset = v_offset + k2;
          int x2;
          if (k2 == -d || k2 != d && v2[k2_offset - 1] < v2[k2_offset + 1]) {
            x2 = v2[k2_offset + 1];
          } else {
            x2 = v2[k2_offset - 1] + 1;
          }
          int y2 = x2 - k2;
          while (x2 < text1_length && y2 < text2_length
              && text1[text1_length - x2 - 1]
              == text2[text2_length - y2 - 1]) {
            x2++;
            y2++;
          }
          v2[k2_offset] = x2;
          if (x2 > text1_length) {
            // Ran off the left of the graph.
            k2end += 2;
          } else if (y2 > text2_length) {
            // Ran off the top of the graph.
            k2start += 2;
          } else if (!front) {
            int k1_offset = v_offset + delta - k2;
            if (k1_offset >= 0 && k1_offset < v_length && v1[k1_offset] != -1) {
              int x1 = v1[k1_offset];
              int y1 = v_offset + x1 - k1_offset;
              // Mirror x2 onto top-left coordinate system.
              x2 = text1_length - v2[k2_offset];
              if (x1 >= x2) {
                // Overlap detected.
                return diff_bisectSplit(text1, text2, x1, y1, deadline);
              }
            }
          }
        }
      }
      // Diff took too long and hit the deadline or
      // number of diffs equals number of characters, no commonality at all.
      List<Diff> diffs = new List<Diff>();
      diffs.Add(new Diff(Operation.DELETE, text1));
      diffs.Add(new Diff(Operation.INSERT, text2));
      return diffs;
    }

    /**
     * Given the location of the 'middle snake', split the diff in two parts
     * and recurse.
     * @param text1 Old string to be diffed.
     * @param text2 New string to be diffed.
     * @param x Index of split point in text1.
     * @param y Index of split point in text2.
     * @param deadline Time at which to bail if not yet complete.
     * @return LinkedList of Diff objects.
     */
    private List<Diff> diff_bisectSplit(string text1, string text2,
        int x, int y, DateTime deadline) {
      string text1a = text1.Substring(0, x);
      string text2a = text2.Substring(0, y);
      string text1b = text1.Substring(x);
      string text2b = text2.Substring(y);

      // Compute both diffs serially.
      List<Diff> diffs = diff_main(text1a, text2a, false, deadline);
      List<Diff> diffsb = diff_main(text1b, text2b, false, deadline);

      diffs.AddRange(diffsb);
      return diffs;
    }

    /**
     * Split two texts into a list of strings.  Reduce the texts to a string of
     * hashes where each Unicode character represents one line.
     * @param text1 First string.
     * @param text2 Second string.
     * @return Three element Object array, containing the encoded text1, the
     *     encoded text2 and the List of unique strings.  The zeroth element
     *     of the List of unique strings is intentionally blank.
     */
    protected Object[] diff_linesToChars(string text1, string text2) {
      List<string> lineArray = new List<string>();
      Dictionary<string, int> lineHash = new Dictionary<string, int>();
      // e.g. linearray[4] == "Hello\n"
      // e.g. linehash.get("Hello\n") == 4

      // "\x00" is a valid character, but various debuggers don't like it.
      // So we'll insert a junk entry to avoid generating a null character.
      lineArray.Add(string.Empty);

      // Allocate 2/3rds of the space for text1, the rest for text2.
      string chars1 = diff_linesToCharsMunge(text1, lineArray, lineHash, 40000);
      string chars2 = diff_linesToCharsMunge(text2, lineArray, lineHash, 65535);
      return new Object[] { chars1, chars2, lineArray };
    }

    /**
     * Split a text into a list of strings.  Reduce the texts to a string of
     * hashes where each Unicode character represents one line.
     * @param text String to encode.
     * @param lineArray List of unique strings.
     * @param lineHash Map of strings to indices.
     * @param maxLines Maximum length of lineArray.
     * @return Encoded string.
     */
    private string diff_linesToCharsMunge(string text, List<string> lineArray,
        Dictionary<string, int> lineHash, int maxLines) {
      int lineStart = 0;
      int lineEnd = -1;
      string line;
      StringBuilder chars = new StringBuilder();
      // Walk the text, pulling out a Substring for each line.
      // text.split('\n') would would temporarily double our memory footprint.
      // Modifying text would create many large strings to garbage collect.
      while (lineEnd < text.Length - 1) {
        lineEnd = text.IndexOf('\n', lineStart);
        if (lineEnd == -1) {
          lineEnd = text.Length - 1;
        }
        line = text.JavaSubstring(lineStart, lineEnd + 1);

        if (lineHash.ContainsKey(line)) {
          chars.Append(((char)(int)lineHash[line]));
        } else {
          if (lineArray.Count == maxLines) {
            // Bail out at 65535 because char 65536 == char 0.
            line = text.Substring(lineStart);
            lineEnd = text.Length;
          }
          lineArray.Add(line);
          lineHash.Add(line, lineArray.Count - 1);
          chars.Append(((char)(lineArray.Count - 1)));
        }
        lineStart = lineEnd + 1;
      }
      return chars.ToString();
    }

    /**
     * Rehydrate the text in a diff from a string of line hashes to real lines
     * of text.
     * @param diffs List of Diff objects.
     * @param lineArray List of unique strings.
     */
    protected void diff_charsToLines(ICollection<Diff> diffs,
                    IList<string> lineArray) {
      StringBuilder text;
      foreach (Diff diff in diffs) {
        text = new StringBuilder();
        for (int j = 0; j < diff.text.Length; j++) {
          text.Append(lineArray[diff.text[j]]);
        }
        diff.text = text.ToString();
      }
    }

    /**
     * Determine the common prefix of two strings.
     * @param text1 First string.
     * @param text2 Second string.
     * @return The number of characters common to the start of each string.
     */
    public int diff_commonPrefix(string text1, string text2) {
      // Performance analysis: https://neil.fraser.name/news/2007/10/09/
      int n = Math.Min(text1.Length, text2.Length);
      for (int i = 0; i < n; i++) {
        if (text1[i] != text2[i]) {
          return i;
        }
      }
      return n;
    }

    /**
     * Determine the common suffix of two strings.
     * @param text1 First string.
     * @param text2 Second string.
     * @return The number of characters common to the end of each string.
     */
    public int diff_commonSuffix(string text1, string text2) {
      // Performance analysis: https://neil.fraser.name/news/2007/10/09/
      int text1_length = text1.Length;
      int text2_length = text2.Length;
      int n = Math.Min(text1.Length, text2.Length);
      for (int i = 1; i <= n; i++) {
        if (text1[text1_length - i] != text2[text2_length - i]) {
          return i - 1;
        }
      }
      return n;
    }

    /**
     * Determine if the suffix of one string is the prefix of another.
     * @param text1 First string.
     * @param text2 Second string.
     * @return The number of characters common to the end of the first
     *     string and the start of the second string.
     */
    protected int diff_commonOverlap(string text1, string text2) {
      // Cache the text lengths to prevent multiple calls.
      int text1_length = text1.Length;
      int text2_length = text2.Length;
      // Eliminate the null case.
      if (text1_length == 0 || text2_length == 0) {
        return 0;
      }
      // Truncate the longer string.
      if (text1_length > text2_length) {
        text1 = text1.Substring(text1_length - text2_length);
      } else if (text1_length < text2_length) {
        text2 = text2.Substring(0, text1_length);
      }
      int text_length = Math.Min(text1_length, text2_length);
      // Quick check for the worst case.
      if (text1 == text2) {
        return text_length;
      }

      // Start by looking for a single character match
      // and increase length until no match is found.
      // Performance analysis: https://neil.fraser.name/news/2010/11/04/
      int best = 0;
      int length = 1;
      while (true) {
        string pattern = text1.Substring(text_length - length);
        int found = text2.IndexOf(pattern, StringComparison.Ordinal);
        if (found == -1) {
          return best;
        }
        length += found;
        if (found == 0 || text1.Substring(text_length - length) ==
            text2.Substring(0, length)) {
          best = length;
          length++;
        }
      }
    }

    /**
     * Do the two texts share a Substring which is at least half the length of
     * the longer text?
     * This speedup can produce non-minimal diffs.
     * @param text1 First string.
     * @param text2 Second string.
     * @return Five element String array, containing the prefix of text1, the
     *     suffix of text1, the prefix of text2, the suffix of text2 and the
     *     common middle.  Or null if there was no match.
     */

    protected string[] diff_halfMatch(string text1, string text2) {
      if (this.Diff_Timeout <= 0) {
        // Don't risk returning a non-optimal diff if we have unlimited time.
        return null;
      }
      string longtext = text1.Length > text2.Length ? text1 : text2;
      string shorttext = text1.Length > text2.Length ? text2 : text1;
      if (longtext.Length < 4 || shorttext.Length * 2 < longtext.Length) {
        return null;  // Pointless.
      }

      // First check if the second quarter is the seed for a half-match.
      string[] hm1 = diff_halfMatchI(longtext, shorttext,
                                     (longtext.Length + 3) / 4);
      // Check again based on the third quarter.
      string[] hm2 = diff_halfMatchI(longtext, shorttext,
                                     (longtext.Length + 1) / 2);
      string[] hm;
      if (hm1 == null && hm2 == null) {
        return null;
      } else if (hm2 == null) {
        hm = hm1;
      } else if (hm1 == null) {
        hm = hm2;
      } else {
        // Both matched.  Select the longest.
        hm = hm1[4].Length > hm2[4].Length ? hm1 : hm2;
      }

      // A half-match was found, sort out the return data.
      if (text1.Length > text2.Length) {
        return hm;
        //return new string[]{hm[0], hm[1], hm[2], hm[3], hm[4]};
      } else {
        return new string[] { hm[2], hm[3], hm[0], hm[1], hm[4] };
      }
    }

    /**
     * Does a Substring of shorttext exist within longtext such that the
     * Substring is at least half the length of longtext?
     * @param longtext Longer string.
     * @param shorttext Shorter string.
     * @param i Start index of quarter length Substring within longtext.
     * @return Five element string array, containing the prefix of longtext, the
     *     suffix of longtext, the prefix of shorttext, the suffix of shorttext
     *     and the common middle.  Or null if there was no match.
     */
    private string[] diff_halfMatchI(string longtext, string shorttext, int i) {
      // Start with a 1/4 length Substring at position i as a seed.
      string seed = longtext.Substring(i, longtext.Length / 4);
      int j = -1;
      string best_common = string.Empty;
      string best_longtext_a = string.Empty, best_longtext_b = string.Empty;
      string best_shorttext_a = string.Empty, best_shorttext_b = string.Empty;
      while (j < shorttext.Length && (j = shorttext.IndexOf(seed, j + 1,
          StringComparison.Ordinal)) != -1) {
        int prefixLength = diff_commonPrefix(longtext.Substring(i),
                                             shorttext.Substring(j));
        int suffixLength = diff_commonSuffix(longtext.Substring(0, i),
                                             shorttext.Substring(0, j));
        if (best_common.Length < suffixLength + prefixLength) {
          best_common = shorttext.Substring(j - suffixLength, suffixLength)
              + shorttext.Substring(j, prefixLength);
          best_longtext_a = longtext.Substring(0, i - suffixLength);
          best_longtext_b = longtext.Substring(i + prefixLength);
          best_shorttext_a = shorttext.Substring(0, j - suffixLength);
          best_shorttext_b = shorttext.Substring(j + prefixLength);
        }
      }
      if (best_common.Length * 2 >= longtext.Length) {
        return new string[]{best_longtext_a, best_longtext_b,
            best_shorttext_a, best_shorttext_b, best_common};
      } else {
        return null;
      }
    }

    /**
     * Reduce the number of edits by eliminating semantically trivial
     * equalities.
     * @param diffs List of Diff objects.
     */
    public void diff_cleanupSemantic(List<Diff> diffs) {
      bool changes = false;
      // Stack of indices where equalities are found.
      Stack<int> equalities = new Stack<int>();
      // Always equal to equalities[equalitiesLength-1][1]
      string lastEquality = null;
      int pointer = 0;  // Index of current position.
      // Number of characters that changed prior to the equality.
      int length_insertions1 = 0;
      int length_deletions1 = 0;
      // Number of characters that changed after the equality.
      int length_insertions2 = 0;
      int length_deletions2 = 0;
      while (pointer < diffs.Count) {
        if (diffs[pointer].operation == Operation.EQUAL) {  // Equality found.
          equalities.Push(pointer);
          length_insertions1 = length_insertions2;
          length_deletions1 = length_deletions2;
          length_insertions2 = 0;
          length_deletions2 = 0;
          lastEquality = diffs[pointer].text;
        } else {  // an insertion or deletion
          if (diffs[pointer].operation == Operation.INSERT) {
            length_insertions2 += diffs[pointer].text.Length;
          } else {
            length_deletions2 += diffs[pointer].text.Length;
          }
          // Eliminate an equality that is smaller or equal to the edits on both
          // sides of it.
          if (lastEquality != null && (lastEquality.Length
              <= Math.Max(length_insertions1, length_deletions1))
              && (lastEquality.Length
                  <= Math.Max(length_insertions2, length_deletions2))) {
            // Duplicate record.
            diffs.Insert(equalities.Peek(),
                         new Diff(Operation.DELETE, lastEquality));
            // Change second copy to insert.
            diffs[equalities.Peek() + 1].operation = Operation.INSERT;
            // Throw away the equality we just deleted.
            equalities.Pop();
            if (equalities.Count > 0) {
              equalities.Pop();
            }
            pointer = equalities.Count > 0 ? equalities.Peek() : -1;
            length_insertions1 = 0;  // Reset the counters.
            length_deletions1 = 0;
            length_insertions2 = 0;
            length_deletions2 = 0;
            lastEquality = null;
            changes = true;
          }
        }
        pointer++;
      }

      // Normalize the diff.
      if (changes) {
        diff_cleanupMerge(diffs);
      }
      diff_cleanupSemanticLossless(diffs);

      // Find any overlaps between deletions and insertions.
      // e.g: <del>abcxxx</del><ins>xxxdef</ins>
      //   -> <del>abc</del>xxx<ins>def</ins>
      // e.g: <del>xxxabc</del><ins>defxxx</ins>
      //   -> <ins>def</ins>xxx<del>abc</del>
      // Only extract an overlap if it is as big as the edit ahead or behind it.
      pointer = 1;
      while (pointer < diffs.Count) {
        if (diffs[pointer - 1].operation == Operation.DELETE &&
            diffs[pointer].operation == Operation.INSERT) {
          string deletion = diffs[pointer - 1].text;
          string insertion = diffs[pointer].text;
          int overlap_length1 = diff_commonOverlap(deletion, insertion);
          int overlap_length2 = diff_commonOverlap(insertion, deletion);
          if (overlap_length1 >= overlap_length2) {
            if (overlap_length1 >= deletion.Length / 2.0 ||
                overlap_length1 >= insertion.Length / 2.0) {
              // Overlap found.
              // Insert an equality and trim the surrounding edits.
              diffs.Insert(pointer, new Diff(Operation.EQUAL,
                  insertion.Substring(0, overlap_length1)));
              diffs[pointer - 1].text =
                  deletion.Substring(0, deletion.Length - overlap_length1);
              diffs[pointer + 1].text = insertion.Substring(overlap_length1);
              pointer++;
            }
          } else {
            if (overlap_length2 >= deletion.Length / 2.0 ||
                overlap_length2 >= insertion.Length / 2.0) {
              // Reverse overlap found.
              // Insert an equality and swap and trim the surrounding edits.
              diffs.Insert(pointer, new Diff(Operation.EQUAL,
                  deletion.Substring(0, overlap_length2)));
              diffs[pointer - 1].operation = Operation.INSERT;
              diffs[pointer - 1].text =
                  insertion.Substring(0, insertion.Length - overlap_length2);
              diffs[pointer + 1].operation = Operation.DELETE;
              diffs[pointer + 1].text = deletion.Substring(overlap_length2);
              pointer++;
            }
          }
          pointer++;
        }
        pointer++;
      }
    }

    /**
     * Look for single edits surrounded on both sides by equalities
     * which can be shifted sideways to align the edit to a word boundary.
     * e.g: The c<ins>at c</ins>ame. -> The <ins>cat </ins>came.
     * @p
Download .txt
gitextract_e25j56v0/

├── .gitignore
├── AUTHORS
├── CONTRIBUTING.md
├── LICENSE
├── README.md
├── cpp/
│   ├── diff_match_patch.cpp
│   ├── diff_match_patch.h
│   ├── diff_match_patch.pro
│   ├── diff_match_patch_test.cpp
│   └── diff_match_patch_test.h
├── csharp/
│   ├── DiffMatchPatch.cs
│   └── tests/
│       ├── DiffMatchPatchTest.cs
│       ├── Speedtest.cs
│       ├── Speedtest1.txt
│       └── Speedtest2.txt
├── dart/
│   ├── DMPClass.dart
│   ├── DiffClass.dart
│   ├── DiffMatchPatch.dart
│   ├── PatchClass.dart
│   └── tests/
│       ├── DiffMatchPatchTest.dart
│       ├── Speedtest.dart
│       ├── Speedtest.dart.js
│       ├── Speedtest.html
│       └── SpeedtestVM.dart
├── demos/
│   ├── diff.html
│   ├── match.html
│   └── patch.html
├── java/
│   ├── src/
│   │   └── name/
│   │       └── fraser/
│   │           └── neil/
│   │               └── plaintext/
│   │                   └── diff_match_patch.java
│   └── tests/
│       └── name/
│           └── fraser/
│               └── neil/
│                   └── plaintext/
│                       ├── Speedtest.java
│                       ├── Speedtest1.txt
│                       ├── Speedtest2.txt
│                       └── diff_match_patch_test.java
├── javascript/
│   ├── diff_match_patch.js
│   ├── diff_match_patch_uncompressed.js
│   └── tests/
│       ├── diff_match_patch_test.html
│       ├── diff_match_patch_test.js
│       └── speedtest.html
├── lua/
│   ├── diff_match_patch.lua
│   └── tests/
│       ├── diff_match_patch_test.lua
│       ├── speedtest.lua
│       ├── speedtest1.txt
│       └── speedtest2.txt
├── objectivec/
│   ├── DiffMatchPatch.h
│   ├── DiffMatchPatch.m
│   ├── DiffMatchPatch.xcodeproj/
│   │   ├── project.pbxproj
│   │   └── project.xcworkspace/
│   │       ├── contents.xcworkspacedata
│   │       └── xcshareddata/
│   │           └── WorkspaceSettings.xcsettings
│   ├── DiffMatchPatchCFUtilities.c
│   ├── DiffMatchPatchCFUtilities.h
│   ├── DiffMatchPatch_Prefix.pch
│   ├── English.lproj/
│   │   └── InfoPlist.strings
│   ├── Info.plist
│   ├── MinMaxMacros.h
│   ├── NSMutableDictionary+DMPExtensions.h
│   ├── NSMutableDictionary+DMPExtensions.m
│   ├── NSString+JavaSubstring.h
│   ├── NSString+JavaSubstring.m
│   ├── NSString+UnicharUtilities.h
│   ├── NSString+UnicharUtilities.m
│   ├── NSString+UriCompatibility.h
│   ├── NSString+UriCompatibility.m
│   ├── Tests/
│   │   ├── DiffMatchPatchTest-Info.plist
│   │   ├── DiffMatchPatchTest.h
│   │   ├── DiffMatchPatchTest.m
│   │   ├── Speedtest1.txt
│   │   ├── Speedtest2.txt
│   │   └── speedtest.m
│   └── speedtest_Prefix.pch
├── python2/
│   ├── __init__.py
│   ├── diff_match_patch.py
│   └── tests/
│       ├── diff_match_patch_test.py
│       ├── speedtest.py
│       ├── speedtest1.txt
│       └── speedtest2.txt
└── python3/
    ├── __init__.py
    ├── diff_match_patch.py
    └── tests/
        ├── diff_match_patch_test.py
        ├── speedtest.py
        ├── speedtest1.txt
        └── speedtest2.txt
Download .txt
SYMBOL INDEX (558 symbols across 29 files)

FILE: cpp/diff_match_patch.cpp
  function QString (line 48) | QString Diff::strOperation(Operation op) {
  function QString (line 64) | QString Diff::toString() const {
  function QString (line 116) | QString Patch::toString() {
  function foreach (line 350) | foreach(Diff newDiff,
  function QString (line 523) | QString diff_match_patch::diff_linesToCharsMunge(const QString &text,
  function QStringList (line 638) | QStringList diff_match_patch::diff_halfMatch(const QString &text1,
  function QStringList (line 679) | QStringList diff_match_patch::diff_halfMatchI(const QString &longtext,
  function foreach (line 1247) | foreach(Diff aDiff, diffs) {
  function QString (line 1273) | QString diff_match_patch::diff_prettyHtml(const QList<Diff> &diffs) {
  function QString (line 1298) | QString diff_match_patch::diff_text1(const QList<Diff> &diffs) {
  function QString (line 1309) | QString diff_match_patch::diff_text2(const QList<Diff> &diffs) {
  function foreach (line 1324) | foreach(Diff aDiff, diffs) {
  function QString (line 1345) | QString diff_match_patch::diff_toDelta(const QList<Diff> &diffs) {
  function foreach (line 1378) | foreach(QString token, tokens) {
  function foreach (line 1678) | foreach(Diff aDiff, diffs) {
  function foreach (line 1744) | foreach(Patch aPatch, patches) {
  function foreach (line 1781) | foreach(Patch aPatch, patchesCopy) {
  function QString (line 1862) | QString diff_match_patch::patch_addPadding(QList<Patch> &patches) {
  function QString (line 2024) | QString diff_match_patch::patch_toText(const QList<Patch> &patches) {

FILE: cpp/diff_match_patch.h
  type Operation (line 66) | enum Operation {
  function isNull (line 88) | inline bool isNull() const;
  function class (line 121) | class diff_match_patch {

FILE: cpp/diff_match_patch_test.cpp
  function main (line 24) | int main(int argc, char **argv) {
  function foreach (line 955) | foreach(Diff d1, list1) {
  function foreach (line 971) | foreach(Diff d1, list1) {
  function foreach (line 981) | foreach(Diff d2, list2) {
  function foreach (line 1000) | foreach(QVariant q1, list1) {
  function foreach (line 1016) | foreach(QVariant q1, list1) {
  function foreach (line 1026) | foreach(QVariant q2, list2) {
  function QStringList (line 1105) | QStringList diff_match_patch_test::diff_rebuildtexts(QList<Diff> diffs) {

FILE: cpp/diff_match_patch_test.h
  function class (line 22) | class diff_match_patch_test {

FILE: csharp/DiffMatchPatch.cs
  class CompatibilityExtensions (line 27) | internal static class CompatibilityExtensions {
    method Splice (line 29) | public static List<T> Splice<T>(this List<T> input, int start, int count,
    method JavaSubstring (line 39) | public static string JavaSubstring(this string s, int begin, int end) {
  type Operation (line 50) | public enum Operation {
  class Diff (line 58) | public class Diff {
    method Diff (line 69) | public Diff(Operation operation, string text) {
    method ToString (line 79) | public override string ToString() {
    method Equals (line 89) | public override bool Equals(Object obj) {
    method Equals (line 105) | public bool Equals(Diff obj) {
    method GetHashCode (line 115) | public override int GetHashCode() {
  class Patch (line 124) | public class Patch {
    method ToString (line 137) | public override string ToString() {
  class diff_match_patch (line 181) | public class diff_match_patch {
    method diff_main (line 219) | public List<Diff> diff_main(string text1, string text2) {
    method diff_main (line 232) | public List<Diff> diff_main(string text1, string text2, bool checkline...
    method diff_main (line 257) | private List<Diff> diff_main(string text1, string text2, bool checklines,
    method diff_compute (line 309) | private List<Diff> diff_compute(string text1, string text2,
    method diff_lineMode (line 381) | private List<Diff> diff_lineMode(string text1, string text2,
    method diff_bisect (line 448) | protected List<Diff> diff_bisect(string text1, string text2,
    method diff_bisectSplit (line 571) | private List<Diff> diff_bisectSplit(string text1, string text2,
    method diff_linesToChars (line 595) | protected Object[] diff_linesToChars(string text1, string text2) {
    method diff_linesToCharsMunge (line 620) | private string diff_linesToCharsMunge(string text, List<string> lineAr...
    method diff_charsToLines (line 659) | protected void diff_charsToLines(ICollection<Diff> diffs,
    method diff_commonPrefix (line 677) | public int diff_commonPrefix(string text1, string text2) {
    method diff_commonSuffix (line 694) | public int diff_commonSuffix(string text1, string text2) {
    method diff_commonOverlap (line 714) | protected int diff_commonOverlap(string text1, string text2) {
    method diff_halfMatch (line 765) | protected string[] diff_halfMatch(string text1, string text2) {
    method diff_halfMatchI (line 813) | private string[] diff_halfMatchI(string longtext, string shorttext, in...
    method diff_cleanupSemantic (line 848) | public void diff_cleanupSemantic(List<Diff> diffs) {
    method diff_cleanupSemanticLossless (line 962) | public void diff_cleanupSemanticLossless(List<Diff> diffs) {
    method diff_cleanupSemanticScore (line 1035) | private int diff_cleanupSemanticScore(string one, string two) {
    method diff_cleanupEfficiency (line 1085) | public void diff_cleanupEfficiency(List<Diff> diffs) {
    method diff_cleanupMerge (line 1169) | public void diff_cleanupMerge(List<Diff> diffs) {
    method diff_xIndex (line 1301) | public int diff_xIndex(List<Diff> diffs, int loc) {
    method diff_prettyHtml (line 1337) | public string diff_prettyHtml(List<Diff> diffs) {
    method diff_text1 (line 1364) | public string diff_text1(List<Diff> diffs) {
    method diff_text2 (line 1379) | public string diff_text2(List<Diff> diffs) {
    method diff_levenshtein (line 1395) | public int diff_levenshtein(List<Diff> diffs) {
    method diff_toDelta (line 1428) | public string diff_toDelta(List<Diff> diffs) {
    method diff_fromDelta (line 1459) | public List<Diff> diff_fromDelta(string text1, string delta) {
    method match_main (line 1542) | public int match_main(string text, string pattern, int loc) {
    method match_bitap (line 1570) | protected int match_bitap(string text, string pattern, int loc) {
    method match_bitapScore (line 1675) | private double match_bitapScore(int e, int x, int loc, string pattern) {
    method match_alphabet (line 1690) | protected Dictionary<char, int> match_alphabet(string pattern) {
    method patch_addContext (line 1717) | protected void patch_addContext(Patch patch, string text) {
    method patch_make (line 1764) | public List<Patch> patch_make(string text1, string text2) {
    method patch_make (line 1781) | public List<Patch> patch_make(List<Diff> diffs) {
    method patch_make (line 1797) | public List<Patch> patch_make(string text1, string text2,
    method patch_make (line 1809) | public List<Patch> patch_make(string text1, List<Diff> diffs) {
    method patch_deepCopy (line 1890) | public List<Patch> patch_deepCopy(List<Patch> patches) {
    method patch_apply (line 1915) | public Object[] patch_apply(List<Patch> patches, string text) {
    method patch_addPadding (line 2022) | public string patch_addPadding(List<Patch> patches) {
    method patch_splitMax (line 2083) | public void patch_splitMax(List<Patch> patches) {
    method patch_toText (line 2183) | public string patch_toText(List<Patch> patches) {
    method patch_fromText (line 2198) | public List<Patch> patch_fromText(string textline) {
    method encodeURI (line 2283) | public static string encodeURI(string str) {

FILE: csharp/tests/DiffMatchPatchTest.cs
  class diff_match_patchTest (line 31) | public class diff_match_patchTest : diff_match_patch {
    method diff_commonPrefixTest (line 32) | public void diff_commonPrefixTest() {
    method diff_commonSuffixTest (line 41) | public void diff_commonSuffixTest() {
    method diff_commonOverlapTest (line 50) | public void diff_commonOverlapTest() {
    method diff_halfmatchTest (line 65) | public void diff_halfmatchTest() {
    method diff_linesToCharsTest (line 92) | public void diff_linesToCharsTest() {
    method diff_charsToLinesTest (line 143) | public void diff_charsToLinesTest() {
    method diff_cleanupMergeTest (line 194) | public void diff_cleanupMergeTest() {
    method diff_cleanupSemanticLosslessTest (line 253) | public void diff_cleanupSemanticLosslessTest() {
    method diff_cleanupSemanticTest (line 329) | public void diff_cleanupSemanticTest() {
    method diff_cleanupEfficiencyTest (line 448) | public void diff_cleanupEfficiencyTest() {
    method diff_prettyHtmlTest (line 517) | public void diff_prettyHtmlTest() {
    method diff_textTest (line 527) | public void diff_textTest() {
    method diff_deltaTest (line 542) | public void diff_deltaTest() {
    method diff_xIndexTest (line 628) | public void diff_xIndexTest() {
    method diff_levenshteinTest (line 643) | public void diff_levenshteinTest() {
    method diff_bisectTest (line 663) | public void diff_bisectTest() {
    method diff_mainTest (line 678) | public void diff_mainTest() {
    method match_alphabetTest (line 760) | public void match_alphabetTest() {
    method match_bitapTest (line 771) | public void match_bitapTest() {
    method match_mainTest (line 816) | public void match_mainTest() {
    method patch_patchObjTest (line 837) | public void patch_patchObjTest() {
    method patch_fromTextTest (line 856) | public void patch_fromTextTest() {
    method patch_toTextTest (line 877) | public void patch_toTextTest() {
    method patch_addContextTest (line 890) | public void patch_addContextTest() {
    method patch_makeTest (line 910) | public void patch_makeTest() {
    method patch_splitMaxTest (line 960) | public void patch_splitMaxTest() {
    method patch_addPaddingTest (line 982) | public void patch_addPaddingTest() {
    method patch_applyTest (line 1012) | public void patch_applyTest() {
    method diff_rebuildtexts (line 1098) | private string[] diff_rebuildtexts(List<Diff> diffs) {
    method assertEquals (line 1111) | private static void assertEquals(string error_msg, string expected, st...
    method assertEquals (line 1117) | private static void assertEquals(string error_msg, string[] expected, ...
    method assertEquals (line 1128) | private static void assertEquals(string error_msg, List<string> expect...
    method assertEquals (line 1139) | private static void assertEquals(string error_msg, List<Diff> expected...
    method assertEquals (line 1150) | private static void assertEquals(string error_msg, Diff expected, Diff...
    method assertEquals (line 1156) | private static void assertEquals(string error_msg, Dictionary<char, in...
    method assertEquals (line 1172) | private static void assertEquals(string error_msg, int expected, int a...
    method assertTrue (line 1178) | private static void assertTrue(string error_msg, bool expected) {
    method assertNull (line 1184) | private static void assertNull(string error_msg, object value) {
    method assertFail (line 1190) | private static void assertFail(string error_msg) {
    method Main (line 1194) | public static void Main(string[] args) {

FILE: csharp/tests/Speedtest.cs
  class Speedtest (line 15) | public class Speedtest {
    method Main (line 16) | public static void Main(string[] args) {

FILE: dart/DMPClass.dart
  type Operation (line 35) | enum Operation { delete, insert, equal }
  class DiffMatchPatch (line 41) | class DiffMatchPatch {
    method diff_main (line 94) | List<Diff> diff_main(String text1, String text2,
    method _diff_compute (line 160) | List<Diff> _diff_compute(
    method _diff_lineMode (line 232) | List<Diff> _diff_lineMode(String text1, String text2, DateTime deadline)
    method _diff_bisect (line 299) | List<Diff> _diff_bisect(String text1, String text2, DateTime deadline)
    method test_diff_bisect (line 414) | List<Diff> test_diff_bisect(String text1, String text2, DateTime deadl...
    method _diff_bisectSplit (line 428) | List<Diff> _diff_bisectSplit(
    method _diff_linesToChars (line 452) | Map<String, dynamic> _diff_linesToChars(String text1, String text2)
    method test_diff_linesToChars (line 471) | Map<String, dynamic> test_diff_linesToChars(String text1, String text2)
    method _diff_linesToCharsMunge (line 484) | String _diff_linesToCharsMunge(String text, List<String> lineArray,
    method _diff_charsToLines (line 526) | void _diff_charsToLines(List<Diff> diffs, List<String> lineArray)
    method test_diff_charsToLines (line 540) | void test_diff_charsToLines(List<Diff> diffs, List<String> lineArray)
    method diff_commonPrefix (line 550) | int diff_commonPrefix(String text1, String text2)
    method diff_commonSuffix (line 569) | int diff_commonSuffix(String text1, String text2)
    method _diff_commonOverlap (line 591) | int _diff_commonOverlap(String text1, String text2)
    method test_diff_commonOverlap (line 634) | int test_diff_commonOverlap(String text1, String text2)
    method _diff_halfMatch (line 648) | List<String> _diff_halfMatch(String text1, String text2)
    method test_diff_halfMatch (line 689) | List<String> test_diff_halfMatch(String text1, String text2)
    method _diff_halfMatchI (line 703) | List<String> _diff_halfMatchI(String longtext, String shorttext, int i)
    method diff_cleanupSemantic (line 742) | void diff_cleanupSemantic(List<Diff> diffs)
    method _diff_cleanupSemanticLossless (line 863) | void _diff_cleanupSemanticLossless(List<Diff> diffs)
    method _diff_cleanupSemanticScore (line 873) | int _diff_cleanupSemanticScore(String one, String two)
    method test_diff_cleanupSemanticLossless (line 978) | void test_diff_cleanupSemanticLossless(List<Diff> diffs)
    method diff_cleanupEfficiency (line 993) | void diff_cleanupEfficiency(List<Diff> diffs)
    method diff_cleanupMerge (line 1081) | void diff_cleanupMerge(List<Diff> diffs)
    method diff_xIndex (line 1216) | int diff_xIndex(List<Diff> diffs, int loc)
    method diff_prettyHtml (line 1252) | String diff_prettyHtml(List<Diff> diffs)
    method diff_text1 (line 1286) | String diff_text1(List<Diff> diffs)
    method diff_text2 (line 1301) | String diff_text2(List<Diff> diffs)
    method diff_levenshtein (line 1317) | int diff_levenshtein(List<Diff> diffs)
    method diff_toDelta (line 1349) | String diff_toDelta(List<Diff> diffs)
    method diff_fromDelta (line 1386) | List<Diff> diff_fromDelta(String text1, String delta)
    method match_main (line 1459) | int match_main(String text, String pattern, int loc)
    method _match_bitap (line 1490) | int _match_bitap(String text, String pattern, int loc)
    method test_match_bitap (line 1588) | int test_match_bitap(String text, String pattern, int loc)
    method _match_bitapScore (line 1600) | double _match_bitapScore(int e, int x, int loc, String pattern)
    method _match_alphabet (line 1615) | Map<String, int> _match_alphabet(String pattern)
    method test_match_alphabet (line 1629) | Map<String, int> test_match_alphabet(String pattern)
    method _patch_addContext (line 1641) | void _patch_addContext(Patch patch, String text)
    method test_patch_addContext (line 1682) | void test_patch_addContext(Patch patch, String text)
    method patch_make (line 1701) | List<Patch> patch_make(a, [opt_b, opt_c])
    method patch_deepCopy (line 1813) | List<Patch> patch_deepCopy(List<Patch> patches)
    method patch_apply (line 1837) | List patch_apply(List<Patch> patches, String text)
    method patch_addPadding (line 1947) | String patch_addPadding(List<Patch> patches)
    method patch_toText (line 2108) | String patch_toText(List<Patch> patches)
    method patch_fromText (line 2121) | List<Patch> patch_fromText(String textline)

FILE: dart/DiffClass.dart
  class Diff (line 24) | class Diff {
    method toString (line 45) | String toString()

FILE: dart/PatchClass.dart
  class Patch (line 24) | class Patch {
    method toString (line 44) | String toString()

FILE: dart/tests/DiffMatchPatchTest.dart
  class Expect (line 22) | class Expect {
    method equals (line 23) | void equals(var expected, var actual, String msg)
    method isNull (line 29) | void isNull(actual, String msg)
    method isTrue (line 34) | void isTrue(var actual, String msg)
    method throws (line 39) | void throws(void f(), String msg)
    method listEquals (line 48) | void listEquals(List expected, List actual, String msg)
    method mapEquals (line 66) | void mapEquals(Map expected, Map actual, String msg)
  function _diff_rebuildtexts (line 83) | List<String> _diff_rebuildtexts(diffs)
  function testDiffCommonPrefix (line 103) | void testDiffCommonPrefix()
  function testDiffCommonSuffix (line 112) | void testDiffCommonSuffix()
  function testDiffCommonOverlap (line 121) | void testDiffCommonOverlap()
  function testDiffHalfmatch (line 136) | void testDiffHalfmatch()
  function testDiffLinesToChars (line 164) | void testDiffLinesToChars()
  function assertLinesToCharsResultEquals (line 165) | void assertLinesToCharsResultEquals(Map<String, dynamic> a, Map<String, ...
  function testDiffCharsToLines (line 194) | void testDiffCharsToLines()
  function testDiffCleanupMerge (line 234) | void testDiffCleanupMerge()
  function testDiffCleanupSemanticLossless (line 293) | void testDiffCleanupSemanticLossless()
  function testDiffCleanupSemantic (line 328) | void testDiffCleanupSemantic()
  function testDiffCleanupEfficiency (line 375) | void testDiffCleanupEfficiency()
  function testDiffPrettyHtml (line 405) | void testDiffPrettyHtml()
  function testDiffText (line 411) | void testDiffText()
  function testDiffDelta (line 418) | void testDiffDelta()
  function testDiffXIndex (line 473) | void testDiffXIndex()
  function testDiffLevenshtein (line 482) | void testDiffLevenshtein()
  function testDiffBisect (line 493) | void testDiffBisect()
  function testDiffMain (line 512) | void testDiffMain()
  function testMatchAlphabet (line 599) | void testMatchAlphabet()
  function testMatchBitap (line 608) | void testMatchBitap()
  function testMatchMain (line 653) | void testMatchMain()
  function testPatchObj (line 679) | void testPatchObj()
  function testPatchFromText (line 691) | void testPatchFromText()
  function testPatchToText (line 707) | void testPatchToText()
  function testPatchAddContext (line 718) | void testPatchAddContext()
  function testPatchMake (line 738) | void testPatchMake()
  function testPatchSplitMax (line 784) | void testPatchSplitMax()
  function testPatchAddPadding (line 805) | void testPatchAddPadding()
  function testPatchApply (line 823) | void testPatchApply()
  function main (line 911) | main()

FILE: dart/tests/Speedtest.dart
  function launch (line 7) | void launch(Event e)
  function main (line 27) | void main()
  class TrustedNodeValidator (line 34) | class TrustedNodeValidator implements NodeValidator {
    method allowsElement (line 35) | bool allowsElement(Element element)
    method allowsAttribute (line 36) | bool allowsAttribute(Element element, String attributeName, String value)

FILE: dart/tests/Speedtest.dart.js
  function copyProperties (line 1) | function copyProperties(a,b){var u=Object.keys(a)
  function setFunctionNamesIfNecessary (line 10) | function setFunctionNamesIfNecessary(a){function t(){};if(typeof t.name=...
  function inherit (line 15) | function inherit(a,b){a.prototype.constructor=a
  function inheritMany (line 20) | function inheritMany(a,b){for(var u=0;u<b.length;u++)inherit(b[u],a)}
  function mixin (line 20) | function mixin(a,b){copyProperties(b.prototype,a.prototype)
  function lazy (line 21) | function lazy(a,b,c,d){var u=a
  function makeConstList (line 28) | function makeConstList(a){a.immutable$list=Array
  function convertToFastObject (line 30) | function convertToFastObject(a){function t(){}t.prototype=a
  function convertAllToFastObject (line 32) | function convertAllToFastObject(a){for(var u=0;u<a.length;++u)convertToF...
  function tearOffGetter (line 33) | function tearOffGetter(a,b,c,d,e){return e?new Function("funcs","applyTr...
  function tearOff (line 33) | function tearOff(a,b,c,d,e,f){var u=null
  function installTearOff (line 36) | function installTearOff(a,b,c,d,e,f,g,h,i,j){var u=[]
  function installStaticTearOff (line 49) | function installStaticTearOff(a,b,c,d,e,f,g,h){return installTearOff(a,b...
  function installInstanceTearOff (line 49) | function installInstanceTearOff(a,b,c,d,e,f,g,h,i){return installTearOff...
  function setOrUpdateInterceptorsByTag (line 49) | function setOrUpdateInterceptorsByTag(a){var u=v.interceptorsByTag
  function setOrUpdateLeafTags (line 51) | function setOrUpdateLeafTags(a){var u=v.leafTags
  function updateTypes (line 53) | function updateTypes(a){var u=v.types
  function updateHolder (line 56) | function updateHolder(a,b){copyProperties(b,a)
  function initializeDeferredHunk (line 59) | function initializeDeferredHunk(a){x=v.types.length
  function getGlobalFromName (line 60) | function getGlobalFromName(a){for(var u=0;u<w.length;u++){if(w[u]==C)con...
  function getTag (line 2037) | function getTag(o) {
  function getUnknownTag (line 2041) | function getUnknownTag(object, tag) {
  function getUnknownTagGenericBrowser (line 2048) | function getUnknownTagGenericBrowser(object, tag) {
  function prototypeForTag (line 2052) | function prototypeForTag(tag) {
  function discriminator (line 2059) | function discriminator(tag) { return null; }
  function confirm (line 2073) | function confirm(p) {
  function getTagFixed (line 2088) | function getTagFixed(o) {
  function prototypeForTagFixed (line 2096) | function prototypeForTagFixed(tag) {
  function getTagFirefox (line 2114) | function getTagFirefox(o) {
  function getTagIE (line 2132) | function getTagIE(o) {
  function prototypeForTagIE (line 2141) | function prototypeForTagIE(tag) {
  function onLoad (line 2207) | function onLoad(b){for(var s=0;s<u.length;++s)u[s].removeEventListener("...

FILE: dart/tests/SpeedtestVM.dart
  function main (line 3) | void main()

FILE: java/src/name/fraser/neil/plaintext/diff_match_patch.java
  class diff_match_patch (line 40) | public class diff_match_patch {
    class LinesToCharsResult (line 84) | protected static class LinesToCharsResult {
      method LinesToCharsResult (line 89) | protected LinesToCharsResult(String chars1, String chars2,
    type Operation (line 107) | public enum Operation {
    method diff_main (line 120) | public LinkedList<Diff> diff_main(String text1, String text2) {
    method diff_main (line 133) | public LinkedList<Diff> diff_main(String text1, String text2,
    method diff_main (line 157) | private LinkedList<Diff> diff_main(String text1, String text2,
    method diff_compute (line 212) | private LinkedList<Diff> diff_compute(String text1, String text2,
    method diff_lineMode (line 286) | private LinkedList<Diff> diff_lineMode(String text1, String text2,
    method diff_bisect (line 356) | protected LinkedList<Diff> diff_bisect(String text1, String text2,
    method diff_bisectSplit (line 479) | private LinkedList<Diff> diff_bisectSplit(String text1, String text2,
    method diff_linesToChars (line 503) | protected LinesToCharsResult diff_linesToChars(String text1, String te...
    method diff_linesToCharsMunge (line 528) | private String diff_linesToCharsMunge(String text, List<String> lineAr...
    method diff_charsToLines (line 568) | protected void diff_charsToLines(List<Diff> diffs,
    method diff_commonPrefix (line 586) | public int diff_commonPrefix(String text1, String text2) {
    method diff_commonSuffix (line 603) | public int diff_commonSuffix(String text1, String text2) {
    method diff_commonOverlap (line 623) | protected int diff_commonOverlap(String text1, String text2) {
    method diff_halfMatch (line 673) | protected String[] diff_halfMatch(String text1, String text2) {
    method diff_halfMatchI (line 721) | private String[] diff_halfMatchI(String longtext, String shorttext, in...
    method diff_cleanupSemantic (line 754) | public void diff_cleanupSemantic(LinkedList<Diff> diffs) {
    method diff_cleanupSemanticLossless (line 903) | public void diff_cleanupSemanticLossless(LinkedList<Diff> diffs) {
    method diff_cleanupSemanticScore (line 990) | private int diff_cleanupSemanticScore(String one, String two) {
    method diff_cleanupEfficiency (line 1043) | public void diff_cleanupEfficiency(LinkedList<Diff> diffs) {
    method diff_cleanupMerge (line 1151) | public void diff_cleanupMerge(LinkedList<Diff> diffs) {
    method diff_xIndex (line 1304) | public int diff_xIndex(List<Diff> diffs, int loc) {
    method diff_prettyHtml (line 1340) | public String diff_prettyHtml(List<Diff> diffs) {
    method diff_text1 (line 1367) | public String diff_text1(List<Diff> diffs) {
    method diff_text2 (line 1382) | public String diff_text2(List<Diff> diffs) {
    method diff_levenshtein (line 1398) | public int diff_levenshtein(List<Diff> diffs) {
    method diff_toDelta (line 1430) | public String diff_toDelta(List<Diff> diffs) {
    method diff_fromDelta (line 1468) | public LinkedList<Diff> diff_fromDelta(String text1, String delta)
    method match_main (line 1550) | public int match_main(String text, String pattern, int loc) {
    method match_bitap (line 1581) | protected int match_bitap(String text, String pattern, int loc) {
    method match_bitapScore (line 1684) | private double match_bitapScore(int e, int x, int loc, String pattern) {
    method match_alphabet (line 1699) | protected Map<Character, Integer> match_alphabet(String pattern) {
    method patch_addContext (line 1723) | protected void patch_addContext(Patch patch, String text) {
    method patch_make (line 1769) | public LinkedList<Patch> patch_make(String text1, String text2) {
    method patch_make (line 1788) | public LinkedList<Patch> patch_make(LinkedList<Diff> diffs) {
    method patch_make (line 1806) | @Deprecated public LinkedList<Patch> patch_make(String text1, String t...
    method patch_make (line 1818) | public LinkedList<Patch> patch_make(String text1, LinkedList<Diff> dif...
    method patch_deepCopy (line 1903) | public LinkedList<Patch> patch_deepCopy(LinkedList<Patch> patches) {
    method patch_apply (line 1928) | public Object[] patch_apply(LinkedList<Patch> patches, String text) {
    method patch_addPadding (line 2037) | public String patch_addPadding(LinkedList<Patch> patches) {
    method patch_splitMax (line 2098) | public void patch_splitMax(LinkedList<Patch> patches) {
    method patch_toText (line 2201) | public String patch_toText(List<Patch> patches) {
    method patch_fromText (line 2216) | public List<Patch> patch_fromText(String textline)
    class Diff (line 2308) | public static class Diff {
      method Diff (line 2323) | public Diff(Operation operation, String text) {
      method toString (line 2333) | public String toString() {
      method hashCode (line 2343) | @Override
      method equals (line 2356) | @Override
    class Patch (line 2386) | public static class Patch {
      method Patch (line 2396) | public Patch() {
      method toString (line 2406) | public String toString() {
    method unescapeForEncodeUriCompatability (line 2463) | private static String unescapeForEncodeUriCompatability(String str) {

FILE: java/tests/name/fraser/neil/plaintext/Speedtest.java
  class Speedtest (line 20) | public class Speedtest {
    method main (line 22) | public static void main(String args[]) throws IOException {
    method readFile (line 38) | private static String readFile(String filename) throws IOException {

FILE: java/tests/name/fraser/neil/plaintext/diff_match_patch_test.java
  class diff_match_patch_test (line 40) | public class diff_match_patch_test {
    method testDiffCommonPrefix (line 51) | public static void testDiffCommonPrefix() {
    method testDiffCommonSuffix (line 60) | public static void testDiffCommonSuffix() {
    method testDiffCommonOverlap (line 69) | public static void testDiffCommonOverlap() {
    method testDiffHalfmatch (line 84) | public static void testDiffHalfmatch() {
    method testDiffLinesToChars (line 112) | public static void testDiffLinesToChars() {
    method testDiffCharsToLines (line 151) | public static void testDiffCharsToLines() {
    method testDiffCleanupMerge (line 197) | public static void testDiffCleanupMerge() {
    method testDiffCleanupSemanticLossless (line 256) | public static void testDiffCleanupSemanticLossless() {
    method testDiffCleanupSemantic (line 291) | public static void testDiffCleanupSemantic() {
    method testDiffCleanupEfficiency (line 338) | public static void testDiffCleanupEfficiency() {
    method testDiffPrettyHtml (line 368) | public static void testDiffPrettyHtml() {
    method testDiffText (line 374) | public static void testDiffText() {
    method testDiffDelta (line 381) | public static void testDiffDelta() {
    method testDiffXIndex (line 451) | public static void testDiffXIndex() {
    method testDiffLevenshtein (line 460) | public static void testDiffLevenshtein() {
    method testDiffBisect (line 471) | public static void testDiffBisect() {
    method testDiffMain (line 486) | public static void testDiffMain() {
    method testMatchAlphabet (line 578) | public static void testMatchAlphabet() {
    method testMatchBitap (line 590) | public static void testMatchBitap() {
    method testMatchMain (line 635) | public static void testMatchMain() {
    method testPatchObj (line 666) | public static void testPatchObj() {
    method testPatchFromText (line 678) | public static void testPatchFromText() {
    method testPatchToText (line 699) | public static void testPatchToText() {
    method testPatchAddContext (line 710) | public static void testPatchAddContext() {
    method testPatchMake (line 730) | @SuppressWarnings("deprecation")
    method testPatchSplitMax (line 781) | public static void testPatchSplitMax() {
    method testPatchAddPadding (line 802) | public static void testPatchAddPadding() {
    method testPatchApply (line 820) | public static void testPatchApply() {
    method assertEquals (line 907) | private static void assertEquals(String error_msg, Object a, Object b) {
    method assertTrue (line 914) | private static void assertTrue(String error_msg, boolean a) {
    method assertNull (line 920) | private static void assertNull(String error_msg, Object n) {
    method fail (line 926) | private static void fail(String error_msg) {
    method assertArrayEquals (line 930) | private static void assertArrayEquals(String error_msg, Object[] a, Ob...
    method assertLinesToCharsResultEquals (line 936) | private static void assertLinesToCharsResultEquals(String error_msg,
    method diff_rebuildtexts (line 944) | private static String[] diff_rebuildtexts(LinkedList<Diff> diffs) {
    method diffList (line 958) | private static LinkedList<Diff> diffList(Diff... diffs) {
    method main (line 962) | public static void main(String args[]) {

FILE: javascript/diff_match_patch.js
  function c (line 11) | function c(a){for(var b="",c=0,g=-1,h=d.length;g<a.length-1;){g=a.indexO...
  function c (line 15) | function c(a,b,c){for(var d=a.substring(c,c+Math.floor(a.length/4)),e=-1...
  function b (line 20) | function b(a,b){if(!a||!b)return 6;var c=a.charAt(a.length-1),d=b.charAt...
  function d (line 34) | function d(a,d){var e=a/b.length,g=Math.abs(c-d);return f.Match_Distance...

FILE: javascript/diff_match_patch_uncompressed.js
  function diff_linesToCharsMunge_ (line 482) | function diff_linesToCharsMunge_(text) {
  function diff_halfMatchI_ (line 692) | function diff_halfMatchI_(longtext, shorttext, i) {
  function diff_cleanupSemanticScore_ (line 886) | function diff_cleanupSemanticScore_(one, two) {
  function match_bitapScore_ (line 1488) | function match_bitapScore_(e, x) {

FILE: javascript/tests/diff_match_patch_test.js
  function assertEquivalent (line 21) | function assertEquivalent(msg, expected, actual) {
  function _equivalent (line 37) | function _equivalent(a, b) {
  function diff_rebuildtexts (line 61) | function diff_rebuildtexts(diffs) {
  function testDiffCommonPrefix (line 82) | function testDiffCommonPrefix() {
  function testDiffCommonSuffix (line 94) | function testDiffCommonSuffix() {
  function testDiffCommonOverlap (line 106) | function testDiffCommonOverlap() {
  function testDiffHalfMatch (line 126) | function testDiffHalfMatch() {
  function testDiffLinesToChars (line 159) | function testDiffLinesToChars() {
  function testDiffCharsToLines (line 189) | function testDiffCharsToLines() {
  function testDiffCleanupMerge (line 224) | function testDiffCleanupMerge() {
  function testDiffCleanupSemanticLossless (line 297) | function testDiffCleanupSemanticLossless() {
  function testDiffCleanupSemantic (line 340) | function testDiffCleanupSemantic() {
  function testDiffCleanupEfficiency (line 398) | function testDiffCleanupEfficiency() {
  function testDiffPrettyHtml (line 434) | function testDiffPrettyHtml() {
  function testDiffText (line 440) | function testDiffText() {
  function testDiffDelta (line 448) | function testDiffDelta() {
  function testDiffXIndex (line 519) | function testDiffXIndex() {
  function testDiffLevenshtein (line 528) | function testDiffLevenshtein() {
  function testDiffBisect (line 537) | function testDiffBisect() {
  function testDiffMain (line 550) | function testDiffMain() {
  function testMatchAlphabet (line 642) | function testMatchAlphabet() {
  function testMatchBitap (line 651) | function testMatchBitap() {
  function testMatchMain (line 696) | function testMatchMain() {
  function testPatchObj (line 729) | function testPatchObj() {
  function testPatchFromText (line 741) | function testPatchFromText() {
  function testPatchToText (line 762) | function testPatchToText() {
  function testPatchAddContext (line 772) | function testPatchAddContext() {
  function testPatchMake (line 794) | function testPatchMake() {
  function testPatchSplitMax (line 852) | function testPatchSplitMax() {
  function testPatchAddPadding (line 872) | function testPatchAddPadding() {
  function testPatchApply (line 892) | function testPatchApply() {

FILE: objectivec/DiffMatchPatch.h
  type Operation (line 38) | typedef enum {
  function interface (line 48) | interface Diff : NSObject <NSCopying> {

FILE: objectivec/DiffMatchPatchCFUtilities.c
  function CFStringRef (line 44) | CFStringRef diff_CFStringCreateFromUnichar(UniChar ch) {
  function CFStringRef (line 50) | CFStringRef diff_CFStringCreateSubstring(CFStringRef text, CFIndex start...
  function CFRange (line 61) | CFRange diff_RightSubstringRange(CFIndex text_length, CFIndex new_length) {
  function CFStringRef (line 68) | CFStringRef diff_CFStringCreateRightSubstring(CFStringRef text, CFIndex ...
  function CFRange (line 72) | CFRange diff_LeftSubstringRange(CFIndex new_length) {
  function CFStringRef (line 79) | CFStringRef diff_CFStringCreateLeftSubstring(CFStringRef text, CFIndex n...
  function CFStringRef (line 83) | CFStringRef diff_CFStringCreateSubstringWithStartIndex(CFStringRef text,...
  function CFStringRef (line 87) | CFStringRef diff_CFStringCreateJavaSubstring(CFStringRef s, CFIndex begi...
  function CFStringRef (line 91) | CFStringRef diff_CFStringCreateByCombiningTwoStrings(CFStringRef best_co...
  function Boolean (line 101) | Boolean diff_regExMatch(CFStringRef text, const regex_t *re) {
  function CFIndex (line 155) | CFIndex diff_commonPrefix(CFStringRef text1, CFStringRef text2) {
  function CFIndex (line 185) | CFIndex diff_commonSuffix(CFStringRef text1, CFStringRef text2) {
  function CFIndex (line 215) | CFIndex diff_commonOverlap(CFStringRef text1, CFStringRef text2) {
  function CFArrayRef (line 300) | CFArrayRef diff_halfMatchCreate(CFStringRef text1, CFStringRef text2, co...
  function CFArrayRef (line 365) | CFArrayRef diff_halfMatchICreate(CFStringRef longtext, CFStringRef short...
  function CFStringRef (line 456) | CFStringRef diff_linesToCharsMungeCFStringCreate(CFStringRef text, CFMut...
  function CFIndex (line 523) | CFIndex diff_cleanupSemanticScore(CFStringRef one, CFStringRef two) {

FILE: objectivec/DiffMatchPatchCFUtilities.h
  function CF_INLINE (line 38) | CF_INLINE void diff_CFStringPrepareUniCharBuffer(CFStringRef string, con...

FILE: python2/diff_match_patch.py
  class diff_match_patch (line 36) | class diff_match_patch:
    method __init__ (line 42) | def __init__(self):
    method diff_main (line 80) | def diff_main(self, text1, text2, checklines=True, deadline=None):
    method diff_compute (line 140) | def diff_compute(self, text1, text2, checklines, deadline):
    method diff_lineMode (line 199) | def diff_lineMode(self, text1, text2, deadline):
    method diff_bisect (line 256) | def diff_bisect(self, text1, text2, deadline):
    method diff_bisectSplit (line 358) | def diff_bisectSplit(self, text1, text2, x, y, deadline):
    method diff_linesToChars (line 383) | def diff_linesToChars(self, text1, text2):
    method diff_charsToLines (line 446) | def diff_charsToLines(self, diffs, lineArray):
    method diff_commonPrefix (line 460) | def diff_commonPrefix(self, text1, text2):
    method diff_commonSuffix (line 488) | def diff_commonSuffix(self, text1, text2):
    method diff_commonOverlap (line 517) | def diff_commonOverlap(self, text1, text2):
    method diff_halfMatch (line 559) | def diff_halfMatch(self, text1, text2):
    method diff_cleanupSemantic (line 643) | def diff_cleanupSemantic(self, diffs):
    method diff_cleanupSemanticLossless (line 738) | def diff_cleanupSemanticLossless(self, diffs):
    method diff_cleanupEfficiency (line 853) | def diff_cleanupEfficiency(self, diffs):
    method diff_cleanupMerge (line 924) | def diff_cleanupMerge(self, diffs):
    method diff_xIndex (line 1029) | def diff_xIndex(self, diffs, loc):
    method diff_prettyHtml (line 1061) | def diff_prettyHtml(self, diffs):
    method diff_text1 (line 1082) | def diff_text1(self, diffs):
    method diff_text2 (line 1097) | def diff_text2(self, diffs):
    method diff_levenshtein (line 1112) | def diff_levenshtein(self, diffs):
    method diff_toDelta (line 1138) | def diff_toDelta(self, diffs):
    method diff_fromDelta (line 1162) | def diff_fromDelta(self, text1, delta):
    method match_main (line 1218) | def match_main(self, text, pattern, loc):
    method match_bitap (line 1248) | def match_bitap(self, text, pattern, loc):
    method match_alphabet (line 1354) | def match_alphabet(self, pattern):
    method patch_addContext (line 1372) | def patch_addContext(self, patch, text):
    method patch_make (line 1413) | def patch_make(self, a, b=None, c=None):
    method patch_deepCopy (line 1527) | def patch_deepCopy(self, patches):
    method patch_apply (line 1548) | def patch_apply(self, patches, text):
    method patch_addPadding (line 1636) | def patch_addPadding(self, patches):
    method patch_splitMax (line 1694) | def patch_splitMax(self, patches):
    method patch_toText (line 1782) | def patch_toText(self, patches):
    method patch_fromText (line 1796) | def patch_fromText(self, textline):
  class patch_obj (line 1874) | class patch_obj:
    method __init__ (line 1878) | def __init__(self):
    method __str__ (line 1887) | def __str__(self):

FILE: python2/tests/diff_match_patch_test.py
  class DiffMatchPatchTest (line 32) | class DiffMatchPatchTest(unittest.TestCase):
    method setUp (line 34) | def setUp(self):
    method diff_rebuildtexts (line 38) | def diff_rebuildtexts(self, diffs):
  class DiffTest (line 50) | class DiffTest(DiffMatchPatchTest):
    method testDiffCommonPrefix (line 53) | def testDiffCommonPrefix(self):
    method testDiffCommonSuffix (line 64) | def testDiffCommonSuffix(self):
    method testDiffCommonOverlap (line 75) | def testDiffCommonOverlap(self):
    method testDiffHalfMatch (line 93) | def testDiffHalfMatch(self):
    method testDiffLinesToChars (line 125) | def testDiffLinesToChars(self):
    method testDiffCharsToLines (line 147) | def testDiffCharsToLines(self):
    method testDiffCleanupMerge (line 179) | def testDiffCleanupMerge(self):
    method testDiffCleanupSemanticLossless (line 251) | def testDiffCleanupSemanticLossless(self):
    method testDiffCleanupSemantic (line 293) | def testDiffCleanupSemantic(self):
    method testDiffCleanupEfficiency (line 350) | def testDiffCleanupEfficiency(self):
    method testDiffPrettyHtml (line 385) | def testDiffPrettyHtml(self):
    method testDiffText (line 390) | def testDiffText(self):
    method testDiffDelta (line 397) | def testDiffDelta(self):
    method testDiffXIndex (line 466) | def testDiffXIndex(self):
    method testDiffLevenshtein (line 473) | def testDiffLevenshtein(self):
    method testDiffBisect (line 481) | def testDiffBisect(self):
    method testDiffMain (line 493) | def testDiffMain(self):
  class MatchTest (line 580) | class MatchTest(DiffMatchPatchTest):
    method testMatchAlphabet (line 583) | def testMatchAlphabet(self):
    method testMatchBitap (line 589) | def testMatchBitap(self):
    method testMatchMain (line 639) | def testMatchMain(self):
  class PatchTest (line 668) | class PatchTest(DiffMatchPatchTest):
    method testPatchObj (line 671) | def testPatchObj(self):
    method testPatchFromText (line 682) | def testPatchFromText(self):
    method testPatchToText (line 702) | def testPatchToText(self):
    method testPatchAddContext (line 711) | def testPatchAddContext(self):
    method testPatchMake (line 732) | def testPatchMake(self):
    method testPatchSplitMax (line 788) | def testPatchSplitMax(self):
    method testPatchAddPadding (line 807) | def testPatchAddPadding(self):
    method testPatchApply (line 826) | def testPatchApply(self):

FILE: python2/tests/speedtest.py
  function main (line 32) | def main():

FILE: python3/diff_match_patch.py
  class diff_match_patch (line 34) | class diff_match_patch:
    method __init__ (line 40) | def __init__(self):
    method diff_main (line 78) | def diff_main(self, text1, text2, checklines=True, deadline=None):
    method diff_compute (line 138) | def diff_compute(self, text1, text2, checklines, deadline):
    method diff_lineMode (line 197) | def diff_lineMode(self, text1, text2, deadline):
    method diff_bisect (line 254) | def diff_bisect(self, text1, text2, deadline):
    method diff_bisectSplit (line 356) | def diff_bisectSplit(self, text1, text2, x, y, deadline):
    method diff_linesToChars (line 381) | def diff_linesToChars(self, text1, text2):
    method diff_charsToLines (line 444) | def diff_charsToLines(self, diffs, lineArray):
    method diff_commonPrefix (line 458) | def diff_commonPrefix(self, text1, text2):
    method diff_commonSuffix (line 486) | def diff_commonSuffix(self, text1, text2):
    method diff_commonOverlap (line 515) | def diff_commonOverlap(self, text1, text2):
    method diff_halfMatch (line 557) | def diff_halfMatch(self, text1, text2):
    method diff_cleanupSemantic (line 641) | def diff_cleanupSemantic(self, diffs):
    method diff_cleanupSemanticLossless (line 736) | def diff_cleanupSemanticLossless(self, diffs):
    method diff_cleanupEfficiency (line 851) | def diff_cleanupEfficiency(self, diffs):
    method diff_cleanupMerge (line 922) | def diff_cleanupMerge(self, diffs):
    method diff_xIndex (line 1027) | def diff_xIndex(self, diffs, loc):
    method diff_prettyHtml (line 1059) | def diff_prettyHtml(self, diffs):
    method diff_text1 (line 1080) | def diff_text1(self, diffs):
    method diff_text2 (line 1095) | def diff_text2(self, diffs):
    method diff_levenshtein (line 1110) | def diff_levenshtein(self, diffs):
    method diff_toDelta (line 1136) | def diff_toDelta(self, diffs):
    method diff_fromDelta (line 1160) | def diff_fromDelta(self, text1, delta):
    method match_main (line 1212) | def match_main(self, text, pattern, loc):
    method match_bitap (line 1242) | def match_bitap(self, text, pattern, loc):
    method match_alphabet (line 1348) | def match_alphabet(self, pattern):
    method patch_addContext (line 1366) | def patch_addContext(self, patch, text):
    method patch_make (line 1407) | def patch_make(self, a, b=None, c=None):
    method patch_deepCopy (line 1520) | def patch_deepCopy(self, patches):
    method patch_apply (line 1541) | def patch_apply(self, patches, text):
    method patch_addPadding (line 1629) | def patch_addPadding(self, patches):
    method patch_splitMax (line 1687) | def patch_splitMax(self, patches):
    method patch_toText (line 1775) | def patch_toText(self, patches):
    method patch_fromText (line 1789) | def patch_fromText(self, textline):
  class patch_obj (line 1862) | class patch_obj:
    method __init__ (line 1866) | def __init__(self):
    method __str__ (line 1875) | def __str__(self):

FILE: python3/tests/diff_match_patch_test.py
  class DiffMatchPatchTest (line 34) | class DiffMatchPatchTest(unittest.TestCase):
    method setUp (line 36) | def setUp(self):
    method diff_rebuildtexts (line 40) | def diff_rebuildtexts(self, diffs):
  class DiffTest (line 52) | class DiffTest(DiffMatchPatchTest):
    method testDiffCommonPrefix (line 55) | def testDiffCommonPrefix(self):
    method testDiffCommonSuffix (line 66) | def testDiffCommonSuffix(self):
    method testDiffCommonOverlap (line 77) | def testDiffCommonOverlap(self):
    method testDiffHalfMatch (line 95) | def testDiffHalfMatch(self):
    method testDiffLinesToChars (line 127) | def testDiffLinesToChars(self):
    method testDiffCharsToLines (line 149) | def testDiffCharsToLines(self):
    method testDiffCleanupMerge (line 181) | def testDiffCleanupMerge(self):
    method testDiffCleanupSemanticLossless (line 253) | def testDiffCleanupSemanticLossless(self):
    method testDiffCleanupSemantic (line 295) | def testDiffCleanupSemantic(self):
    method testDiffCleanupEfficiency (line 352) | def testDiffCleanupEfficiency(self):
    method testDiffPrettyHtml (line 387) | def testDiffPrettyHtml(self):
    method testDiffText (line 392) | def testDiffText(self):
    method testDiffDelta (line 399) | def testDiffDelta(self):
    method testDiffXIndex (line 469) | def testDiffXIndex(self):
    method testDiffLevenshtein (line 476) | def testDiffLevenshtein(self):
    method testDiffBisect (line 484) | def testDiffBisect(self):
    method testDiffMain (line 496) | def testDiffMain(self):
  class MatchTest (line 583) | class MatchTest(DiffMatchPatchTest):
    method testMatchAlphabet (line 586) | def testMatchAlphabet(self):
    method testMatchBitap (line 592) | def testMatchBitap(self):
    method testMatchMain (line 642) | def testMatchMain(self):
  class PatchTest (line 671) | class PatchTest(DiffMatchPatchTest):
    method testPatchObj (line 674) | def testPatchObj(self):
    method testPatchFromText (line 685) | def testPatchFromText(self):
    method testPatchToText (line 705) | def testPatchToText(self):
    method testPatchAddContext (line 714) | def testPatchAddContext(self):
    method testPatchMake (line 735) | def testPatchMake(self):
    method testPatchSplitMax (line 791) | def testPatchSplitMax(self):
    method testPatchAddPadding (line 810) | def testPatchAddPadding(self):
    method testPatchApply (line 829) | def testPatchApply(self):

FILE: python3/tests/speedtest.py
  function main (line 33) | def main():
Condensed preview — 80 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (1,726K chars).
[
  {
    "path": ".gitignore",
    "chars": 127,
    "preview": "\n*.class\n*.exe\n*.pyc\n*.komodoproject\n\n.DS_STORE\nxcuserdata\n\ndart/tests/Speedtest.dart.js.deps\ndart/tests/Speedtest.dart."
  },
  {
    "path": "AUTHORS",
    "chars": 327,
    "preview": "# Below is a list of people and organizations that have contributed\n# to the Diff Match Patch project.\n\nGoogle Inc.\n\nDun"
  },
  {
    "path": "CONTRIBUTING.md",
    "chars": 969,
    "preview": "# How to Contribute\n\nWe'd love to accept your patches and contributions to this project. There are\njust a few small guid"
  },
  {
    "path": "LICENSE",
    "chars": 11358,
    "preview": "\n                                 Apache License\n                           Version 2.0, January 2004\n                  "
  },
  {
    "path": "README.md",
    "chars": 2941,
    "preview": "The Diff Match and Patch libraries offer robust algorithms to perform the\noperations required for synchronizing plain te"
  },
  {
    "path": "cpp/diff_match_patch.cpp",
    "chars": 68699,
    "preview": "/*\n * Diff Match and Patch\n * Copyright 2018 The diff-match-patch Authors.\n * https://github.com/google/diff-match-patch"
  },
  {
    "path": "cpp/diff_match_patch.h",
    "chars": 20467,
    "preview": "/*\n * Diff Match and Patch\n * Copyright 2018 The diff-match-patch Authors.\n * https://github.com/google/diff-match-patch"
  },
  {
    "path": "cpp/diff_match_patch.pro",
    "chars": 323,
    "preview": "#QT += sql xml network\nTEMPLATE = app\nCONFIG += qt debug_and_release\n\nmac {\n  CONFIG -= app_bundle\n}\n\n# don't embed the "
  },
  {
    "path": "cpp/diff_match_patch_test.cpp",
    "chars": 54231,
    "preview": "/*\n * Diff Match and Patch -- Test Harness\n * Copyright 2018 The diff-match-patch Authors.\n * https://github.com/google/"
  },
  {
    "path": "cpp/diff_match_patch_test.h",
    "chars": 3332,
    "preview": "/*\n * Diff Match and Patch -- Test Harness\n * Copyright 2018 The diff-match-patch Authors.\n * https://github.com/google/"
  },
  {
    "path": "csharp/DiffMatchPatch.cs",
    "chars": 86703,
    "preview": "/*\n * Diff Match and Patch\n * Copyright 2018 The diff-match-patch Authors.\n * https://github.com/google/diff-match-patc"
  },
  {
    "path": "csharp/tests/DiffMatchPatchTest.cs",
    "chars": 60176,
    "preview": "/*\n * Diff Match and Patch -- Test Harness\n * Copyright 2018 The diff-match-patch Authors.\n * https://github.com/google"
  },
  {
    "path": "csharp/tests/Speedtest.cs",
    "chars": 831,
    "preview": "// Copyright 2010 Google Inc.\n// All Right Reserved.\n\n/*\n * To compile with Mono:\n *   mcs Speedtest.cs ../DiffMatchPatc"
  },
  {
    "path": "csharp/tests/Speedtest1.txt",
    "chars": 12979,
    "preview": "This is a '''list of newspapers published by [[Journal Register Company]]'''.\n\nThe company owns daily and weekly newspap"
  },
  {
    "path": "csharp/tests/Speedtest2.txt",
    "chars": 11918,
    "preview": "This is a '''list of newspapers published by [[Journal Register Company]]'''.\n\nThe company owns daily and weekly newspap"
  },
  {
    "path": "dart/DMPClass.dart",
    "chars": 77924,
    "preview": "/*\n * Diff Match and Patch\n * Copyright 2018 The diff-match-patch Authors.\n * https://github.com/google/diff-match-patch"
  },
  {
    "path": "dart/DiffClass.dart",
    "chars": 1980,
    "preview": "/*\n * Diff Match and Patch\n * Copyright 2018 The diff-match-patch Authors.\n * https://github.com/google/diff-match-patch"
  },
  {
    "path": "dart/DiffMatchPatch.dart",
    "chars": 823,
    "preview": "/*\n * Diff Match and Patch\n * Copyright 2018 The diff-match-patch Authors.\n * https://github.com/google/diff-match-patch"
  },
  {
    "path": "dart/PatchClass.dart",
    "chars": 2183,
    "preview": "/*\n * Diff Match and Patch\n * Copyright 2018 The diff-match-patch Authors.\n * https://github.com/google/diff-match-patch"
  },
  {
    "path": "dart/tests/DiffMatchPatchTest.dart",
    "chars": 52022,
    "preview": "/**\n * Diff Match and Patch -- Test Harness\n * Copyright 2018 The diff-match-patch Authors.\n * https://github.com/google"
  },
  {
    "path": "dart/tests/Speedtest.dart",
    "chars": 1262,
    "preview": "import 'dart:html';\nimport '../DiffMatchPatch.dart';\n\n// Compile with:\n// dart2js -O4 --out=Speedtest.dart.js Speedtest."
  },
  {
    "path": "dart/tests/Speedtest.dart.js",
    "chars": 83852,
    "preview": "{}(function dartProgram(){function copyProperties(a,b){var u=Object.keys(a)\nfor(var t=0;t<u.length;t++){var s=u[t]\nb[s]="
  },
  {
    "path": "dart/tests/Speedtest.html",
    "chars": 25583,
    "preview": "<html>\n  <head>\n    <title>Diff Speed Test</title>\n  </head>\n  <body>\n    <h1>Diff Speed Test</h1>\n\n<FORM action=\"#\" ons"
  },
  {
    "path": "dart/tests/SpeedtestVM.dart",
    "chars": 25895,
    "preview": "import '../DiffMatchPatch.dart';\n\nvoid main() {\n  String text1 = \"This is a '''list of newspapers published by [[Journal"
  },
  {
    "path": "demos/diff.html",
    "chars": 3403,
    "preview": "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\" \"http://www.w3.org/TR/html4/loose.dtd\">\n<HTML>\n<HEAD>\n  <"
  },
  {
    "path": "demos/match.html",
    "chars": 4040,
    "preview": "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\" \"http://www.w3.org/TR/html4/loose.dtd\">\n<HTML>\n<HEAD>\n  <"
  },
  {
    "path": "demos/patch.html",
    "chars": 4503,
    "preview": "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\" \"http://www.w3.org/TR/html4/loose.dtd\">\n<HTML>\n<HEAD>\n  <"
  },
  {
    "path": "java/src/name/fraser/neil/plaintext/diff_match_patch.java",
    "chars": 89158,
    "preview": "/*\n * Diff Match and Patch\n * Copyright 2018 The diff-match-patch Authors.\n * https://github.com/google/diff-match-patch"
  },
  {
    "path": "java/tests/name/fraser/neil/plaintext/Speedtest.java",
    "chars": 1661,
    "preview": "// Copyright 2010 Google Inc. All Rights Reserved.\n\n/**\n * Diff Speed Test\n *\n * Compile from diff-match-patch/java with"
  },
  {
    "path": "java/tests/name/fraser/neil/plaintext/Speedtest1.txt",
    "chars": 12979,
    "preview": "This is a '''list of newspapers published by [[Journal Register Company]]'''.\n\nThe company owns daily and weekly newspap"
  },
  {
    "path": "java/tests/name/fraser/neil/plaintext/Speedtest2.txt",
    "chars": 11918,
    "preview": "This is a '''list of newspapers published by [[Journal Register Company]]'''.\n\nThe company owns daily and weekly newspap"
  },
  {
    "path": "java/tests/name/fraser/neil/plaintext/diff_match_patch_test.java",
    "chars": 51899,
    "preview": "/*\n * Diff Match and Patch -- Test harness\n * Copyright 2018 The diff-match-patch Authors.\n * https://github.com/google/"
  },
  {
    "path": "javascript/diff_match_patch.js",
    "chars": 21274,
    "preview": "var diff_match_patch=function(){this.Diff_Timeout=1;this.Diff_EditCost=4;this.Match_Threshold=.5;this.Match_Distance=1E3"
  },
  {
    "path": "javascript/diff_match_patch_uncompressed.js",
    "chars": 78511,
    "preview": "/**\n * Diff Match and Patch\n * Copyright 2018 The diff-match-patch Authors.\n * https://github.com/google/diff-match-patc"
  },
  {
    "path": "javascript/tests/diff_match_patch_test.html",
    "chars": 5071,
    "preview": "<!DOCTYPE html PUBLIC \"-//W3C//DTD HTML 4.01//EN\" \"http://www.w3.org/TR/html4/strict.dtd\">\n<!--\n  Test Harness for diff_"
  },
  {
    "path": "javascript/tests/diff_match_patch_test.js",
    "chars": 39223,
    "preview": "/**\n * Diff Match and Patch -- Test Harness\n * Copyright 2018 The diff-match-patch Authors.\n * https://github.com/google"
  },
  {
    "path": "javascript/tests/speedtest.html",
    "chars": 26327,
    "preview": "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\" \"http://www.w3.org/TR/html4/loose.dtd\">\n<HTML>\n<HEAD>\n  <"
  },
  {
    "path": "lua/diff_match_patch.lua",
    "chars": 73504,
    "preview": "--[[\n* Diff Match and Patch\n* Copyright 2018 The diff-match-patch Authors.\n* https://github.com/google/diff-match-patch\n"
  },
  {
    "path": "lua/tests/diff_match_patch_test.lua",
    "chars": 39796,
    "preview": "--[[\n* Diff Match and Patch -- Test Harness\n* Copyright 2018 The diff-match-patch Authors.\n* https://github.com/google/d"
  },
  {
    "path": "lua/tests/speedtest.lua",
    "chars": 678,
    "preview": "--[[\nCopyright 2010 Google Inc.\nAll Rights Reserved.\n\nDiff Speed Test\n\nfraser@google.com\n--]]\n\npackage.path = package.pa"
  },
  {
    "path": "lua/tests/speedtest1.txt",
    "chars": 12979,
    "preview": "This is a '''list of newspapers published by [[Journal Register Company]]'''.\n\nThe company owns daily and weekly newspap"
  },
  {
    "path": "lua/tests/speedtest2.txt",
    "chars": 11918,
    "preview": "This is a '''list of newspapers published by [[Journal Register Company]]'''.\n\nThe company owns daily and weekly newspap"
  },
  {
    "path": "objectivec/DiffMatchPatch.h",
    "chars": 7435,
    "preview": "/*\n * Diff Match and Patch\n * Copyright 2018 The diff-match-patch Authors.\n * https://github.com/google/diff-match-patch"
  },
  {
    "path": "objectivec/DiffMatchPatch.m",
    "chars": 92111,
    "preview": "/*\n * Diff Match and Patch\n * Copyright 2018 The diff-match-patch Authors.\n * https://github.com/google/diff-match-patch"
  },
  {
    "path": "objectivec/DiffMatchPatch.xcodeproj/project.pbxproj",
    "chars": 46843,
    "preview": "// !$*UTF8*$!\n{\n\tarchiveVersion = 1;\n\tclasses = {\n\t};\n\tobjectVersion = 45;\n\tobjects = {\n\n/* Begin PBXBuildFile section *"
  },
  {
    "path": "objectivec/DiffMatchPatch.xcodeproj/project.xcworkspace/contents.xcworkspacedata",
    "chars": 135,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Workspace\n   version = \"1.0\">\n   <FileRef\n      location = \"self:\">\n   </FileRef"
  },
  {
    "path": "objectivec/DiffMatchPatch.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings",
    "chars": 181,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/P"
  },
  {
    "path": "objectivec/DiffMatchPatchCFUtilities.c",
    "chars": 21640,
    "preview": "/*\n * Diff Match and Patch\n * Copyright 2018 The diff-match-patch Authors.\n * https://github.com/google/diff-match-patch"
  },
  {
    "path": "objectivec/DiffMatchPatchCFUtilities.h",
    "chars": 2110,
    "preview": "/*\n * Diff Match and Patch\n * Copyright 2018 The diff-match-patch Authors.\n * https://github.com/google/diff-match-patch"
  },
  {
    "path": "objectivec/DiffMatchPatch_Prefix.pch",
    "chars": 170,
    "preview": "//\n// Prefix header for all source files of the 'DiffMatchPatch' target in the 'DiffMatchPatch' project.\n//\n\n#ifdef __OB"
  },
  {
    "path": "objectivec/English.lproj/InfoPlist.strings",
    "chars": 46,
    "preview": "/* Localized versions of Info.plist keys */\n\n"
  },
  {
    "path": "objectivec/Info.plist",
    "chars": 868,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/P"
  },
  {
    "path": "objectivec/MinMaxMacros.h",
    "chars": 1143,
    "preview": "/*\n * Diff Match and Patch\n * Copyright 2018 The diff-match-patch Authors.\n * https://github.com/google/diff-match-patch"
  },
  {
    "path": "objectivec/NSMutableDictionary+DMPExtensions.h",
    "chars": 1802,
    "preview": "/*\n * Diff Match and Patch\n * Copyright 2018 The diff-match-patch Authors.\n * https://github.com/google/diff-match-patch"
  },
  {
    "path": "objectivec/NSMutableDictionary+DMPExtensions.m",
    "chars": 3230,
    "preview": "/*\n * Diff Match and Patch\n * Copyright 2018 The diff-match-patch Authors.\n * https://github.com/google/diff-match-patch"
  },
  {
    "path": "objectivec/NSString+JavaSubstring.h",
    "chars": 933,
    "preview": "/*\n * Diff Match and Patch\n * Copyright 2018 The diff-match-patch Authors.\n * https://github.com/google/diff-match-patch"
  },
  {
    "path": "objectivec/NSString+JavaSubstring.m",
    "chars": 1144,
    "preview": "/*\n * Diff Match and Patch\n * Copyright 2018 The diff-match-patch Authors.\n * https://github.com/google/diff-match-patch"
  },
  {
    "path": "objectivec/NSString+UnicharUtilities.h",
    "chars": 973,
    "preview": "/*\n * Diff Match and Patch\n * Copyright 2018 The diff-match-patch Authors.\n * https://github.com/google/diff-match-patch"
  },
  {
    "path": "objectivec/NSString+UnicharUtilities.m",
    "chars": 1190,
    "preview": "/*\n * Diff Match and Patch\n * Copyright 2018 The diff-match-patch Authors.\n * https://github.com/google/diff-match-patch"
  },
  {
    "path": "objectivec/NSString+UriCompatibility.h",
    "chars": 1004,
    "preview": "/*\n * Diff Match and Patch\n * Copyright 2018 The diff-match-patch Authors.\n * https://github.com/google/diff-match-patch"
  },
  {
    "path": "objectivec/NSString+UriCompatibility.m",
    "chars": 1762,
    "preview": "/*\n * Diff Match and Patch\n * Copyright 2018 The diff-match-patch Authors.\n * https://github.com/google/diff-match-patch"
  },
  {
    "path": "objectivec/Tests/DiffMatchPatchTest-Info.plist",
    "chars": 701,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/P"
  },
  {
    "path": "objectivec/Tests/DiffMatchPatchTest.h",
    "chars": 890,
    "preview": "/*\n * Diff Match and Patch -- Test harness\n * Copyright 2018 The diff-match-patch Authors.\n * https://github.com/google/"
  },
  {
    "path": "objectivec/Tests/DiffMatchPatchTest.m",
    "chars": 74575,
    "preview": "/*\n * Diff Match and Patch -- Test harness\n * Copyright 2018 The diff-match-patch Authors.\n * https://github.com/google/"
  },
  {
    "path": "objectivec/Tests/Speedtest1.txt",
    "chars": 12979,
    "preview": "This is a '''list of newspapers published by [[Journal Register Company]]'''.\n\nThe company owns daily and weekly newspap"
  },
  {
    "path": "objectivec/Tests/Speedtest2.txt",
    "chars": 11918,
    "preview": "This is a '''list of newspapers published by [[Journal Register Company]]'''.\n\nThe company owns daily and weekly newspap"
  },
  {
    "path": "objectivec/Tests/speedtest.m",
    "chars": 1996,
    "preview": "/*\n * Diff Match and Patch -- Test harness\n * Copyright 2018 The diff-match-patch Authors.\n * https://github.com/google/"
  },
  {
    "path": "objectivec/speedtest_Prefix.pch",
    "chars": 163,
    "preview": "//\n// Prefix header for all source files of the 'speedtest' target in the 'DiffMatchPatch' project.\n//\n\n#ifdef __OBJC__\n"
  },
  {
    "path": "python2/__init__.py",
    "chars": 59,
    "preview": "from .diff_match_patch import diff_match_patch, patch_obj\n\n"
  },
  {
    "path": "python2/diff_match_patch.py",
    "chars": 68015,
    "preview": "#!/usr/bin/python2.4\n\nfrom __future__ import division\n\n\"\"\"Diff Match and Patch\nCopyright 2018 The diff-match-patch Autho"
  },
  {
    "path": "python2/tests/diff_match_patch_test.py",
    "chars": 43028,
    "preview": "#!/usr/bin/python2.4\n\n\"\"\"Diff Match and Patch -- Test harness\nCopyright 2018 The diff-match-patch Authors.\nhttps://githu"
  },
  {
    "path": "python2/tests/speedtest.py",
    "chars": 1411,
    "preview": "#!/usr/bin/python2.4\n\n\"\"\"Diff Speed Test\nCopyright 2018 The diff-match-patch Authors.\nhttps://github.com/google/diff-mat"
  },
  {
    "path": "python2/tests/speedtest1.txt",
    "chars": 12979,
    "preview": "This is a '''list of newspapers published by [[Journal Register Company]]'''.\n\nThe company owns daily and weekly newspap"
  },
  {
    "path": "python2/tests/speedtest2.txt",
    "chars": 11918,
    "preview": "This is a '''list of newspapers published by [[Journal Register Company]]'''.\n\nThe company owns daily and weekly newspap"
  },
  {
    "path": "python3/__init__.py",
    "chars": 59,
    "preview": "from .diff_match_patch import diff_match_patch, patch_obj\n\n"
  },
  {
    "path": "python3/diff_match_patch.py",
    "chars": 67406,
    "preview": "#!/usr/bin/python3\n\n\"\"\"Diff Match and Patch\nCopyright 2018 The diff-match-patch Authors.\nhttps://github.com/google/diff-"
  },
  {
    "path": "python3/tests/diff_match_patch_test.py",
    "chars": 42906,
    "preview": "#!/usr/bin/python3\n\n\"\"\"Diff Match and Patch -- Test harness\nCopyright 2018 The diff-match-patch Authors.\nhttps://github."
  },
  {
    "path": "python3/tests/speedtest.py",
    "chars": 1425,
    "preview": "#!/usr/bin/python3\n\n\"\"\"Diff Speed Test\nCopyright 2018 The diff-match-patch Authors.\nhttps://github.com/google/diff-match"
  },
  {
    "path": "python3/tests/speedtest1.txt",
    "chars": 12979,
    "preview": "This is a '''list of newspapers published by [[Journal Register Company]]'''.\n\nThe company owns daily and weekly newspap"
  },
  {
    "path": "python3/tests/speedtest2.txt",
    "chars": 11918,
    "preview": "This is a '''list of newspapers published by [[Journal Register Company]]'''.\n\nThe company owns daily and weekly newspap"
  }
]

About this extraction

This page contains the full source code of the google/diff-match-patch GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 80 files (1.6 MB), approximately 465.1k tokens, and a symbol index with 558 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!