Verzeichnisstruktur phpBB-3.1.0


Veröffentlicht
27.10.2014

So funktioniert es


Auf das letzte Element klicken. Dies geht jeweils ein Schritt zurück

Auf das Icon klicken, dies öffnet das Verzeichnis. Nochmal klicken schließt das Verzeichnis.
Auf den Verzeichnisnamen klicken, dies zeigt nur das Verzeichnis mit Inhalt an

(Beispiel Datei-Icons)

Auf das Icon klicken um den Quellcode anzuzeigen

diff.php

Zuletzt modifiziert: 09.10.2024, 12:52 - Dateigröße: 24.01 KiB


0001  <?php
0002  /**
0003  *
0004  * This file is part of the phpBB Forum Software package.
0005  *
0006  * @copyright (c) phpBB Limited <https://www.phpbb.com>
0007  * @license GNU General Public License, version 2 (GPL-2.0)
0008  *
0009  * For full copyright and license information, please see
0010  * the docs/CREDITS.txt file.
0011  *
0012  */
0013   
0014  /**
0015  * @ignore
0016  */
0017  if (!defined('IN_PHPBB'))
0018  {
0019      exit;
0020  }
0021   
0022  /**
0023  * Code from pear.php.net, Text_Diff-1.1.0 package
0024  * http://pear.php.net/package/Text_Diff/
0025  *
0026  * Modified by phpBB Limited to meet our coding standards
0027  * and being able to integrate into phpBB
0028  *
0029  * General API for generating and formatting diffs - the differences between
0030  * two sequences of strings.
0031  *
0032  * Copyright 2004 Geoffrey T. Dairiki <dairiki@dairiki.org>
0033  * Copyright 2004-2008 The Horde Project (http://www.horde.org/)
0034  *
0035  * @package diff
0036  * @author  Geoffrey T. Dairiki <dairiki@dairiki.org>
0037  */
0038  class diff
0039  {
0040      /**
0041      * Array of changes.
0042      * @var array
0043      */
0044      var $_edits;
0045   
0046      /**
0047      * Computes diffs between sequences of strings.
0048      *
0049      * @param array    &$from_content    An array of strings. Typically these are lines from a file.
0050      * @param array    &$to_content    An array of strings.
0051      * @param bool    $preserve_cr    If true, \r is replaced by a new line in the diff output
0052      */
0053      function diff(&$from_content, &$to_content, $preserve_cr = true)
0054      {
0055          $diff_engine = new diff_engine();
0056          $this->_edits = $diff_engine->diff($from_content, $to_content, $preserve_cr);
0057      }
0058   
0059      /**
0060      * Returns the array of differences.
0061      */
0062      function get_diff()
0063      {
0064          return $this->_edits;
0065      }
0066   
0067      /**
0068      * returns the number of new (added) lines in a given diff.
0069      *
0070      * @since Text_Diff 1.1.0
0071      *
0072      * @return integer The number of new lines
0073      */
0074      function count_added_lines()
0075      {
0076          $count = 0;
0077   
0078          for ($i = 0, $size = sizeof($this->_edits); $i < $size; $i++)
0079          {
0080              $edit = $this->_edits[$i];
0081   
0082              if (is_a($edit, 'diff_op_add') || is_a($edit, 'diff_op_change'))
0083              {
0084                  $count += $edit->nfinal();
0085              }
0086          }
0087          return $count;
0088      }
0089   
0090      /**
0091      * Returns the number of deleted (removed) lines in a given diff.
0092      *
0093      * @since Text_Diff 1.1.0
0094      *
0095      * @return integer The number of deleted lines
0096      */
0097      function count_deleted_lines()
0098      {
0099          $count = 0;
0100   
0101          for ($i = 0, $size = sizeof($this->_edits); $i < $size; $i++)
0102          {
0103              $edit = $this->_edits[$i];
0104   
0105              if (is_a($edit, 'diff_op_delete') || is_a($edit, 'diff_op_change'))
0106              {
0107                  $count += $edit->norig();
0108              }
0109          }
0110          return $count;
0111      }
0112   
0113      /**
0114      * Computes a reversed diff.
0115      *
0116      * Example:
0117      * <code>
0118      * $diff = new diff($lines1, $lines2);
0119      * $rev = $diff->reverse();
0120      * </code>
0121      *
0122      * @return diff  A Diff object representing the inverse of the original diff.
0123      *               Note that we purposely don't return a reference here, since
0124      *               this essentially is a clone() method.
0125      */
0126      function reverse()
0127      {
0128          if (version_compare(zend_version(), '2', '>'))
0129          {
0130              $rev = clone($this);
0131          }
0132          else
0133          {
0134              $rev = $this;
0135          }
0136   
0137          $rev->_edits = array();
0138   
0139          for ($i = 0, $size = sizeof($this->_edits); $i < $size; $i++)
0140          {
0141              $edit = $this->_edits[$i];
0142              $rev->_edits[] = $edit->reverse();
0143          }
0144   
0145          return $rev;
0146      }
0147   
0148      /**
0149      * Checks for an empty diff.
0150      *
0151      * @return boolean  True if two sequences were identical.
0152      */
0153      function is_empty()
0154      {
0155          for ($i = 0, $size = sizeof($this->_edits); $i < $size; $i++)
0156          {
0157              $edit = $this->_edits[$i];
0158   
0159              // skip diff_op_copy
0160              if (is_a($edit, 'diff_op_copy'))
0161              {
0162                  continue;
0163              }
0164   
0165              if (is_a($edit, 'diff_op_delete') || is_a($edit, 'diff_op_add'))
0166              {
0167                  $orig = $edit->orig;
0168                  $final = $edit->final;
0169   
0170                  // We can simplify one case where the array is usually supposed to be empty...
0171                  if (sizeof($orig) == 1 && trim($orig[0]) === '') $orig = array();
0172                  if (sizeof($final) == 1 && trim($final[0]) === '') $final = array();
0173   
0174                  if (!$orig && !$final)
0175                  {
0176                      continue;
0177                  }
0178   
0179                  return false;
0180              }
0181   
0182              return false;
0183          }
0184   
0185          return true;
0186      }
0187   
0188      /**
0189      * Computes the length of the Longest Common Subsequence (LCS).
0190      *
0191      * This is mostly for diagnostic purposes.
0192      *
0193      * @return integer  The length of the LCS.
0194      */
0195      function lcs()
0196      {
0197          $lcs = 0;
0198   
0199          for ($i = 0, $size = sizeof($this->_edits); $i < $size; $i++)
0200          {
0201              $edit = $this->_edits[$i];
0202   
0203              if (is_a($edit, 'diff_op_copy'))
0204              {
0205                  $lcs += sizeof($edit->orig);
0206              }
0207          }
0208          return $lcs;
0209      }
0210   
0211      /**
0212      * Gets the original set of lines.
0213      *
0214      * This reconstructs the $from_lines parameter passed to the constructor.
0215      *
0216      * @return array  The original sequence of strings.
0217      */
0218      function get_original()
0219      {
0220          $lines = array();
0221   
0222          for ($i = 0, $size = sizeof($this->_edits); $i < $size; $i++)
0223          {
0224              $edit = $this->_edits[$i];
0225   
0226              if ($edit->orig)
0227              {
0228                  array_splice($lines, sizeof($lines), 0, $edit->orig);
0229              }
0230          }
0231          return $lines;
0232      }
0233   
0234      /**
0235      * Gets the final set of lines.
0236      *
0237      * This reconstructs the $to_lines parameter passed to the constructor.
0238      *
0239      * @return array  The sequence of strings.
0240      */
0241      function get_final()
0242      {
0243          $lines = array();
0244   
0245          for ($i = 0, $size = sizeof($this->_edits); $i < $size; $i++)
0246          {
0247              $edit = $this->_edits[$i];
0248   
0249              if ($edit->final)
0250              {
0251                  array_splice($lines, sizeof($lines), 0, $edit->final);
0252              }
0253          }
0254          return $lines;
0255      }
0256   
0257      /**
0258      * Removes trailing newlines from a line of text. This is meant to be used with array_walk().
0259      *
0260      * @param string &$line  The line to trim.
0261      * @param integer $key  The index of the line in the array. Not used.
0262      */
0263      function trim_newlines(&$line, $key)
0264      {
0265          $line = str_replace(array("\n", "\r"), '', $line);
0266      }
0267   
0268      /**
0269      * Checks a diff for validity.
0270      *
0271      * This is here only for debugging purposes.
0272      */
0273      function _check($from_lines, $to_lines)
0274      {
0275          if (serialize($from_lines) != serialize($this->get_original()))
0276          {
0277              trigger_error("[diff] Reconstructed original doesn't match", E_USER_ERROR);
0278          }
0279   
0280          if (serialize($to_lines) != serialize($this->get_final()))
0281          {
0282              trigger_error("[diff] Reconstructed final doesn't match", E_USER_ERROR);
0283          }
0284   
0285          $rev = $this->reverse();
0286   
0287          if (serialize($to_lines) != serialize($rev->get_original()))
0288          {
0289              trigger_error("[diff] Reversed original doesn't match", E_USER_ERROR);
0290          }
0291   
0292          if (serialize($from_lines) != serialize($rev->get_final()))
0293          {
0294              trigger_error("[diff] Reversed final doesn't match", E_USER_ERROR);
0295          }
0296   
0297          $prevtype = null;
0298   
0299          for ($i = 0, $size = sizeof($this->_edits); $i < $size; $i++)
0300          {
0301              $edit = $this->_edits[$i];
0302   
0303              if ($prevtype == get_class($edit))
0304              {
0305                  trigger_error("[diff] Edit sequence is non-optimal", E_USER_ERROR);
0306              }
0307              $prevtype = get_class($edit);
0308          }
0309   
0310          return true;
0311      }
0312  }
0313   
0314  /**
0315  * @package diff
0316  * @author  Geoffrey T. Dairiki <dairiki@dairiki.org>
0317  */
0318  class mapped_diff extends diff
0319  {
0320      /**
0321      * Computes a diff between sequences of strings.
0322      *
0323      * This can be used to compute things like case-insensitve diffs, or diffs
0324      * which ignore changes in white-space.
0325      *
0326      * @param array $from_lines         An array of strings.
0327      * @param array $to_lines           An array of strings.
0328      * @param array $mapped_from_lines  This array should have the same size number of elements as $from_lines.
0329      *                                  The elements in $mapped_from_lines and $mapped_to_lines are what is actually
0330      *                                  compared when computing the diff.
0331      * @param array $mapped_to_lines    This array should have the same number of elements as $to_lines.
0332      */
0333      function mapped_diff(&$from_lines, &$to_lines, &$mapped_from_lines, &$mapped_to_lines)
0334      {
0335          if (sizeof($from_lines) != sizeof($mapped_from_lines) || sizeof($to_lines) != sizeof($mapped_to_lines))
0336          {
0337              return false;
0338          }
0339   
0340          parent::diff($mapped_from_lines, $mapped_to_lines);
0341   
0342          $xi = $yi = 0;
0343          for ($i = 0; $i < sizeof($this->_edits); $i++)
0344          {
0345              $orig = &$this->_edits[$i]->orig;
0346              if (is_array($orig))
0347              {
0348                  $orig = array_slice($from_lines, $xi, sizeof($orig));
0349                  $xi += sizeof($orig);
0350              }
0351   
0352              $final = &$this->_edits[$i]->final;
0353              if (is_array($final))
0354              {
0355                  $final = array_slice($to_lines, $yi, sizeof($final));
0356                  $yi += sizeof($final);
0357              }
0358          }
0359      }
0360  }
0361   
0362  /**
0363  * @package diff
0364  * @author  Geoffrey T. Dairiki <dairiki@dairiki.org>
0365  *
0366  * @access private
0367  */
0368  class diff_op
0369  {
0370      var $orig;
0371      var $final;
0372   
0373      function &reverse()
0374      {
0375          trigger_error('[diff] Abstract method', E_USER_ERROR);
0376      }
0377   
0378      function norig()
0379      {
0380          return ($this->orig) ? sizeof($this->orig) : 0;
0381      }
0382   
0383      function nfinal()
0384      {
0385          return ($this->final) ? sizeof($this->final) : 0;
0386      }
0387  }
0388   
0389  /**
0390  * @package diff
0391  * @author  Geoffrey T. Dairiki <dairiki@dairiki.org>
0392  *
0393  * @access private
0394  */
0395  class diff_op_copy extends diff_op
0396  {
0397      function diff_op_copy($orig, $final = false)
0398      {
0399          if (!is_array($final))
0400          {
0401              $final = $orig;
0402          }
0403          $this->orig = $orig;
0404          $this->final = $final;
0405      }
0406   
0407      function &reverse()
0408      {
0409          $reverse = new diff_op_copy($this->final, $this->orig);
0410          return $reverse;
0411      }
0412  }
0413   
0414  /**
0415  * @package diff
0416  * @author  Geoffrey T. Dairiki <dairiki@dairiki.org>
0417  *
0418  * @access private
0419  */
0420  class diff_op_delete extends diff_op
0421  {
0422      function diff_op_delete($lines)
0423      {
0424          $this->orig = $lines;
0425          $this->final = false;
0426      }
0427   
0428      function &reverse()
0429      {
0430          $reverse = new diff_op_add($this->orig);
0431          return $reverse;
0432      }
0433  }
0434   
0435  /**
0436  * @package diff
0437  * @author  Geoffrey T. Dairiki <dairiki@dairiki.org>
0438  *
0439  * @access private
0440  */
0441  class diff_op_add extends diff_op
0442  {
0443      function diff_op_add($lines)
0444      {
0445          $this->final = $lines;
0446          $this->orig = false;
0447      }
0448   
0449      function &reverse()
0450      {
0451          $reverse = new diff_op_delete($this->final);
0452          return $reverse;
0453      }
0454  }
0455   
0456  /**
0457  * @package diff
0458  * @author  Geoffrey T. Dairiki <dairiki@dairiki.org>
0459  *
0460  * @access private
0461  */
0462  class diff_op_change extends diff_op
0463  {
0464      function diff_op_change($orig, $final)
0465      {
0466          $this->orig = $orig;
0467          $this->final = $final;
0468      }
0469   
0470      function &reverse()
0471      {
0472          $reverse = new diff_op_change($this->final, $this->orig);
0473          return $reverse;
0474      }
0475  }
0476   
0477   
0478  /**
0479  * A class for computing three way diffs.
0480  *
0481  * @package diff
0482  * @author  Geoffrey T. Dairiki <dairiki@dairiki.org>
0483  */
0484  class diff3 extends diff
0485  {
0486      /**
0487      * Conflict counter.
0488      * @var integer
0489      */
0490      var $_conflicting_blocks = 0;
0491   
0492      /**
0493      * Computes diff between 3 sequences of strings.
0494      *
0495      * @param array &$orig        The original lines to use.
0496      * @param array &$final1        The first version to compare to.
0497      * @param array &$final2        The second version to compare to.
0498      * @param bool $preserve_cr    If true, \r\n and bare \r are replaced by a new line
0499      *                            in the diff output
0500      */
0501      function diff3(&$orig, &$final1, &$final2, $preserve_cr = true)
0502      {
0503          $diff_engine = new diff_engine();
0504   
0505          $diff_1 = $diff_engine->diff($orig, $final1, $preserve_cr);
0506          $diff_2 = $diff_engine->diff($orig, $final2, $preserve_cr);
0507   
0508          unset($diff_engine);
0509   
0510          $this->_edits = $this->_diff3($diff_1, $diff_2);
0511      }
0512   
0513      /**
0514      * Return number of conflicts
0515      */
0516      function get_num_conflicts()
0517      {
0518          $conflicts = 0;
0519   
0520          for ($i = 0, $size = sizeof($this->_edits); $i < $size; $i++)
0521          {
0522              $edit = $this->_edits[$i];
0523   
0524              if ($edit->is_conflict())
0525              {
0526                  $conflicts++;
0527              }
0528          }
0529   
0530          return $conflicts;
0531      }
0532   
0533      /**
0534      * Get conflicts content for download. This is generally a merged file, but preserving conflicts and adding explanations to it.
0535      * A user could then go through this file, search for the conflicts and changes the code accordingly.
0536      *
0537      * @param string $label1 the cvs file version/label from the original set of lines
0538      * @param string $label2 the cvs file version/label from the new set of lines
0539      * @param string $label_sep the explanation between label1 and label2 - more of a helper for the user
0540      *
0541      * @return mixed the merged output
0542      */
0543      function get_conflicts_content($label1 = 'CURRENT_FILE', $label2 = 'NEW_FILE', $label_sep = 'DIFF_SEP_EXPLAIN')
0544      {
0545          global $user;
0546   
0547          $label1 = (!empty($user->lang[$label1])) ? $user->lang[$label1] : $label1;
0548          $label2 = (!empty($user->lang[$label2])) ? $user->lang[$label2] : $label2;
0549          $label_sep = (!empty($user->lang[$label_sep])) ? $user->lang[$label_sep] : $label_sep;
0550   
0551          $lines = array();
0552   
0553          for ($i = 0, $size = sizeof($this->_edits); $i < $size; $i++)
0554          {
0555              $edit = $this->_edits[$i];
0556   
0557              if ($edit->is_conflict())
0558              {
0559                  // Start conflict label
0560                  $label_start    = array('<<<<<<< ' . $label1);
0561                  $label_mid        = array('======= ' . $label_sep);
0562                  $label_end        = array('>>>>>>> ' . $label2);
0563   
0564                  $lines = array_merge($lines, $label_start, $edit->final1, $label_mid, $edit->final2, $label_end);
0565                  $this->_conflicting_blocks++;
0566              }
0567              else
0568              {
0569                  $lines = array_merge($lines, $edit->merged());
0570              }
0571          }
0572   
0573          return $lines;
0574      }
0575   
0576      /**
0577      * Return merged output (used by the renderer)
0578      *
0579      * @return mixed the merged output
0580      */
0581      function merged_output()
0582      {
0583          return $this->get_conflicts_content();
0584      }
0585   
0586      /**
0587      * Merge the output and use the new file code for conflicts
0588      */
0589      function merged_new_output()
0590      {
0591          $lines = array();
0592   
0593          for ($i = 0, $size = sizeof($this->_edits); $i < $size; $i++)
0594          {
0595              $edit = $this->_edits[$i];
0596   
0597              if ($edit->is_conflict())
0598              {
0599                  $lines = array_merge($lines, $edit->final2);
0600              }
0601              else
0602              {
0603                  $lines = array_merge($lines, $edit->merged());
0604              }
0605          }
0606   
0607          return $lines;
0608      }
0609   
0610      /**
0611      * Merge the output and use the original file code for conflicts
0612      */
0613      function merged_orig_output()
0614      {
0615          $lines = array();
0616   
0617          for ($i = 0, $size = sizeof($this->_edits); $i < $size; $i++)
0618          {
0619              $edit = $this->_edits[$i];
0620   
0621              if ($edit->is_conflict())
0622              {
0623                  $lines = array_merge($lines, $edit->final1);
0624              }
0625              else
0626              {
0627                  $lines = array_merge($lines, $edit->merged());
0628              }
0629          }
0630   
0631          return $lines;
0632      }
0633   
0634      /**
0635      * Get conflicting block(s)
0636      */
0637      function get_conflicts()
0638      {
0639          $conflicts = array();
0640   
0641          for ($i = 0, $size = sizeof($this->_edits); $i < $size; $i++)
0642          {
0643              $edit = $this->_edits[$i];
0644   
0645              if ($edit->is_conflict())
0646              {
0647                  $conflicts[] = array($edit->final1, $edit->final2);
0648              }
0649          }
0650   
0651          return $conflicts;
0652      }
0653   
0654      /**
0655      * @access private
0656      */
0657      function _diff3(&$edits1, &$edits2)
0658      {
0659          $edits = array();
0660          $bb = new diff3_block_builder();
0661   
0662          $e1 = current($edits1);
0663          $e2 = current($edits2);
0664   
0665          while ($e1 || $e2)
0666          {
0667              if ($e1 && $e2 && is_a($e1, 'diff_op_copy') && is_a($e2, 'diff_op_copy'))
0668              {
0669                  // We have copy blocks from both diffs. This is the (only) time we want to emit a diff3 copy block.
0670                  // Flush current diff3 diff block, if any.
0671                  if ($edit = $bb->finish())
0672                  {
0673                      $edits[] = $edit;
0674                  }
0675   
0676                  $ncopy = min($e1->norig(), $e2->norig());
0677                  $edits[] = new diff3_op_copy(array_slice($e1->orig, 0, $ncopy));
0678   
0679                  if ($e1->norig() > $ncopy)
0680                  {
0681                      array_splice($e1->orig, 0, $ncopy);
0682                      array_splice($e1->final, 0, $ncopy);
0683                  }
0684                  else
0685                  {
0686                      $e1 = next($edits1);
0687                  }
0688   
0689                  if ($e2->norig() > $ncopy)
0690                  {
0691                      array_splice($e2->orig, 0, $ncopy);
0692                      array_splice($e2->final, 0, $ncopy);
0693                  }
0694                  else
0695                  {
0696                      $e2 = next($edits2);
0697                  }
0698              }
0699              else
0700              {
0701                  if ($e1 && $e2)
0702                  {
0703                      if ($e1->orig && $e2->orig)
0704                      {
0705                          $norig = min($e1->norig(), $e2->norig());
0706                          $orig = array_splice($e1->orig, 0, $norig);
0707                          array_splice($e2->orig, 0, $norig);
0708                          $bb->input($orig);
0709                      }
0710                      else
0711                      {
0712                          $norig = 0;
0713                      }
0714   
0715                      if (is_a($e1, 'diff_op_copy'))
0716                      {
0717                          $bb->out1(array_splice($e1->final, 0, $norig));
0718                      }
0719   
0720                      if (is_a($e2, 'diff_op_copy'))
0721                      {
0722                          $bb->out2(array_splice($e2->final, 0, $norig));
0723                      }
0724                  }
0725   
0726                  if ($e1 && ! $e1->orig)
0727                  {
0728                      $bb->out1($e1->final);
0729                      $e1 = next($edits1);
0730                  }
0731   
0732                  if ($e2 && ! $e2->orig)
0733                  {
0734                      $bb->out2($e2->final);
0735                      $e2 = next($edits2);
0736                  }
0737              }
0738          }
0739   
0740          if ($edit = $bb->finish())
0741          {
0742              $edits[] = $edit;
0743          }
0744   
0745          return $edits;
0746      }
0747  }
0748   
0749  /**
0750  * @package diff
0751  * @author  Geoffrey T. Dairiki <dairiki@dairiki.org>
0752  *
0753  * @access private
0754  */
0755  class diff3_op
0756  {
0757      function diff3_op($orig = false, $final1 = false, $final2 = false)
0758      {
0759          $this->orig = $orig ? $orig : array();
0760          $this->final1 = $final1 ? $final1 : array();
0761          $this->final2 = $final2 ? $final2 : array();
0762      }
0763   
0764      function merged()
0765      {
0766          if (!isset($this->_merged))
0767          {
0768              // Prepare the arrays before we compare them. ;)
0769              $this->solve_prepare();
0770   
0771              if ($this->final1 === $this->final2)
0772              {
0773                  $this->_merged = &$this->final1;
0774              }
0775              else if ($this->final1 === $this->orig)
0776              {
0777                  $this->_merged = &$this->final2;
0778              }
0779              else if ($this->final2 === $this->orig)
0780              {
0781                  $this->_merged = &$this->final1;
0782              }
0783              else
0784              {
0785                  // The following tries to aggressively solve conflicts...
0786                  $this->_merged = false;
0787                  $this->solve_conflict();
0788              }
0789          }
0790   
0791          return $this->_merged;
0792      }
0793   
0794      function is_conflict()
0795      {
0796          return ($this->merged() === false) ? true : false;
0797      }
0798   
0799      /**
0800      * Function to prepare the arrays for comparing - we want to skip over newline changes
0801      * @author acydburn
0802      */
0803      function solve_prepare()
0804      {
0805          // We can simplify one case where the array is usually supposed to be empty...
0806          if (sizeof($this->orig) == 1 && trim($this->orig[0]) === '') $this->orig = array();
0807          if (sizeof($this->final1) == 1 && trim($this->final1[0]) === '') $this->final1 = array();
0808          if (sizeof($this->final2) == 1 && trim($this->final2[0]) === '') $this->final2 = array();
0809   
0810          // Now we only can have the case where the only difference between arrays are newlines, so compare all cases
0811   
0812          // First, some strings we can compare...
0813          $orig = $final1 = $final2 = '';
0814   
0815          foreach ($this->orig as $null => $line) $orig .= trim($line);
0816          foreach ($this->final1 as $null => $line) $final1 .= trim($line);
0817          foreach ($this->final2 as $null => $line) $final2 .= trim($line);
0818   
0819          // final1 === final2
0820          if ($final1 === $final2)
0821          {
0822              // We preserve the part which will be used in the merge later
0823              $this->final2 = $this->final1;
0824          }
0825          // final1 === orig
0826          else if ($final1 === $orig)
0827          {
0828              // Here it does not really matter what we choose, but we will use the new code
0829              $this->orig = $this->final1;
0830          }
0831          // final2 === orig
0832          else if ($final2 === $orig)
0833          {
0834              // Here it does not really matter too (final1 will be used), but we will use the new code
0835              $this->orig = $this->final2;
0836          }
0837      }
0838   
0839      /**
0840      * Find code portions from $orig in $final1 and use $final2 as merged instance if provided
0841      * @author acydburn
0842      */
0843      function _compare_conflict_seq($orig, $final1, $final2 = false)
0844      {
0845          $result = array('merge_found' => false, 'merge' => array());
0846   
0847          $_orig = &$this->$orig;
0848          $_final1 = &$this->$final1;
0849   
0850          // Ok, we basically search for $orig in $final1
0851          $compare_seq = sizeof($_orig);
0852   
0853          // Go through the conflict code
0854          for ($i = 0, $j = 0, $size = sizeof($_final1); $i < $size; $i++, $j = $i)
0855          {
0856              $line = $_final1[$i];
0857              $skip = 0;
0858   
0859              for ($x = 0; $x < $compare_seq; $x++)
0860              {
0861                  // Try to skip all matching lines
0862                  if (trim($line) === trim($_orig[$x]))
0863                  {
0864                      $line = (++$j < $size) ? $_final1[$j] : $line;
0865                      $skip++;
0866                  }
0867              }
0868   
0869              if ($skip === $compare_seq)
0870              {
0871                  $result['merge_found'] = true;
0872   
0873                  if ($final2 !== false)
0874                  {
0875                      $result['merge'] = array_merge($result['merge'], $this->$final2);
0876                  }
0877                  $i += ($skip - 1);
0878              }
0879              else if ($final2 !== false)
0880              {
0881                  $result['merge'][] = $line;
0882              }
0883          }
0884   
0885          return $result;
0886      }
0887   
0888      /**
0889      * Tries to solve conflicts aggressively based on typical "assumptions"
0890      * @author acydburn
0891      */
0892      function solve_conflict()
0893      {
0894          $this->_merged = false;
0895   
0896          // CASE ONE: orig changed into final2, but modified/unknown code in final1.
0897          // IF orig is found "as is" in final1 we replace the code directly in final1 and populate this as final2/merge
0898          if (sizeof($this->orig) && sizeof($this->final2))
0899          {
0900              $result = $this->_compare_conflict_seq('orig', 'final1', 'final2');
0901   
0902              if ($result['merge_found'])
0903              {
0904                  $this->final2 = $result['merge'];
0905                  $this->_merged = &$this->final2;
0906                  return;
0907              }
0908   
0909              $result = $this->_compare_conflict_seq('final2', 'final1');
0910   
0911              if ($result['merge_found'])
0912              {
0913                  $this->_merged = &$this->final1;
0914                  return;
0915              }
0916   
0917              // Try to solve $Id$ issues. ;)
0918              if (sizeof($this->orig) == 1 && sizeof($this->final1) == 1 && sizeof($this->final2) == 1)
0919              {
0920                  $match = '#^' . preg_quote('* @version $Id: ', '#') . '[a-z\._\- ]+[0-9]+ [0-9]{4}-[0-9]{2}-[0-9]{2} [0-9\:Z]+ [a-z0-9_\- ]+\$$#';
0921   
0922                  if (preg_match($match, $this->orig[0]) && preg_match($match, $this->final1[0]) && preg_match($match, $this->final2[0]))
0923                  {
0924                      $this->_merged = &$this->final2;
0925                      return;
0926                  }
0927              }
0928   
0929              $second_run = false;
0930   
0931              // Try to solve issues where the only reason why the above did not work is a newline being removed in the final1 code but exist in the orig/final2 code
0932              if (trim($this->orig[0]) === '' && trim($this->final2[0]) === '')
0933              {
0934                  unset($this->orig[0], $this->final2[0]);
0935                  $this->orig = array_values($this->orig);
0936                  $this->final2 = array_values($this->final2);
0937   
0938                  $second_run = true;
0939              }
0940   
0941              // The same is true for a line at the end. ;)
0942              if (sizeof($this->orig) && sizeof($this->final2) && sizeof($this->orig) === sizeof($this->final2) && trim($this->orig[sizeof($this->orig)-1]) === '' && trim($this->final2[sizeof($this->final2)-1]) === '')
0943              {
0944                  unset($this->orig[sizeof($this->orig)-1], $this->final2[sizeof($this->final2)-1]);
0945                  $this->orig = array_values($this->orig);
0946                  $this->final2 = array_values($this->final2);
0947   
0948                  $second_run = true;
0949              }
0950   
0951              if ($second_run)
0952              {
0953                  $result = $this->_compare_conflict_seq('orig', 'final1', 'final2');
0954   
0955                  if ($result['merge_found'])
0956                  {
0957                      $this->final2 = $result['merge'];
0958                      $this->_merged = &$this->final2;
0959                      return;
0960                  }
0961   
0962                  $result = $this->_compare_conflict_seq('final2', 'final1');
0963   
0964                  if ($result['merge_found'])
0965                  {
0966                      $this->_merged = &$this->final1;
0967                      return;
0968                  }
0969              }
0970   
0971              return;
0972          }
0973   
0974          // CASE TWO: Added lines from orig to final2 but final1 had added lines too. Just merge them.
0975          if (!sizeof($this->orig) && $this->final1 !== $this->final2 && sizeof($this->final1) && sizeof($this->final2))
0976          {
0977              $result = $this->_compare_conflict_seq('final2', 'final1');
0978   
0979              if ($result['merge_found'])
0980              {
0981                  $this->final2 = $this->final1;
0982                  $this->_merged = &$this->final1;
0983              }
0984              else
0985              {
0986                  $result = $this->_compare_conflict_seq('final1', 'final2');
0987   
0988                  if (!$result['merge_found'])
0989                  {
0990                      $this->final2 = array_merge($this->final1, $this->final2);
0991                      $this->_merged = &$this->final2;
0992                  }
0993                  else
0994                  {
0995                      $this->final2 = $this->final1;
0996                      $this->_merged = &$this->final1;
0997                  }
0998              }
0999   
1000              return;
1001          }
1002   
1003          // CASE THREE: Removed lines (orig has the to-remove line(s), but final1 has additional lines which does not need to be removed). Just remove orig from final1 and then use final1 as final2/merge
1004          if (!sizeof($this->final2) && sizeof($this->orig) && sizeof($this->final1) && $this->orig !== $this->final1)
1005          {
1006              $result = $this->_compare_conflict_seq('orig', 'final1');
1007   
1008              if (!$result['merge_found'])
1009              {
1010                  return;
1011              }
1012   
1013              // First of all, try to find the code in orig in final1. ;)
1014              $compare_seq = sizeof($this->orig);
1015              $begin = $end = -1;
1016              $j = 0;
1017   
1018              for ($i = 0, $size = sizeof($this->final1); $i < $size; $i++)
1019              {
1020                  $line = $this->final1[$i];
1021   
1022                  if (trim($line) === trim($this->orig[$j]))
1023                  {
1024                      // Mark begin
1025                      if ($begin === -1)
1026                      {
1027                          $begin = $i;
1028                      }
1029   
1030                      // End is always $i, the last found line
1031                      $end = $i;
1032   
1033                      if (isset($this->orig[$j+1]))
1034                      {
1035                          $j++;
1036                      }
1037                  }
1038              }
1039   
1040              if ($begin !== -1 && $begin + ($compare_seq - 1) == $end)
1041              {
1042                  foreach ($this->final1 as $i => $line)
1043                  {
1044                      if ($i < $begin || $i > $end)
1045                      {
1046                          $merged[] = $line;
1047                      }
1048                  }
1049   
1050                  $this->final2 = $merged;
1051                  $this->_merged = &$this->final2;
1052              }
1053   
1054              return;
1055          }
1056   
1057          return;
1058      }
1059  }
1060   
1061  /**
1062  * @package diff
1063  * @author  Geoffrey T. Dairiki <dairiki@dairiki.org>
1064  *
1065  * @access private
1066  */
1067  class diff3_op_copy extends diff3_op
1068  {
1069      function diff3_op_copy($lines = false)
1070      {
1071          $this->orig = $lines ? $lines : array();
1072          $this->final1 = &$this->orig;
1073          $this->final2 = &$this->orig;
1074      }
1075   
1076      function merged()
1077      {
1078          return $this->orig;
1079      }
1080   
1081      function is_conflict()
1082      {
1083          return false;
1084      }
1085  }
1086   
1087  /**
1088  * @package diff
1089  * @author  Geoffrey T. Dairiki <dairiki@dairiki.org>
1090  *
1091  * @access private
1092  */
1093  class diff3_block_builder
1094  {
1095      function diff3_block_builder()
1096      {
1097          $this->_init();
1098      }
1099   
1100      function input($lines)
1101      {
1102          if ($lines)
1103          {
1104              $this->_append($this->orig, $lines);
1105          }
1106      }
1107   
1108      function out1($lines)
1109      {
1110          if ($lines)
1111          {
1112              $this->_append($this->final1, $lines);
1113          }
1114      }
1115   
1116      function out2($lines)
1117      {
1118          if ($lines)
1119          {
1120              $this->_append($this->final2, $lines);
1121          }
1122      }
1123   
1124      function is_empty()
1125      {
1126          return !$this->orig && !$this->final1 && !$this->final2;
1127      }
1128   
1129      function finish()
1130      {
1131          if ($this->is_empty())
1132          {
1133              return false;
1134          }
1135          else
1136          {
1137              $edit = new diff3_op($this->orig, $this->final1, $this->final2);
1138              $this->_init();
1139              return $edit;
1140          }
1141      }
1142   
1143      function _init()
1144      {
1145          $this->orig = $this->final1 = $this->final2 = array();
1146      }
1147   
1148      function _append(&$array, $lines)
1149      {
1150          array_splice($array, sizeof($array), 0, $lines);
1151      }
1152  }
1153