Вход Регистрация
Файл: library/XenForo/Diff3.php
Строк: 319
<?php

class XenForo_Diff3
{
    const 
UPDATE 'u';
    const 
CONFLICT 'c';
    const 
EQUAL  'e';

    const 
MINE 'm';
    const 
YOURS 'y';
    const 
BOTH 'b';

    
/**
     * @var XenForo_Diff
     */
    
protected $_comparer;

    protected 
$_currentOrig;
    protected 
$_currentMine;
    protected 
$_currentYours;

    protected 
$_bigConflicts true;

    public function 
__construct(XenForo_Diff $comparer null)
    {
        if (!
$comparer)
        {
            
$comparer = new XenForo_Diff();
        }

        
$this->_comparer $comparer;
    }

    protected function 
_initBlock()
    {
        
$this->_currentOrig $this->_currentMine $this->_currentYours = array();
    }

    protected function 
_appendOrig(array $blocks)
    {
        
array_splice($this->_currentOrigcount($this->_currentOrig), 0$blocks);
    }

    protected function 
_appendMine(array $blocks)
    {
        
array_splice($this->_currentMinecount($this->_currentMine), 0$blocks);
    }

    protected function 
_appendYours(array $blocks)
    {
        
array_splice($this->_currentYourscount($this->_currentYours), 0$blocks);
    }

    protected function 
_finishBlock(array &$output$init true)
    {
        if (
$this->_currentMine || $this->_currentYours || $this->_currentOrig)
        {
            if (
$this->_currentMine == $this->_currentYours)
            {
                if (
$this->_currentMine == $this->_currentOrig)
                {
                    
$output[] = array(self::EQUAL$this->_currentMine);
                }
                else
                {
                    
$output[] = array(self::UPDATE$this->_currentMine$this->_currentOrigself::BOTH);
                }
            }
            else if (
$this->_currentMine == $this->_currentOrig)
            {
                
$output[] = array(self::UPDATE$this->_currentYours$this->_currentOrigself::YOURS);
            }
            else if (
$this->_currentYours == $this->_currentOrig)
            {
                
$output[] = array(self::UPDATE$this->_currentMine$this->_currentOrigself::MINE);
            }
            else
            {
                
// potential conflict - try to resolve prefixes
                
$cM $this->_currentMine;
                
$cY $this->_currentYours;
                
$cO $this->_currentOrig;

                if (
$init)
                {
                    
$childOutput = array();
                }
                else
                {
                    
$childOutput =& $output;
                }

                if (
$i $this->_getMatchLength($this->_currentMine$this->_currentYours))
                {
                    
$update array_splice($this->_currentMine0$i);
                    
array_splice($this->_currentYours0$i);
                    
$childOutput[] = array(self::UPDATE$update, array(), self::BOTH);
                    
$this->_finishBlock($childOutputfalse);
                }
                else if (
$i $this->_getMatchLength($this->_currentMine$this->_currentOrig))
                {
                    
$update array_splice($this->_currentMine0$i);
                    
array_splice($this->_currentOrig0$i);
                    
$childOutput[] = array(self::UPDATE, array(), $updateself::YOURS);
                    
$this->_finishBlock($childOutputfalse);
                }
                else if (
$i $this->_getMatchLength($this->_currentYours$this->_currentOrig))
                {
                    
$update array_splice($this->_currentYours0$i);
                    
array_splice($this->_currentOrig0$i);
                    
$childOutput[] = array(self::UPDATE, array(), $updateself::MINE);
                    
$this->_finishBlock($childOutputfalse);
                }
                else if (
$i $this->_getEndMatchLength($this->_currentMine$this->_currentYours))
                {
                    
$update array_splice($this->_currentMine, -$i);
                    
array_splice($this->_currentYours, -$i);
                    
$this->_finishBlock($childOutputfalse);
                    
$childOutput[] = array(self::UPDATE$update, array(), self::BOTH);
                }
                else if (
$i $this->_getEndMatchLength($this->_currentMine$this->_currentOrig))
                {
                    
$update array_splice($this->_currentMine, -$i);
                    
array_splice($this->_currentOrig, -$i);
                    
$this->_finishBlock($childOutputfalse);
                    
$childOutput[] = array(self::UPDATE, array(), $updateself::YOURS);
                }
                else if (
$i $this->_getEndMatchLength($this->_currentYours$this->_currentOrig))
                {
                    
$update array_splice($this->_currentYours, -$i);
                    
array_splice($this->_currentOrig, -$i);
                    
$this->_finishBlock($childOutputfalse);
                    
$childOutput[] = array(self::UPDATE, array(), $updateself::MINE);
                }
                else if (!
$init)
                {
                    
$childOutput[] = array(self::CONFLICT$this->_currentMine$this->_currentOrig$this->_currentYours);
                }

                if (
$init)
                {
                    if (
$childOutput)
                    {
                        
$hasConflict false;
                        foreach (
$childOutput AS $child)
                        {
                            if (
$child[0] == self::CONFLICT)
                            {
                                
$hasConflict true;
                                break;
                            }
                        }
                        if (
$hasConflict && $this->_bigConflicts)
                        {
                            
// still have a conflict, just mark the whole thing as it originally was
                            
$output[] = array(self::CONFLICT$cM$cO$cY);
                        }
                        else
                        {
                            
// no longer have a conflict or we want the small conflicts
                            
array_splice($outputcount($output), 0$childOutput);
                        }
                    }
                    else
                    {
                        
// couldn't find any matching bits
                        
$output[] = array(self::CONFLICT$this->_currentMine$this->_currentOrig$this->_currentYours);
                    }
                }
            }
        }

        if (
$init)
        {
            
$this->_initBlock();
        }
    }

