?
Path : /home/admin/public_html/old/board/components/com_kunena/lib/ |
Current File : /home/admin/public_html/old/board/components/com_kunena/lib/kunena.parser.bbcode.php |
<?PHP /** * @version $Id: kunena.parser.bbcode.php 4336 2011-01-31 06:05:12Z severdia $ * Kunena Component * @package Kunena * * @Copyright (C) 2008 - 2011 Kunena Team. All rights reserved. * @license http://www.gnu.org/copyleft/gpl.html GNU/GPL * @link http://www.kunena.org * * Based on FireBoard Component * @Copyright (C) 2006 - 2007 Best Of Joomla All rights reserved. * @license http://www.gnu.org/copyleft/gpl.html GNU/GPL * @link http://www.bestofjoomla.com **/ /* ############################################################################ # CATEGORY: Parser.TagParser DEVELOPMENT DATUM: 13.11.2007 # # VERSION: 00.08.00 LAST EDIT DATUM: 12.12.2007 # # FILENAME: kunena.parser.bbcode.php # # AUTOR: Miro Dietiker, MD Systems, All rights reserved. # # LICENSE: http://www.gnu.org/copyleft/gpl.html GNU/GPL # # CONTACT: m.dietiker@md-systems.ch � 2007 Miro Dietiker 13.11.2007 # ############################################################################ # This parser is based on an earlier CMS parser implementation. # It has been completely rewritten and generalized for Kunena and # was also heavily tested. # However it should be: extensible, fast, ungreedy regarding resources # stateful, enforcing strict output rules as defined # Hope it works ;-) ############################################################################ # parser interpreter task -interaction # check interfaces & description (strip in implementation, extend interface decl) # test execution # update all tags to fb standard ## quote ## username ## call missingtag replacement on close (IMG) # list implement # errors # ERROR # implement self-link parsing (on Encode) # # */ defined( '_JEXEC' ) or die(); // parser states define('BBCODE_PARSE_START', 'start'); define('BBCODE_PARSE_NAME', 'name'); define('BBCODE_PARSE_SPACE', 'space'); define('BBCODE_PARSE_KEY_OR_END', 'key_or_end'); define('BBCODE_PARSE_EQUAL', 'equal'); define('BBCODE_PARSE_VAL', 'val'); define('BBCODE_PARSE_VALQUOT', 'valquot'); function fb_stripos($haystack , $needle , $offset=0) { if (strlen($haystack) <= $offset) return false; return stripos($haystack, $needle, $offset); } class BBCodeInterpreter extends TagInterpreter { // Extension for TagParser to interprete BBCode (with noparse, code state) var $tag_start = '['; var $tag_end = ']'; function &NewTask() { // Builds new Task // RET // object: the task object // TAGPARSER_RET_ERR $task = new BBCodeParserTask($this); return $task; } function ParseNext(&$task) { // function ParseNext($text, &$pos_act) { // Parse next candidate for execution // Candidate could be cancelled later on! // $text: the full text // &$pos_act: position to begin parsing // RET: TAGPARSER_RET_OK found, TAGPARSER_RET_ERR end $text =& $task->text; $pos_act =& $task->pos_act; if (strlen($text) < $pos_act) return TAGPARSER_RET_ERR; // in_code state if($task->in_code) { // seek [/code] only // ERROR: code NOT caseinsensitive! Correct core logic! // throw this into interpreter part! $checkpos = fb_stripos($text, '[/code]', $pos_act); if($checkpos!==FALSE) { $pos_act = $checkpos; return TAGPARSER_RET_OK; } $checkpos = fb_stripos($text, '[/code:1]', $pos_act); if($checkpos!==FALSE) { $pos_act = $checkpos; return TAGPARSER_RET_OK; } // temporarily close code tag if not exists $task->in_code = 0; return TAGPARSER_RET_ERR; } // in_noparse state if($task->in_noparse) { // seek [/noparse] only $checkpos = fb_stripos($text, '[/noparse]', $pos_act); // ERROR: noparse NOT caseinsensitive! Correct core logic! // throw this into interpreter part! if($checkpos!==FALSE) { $pos_act = $checkpos; return TAGPARSER_RET_OK; } return TAGPARSER_RET_ERR; } // parse tag_start in regular case // need text, pos_act, [length] $checkpos = fb_stripos($text, $this->tag_start, $pos_act); if($checkpos!==FALSE) { $pos_act = $checkpos; return TAGPARSER_RET_OK; } return TAGPARSER_RET_ERR; } function UnEscape(&$task) { // Check if current tag is escaped, unescape // RET: 0 continue, $text =& $task->text; $pos_act =& $task->pos_act; $nextchar = substr($text, $pos_act+1, 1); if($nextchar==$this->tag_start) { // escaped tagstart: remove escape! // abc[[def => pos_act@3, [@3, [@4 => abc[def if($task->dry) { // omit this tag $pos_act += 2; return TAGPARSER_RET_REPLACED; } $text = substr($text, 0, $pos_act).substr($text, $pos_act+1); $pos_act += 1; return TAGPARSER_RET_REPLACED; } // no escape return TAGPARSER_RET_NOTHING; } function ParseTag(&$tag, &$task) { // Parse Tag content and create construct // logs error itself to task // RET: // TAGPARSER_RET_OK continue // TAGPARSER_RET_ERR tag parse error, skip // this is a real char-by-char parser! $text =& $task->text; $pos =& $task->pos_act; $pos_start = $pos; $tagname = ''; $nowkey = ''; $nowval = ''; $arr = array(); $quot=''; // ' or " $isesc = FALSE; // escape \ used for quotes! $isend = FALSE; // TRUE if endtag $mode = BBCODE_PARSE_START; // scan through string //echo 'POS:'.$pos."\n"; $textlen = strlen($text); while(++$pos<$textlen) { $char = substr($text, $pos, 1); //echo 'CHAR:'.$mode.':'.$char."\n"; // missing tag end, overflow prevention! if($char===FALSE) { // cancel this tag $err = new ParserErrorContext('parser.err.tag.parsetag.endless'); $err->GrabContext($task); $task->ErrorPush($err); unset($err); //opt $tag->tag_end = $pos+1; return TAGPARSER_RET_ERR; } // modes if($mode==BBCODE_PARSE_START) { // switch to name in any case $mode=BBCODE_PARSE_NAME; if($char=='/') { $isend = TRUE; continue; } // continue on name totally } if($mode==BBCODE_PARSE_NAME) { if($char==$this->tag_end || $char=='=' || $char==' ') { if($tagname=='') { // cancel this nameless tag $err = new ParserErrorContext('parser.err.tag.parsetag.noname'); $err->GrabContext($task); $task->ErrorPush($err); unset($err); //opt $tag->tag_end = $pos+1; return TAGPARSER_RET_ERR; } } if($char==$this->tag_end) { break; } if($char=='=') { $mode = BBCODE_PARSE_EQUAL; $nowkey .= 'default'; continue; } if($char==' ') { $mode = BBCODE_PARSE_SPACE; continue; } // build tagname $tagname .= JString::strtolower($char); //echo 'TAG:'.$tagname."\n"; continue; } if($mode==BBCODE_PARSE_SPACE) { if($char==' ') { continue; // eat up spaces } if($char==$this->tag_end) { break; } $nowkey .= JString::strtolower($char); $mode=BBCODE_PARSE_KEY_OR_END; continue; } if($mode==BBCODE_PARSE_KEY_OR_END) { if($char=='=') { $mode = BBCODE_PARSE_EQUAL; continue; } if($char==$this->tag_end) { $arr[$nowkey] = TRUE; break; } if($char==' ') { $arr[$nowkey] = TRUE; $nowkey = ''; $mode = BBCODE_PARSE_SPACE; continue; } $nowkey .= JString::strtolower($char); } if($mode==BBCODE_PARSE_EQUAL) { $quot=''; // quotescan " if($char=='"') { $quot='"'; $mode = BBCODE_PARSE_VALQUOT; continue; } // quotescan ' if($char=='\'') { $quot='\''; $mode = BBCODE_PARSE_VALQUOT; continue; } if($char==' ') { $arr[$nowkey] = TRUE; $nowkey = ''; $mode = BBCODE_PARSE_SPACE; continue; } if($char==$this->tag_end) { $arr[$nowkey] = TRUE; break; } $nowval .= $char; $mode=BBCODE_PARSE_VAL; continue; } if($mode==BBCODE_PARSE_VALQUOT) { if($isesc) { $nowval .= $char; $isesc = FALSE; continue; } if($char=='\\') { // ONE backspace //echo 'ESCAPE'."\n"; $isesc = TRUE; continue; } if($char==$quot) { $arr[$nowkey] = $nowval; $nowkey = $nowval = ''; $mode = BBCODE_PARSE_SPACE; continue; } $nowval .= $char; continue; //opt } if($mode==BBCODE_PARSE_VAL) { if($char==' ') { $arr[$nowkey] = $nowval; $nowkey = $nowval = ''; $mode = BBCODE_PARSE_SPACE; continue; } if($char==$this->tag_end) { $arr[$nowkey] = $nowval; break; } $nowval .= $char; continue; //opt } } // end position points to tag closing //$pos_end = $pos; // create tag object if($isend) { // no reference! //echo 'TAGEND:'.$tagname.':'.$pos_start.":".$pos_end."\n"; $tag = new ParserEventTagEnd($pos_start, $pos, $tagname); } else { // no reference! //echo 'TAG:'.$tagname.':'.$pos_start.":".$pos_end."\n"; $tag = new ParserEventTag($pos_start, $pos, $tagname); $tag->setOptions($arr); } // parser position after tag: this is next char $pos++; return TAGPARSER_RET_OK; } function CheckTag(&$task, $tag) { // Parse Tag content and create construct // RET: 0 OK, errorinfo // check tagname regexp // $tag->name // dropping [*] here would lead to remove! so it goes to stack! /* $err = new ParserErrorContext('parser.err.tag.check'); $err->GrabContext($task, $tag); $task->ErrorPush($err); */ // optionally check tag return TAGPARSER_RET_OK; } } class BBCodeParserTask extends ParserTask { // stateful task for parser runs // parse state in_code in [code] var $in_code = FALSE; // parse state in_noparse in [noparse] var $in_noparse = FALSE; } ?>