Files
roi-theme/wp-content/plugins/ajax-search-pro/includes/externals/class.rtf-html-php.php
root a22573bf0b Commit inicial - WordPress Análisis de Precios Unitarios
- WordPress core y plugins
- Tema Twenty Twenty-Four configurado
- Plugin allow-unfiltered-html.php simplificado
- .gitignore configurado para excluir wp-config.php y uploads

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-03 21:04:30 -06:00

481 lines
15 KiB
PHP
Executable File

<?php
defined( 'ABSPATH' ) or die( "You can't access this file directly." );
/**
* RTF parser/formatter
*
* This code reads RTF files and formats the RTF data to HTML.
* Original from: https://github.com/henck/rtf-html-php
*
* PHP version 5
*
* @author Alexander van Oostenrijk
* @copyright 2014 Alexander van Oostenrijk
* @license GNU
* @version 1
* @link http://www.independent-software.com
*
* Sample of use:
*
* $reader = new ASP_RtfReader();
* $rtf = file_get_contents("test.rtf"); // or use a string
* $reader->Parse($rtf);
* //$reader->root->dump(); // to see what the reader read
* $formatter = new ASP_RtfHtml();
* echo $formatter->Format($reader->root);
*
* -----------------------------------------------------------
* Notice: Class names have been prefixed with 'ASP_' to avoid compatibility issiues
* (namespaces cannot be used, as WordPress supports php5.2)
*/
class ASP_RtfElement {
protected function Indent($level) {
for ($i = 0; $i < $level * 2; $i++) echo "&nbsp;";
}
}
class ASP_RtfGroup extends ASP_RtfElement {
public $parent;
public $children;
public function __construct() {
$this->parent = null;
$this->children = array();
}
public function GetType() {
// No children?
if (sizeof($this->children) == 0) return null;
// First child not a control word?
$child = $this->children[0];
if (!$child instanceof ASP_RtfControlWord) return null;
return $child->word;
}
public function IsDestination() {
// No children?
if (sizeof($this->children) == 0) return null;
// First child not a control symbol?
$child = $this->children[0];
if (!$child instanceof ASP_RtfControlSymbol) return null;
return $child->symbol == '*';
}
public function dump($level = 0) {
echo "<div>";
$this->Indent($level);
echo "{";
echo "</div>";
foreach ($this->children as $child) {
if ($child instanceof ASP_RtfGroup) {
if ($child->GetType() == "fonttbl") continue;
if ($child->GetType() == "colortbl") continue;
if ($child->GetType() == "stylesheet") continue;
if ($child->GetType() == "info") continue;
// Skip any pictures:
if (substr($child->GetType(), 0, 4) == "pict") continue;
if ($child->IsDestination()) continue;
}
$child->dump($level + 2);
}
echo "<div>";
$this->Indent($level);
echo "}";
echo "</div>";
}
}
class ASP_RtfControlWord extends ASP_RtfElement {
public $word;
public $parameter;
public function dump($level) {
echo "<div style='color:green'>";
$this->Indent($level);
echo "WORD {$this->word} ({$this->parameter})";
echo "</div>";
}
}
class ASP_RtfControlSymbol extends ASP_RtfElement {
public $symbol;
public $parameter = 0;
public function dump($level) {
echo "<div style='color:blue'>";
$this->Indent($level);
echo "SYMBOL {$this->symbol} ({$this->parameter})";
echo "</div>";
}
}
class ASP_RtfText extends ASP_RtfElement {
public $text;
public function dump($level) {
echo "<div style='color:red'>";
$this->Indent($level);
echo "TEXT {$this->text}";
echo "</div>";
}
}
class ASP_RtfReader {
public $root = null;
protected function GetChar() {
$this->char = null;
if ($this->pos < strlen($this->rtf)) {
$this->char = $this->rtf[$this->pos++];
} else {
$this->err = "Tried to read past EOF, RTF is probably truncated";
}
}
protected function ParseStartGroup() {
// Store state of document on stack.
$group = new ASP_RtfGroup();
if ($this->group != null) $group->parent = $this->group;
if ($this->root == null) {
$this->group = $group;
$this->root = $group;
} else {
array_push($this->group->children, $group);
$this->group = $group;
}
}
protected function is_letter() {
if (ord($this->char) >= 65 && ord($this->char) <= 90) return TRUE;
if (ord($this->char) >= 97 && ord($this->char) <= 122) return TRUE;
return FALSE;
}
protected function is_digit() {
if (ord($this->char) >= 48 && ord($this->char) <= 57) return TRUE;
return FALSE;
}
protected function ParseEndGroup() {
// Retrieve state of document from stack.
$this->group = $this->group->parent;
}
protected function ParseControlWord() {
$this->GetChar();
$word = "";
while ($this->is_letter()) {
$word .= $this->char;
$this->GetChar();
}
// Read parameter (if any) consisting of digits.
// Paramater may be negative.
$parameter = null;
$negative = false;
if ($this->char == '-') {
$this->GetChar();
$negative = true;
}
while ($this->is_digit()) {
if ($parameter == null) $parameter = 0;
$parameter = $parameter * 10 + $this->char;
$this->GetChar();
}
if ($parameter === null) $parameter = 1;
if ($negative) $parameter = -$parameter;
// If this is \u, then the parameter will be followed by
// a character.
if ($word == "u") {
// Ignore space delimiter
if ($this->char == ' ') $this->GetChar();
// if the replacement character is encoded as
// hexadecimal value \'hh then jump over it
if ($this->char == '\\' && $this->rtf[$this->pos] == '\'')
$this->pos = $this->pos + 3;
// Convert to UTF unsigned decimal code
if ($negative) $parameter = 65536 + $parameter;
}
// If the current character is a space, then
// it is a delimiter. It is consumed.
// If it's not a space, then it's part of the next
// item in the text, so put the character back.
else {
if ($this->char != ' ') $this->pos--;
}
$rtfword = new ASP_RtfControlWord();
$rtfword->word = $word;
$rtfword->parameter = $parameter;
array_push($this->group->children, $rtfword);
}
protected function ParseControlSymbol() {
// Read symbol (one character only).
$this->GetChar();
$symbol = $this->char;
// Symbols ordinarily have no parameter. However,
// if this is \', then it is followed by a 2-digit hex-code:
$parameter = 0;
if ($symbol == '\'') {
$this->GetChar();
$parameter = $this->char;
$this->GetChar();
$parameter = hexdec($parameter . $this->char);
}
$rtfsymbol = new ASP_RtfControlSymbol();
$rtfsymbol->symbol = $symbol;
$rtfsymbol->parameter = $parameter;
array_push($this->group->children, $rtfsymbol);
}
protected function ParseControl() {
// Beginning of an RTF control word or control symbol.
// Look ahead by one character to see if it starts with
// a letter (control world) or another symbol (control symbol):
$this->GetChar();
$this->pos--;
if ($this->is_letter())
$this->ParseControlWord();
else
$this->ParseControlSymbol();
}
protected function ParseText() {
// Parse plain text up to backslash or brace,
// unless escaped.
$text = "";
do {
$terminate = false;
$escape = false;
// Is this an escape?
if ($this->char == '\\') {
// Perform lookahead to see if this
// is really an escape sequence.
$this->GetChar();
switch ($this->char) {
case '\\':
$text .= '\\';
break;
case '{':
$text .= '{';
break;
case '}':
$text .= '}';
break;
default:
// Not an escape. Roll back.
$this->pos = $this->pos - 2;
$terminate = true;
break;
}
} else if ($this->char == '{' || $this->char == '}') {
$this->pos--;
$terminate = true;
}
if (!$terminate && !$escape) {
$text .= $this->char;
$this->GetChar();
}
} while (!$terminate && $this->pos < $this->len);
$rtftext = new ASP_RtfText();
$rtftext->text = $text;
// If group does not exist, then this is not a valid RTF file. Throw an exception.
if ($this->group == NULL) {
throw new Exception();
}
array_push($this->group->children, $rtftext);
}
/*
* Attempt to parse an RTF string. Parsing returns TRUE on success or FALSE on failure
*/
public function Parse($rtf) {
if ( function_exists( 'mb_internal_encoding' ) ) {
mb_internal_encoding( "UTF-8" );
}
try {
$this->rtf = utf8_encode( $rtf );
$this->pos = 0;
$this->len = strlen($this->rtf);
$this->group = null;
$this->root = null;
while ($this->pos < $this->len) {
// Read next character:
$this->GetChar();
// Ignore \r and \n
if ($this->char == "\n" || $this->char == "\r") continue;
// What type of character is this?
switch ($this->char) {
case '{':
$this->ParseStartGroup();
break;
case '}':
$this->ParseEndGroup();
break;
case '\\':
$this->ParseControl();
break;
default:
$this->ParseText();
break;
}
}
return TRUE;
} catch (Exception $ex) {
return FALSE;
}
}
}
class ASP_RtfState {
public function __construct() {
$this->Reset();
}
public function Reset() {
$this->bold = false;
$this->italic = false;
$this->underline = false;
$this->end_underline = false;
$this->strike = false;
$this->hidden = false;
$this->fontsize = 0;
}
}
class ASP_RtfHtml {
public function Format($root) {
$this->output = "";
// Keeping track of style modifications
$this->previousState = null;
$this->openedTags = array('span' => False, 'p' => False);
// Create a stack of states:
$this->states = array();
// Put an initial standard state onto the stack:
$this->state = new ASP_RtfState();
array_push($this->states, $this->state);
$this->FormatGroup($root);
return $this->output;
}
protected function FormatGroup($group) {
// Can we ignore this group?
if ($group->GetType() == "fonttbl") return;
elseif ($group->GetType() == "colortbl") return;
elseif ($group->GetType() == "stylesheet") return;
elseif ($group->GetType() == "info") return;
// Skip any pictures:
if (substr($group->GetType(), 0, 4) == "pict") return;
if ($group->IsDestination()) return;
// Push a new state onto the stack:
$this->state = clone $this->state;
array_push($this->states, $this->state);
foreach ($group->children as $child) {
if ($child instanceof ASP_RtfGroup) $this->FormatGroup($child);
elseif ($child instanceof ASP_RtfControlWord) $this->FormatControlWord($child);
elseif ($child instanceof ASP_RtfControlSymbol) $this->FormatControlSymbol($child);
elseif ($child instanceof ASP_RtfText) $this->FormatText($child);
}
// Pop state from stack.
array_pop($this->states);
$this->state = $this->states[sizeof($this->states) - 1];
}
protected function FormatControlWord($word) {
if ($word->word == "plain") $this->state->Reset();
elseif ($word->word == "b") $this->state->bold = $word->parameter;
elseif ($word->word == "i") $this->state->italic = $word->parameter;
elseif ($word->word == "ul") $this->state->underline = $word->parameter;
elseif ($word->word == "ulnone") $this->state->end_underline = $word->parameter;
elseif ($word->word == "strike") $this->state->strike = $word->parameter;
elseif ($word->word == "v") $this->state->hidden = $word->parameter;
elseif ($word->word == "fs") $this->state->fontsize = ceil(($word->parameter / 24) * 16);
elseif ($word->word == "par") {
// close previously opened 'span' tag
$this->CloseTag();
// decide whether to open or to close a 'p' tag
if ($this->openedTags["p"]) $this->CloseTag("p");
else {
$this->output .= "<p>";
$this->openedTags['p'] = True;
}
} // Characters:
elseif ($word->word == "lquote") $this->output .= "&lsquo;";
elseif ($word->word == "rquote") $this->output .= "&rsquo;";
elseif ($word->word == "ldblquote") $this->output .= "&ldquo;";
elseif ($word->word == "rdblquote") $this->output .= "&rdquo;";
elseif ($word->word == "emdash") $this->output .= "&mdash;";
elseif ($word->word == "endash") $this->output .= "&ndash;";
elseif ($word->word == "bullet") $this->output .= "&bull;";
// Print Unicode character
elseif ($word->word == "u")
$this->ApplyStyle("&#" . $word->parameter . ";");
}
protected function ApplyStyle($txt) {
// create span only when a style change occur
if ($this->previousState != $this->state) {
$span = "";
if ($this->state->bold) $span .= "font-weight:bold;";
if ($this->state->italic) $span .= "font-style:italic;";
if ($this->state->underline) $span .= "text-decoration:underline;";
if ($this->state->end_underline) $span .= "text-decoration:none;";
if ($this->state->strike) $span .= "text-decoration:strikethrough;";
if ($this->state->hidden) $span .= "display:none;";
if ($this->state->fontsize != 0) $span .= "font-size: {$this->state->fontsize}px;";
// Keep track of preceding style
$this->previousState = clone $this->state;
// close previously opened 'span' tag
$this->CloseTag();
$this->output .= "<span style=\"{$span}\">" . $txt;
$this->openedTags["span"] = True;
} else $this->output .= $txt;
}
protected function CloseTag($tag = "span") {
if ($this->openedTags[$tag]) {
$this->output .= "</{$tag}>";
$this->openedTags[$tag] = False;
}
}
protected function FormatControlSymbol($symbol) {
if ($symbol->symbol == '\'')
$this->ApplyStyle(htmlentities(chr($symbol->parameter), ENT_QUOTES, 'UTF-8'));
}
protected function FormatText($text) {
$this->ApplyStyle($text->text);
}
}