    protected function 
_getMatchLength(array $blocks1, array $blocks2)
    {
        
$i 0;
        while (isset(
$blocks1[$i]) && isset($blocks2[$i]) && $blocks1[$i] === $blocks2[$i])
        {
            
$i++;
        }

        return 
$i;
    }

    protected function 
_getEndMatchLength(array $blocks1, array $blocks2)
    {
        
$match 0;
        
$end1 count($blocks1) - 1;
        
$end2 count($blocks2) - 1;
        while (isset(
$blocks1[$end1]) && isset($blocks2[$end2]) && $blocks1[$end1] === $blocks2[$end2])
        {
            
$match++;
            
$end1--;
            
$end2--;
        }

        return 
$match;
    }

    public function 
findDifferences($mine$original$yours$type XenForo_Diff::DIFF_TYPE_LINE)
    {
        
$mineDiff $this->_comparer->findDifferences($original$mine$type);
        
$yourDiff $this->_comparer->findDifferences($original$yours$type);

        
$output = array();
        
$this->_initBlock();

        
$m reset($mineDiff);
        
$y reset($yourDiff);
        while (
$m || $y)
        {
            if (
$m && $y)
            {
                
$mType $m[0];
                
$mBlocks =& $m[1];

                
$yType $y[0];
                
$yBlocks =& $y[1];

                if (
$mType == XenForo_Diff::EQUAL && $yType == XenForo_Diff::EQUAL)
                {
                    
$this->_finishBlock($output);

                    
$i $this->_getMatchLength($mBlocks$yBlocks);
                    if (!
$i)
                    {
                        throw new 
Exception("Both equal but no leading match?");
                    }

                    
$matches array_splice($mBlocks0$i);
                    
$output[] = array(self::EQUAL$matches);
                    
array_splice($yBlocks0$i);

                    if (!
$mBlocks)
                    {
                        
$m next($mineDiff);
                    }
                    if (!
$yBlocks)
                    {
                        
$y next($yourDiff);
                    }
                }
                else if (
$mType == XenForo_Diff::INSERT)
                {
                    
$this->_appendMine($mBlocks);
                    
$m next($mineDiff);
                }
                else if (
$yType == XenForo_Diff::INSERT)
                {
                    
$this->_appendYours($yBlocks);
                    
$y next($yourDiff);
                }
                else if (
$mType == XenForo_Diff::DELETE && $yType == XenForo_Diff::DELETE)
                {
                    
$this->_finishBlock($output);

                    
$i $this->_getMatchLength($mBlocks$yBlocks);
                    if (!
$i)
                    {
                        throw new 
Exception("Both deletes but no leading match?");
                    }

                    
$this->_appendOrig(array_splice($mBlocks0$i));
                    
array_splice($yBlocks0$i);

                    if (!
$mBlocks)
                    {
                        
$m next($mineDiff);
                    }
                    if (!
$yBlocks)
                    {
                        
$y next($yourDiff);
                    }
                }
                else if (
$mType == XenForo_Diff::DELETE && $yType == XenForo_Diff::EQUAL)
                {
                    
$min min(count($mBlocks), count($yBlocks));

                    
array_splice($mBlocks0$min); // removed
                    
$block array_splice($yBlocks0$min);
                    
$this->_appendOrig($block);
                    
$this->_appendYours($block);

                    if (!
$mBlocks)
                    {
                        
$m next($mineDiff);
                    }
                    if (!
$yBlocks)
                    {
                        
$y next($yourDiff);
                    }
                }
                else if (
$yType == XenForo_Diff::DELETE && $mType == XenForo_Diff::EQUAL)
                {
                    
$min min(count($mBlocks), count($yBlocks));

                    
array_splice($yBlocks0$min); // removed
                    
$block array_splice($mBlocks0$min);
                    
$this->_appendOrig($block);
                    
$this->_appendMine($block);

                    if (!
$mBlocks)
                    {
                        
$m next($mineDiff);
                    }
                    if (!
$yBlocks)
                    {
                        
$y next($yourDiff);
                    }
                }
            }
            else if (
$m)
            {
                if (
$m[0] != XenForo_Diff::INSERT)
                {
                    throw new 
Exception("Had m only but wasn't insert");
                }

                
$this->_appendMine($m[1]);
                
$m next($mineDiff);
            }
            else if (
$y)
            {
                if (
$y[0] != XenForo_Diff::INSERT)
                {
                    throw new 
Exception("Had y only but wasn't insert");
                }

                
$this->_appendYours($y[1]);
                
$y next($yourDiff);
            }
        }

        
$this->_finishBlock($output);

        return 
$this->_finalize($output);
    }

    protected function 
_finalize(array $output)
    {
        
$newOutput = array();
        
$i = -1;
        
$lastType null;
        foreach (
$output AS $hunk)
        {
            if (
$hunk[0] == self::CONFLICT && $lastType === self::CONFLICT)
            {
                
// back to back conflicts: merge
                
$newOutput[$i][1] = array_merge($newOutput[$i][1], $hunk[1]);
                
$newOutput[$i][2] = array_merge($newOutput[$i][2], $hunk[2]);
                
$newOutput[$i][3] = array_merge($newOutput[$i][3], $hunk[3]);
            }
            else
            {
                
$i++;
                
$newOutput[$i] = $hunk;
                
$lastType $hunk[0];
            }
        }

        return 
$newOutput;
    }

    public function 
mergeToFinal($mine$original$yours$type XenForo_Diff::DIFF_TYPE_LINE)
    {
        
$diffs $this->findDifferences($mine$original$yours$type);
        
$output = array();

        foreach (
$diffs AS $diff)
        {
            if (
$diff[0] == self::CONFLICT)
            {
                return 
false;
            }

            
array_splice($outputcount($output), 0$diff[1]);
        }

        switch (
$type)
        {
            case 
XenForo_Diff::DIFF_TYPE_CHAR:
                
$joiner '';
                break;

            case 
XenForo_Diff::DIFF_TYPE_WORD:
                
$joiner ' ';
                break;

            case 
XenForo_Diff::DIFF_TYPE_LINE:
            default:
                
$joiner "n";
        }

        return 
implode($joiner$output);
    }
}
Онлайн: 0
Реклама