📄 rtfclass.php
字号:
if( ereg( "^([A-Za-z]+)(-?[0-9]*) ?$", $this->cword, $match)) {
$this->parseControl( $match[1], $match[2]);
if( $this->wantXML) {
$this->out.="<control word=\"".$match[1]."\"";
if( strlen( $match[2]) > 0)
$this->out.=" param=\"".$match[2]."\"";
$this->out.="/>";
}
}
}
/*
If output stream supports comments, dispatch it
*/
function flushComment( $comment) {
if( $this->wantXML || $this->wantHTML) {
$this->out.="<!-- ".$comment." -->";
}
}
/*
Dispatch start/end of logical rtf groups
(not every output type needs it; merely debugging purpose)
*/
function flushGroup( $state) {
if( $state == "open") {
/* push onto the stack */
array_push( $this->stack, $this->flags);
if( $this->wantXML)
$this->out.="<group>";
}
if( $state == "close") {
/* pop from the stack */
$this->last_flags = $this->flags;
$this->flags = array_pop( $this->stack);
$this->flags["fonttbl_current_write"] = ""; // on group close, no more fontdefinition will be written to this id
// this is not really the right way to do it !
// of course a '}' not necessarily donates a fonttable end; a fonttable
// group at least *can* contain sub-groups
// therefore an stacked approach is heavily needed
$this->flags["fonttbl"] = false; // no matter what you do, if a group closes, its fonttbl definition is closed too
if( $this->wantXML)
$this->out.="</group>";
}
}
function flushHead() {
if( $this->wantXML)
$this->out.="<rtf>";
}
function flushBottom() {
if( $this->wantXML)
$this->out.="</rtf>";
}
function checkHtmlSpanContent( $command) {
reset( $this->fontmodifier_table);
while( list( $rtf, $html) = each( $this->fontmodifier_table)) {
if( $this->flags[$rtf] == true) {
if( $command == "start")
$this->out .= "<".$html.">";
else
$this->out .= "</".$html.">";
}
}
}
/*
flush text in queue
*/
function flushQueue() {
if( strlen( $this->queue)) {
// processing logic
if( ereg( "^[0-9]+$", $this->flags["fonttbl_want_fcharset"])) {
$this->fonttable[$this->flags["fonttbl_want_fcharset"]]["charset"] = $this->queue;
$this->flags["fonttbl_want_fcharset"] = "";
$this->queue = "";
}
// output logic
if( strlen( $this->queue)) {
/*
Everything which passes this is (or, at leat, *should*) be only outputted plaintext
Thats why we can safely add the css-stylesheet when using wantHTML
*/
if( $this->wantXML)
$this->out.= "<plain>".$this->queue."</plain>";
if( $this->wantHTML) {
// only output html if a valid (for now, just numeric;) fonttable is given
if( ereg( "^[0-9]+$", $this->flags["fonttbl_current_read"])) {
if( $this->flags["beginparagraph"] == true) {
$this->flags["beginparagraph"] = false;
$this->out .= "<div align=\"";
switch( $this->flags["alignment"]) {
case "right":
$this->out .= "right";
break;
case "center":
$this->out .= "center";
break;
case "left":
default:
$this->out .= "left";
}
$this->out .= "\">";
}
/* define new style for that span */
$this->styles["f".$this->flags["fonttbl_current_read"]."s".$this->flags["fontsize"]] = "font-family:".$this->fonttable[$this->flags["fonttbl_current_read"]]["charset"]." font-size:".$this->flags["fontsize"].";";
/* write span start */
$this->out .= "<span class=\"f".$this->flags["fonttbl_current_read"]."s".$this->flags["fontsize"]."\">";
/* check if the span content has a modifier */
$this->checkHtmlSpanContent( "start");
/* write span content */
$this->out .= $this->queue;
/* close modifiers */
$this->checkHtmlSpanContent( "stop");
/* close span */
"</span>";
}
}
$this->queue = "";
}
}
}
/*
handle special charactes like \'ef
*/
function flushSpecial( $special) {
if( strlen( $special) == 2) {
if( $this->wantXML)
$this->out .= "<special value=\"".$special."\"/>";
}
}
/*
Output errors at end
*/
function flushErrors() {
if( count( $this->err) > 0) {
if( $this->wantXML) {
$this->out .= "<errors>";
while( list($num,$value) = each( $this->err)) {
$this->out .= "<message>".$value."</message>";
}
$this->out .= "</errors>";
}
}
}
function makeStyles() {
$this->outstyles = "<style type=\"text/css\"><!--\n";
reset( $this->styles);
while( list( $stylename, $styleattrib) = each( $this->styles)) {
$this->outstyles .= ".".$stylename." { ".$styleattrib." }\n";
}
$this->outstyles .= "--></style>\n";
}
/*
finally ..
How this parser (is supposed) to work:
======================================
This parse simple starts at the beginning of the rtf core stream, catches every
controlling character {,} and \, automatically builds control words and control
symbols during his livetime, trashes every other character into the plain text
queue
*/
function parse() {
$this->parserInit();
$i = 0;
$this->cw= false; // flag if control word is currently parsed
$this->cfirst = false;// first control character ?
$this->cword = ""; // last or current control word ( depends on $this->cw
$this->queue = ""; // plain text data found during parsing
$this->flushHead();
while( $i < $this->len) {
switch( $this->rtf[$i]) {
case "{": if( $this->cw) {
$this->flushControl();
$this->cw= false; $this->cfirst = false;
} else
$this->flushQueue();
$this->flushGroup( "open");
break;
case "}": if( $this->cw) {
$this->flushControl();
$this->cw= false; $this->cfirst = false;
} else
$this->flushQueue();
$this->flushGroup( "close");
break;
case "\\": if( $this->cfirst) { // catches '\\'
$this->queue .= '\\';
$this->cfirst = false;
$this->cw= false;
break;
}
if( $this->cw) {
$this->flushControl();
} else
$this->flushQueue();
$this->cw = true;
$this->cfirst = true;
$this->cword = "";
break;
default:
if( (ord( $this->rtf[$i]) == 10) || (ord($this->rtf[$i]) == 13)) break; // eat line breaks
if( $this->cw) { // active control word ?
/*
Watch the RE: there's an optional space at the end which IS part of
the control word (but actually its ignored by flushControl)
*/
if( ereg( "^[a-zA-Z0-9-]?$", $this->rtf[$i])) { // continue parsing
$this->cword .= $this->rtf[$i];
$this->cfirst = false;
} else {
/*
Control word could be a 'control symbol', like \~ or \* etc.
*/
$specialmatch = false;
if( $this->cfirst) {
if( $this->rtf[$i] == '\'') { // expect to get some special chars
$this->flushQueue();
$this->flushSpecial( $this->rtf[$i+1].$this->rtf[$i+2]);
$i+=2;
$specialmatch = true;
$this->cw = false; $this->cfirst = false; $this->cword = "";
} else
if( ereg( "^[{}\*]$", $this->rtf[$i])) {
$this->flushComment( "control symbols not yet handled");
$specialmatch = true;
}
$this->cfirst = false;
} else {
if( $this->rtf[$i] == ' ') { // space delimtes control words, so just discard it and flush the controlword
$this->cw = false;
$this->flushControl();
break;
}
}
if( ! $specialmatch) {
$this->flushControl();
$this->cw = false; $this->cfirst = false;
/*
The current character is a delimeter, but is NOT
part of the control word so we hop one step back
in the stream and process it again
*/
$i--;
}
}
} else {
// < and > need translation before putting into queue when XML or HTML is wanted
if( ($this->wantHTML) || ($this->wantXML)) {
switch( $this->rtf[$i]) {
case "<":
$this->queue .= "<";
break;
case ">":
$this->queue .= ">";
break;
default:
$this->queue .= $this->rtf[$i];
break;
}
} else
$this->queue .= $this->rtf[$i];
}
}
$i++;
}
$this->flushQueue();
$this->flushErrors();
$this->flushBottom();
if( $this->wantHTML) {
$this->makeStyles();
}
}
}
?>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -