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 |
renderer.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 * A class to render Diffs in different formats.
027 *
028 * This class renders the diff in classic diff format. It is intended that
029 * this class be customized via inheritance, to obtain fancier outputs.
030 *
031 * @package diff
032 */
033 class diff_renderer
034 {
035 /**
036 * Number of leading context "lines" to preserve.
037 *
038 * This should be left at zero for this class, but subclasses may want to
039 * set this to other values.
040 */
041 var $_leading_context_lines = 0;
042
043 /**
044 * Number of trailing context "lines" to preserve.
045 *
046 * This should be left at zero for this class, but subclasses may want to
047 * set this to other values.
048 */
049 var $_trailing_context_lines = 0;
050
051 /**
052 * Constructor.
053 */
054 function diff_renderer($params = array())
055 {
056 foreach ($params as $param => $value)
057 {
058 $v = '_' . $param;
059 if (isset($this->$v))
060 {
061 $this->$v = $value;
062 }
063 }
064 }
065
066 /**
067 * Get any renderer parameters.
068 *
069 * @return array All parameters of this renderer object.
070 */
071 function get_params()
072 {
073 $params = array();
074 foreach (get_object_vars($this) as $k => $v)
075 {
076 if ($k[0] == '_')
077 {
078 $params[substr($k, 1)] = $v;
079 }
080 }
081
082 return $params;
083 }
084
085 /**
086 * Renders a diff.
087 *
088 * @param diff &$diff A diff object.
089 *
090 * @return string The formatted output.
091 */
092 function render(&$diff)
093 {
094 $xi = $yi = 1;
095 $block = false;
096 $context = array();
097
098 // Create a new diff object if it is a 3-way diff
099 if (is_a($diff, 'diff3'))
100 {
101 $diff3 = &$diff;
102
103 $diff_1 = $diff3->get_original();
104 $diff_2 = $diff3->merged_output();
105
106 unset($diff3);
107
108 $diff = &new diff($diff_1, $diff_2);
109 }
110
111 $nlead = $this->_leading_context_lines;
112 $ntrail = $this->_trailing_context_lines;
113
114 $output = $this->_start_diff();
115 $diffs = $diff->get_diff();
116
117 foreach ($diffs as $i => $edit)
118 {
119 if (is_a($edit, 'diff_op_copy'))
120 {
121 if (is_array($block))
122 {
123 $keep = ($i == sizeof($diffs) - 1) ? $ntrail : $nlead + $ntrail;
124 if (sizeof($edit->orig) <= $keep)
125 {
126 $block[] = $edit;
127 }
128 else
129 {
130 if ($ntrail)
131 {
132 $context = array_slice($edit->orig, 0, $ntrail);
133 $block[] = &new diff_op_copy($context);
134 }
135
136 $output .= $this->_block($x0, $ntrail + $xi - $x0, $y0, $ntrail + $yi - $y0, $block);
137 $block = false;
138 }
139 }
140 $context = $edit->orig;
141 }
142 else
143 {
144 if (!is_array($block))
145 {
146 $context = array_slice($context, sizeof($context) - $nlead);
147 $x0 = $xi - sizeof($context);
148 $y0 = $yi - sizeof($context);
149 $block = array();
150
151 if ($context)
152 {
153 $block[] = &new diff_op_copy($context);
154 }
155 }
156 $block[] = $edit;
157 }
158
159 $xi += ($edit->orig) ? sizeof($edit->orig) : 0;
160 $yi += ($edit->final) ? sizeof($edit->final) : 0;
161 }
162
163 if (is_array($block))
164 {
165 $output .= $this->_block($x0, $xi - $x0, $y0, $yi - $y0, $block);
166 }
167
168 return $output . $this->_end_diff();
169 }
170
171 function _block($xbeg, $xlen, $ybeg, $ylen, &$edits)
172 {
173 $output = $this->_start_block($this->_block_header($xbeg, $xlen, $ybeg, $ylen));
174
175 foreach ($edits as $edit)
176 {
177 switch (get_class($edit))
178 {
179 case 'diff_op_copy':
180 $output .= $this->_context($edit->orig);
181 break;
182
183 case 'diff_op_add':
184 $output .= $this->_added($edit->final);
185 break;
186
187 case 'diff_op_delete':
188 $output .= $this->_deleted($edit->orig);
189 break;
190
191 case 'diff_op_change':
192 $output .= $this->_changed($edit->orig, $edit->final);
193 break;
194 }
195 }
196
197 return $output . $this->_end_block();
198 }
199
200 function _start_diff()
201 {
202 return '';
203 }
204
205 function _end_diff()
206 {
207 return '';
208 }
209
210 function _block_header($xbeg, $xlen, $ybeg, $ylen)
211 {
212 if ($xlen > 1)
213 {
214 $xbeg .= ',' . ($xbeg + $xlen - 1);
215 }
216
217 if ($ylen > 1)
218 {
219 $ybeg .= ',' . ($ybeg + $ylen - 1);
220 }
221
222 return $xbeg . ($xlen ? ($ylen ? 'c' : 'd') : 'a') . $ybeg;
223 }
224
225 function _start_block($header)
226 {
227 return $header . "\n";
228 }
229
230 function _end_block()
231 {
232 return '';
233 }
234
235 function _lines($lines, $prefix = ' ')
236 {
237 return $prefix . implode("\n$prefix", $lines) . "\n";
238 }
239
240 function _context($lines)
241 {
242 return $this->_lines($lines, ' ');
243 }
244
245 function _added($lines)
246 {
247 return $this->_lines($lines, '> ');
248 }
249
250 function _deleted($lines)
251 {
252 return $this->_lines($lines, '< ');
253 }
254
255 function _changed($orig, $final)
256 {
257 return $this->_deleted($orig) . "---\n" . $this->_added($final);
258 }
259
260 /**
261 * Our function to get the diff
262 */
263 function get_diff_content($diff)
264 {
265 return $this->render($diff);
266 }
267 }
268
269 /**
270 * Renders a unified diff
271 * @package diff
272 */
273 class diff_renderer_unified extends diff_renderer
274 {
275 var $_leading_context_lines = 4;
276 var $_trailing_context_lines = 4;
277
278 /**
279 * Our function to get the diff
280 */
281 function get_diff_content($diff)
282 {
283 return nl2br($this->render($diff));
284 }
285
286 function _block_header($xbeg, $xlen, $ybeg, $ylen)
287 {
288 if ($xlen != 1)
289 {
290 $xbeg .= ',' . $xlen;
291 }
292
293 if ($ylen != 1)
294 {
295 $ybeg .= ',' . $ylen;
296 }
297 return '<div class="diff"><big class="info">@@ -' . $xbeg . ' +' . $ybeg . ' @@</big></div>';
298 }
299
300 function _context($lines)
301 {
302 return '<pre class="diff context">' . htmlspecialchars($this->_lines($lines, ' ')) . '<br /></pre>';
303 }
304
305 function _added($lines)
306 {
307 return '<pre class="diff added">' . htmlspecialchars($this->_lines($lines, '+')) . '<br /></pre>';
308 }
309
310 function _deleted($lines)
311 {
312 return '<pre class="diff removed">' . htmlspecialchars($this->_lines($lines, '-')) . '<br /></pre>';
313 }
314
315 function _changed($orig, $final)
316 {
317 return $this->_deleted($orig) . $this->_added($final);
318 }
319
320 function _start_diff()
321 {
322 $start = '<div class="file">';
323
324 return $start;
325 }
326
327 function _end_diff()
328 {
329 return '</div>';
330 }
331
332 function _end_block()
333 {
334 return '';
335 }
336 }
337
338 /**
339 * "Inline" diff renderer.
340 *
341 * This class renders diffs in the Wiki-style "inline" format.
342 *
343 * @author Ciprian Popovici
344 * @package diff
345 */
346 class diff_renderer_inline extends diff_renderer
347 {
348 var $_leading_context_lines = 10000;
349 var $_trailing_context_lines = 10000;
350
351 // Prefix and suffix for inserted text
352 var $_ins_prefix = '<span class="ins">';
353 var $_ins_suffix = '</span>';
354
355 // Prefix and suffix for deleted text
356 var $_del_prefix = '<span class="del">';
357 var $_del_suffix = '</span>';
358
359 var $_block_head = '';
360
361 // What are we currently splitting on? Used to recurse to show word-level
362 var $_split_level = 'lines';
363
364 /**
365 * Our function to get the diff
366 */
367 function get_diff_content($diff)
368 {
369 return '<pre>' . nl2br($this->render($diff)) . '<br /></pre>';
370 }
371
372 function _start_diff()
373 {
374 return '';
375 }
376
377 function _end_diff()
378 {
379 return '';
380 }
381
382 function _block_header($xbeg, $xlen, $ybeg, $ylen)
383 {
384 return $this->_block_head;
385 }
386
387 function _start_block($header)
388 {
389 return $header;
390 }
391
392 function _lines($lines, $prefix = ' ', $encode = true)
393 {
394 if ($encode)
395 {
396 array_walk($lines, array(&$this, '_encode'));
397 }
398
399 if ($this->_split_level == 'words')
400 {
401 return implode('', $lines);
402 }
403 else
404 {
405 return implode("\n", $lines) . "\n";
406 }
407 }
408
409 function _added($lines)
410 {
411 array_walk($lines, array(&$this, '_encode'));
412 $lines[0] = $this->_ins_prefix . $lines[0];
413 $lines[sizeof($lines) - 1] .= $this->_ins_suffix;
414 return $this->_lines($lines, ' ', false);
415 }
416
417 function _deleted($lines, $words = false)
418 {
419 array_walk($lines, array(&$this, '_encode'));
420 $lines[0] = $this->_del_prefix . $lines[0];
421 $lines[sizeof($lines) - 1] .= $this->_del_suffix;
422 return $this->_lines($lines, ' ', false);
423 }
424
425 function _changed($orig, $final)
426 {
427 // If we've already split on words, don't try to do so again - just display.
428 if ($this->_split_level == 'words')
429 {
430 $prefix = '';
431 while ($orig[0] !== false && $final[0] !== false && substr($orig[0], 0, 1) == ' ' && substr($final[0], 0, 1) == ' ')
432 {
433 $prefix .= substr($orig[0], 0, 1);
434 $orig[0] = substr($orig[0], 1);
435 $final[0] = substr($final[0], 1);
436 }
437
438 return $prefix . $this->_deleted($orig) . $this->_added($final);
439 }
440
441 $text1 = implode("\n", $orig);
442 $text2 = implode("\n", $final);
443
444 // Non-printing newline marker.
445 $nl = "\0";
446
447 // We want to split on word boundaries, but we need to preserve whitespace as well.
448 // Therefore we split on words, but include all blocks of whitespace in the wordlist.
449 $splitted_text_1 = $this->_split_on_words($text1, $nl);
450 $splitted_text_2 = $this->_split_on_words($text2, $nl);
451
452 $diff = &new diff($splitted_text_1, $splitted_text_2);
453 unset($splitted_text_1, $splitted_text_2);
454
455 // Get the diff in inline format.
456 $renderer = &new diff_renderer_inline(array_merge($this->get_params(), array('split_level' => 'words')));
457
458 // Run the diff and get the output.
459 return str_replace($nl, "\n", $renderer->render($diff)) . "\n";
460 }
461
462 function _split_on_words($string, $newline_escape = "\n")
463 {
464 // Ignore \0; otherwise the while loop will never finish.
465 $string = str_replace("\0", '', $string);
466
467 $words = array();
468 $length = strlen($string);
469 $pos = 0;
470
471 $tab_there = true;
472 while ($pos < $length)
473 {
474 // Check for tabs... do not include them
475 if ($tab_there && substr($string, $pos, 1) === "\t")
476 {
477 $words[] = "\t";
478 $pos++;
479
480 continue;
481 }
482 else
483 {
484 $tab_there = false;
485 }
486
487 // Eat a word with any preceding whitespace.
488 $spaces = strspn(substr($string, $pos), " \n");
489 $nextpos = strcspn(substr($string, $pos + $spaces), " \n");
490 $words[] = str_replace("\n", $newline_escape, substr($string, $pos, $spaces + $nextpos));
491 $pos += $spaces + $nextpos;
492 }
493
494 return $words;
495 }
496
497 function _encode(&$string)
498 {
499 $string = htmlspecialchars($string);
500 }
501 }
502
503 /**
504 * "raw" diff renderer.
505 * This class could be used to output a raw unified patch file
506 *
507 * @package diff
508 */
509 class diff_renderer_raw extends diff_renderer
510 {
511 var $_leading_context_lines = 4;
512 var $_trailing_context_lines = 4;
513
514 /**
515 * Our function to get the diff
516 */
517 function get_diff_content($diff)
518 {
519 return '<textarea style="height: 290px;" class="full">' . htmlspecialchars($this->render($diff)) . '</textarea>';
520 }
521
522 function _block_header($xbeg, $xlen, $ybeg, $ylen)
523 {
524 if ($xlen != 1)
525 {
526 $xbeg .= ',' . $xlen;
527 }
528
529 if ($ylen != 1)
530 {
531 $ybeg .= ',' . $ylen;
532 }
533 return '@@ -' . $xbeg . ' +' . $ybeg . ' @@';
534 }
535
536 function _context($lines)
537 {
538 return $this->_lines($lines, ' ');
539 }
540
541 function _added($lines)
542 {
543 return $this->_lines($lines, '+');
544 }
545
546 function _deleted($lines)
547 {
548 return $this->_lines($lines, '-');
549 }
550
551 function _changed($orig, $final)
552 {
553 return $this->_deleted($orig) . $this->_added($final);
554 }
555 }
556
557 /**
558 * "chora (Horde)" diff renderer - similar style.
559 * This renderer class is a modified human_readable function from the Horde Framework.
560 *
561 * @package diff
562 */
563 class diff_renderer_side_by_side extends diff_renderer
564 {
565 var $_leading_context_lines = 3;
566 var $_trailing_context_lines = 3;
567
568 var $lines = array();
569
570 // Hold the left and right columns of lines for change blocks.
571 var $cols;
572 var $state;
573
574 var $data = false;
575
576 /**
577 * Our function to get the diff
578 */
579 function get_diff_content($diff)
580 {
581 global $user;
582
583 $output = '';
584 $output .= '<table cellspacing="0" class="hrdiff">
585 <caption>
586 <span class="unmodified"> </span> ' . $user->lang['LINE_UNMODIFIED'] . '
587 <span class="added"> </span> ' . $user->lang['LINE_ADDED'] . '
588 <span class="modified"> </span> ' . $user->lang['LINE_MODIFIED'] . '
589 <span class="removed"> </span> ' . $user->lang['LINE_REMOVED'] . '
590 </caption>
591 <tbody>
592 ';
593
594 $this->render($diff);
595
596 // Is the diff empty?
597 if (!sizeof($this->lines))
598 {
599 $output .= '<tr><th colspan="2">' . $user->lang['NO_VISIBLE_CHANGES'] . '</th></tr>';
600 }
601 else
602 {
603 // Iterate through every header block of changes
604 foreach ($this->lines as $header)
605 {
606 $output .= '<tr><th>Line ' . $header['oldline'] . '</th><th>' . $user->lang['LINE'] . ' ' . $header['newline'] . '</th></tr>';
607
608 // Each header block consists of a number of changes (add, remove, change).
609 $current_context = '';
610
611 foreach ($header['contents'] as $change)
612 {
613 if (!empty($current_context) && $change['type'] != 'empty')
614 {
615 $line = $current_context;
616 $current_context = '';
617
618 $output .= '<tr class="unmodified"><td><pre>' . ((strlen($line)) ? $line : ' ') . '<br /></pre></td>
619 <td><pre>' . ((strlen($line)) ? $line : ' ') . '<br /></pre></td></tr>';
620 }
621
622 switch ($change['type'])
623 {
624 case 'add':
625 $line = '';
626
627 foreach ($change['lines'] as $_line)
628 {
629 $line .= htmlspecialchars($_line) . '<br />';
630 }
631
632 $output .= '<tr><td class="added_empty"> </td><td class="added"><pre>' . ((strlen($line)) ? $line : ' ') . '<br /></pre></td></tr>';
633 break;
634
635 case 'remove':
636 $line = '';
637
638 foreach ($change['lines'] as $_line)
639 {
640 $line .= htmlspecialchars($_line) . '<br />';
641 }
642
643 $output .= '<tr><td class="removed"><pre>' . ((strlen($line)) ? $line : ' ') . '<br /></pre></td><td class="removed_empty"> </td></tr>';
644 break;
645
646 case 'empty':
647 $current_context .= htmlspecialchars($change['line']) . '<br />';
648 break;
649
650 case 'change':
651 // Pop the old/new stacks one by one, until both are empty.
652 $oldsize = sizeof($change['old']);
653 $newsize = sizeof($change['new']);
654 $left = $right = '';
655
656 for ($row = 0, $row_max = max($oldsize, $newsize); $row < $row_max; ++$row)
657 {
658 $left .= isset($change['old'][$row]) ? htmlspecialchars($change['old'][$row]) : '';
659 $left .= '<br />';
660 $right .= isset($change['new'][$row]) ? htmlspecialchars($change['new'][$row]) : '';
661 $right .= '<br />';
662 }
663
664 $output .= '<tr>';
665
666 if (!empty($left))
667 {
668 $output .= '<td class="modified"><pre>' . $left . '<br /></pre></td>';
669 }
670 else if ($row < $oldsize)
671 {
672 $output .= '<td class="modified"> </td>';
673 }
674 else
675 {
676 $output .= '<td class="unmodified"> </td>';
677 }
678
679 if (!empty($right))
680 {
681 $output .= '<td class="modified"><pre>' . $right . '<br /></pre></td>';
682 }
683 else if ($row < $newsize)
684 {
685 $output .= '<td class="modified"> </td>';
686 }
687 else
688 {
689 $output .= '<td class="unmodified"> </td>';
690 }
691
692 $output .= '</tr>';
693 break;
694 }
695 }
696
697 if (!empty($current_context))
698 {
699 $line = $current_context;
700 $current_context = '';
701
702 $output .= '<tr class="unmodified"><td><pre>' . ((strlen($line)) ? $line : ' ') . '<br /></pre></td>';
703 $output .= '<td><pre>' . ((strlen($line)) ? $line : ' ') . '<br /></pre></td></tr>';
704 }
705 }
706 }
707
708 $output .= '</tbody></table>';
709
710 return $output;
711 }
712
713 function _start_diff()
714 {
715 $this->lines = array();
716
717 $this->data = false;
718 $this->cols = array(array(), array());
719 $this->state = 'empty';
720
721 return '';
722 }
723
724 function _end_diff()
725 {
726 // Just flush any remaining entries in the columns stack.
727 switch ($this->state)
728 {
729 case 'add':
730 $this->data['contents'][] = array('type' => 'add', 'lines' => $this->cols[0]);
731 break;
732
733 case 'remove':
734 // We have some removal lines pending in our stack, so flush them.
735 $this->data['contents'][] = array('type' => 'remove', 'lines' => $this->cols[0]);
736 break;
737
738 case 'change':
739 // We have both remove and addition lines, so this is a change block.
740 $this->data['contents'][] = array('type' => 'change', 'old' => $this->cols[0], 'new' => $this->cols[1]);
741 break;
742 }
743
744 if ($this->data !== false)
745 {
746 $this->lines[] = $this->data;
747 }
748
749 return '';
750 }
751
752 function _block_header($xbeg, $xlen, $ybeg, $ylen)
753 {
754 // Push any previous header information to the return stack.
755 if ($this->data !== false)
756 {
757 $this->lines[] = $this->data;
758 }
759
760 $this->data = array('type' => 'header', 'oldline' => $xbeg, 'newline' => $ybeg, 'contents' => array());
761 $this->state = 'dump';
762 }
763
764 function _added($lines)
765 {
766 array_walk($lines, array(&$this, '_perform_add'));
767 }
768
769 function _perform_add($line)
770 {
771 if ($this->state == 'empty')
772 {
773 return '';
774 }
775
776 // This is just an addition line.
777 if ($this->state == 'dump' || $this->state == 'add')
778 {
779 // Start adding to the addition stack.
780 $this->cols[0][] = $line;
781 $this->state = 'add';
782 }
783 else
784 {
785 // This is inside a change block, so start accumulating lines.
786 $this->state = 'change';
787 $this->cols[1][] = $line;
788 }
789 }
790
791 function _deleted($lines)
792 {
793 array_walk($lines, array(&$this, '_perform_delete'));
794 }
795
796 function _perform_delete($line)
797 {
798 // This is a removal line.
799 $this->state = 'remove';
800 $this->cols[0][] = $line;
801 }
802
803 function _context($lines)
804 {
805 array_walk($lines, array(&$this, '_perform_context'));
806 }
807
808 function _perform_context($line)
809 {
810 // An empty block with no action.
811 switch ($this->state)
812 {
813 case 'add':
814 $this->data['contents'][] = array('type' => 'add', 'lines' => $this->cols[0]);
815 break;
816
817 case 'remove':
818 // We have some removal lines pending in our stack, so flush them.
819 $this->data['contents'][] = array('type' => 'remove', 'lines' => $this->cols[0]);
820 break;
821
822 case 'change':
823 // We have both remove and addition lines, so this is a change block.
824 $this->data['contents'][] = array('type' => 'change', 'old' => $this->cols[0], 'new' => $this->cols[1]);
825 break;
826 }
827
828 $this->cols = array(array(), array());
829 $this->data['contents'][] = array('type' => 'empty', 'line' => $line);
830 $this->state = 'dump';
831 }
832
833 function _changed($orig, $final)
834 {
835 return $this->_deleted($orig) . $this->_added($final);
836 }
837
838 }
839
840 ?>