<?php
/**
 * RTF Parser
 *
 * @author        HSDN Team
 * @copyright    Copyright (c) 2011, Information Networks Ltd.
 * @link        http://www.hsdn.org
 * @version        1.0
 */

/**
 * Класс RTF
 *
 * @category    Libraries
 * @author        HSDN Team
 */
class RTF
{
    
/**
     * Разбор RTF и преобразование его в простой текст
     *
     * @access    public
     * @param    string
     * @return    string
     */
    
public static function parse($string)
    {
        
$structure self::parse_structure($string);

        
$return '';

        foreach (
$structure as $child)
        {
            
$return .= self::parse_child($child);
        }

        return 
$return;
    }

    
/**
     * Разбор подструктур и преобразование в строку
     *
     * @access    private
     * @param    array
     * @return    string
     */
    
private static function parse_child($childs)
    {
        
$return '';

        if (!
is_array($childs))
        {
            return 
$childs;
        }

        foreach (
$childs as $child)
        {
            if (
is_array($child))
            {
                
$return .= self::parse_child($child);
            }
            else
            {
                
$return .= $child;
            }
        }

        return 
$return;
    }

    
/**
     * Разбор структур документа
     *
     * @access    private
     * @param    string
     * @return    array
     */
    
private static function parse_structure($string)
    {
        
$j 0;
        
$k 0;
        
$token_open 0;
        
$token_close 0;

        
$token '';
        
$word[$k] = '';
        
$group[$j] = '';

        
$skip_group FALSE;

        
$return = array();

        for (
$i 0$i strlen($string); $i++)
        {
            
$char $string{$i};
            
$before_char = isset($string{$i 1}) ? $string{$i 1} : '';

            if (
$char == '{' AND $before_char != "\\")
            {
                
$skip_group FALSE;

                if (isset(
$word[$k]) AND $word[$k] != '')
                {
                    if ((
$parsed_string self::parse_string($word[$k])) === FALSE)
                    {
                        
$skip_group TRUE;
                    }
                    else
                    {
                        
array_push($return$parsed_string);
                        
$word[++$k] = '';
                    }
                }

                
$token_open++;
            }

            if (
$char == '}' AND $before_char != "\\")
            {
                
$token_close++;
            }

            if (isset(
$word[$k]) AND $token_open == AND $token_close == 0)
            {
                
$word[$k] .= $char;
            }

            if (isset(
$group[$j]) AND ($token_open != OR $token_close != 0))
            {
                if ((
$token_open != AND $token_open != $token_close) OR ($char != '{' AND $char != '}'))
                {
                    
$group[$j] .= $char;
                }
            }

            if (
$token_open == $token_close)
            {
                if (
$group[$j] != '' AND $skip_group == FALSE)
                {
                    
array_push($returnself::parse_structure($group[$j]));
                    
$group[++$j] = '';
                }
    
                
$token_open 0;
                
$token_close 0;
            }
        }

        if (isset(
$word[$k]) AND $word[$k] != '')
        {
            
array_push($returnself::parse_string($word[$k]));
        }

        return 
$return;
    }

    
/**
     * Разбор управляющих последовательностей
     *
     * @access    private
     * @param    string
     * @return    array
     */
    
private static function parse_control($string)
    {
        
$j 0;
        
$word '';
        
$return = array();

        for (
$i 0$i strlen($string); $i++)
        {
            
$char $string{$i};
            
$next_char = isset($string{$i 1}) ? $string{$i 1} : '';

            if (
$char == "\\" AND $next_char != "\\")
            {
                if (
$word != '')
                {
                    
$return[++$j] = $word;
                }
                
                
$word '';
            }
            
            if ((isset(
$return[$j]) OR $return == array()))
            {
                
$word .= $char;
            }
        }

        if (
$word != '')
        {
            
$return[++$j] = $word;
        }

        return 
$return;
    }

    
/**
     * Разбор строк
     *
     * @access    private
     * @param    string
     * @return    string
     */
    
private static function parse_string($string)
    {
        
$string str_replace(array("\r\n""\n""\t"), ''$string);

        
$elements self::parse_control($string);

        
$word '';
        
$return '';

        foreach (
$elements as $element)
        {
            if (!isset(
$element{1}))
            {
                
$return .= $element;

                continue;
            }

            switch (
$element{1})
            {
                
// Контрольный символ
                
case "\\":
                    
$word "\\";
                    break;

                
// Перенос слова
                
case '_':
                case 
'-':
                    
$word '';
                    break;

                
// Подпункт индекса
                
case ':':
                    
$word "\t";
                    break;

                
// Жесткий пробел
                
case '~':
                    
$word ' ';
                    break;

                
// Пропустить строку
                
case '*':
                case 
'|':
                    return 
FALSE;

                
// Код символа
                
case "'":
                    if (
preg_match('#^[0-9a-f]{2}$#i', ($hex substr($element22))))
                    {
                        
$word self::decode_hex($hex).substr($element4);
                    }
                    break;

                default:
                    
// Контрольные слова
                    
if (preg_match('#^\\\([0-9a-z]+)(.*)?#i'$element$match))
                    {
                        if ((
$word self::parse_control_words($match[1])) === FALSE)
                        {
                            return 
FALSE;
                        }

                        
$word .= isset($match[2]) ? ltrim($match[2]) : '';
                    }
                    else
                    {
                        
$word $element;
                    }
            }

            
$return .= $word;
        }

        return 
$return;
    }

    
/**
     * Разбор управляющих слов
     *
     * @access    private
     * @param    string
     * @return    string
     */
    
private static function parse_control_words($word)
    {
        
$return '';

        switch (
$word)
        {
            
// Переход на новую строку
            
case 'par'
            case 
'page'
            case 
'column'
            case 
'line'
            case 
'lbr':
                
$return "\n";
                break;

            
// Пробелы
            
case 'emspace':
            case 
'enspace':
            case 
'qmspace':
                
$return ' ';
                break;

            
// Табуляция
            
case 'tab'
                
$return "\t"
                break;

            
// Тире
            
case 'emdash':
            case 
'endash':
                
$return "-";
                break;

            
// Кавычки
            
case 'lquote':
            case 
'rquote':
            case 
'ldblquote':
            case 
'rdblquote':
                
$return '"';
                break;

            
// Убрать невходящие группы
            
case 'author':
            case 
'operator':
            case 
'fonttbl':
            case 
'colortbl':
            case 
'datastore':
            case 
'themedata':
            case 
'info':
                return 
FALSE;
        }

        
// Пропустить описания стилей
        
$excludes = array
        (
            
'sbasedon''snext''keycode'
        
);

        foreach (
$excludes as $exclude)
        {
            if (
strpos($word$exclude) === 0)
            {
                return 
FALSE;
            }
        }

        return 
$return;
    }

    
/**
     * Преобразование кода символа в строку
     *
     * @access    private
     * @param    int
     * @return    string
     */
    
private static function decode_hex($hex)
    {
        return 
chr(hexdec($hex));
    }
}

/* EOF RTF.class.php */