Verzeichnisstruktur phpBB-3.0.0
- Veröffentlicht
- 12.12.2007
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. |
|
(Beispiel Datei-Icons)
|
Auf das Icon klicken um den Quellcode anzuzeigen |
diff.php
001 <?php
002 /**
003 *
004 * @package diff
005 * @version $Id$
006 * @copyright (c) 2006 phpBB Group
007 * @license http://opensource.org/licenses/gpl-license.php GNU Public License
008 *
009 */
010
011 /**
012 * @ignore
013 */
014 if (!defined('IN_PHPBB'))
015 {
016 exit;
017 }
018
019 /**
020 * Code from pear.php.net, Text_Diff-0.2.1 (beta) package
021 * http://pear.php.net/package/Text_Diff/
022 *
023 * Modified by phpBB Group to meet our coding standards
024 * and being able to integrate into phpBB
025 *
026 * General API for generating and formatting diffs - the differences between
027 * two sequences of strings.
028 *
029 * @package diff
030 * @author Geoffrey T. Dairiki <dairiki@dairiki.org>
031 */
032 class diff
033 {
034 /**
035 * Array of changes.
036 * @var array
037 */
038 var $_edits;
039
040 /**
041 * Computes diffs between sequences of strings.
042 *
043 * @param array $from_lines An array of strings. Typically these are lines from a file.
044 * @param array $to_lines An array of strings.
045 */
046 function diff(&$from_content, &$to_content, $preserve_cr = true)
047 {
048 $diff_engine = &new diff_engine();
049 $this->_edits = $diff_engine->diff($from_content, $to_content, $preserve_cr);
050 }
051
052 /**
053 * Returns the array of differences.
054 */
055 function get_diff()
056 {
057 return $this->_edits;
058 }
059
060 /**
061 * Computes a reversed diff.
062 *
063 * Example:
064 * <code>
065 * $diff = &new diff($lines1, $lines2);
066 * $rev = $diff->reverse();
067 * </code>
068 *
069 * @return diff A Diff object representing the inverse of the original diff.
070 * Note that we purposely don't return a reference here, since
071 * this essentially is a clone() method.
072 */
073 function reverse()
074 {
075 if (version_compare(zend_version(), '2', '>'))
076 {
077 $rev = clone($this);
078 }
079 else
080 {
081 $rev = $this;
082 }
083
084 $rev->_edits = array();
085
086 foreach ($this->_edits as $edit)
087 {
088 $rev->_edits[] = $edit->reverse();
089 }
090
091 return $rev;
092 }
093
094 /**
095 * Checks for an empty diff.
096 *
097 * @return boolean True if two sequences were identical.
098 */
099 function is_empty()
100 {
101 foreach ($this->_edits as $edit)
102 {
103 if (!is_a($edit, 'diff_op_copy'))
104 {
105 return false;
106 }
107 }
108 return true;
109 }
110
111 /**
112 * Computes the length of the Longest Common Subsequence (LCS).
113 *
114 * This is mostly for diagnostic purposes.
115 *
116 * @return integer The length of the LCS.
117 */
118 function lcs()
119 {
120 $lcs = 0;
121
122 foreach ($this->_edits as $edit)
123 {
124 if (is_a($edit, 'diff_op_copy'))
125 {
126 $lcs += sizeof($edit->orig);
127 }
128 }
129 return $lcs;
130 }
131
132 /**
133 * Gets the original set of lines.
134 *
135 * This reconstructs the $from_lines parameter passed to the constructor.
136 *
137 * @return array The original sequence of strings.
138 */
139 function get_original()
140 {
141 $lines = array();
142
143 foreach ($this->_edits as $edit)
144 {
145 if ($edit->orig)
146 {
147 array_splice($lines, sizeof($lines), 0, $edit->orig);
148 }
149 }
150 return $lines;
151 }
152
153 /**
154 * Gets the final set of lines.
155 *
156 * This reconstructs the $to_lines parameter passed to the constructor.
157 *
158 * @return array The sequence of strings.
159 */
160 function get_final()
161 {
162 $lines = array();
163
164 foreach ($this->_edits as $edit)
165 {
166 if ($edit->final)
167 {
168 array_splice($lines, sizeof($lines), 0, $edit->final);
169 }
170 }
171 return $lines;
172 }
173
174 /**
175 * Removes trailing newlines from a line of text. This is meant to be used with array_walk().
176 *
177 * @param string &$line The line to trim.
178 * @param integer $key The index of the line in the array. Not used.
179 */
180 function trim_newlines(&$line, $key)
181 {
182 $line = str_replace(array("\n", "\r"), '', $line);
183 }
184
185 /**
186 * Checks a diff for validity.
187 *
188 * This is here only for debugging purposes.
189 */
190 function _check($from_lines, $to_lines)
191 {
192 if (serialize($from_lines) != serialize($this->get_original()))
193 {
194 trigger_error("[diff] Reconstructed original doesn't match", E_USER_ERROR);
195 }
196
197 if (serialize($to_lines) != serialize($this->get_final()))
198 {
199 trigger_error("[diff] Reconstructed final doesn't match", E_USER_ERROR);
200 }
201
202 $rev = $this->reverse();
203
204 if (serialize($to_lines) != serialize($rev->get_original()))
205 {
206 trigger_error("[diff] Reversed original doesn't match", E_USER_ERROR);
207 }
208
209 if (serialize($from_lines) != serialize($rev->get_final()))
210 {
211 trigger_error("[diff] Reversed final doesn't match", E_USER_ERROR);
212 }
213
214 $prevtype = null;
215
216 foreach ($this->_edits as $edit)
217 {
218 if ($prevtype == get_class($edit))
219 {
220 trigger_error("[diff] Edit sequence is non-optimal", E_USER_ERROR);
221 }
222 $prevtype = get_class($edit);
223 }
224
225 return true;
226 }
227 }
228
229 /**
230 * @package diff
231 * @author Geoffrey T. Dairiki <dairiki@dairiki.org>
232 */
233 class mapped_diff extends diff
234 {
235 /**
236 * Computes a diff between sequences of strings.
237 *
238 * This can be used to compute things like case-insensitve diffs, or diffs
239 * which ignore changes in white-space.
240 *
241 * @param array $from_lines An array of strings.
242 * @param array $to_lines An array of strings.
243 * @param array $mapped_from_lines This array should have the same size number of elements as $from_lines.
244 * The elements in $mapped_from_lines and $mapped_to_lines are what is actually
245 * compared when computing the diff.
246 * @param array $mapped_to_lines This array should have the same number of elements as $to_lines.
247 */
248 function mapped_diff(&$from_lines, &$to_lines, &$mapped_from_lines, &$mapped_to_lines)
249 {
250 if (sizeof($from_lines) != sizeof($mapped_from_lines) || sizeof($to_lines) != sizeof($mapped_to_lines))
251 {
252 return false;
253 }
254
255 parent::diff($mapped_from_lines, $mapped_to_lines);
256
257 $xi = $yi = 0;
258 for ($i = 0; $i < sizeof($this->_edits); $i++)
259 {
260 $orig = &$this->_edits[$i]->orig;
261 if (is_array($orig))
262 {
263 $orig = array_slice($from_lines, $xi, sizeof($orig));
264 $xi += sizeof($orig);
265 }
266
267 $final = &$this->_edits[$i]->final;
268 if (is_array($final))
269 {
270 $final = array_slice($to_lines, $yi, sizeof($final));
271 $yi += sizeof($final);
272 }
273 }
274 }
275 }
276
277 /**
278 * @package diff
279 * @author Geoffrey T. Dairiki <dairiki@dairiki.org>
280 *
281 * @access private
282 */
283 class diff_op
284 {
285 var $orig;
286 var $final;
287
288 function reverse()
289 {
290 trigger_error('[diff] Abstract method', E_USER_ERROR);
291 }
292
293 function norig()
294 {
295 return ($this->orig) ? sizeof($this->orig) : 0;
296 }
297
298 function nfinal()
299 {
300 return ($this->final) ? sizeof($this->final) : 0;
301 }
302 }
303
304 /**
305 * @package diff
306 * @author Geoffrey T. Dairiki <dairiki@dairiki.org>
307 *
308 * @access private
309 */
310 class diff_op_copy extends diff_op
311 {
312 function diff_op_copy($orig, $final = false)
313 {
314 if (!is_array($final))
315 {
316 $final = $orig;
317 }
318 $this->orig = $orig;
319 $this->final = $final;
320 }
321
322 function &reverse()
323 {
324 $reverse = &new diff_op_copy($this->final, $this->orig);
325 return $reverse;
326 }
327 }
328
329 /**
330 * @package diff
331 * @author Geoffrey T. Dairiki <dairiki@dairiki.org>
332 *
333 * @access private
334 */
335 class diff_op_delete extends diff_op
336 {
337 function diff_op_delete($lines)
338 {
339 $this->orig = $lines;
340 $this->final = false;
341 }
342
343 function &reverse()
344 {
345 $reverse = &new diff_op_add($this->orig);
346 return $reverse;
347 }
348 }
349
350 /**
351 * @package diff
352 * @author Geoffrey T. Dairiki <dairiki@dairiki.org>
353 *
354 * @access private
355 */
356 class diff_op_add extends diff_op
357 {
358 function diff_op_add($lines)
359 {
360 $this->final = $lines;
361 $this->orig = false;
362 }
363
364 function &reverse()
365 {
366 $reverse = &new diff_op_delete($this->final);
367 return $reverse;
368 }
369 }
370
371 /**
372 * @package diff
373 * @author Geoffrey T. Dairiki <dairiki@dairiki.org>
374 *
375 * @access private
376 */
377 class diff_op_change extends diff_op
378 {
379 function diff_op_change($orig, $final)
380 {
381 $this->orig = $orig;
382 $this->final = $final;
383 }
384
385 function &reverse()
386 {
387 $reverse = &new diff_op_change($this->final, $this->orig);
388 return $reverse;
389 }
390 }
391
392
393 /**
394 * A class for computing three way diffs.
395 *
396 * @package diff
397 * @author Geoffrey T. Dairiki <dairiki@dairiki.org>
398 */
399 class diff3 extends diff
400 {
401 /**
402 * Conflict counter.
403 * @var integer
404 */
405 var $_conflicting_blocks = 0;
406
407 /**
408 * Computes diff between 3 sequences of strings.
409 *
410 * @param array $orig The original lines to use.
411 * @param array $final1 The first version to compare to.
412 * @param array $final2 The second version to compare to.
413 */
414 function diff3(&$orig, &$final1, &$final2)
415 {
416 $diff_engine = &new diff_engine();
417
418 $diff_1 = $diff_engine->diff($orig, $final1);
419 $diff_2 = $diff_engine->diff($orig, $final2);
420
421 unset($engine);
422
423 $this->_edits = $this->_diff3($diff_1, $diff_2);
424 }
425
426 /**
427 * Return merged output
428 *
429 * @param string $label1 the cvs file version/label from the original set of lines
430 * @param string $label2 the cvs file version/label from the new set of lines
431 * @param string $label_sep the explanation between label1 and label2 - more of a helper for the user
432 * @param bool $get_conflicts if set to true only the number of conflicts is returned
433 * @param bool $merge_new if set to true the merged output will have the new file contents on a conflicting merge
434 *
435 * @return mixed the merged output
436 */
437 function merged_output($label1 = 'CURRENT_FILE', $label2 = 'NEW_FILE', $label_sep = 'DIFF_SEP_EXPLAIN', $get_conflicts = false, $merge_new = false)
438 {
439 global $user;
440
441 if ($get_conflicts)
442 {
443 foreach ($this->_edits as $edit)
444 {
445 if ($edit->is_conflict())
446 {
447 $this->_conflicting_blocks++;
448 }
449 }
450
451 return $this->_conflicting_blocks;
452 }
453
454 $label1 = (!empty($user->lang[$label1])) ? $user->lang[$label1] : $label1;
455 $label2 = (!empty($user->lang[$label2])) ? $user->lang[$label2] : $label2;
456 $label_sep = (!empty($user->lang[$label_sep])) ? $user->lang[$label_sep] : $label_sep;
457
458 $lines = array();
459
460 foreach ($this->_edits as $edit)
461 {
462 if ($edit->is_conflict())
463 {
464 if (!$merge_new)
465 {
466 $lines = array_merge($lines, array('<<<<<<<' . ($label1 ? ' ' . $label1 : '')), $edit->final1, array('=======' . ($label_sep ? ' ' . $label_sep : '')), $edit->final2, array('>>>>>>>' . ($label2 ? ' ' . $label2 : '')));
467 }
468 else
469 {
470 $lines = array_merge($lines, $edit->final1);
471 }
472 $this->_conflicting_blocks++;
473 }
474 else
475 {
476 $lines = array_merge($lines, $edit->merged());
477 }
478 }
479
480 return $lines;
481 }
482
483 /**
484 * Merge the output and use the new file code for conflicts
485 */
486 function merged_new_output()
487 {
488 $lines = array();
489
490 foreach ($this->_edits as $edit)
491 {
492 if ($edit->is_conflict())
493 {
494 $lines = array_merge($lines, $edit->final2);
495 }
496 else
497 {
498 $lines = array_merge($lines, $edit->merged());
499 }
500 }
501
502 return $lines;
503 }
504
505 /**
506 * Merge the output and use the original file code for conflicts
507 */
508 function merged_orig_output()
509 {
510 $lines = array();
511
512 foreach ($this->_edits as $edit)
513 {
514 if ($edit->is_conflict())
515 {
516 $lines = array_merge($lines, $edit->final1);
517 }
518 else
519 {
520 $lines = array_merge($lines, $edit->merged());
521 }
522 }
523
524 return $lines;
525 }
526
527 /**
528 * Get conflicting block(s)
529 */
530 function get_conflicts()
531 {
532 $conflicts = array();
533
534 foreach ($this->_edits as $edit)
535 {
536 if ($edit->is_conflict())
537 {
538 $conflicts[] = array($edit->final1, $edit->final2);
539 }
540 }
541
542 return $conflicts;
543 }
544
545 /**
546 * @access private
547 */
548 function _diff3(&$edits1, &$edits2)
549 {
550 $edits = array();
551 $bb = &new diff3_block_builder();
552
553 $e1 = current($edits1);
554 $e2 = current($edits2);
555
556 while ($e1 || $e2)
557 {
558 if ($e1 && $e2 && is_a($e1, 'diff_op_copy') && is_a($e2, 'diff_op_copy'))
559 {
560 // We have copy blocks from both diffs. This is the (only) time we want to emit a diff3 copy block.
561 // Flush current diff3 diff block, if any.
562 if ($edit = $bb->finish())
563 {
564 $edits[] = $edit;
565 }
566
567 $ncopy = min($e1->norig(), $e2->norig());
568 $edits[] = &new diff3_op_copy(array_slice($e1->orig, 0, $ncopy));
569
570 if ($e1->norig() > $ncopy)
571 {
572 array_splice($e1->orig, 0, $ncopy);
573 array_splice($e1->final, 0, $ncopy);
574 }
575 else
576 {
577 $e1 = next($edits1);
578 }
579
580 if ($e2->norig() > $ncopy)
581 {
582 array_splice($e2->orig, 0, $ncopy);
583 array_splice($e2->final, 0, $ncopy);
584 }
585 else
586 {
587 $e2 = next($edits2);
588 }
589 }
590 else
591 {
592 if ($e1 && $e2)
593 {
594 if ($e1->orig && $e2->orig)
595 {
596 $norig = min($e1->norig(), $e2->norig());
597 $orig = array_splice($e1->orig, 0, $norig);
598 array_splice($e2->orig, 0, $norig);
599 $bb->input($orig);
600 }
601 else
602 {
603 $norig = 0;
604 }
605
606 if (is_a($e1, 'diff_op_copy'))
607 {
608 $bb->out1(array_splice($e1->final, 0, $norig));
609 }
610
611 if (is_a($e2, 'diff_op_copy'))
612 {
613 $bb->out2(array_splice($e2->final, 0, $norig));
614 }
615 }
616
617 if ($e1 && ! $e1->orig)
618 {
619 $bb->out1($e1->final);
620 $e1 = next($edits1);
621 }
622
623 if ($e2 && ! $e2->orig)
624 {
625 $bb->out2($e2->final);
626 $e2 = next($edits2);
627 }
628 }
629 }
630
631 if ($edit = $bb->finish())
632 {
633 $edits[] = $edit;
634 }
635
636 return $edits;
637 }
638 }
639
640 /**
641 * @package diff
642 * @author Geoffrey T. Dairiki <dairiki@dairiki.org>
643 *
644 * @access private
645 */
646 class diff3_op
647 {
648 function diff3_op($orig = false, $final1 = false, $final2 = false)
649 {
650 $this->orig = $orig ? $orig : array();
651 $this->final1 = $final1 ? $final1 : array();
652 $this->final2 = $final2 ? $final2 : array();
653 }
654
655 function merged()
656 {
657 if (!isset($this->_merged))
658 {
659 if ($this->final1 === $this->final2)
660 {
661 $this->_merged = &$this->final1;
662 }
663 else if ($this->final1 === $this->orig)
664 {
665 $this->_merged = &$this->final2;
666 }
667 else if ($this->final2 === $this->orig)
668 {
669 $this->_merged = &$this->final1;
670 }
671 else
672 {
673 $this->_merged = false;
674 }
675 }
676
677 return $this->_merged;
678 }
679
680 function is_conflict()
681 {
682 return ($this->merged() === false) ? true : false;
683 }
684 }
685
686 /**
687 * @package diff
688 * @author Geoffrey T. Dairiki <dairiki@dairiki.org>
689 *
690 * @access private
691 */
692 class diff3_op_copy extends diff3_op
693 {
694 function diff3_op_copy($lines = false)
695 {
696 $this->orig = $lines ? $lines : array();
697 $this->final1 = &$this->orig;
698 $this->final2 = &$this->orig;
699 }
700
701 function merged()
702 {
703 return $this->orig;
704 }
705
706 function is_conflict()
707 {
708 return false;
709 }
710 }
711
712 /**
713 * @package diff
714 * @author Geoffrey T. Dairiki <dairiki@dairiki.org>
715 *
716 * @access private
717 */
718 class diff3_block_builder
719 {
720 function diff3_block_builder()
721 {
722 $this->_init();
723 }
724
725 function input($lines)
726 {
727 if ($lines)
728 {
729 $this->_append($this->orig, $lines);
730 }
731 }
732
733 function out1($lines)
734 {
735 if ($lines)
736 {
737 $this->_append($this->final1, $lines);
738 }
739 }
740
741 function out2($lines)
742 {
743 if ($lines)
744 {
745 $this->_append($this->final2, $lines);
746 }
747 }
748
749 function is_empty()
750 {
751 return !$this->orig && !$this->final1 && !$this->final2;
752 }
753
754 function finish()
755 {
756 if ($this->is_empty())
757 {
758 return false;
759 }
760 else
761 {
762 $edit = &new diff3_op($this->orig, $this->final1, $this->final2);
763 $this->_init();
764 return $edit;
765 }
766 }
767
768 function _init()
769 {
770 $this->orig = $this->final1 = $this->final2 = array();
771 }
772
773 function _append(&$array, $lines)
774 {
775 array_splice($array, sizeof($array), 0, $lines);
776 }
777 }
778
779 ?>