web/wp-content/plugins/bbpress/includes/admin/parser.php
changeset 196 5e8dcbe22c24
equal deleted inserted replaced
195:c7c0fbc09788 196:5e8dcbe22c24
       
     1 <?php
       
     2 /*
       
     3 This is a compressed copy of NBBC. Do not edit!
       
     4 
       
     5 Copyright (c) 2008-9, the Phantom Inker.  All rights reserved.
       
     6 Portions Copyright (c) 2004-2008 AddedBytes.com
       
     7 
       
     8 Redistribution and use in source and binary forms, with or without
       
     9 modification, are permitted provided that the following conditions
       
    10 are met:
       
    11 
       
    12 * Redistributions of source code must retain the above copyright
       
    13   notice, this list of conditions and the following disclaimer.
       
    14 
       
    15 * Redistributions in binary form must reproduce the above copyright
       
    16   notice, this list of conditions and the following disclaimer in
       
    17   the documentation and/or other materials provided with the
       
    18   distribution.
       
    19 
       
    20 THIS SOFTWARE IS PROVIDED BY THE PHANTOM INKER "AS IS" AND ANY EXPRESS
       
    21 OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
       
    22 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
       
    23 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
       
    24 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
       
    25 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
       
    26 SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
       
    27 BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
       
    28 WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
       
    29 OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
       
    30 IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
       
    31 */
       
    32 
       
    33 define("BBCODE_VERSION", "1.4.5");
       
    34 define("BBCODE_RELEASE", "2010-09-17");
       
    35 define("BBCODE_VERBATIM", 2);
       
    36 define("BBCODE_REQUIRED", 1);
       
    37 define("BBCODE_OPTIONAL", 0);
       
    38 define("BBCODE_PROHIBIT", -1);
       
    39 define("BBCODE_CHECK", 1);
       
    40 define("BBCODE_OUTPUT", 2);
       
    41 define("BBCODE_ENDTAG", 5);
       
    42 define("BBCODE_TAG", 4);
       
    43 define("BBCODE_TEXT", 3);
       
    44 define("BBCODE_NL", 2);
       
    45 define("BBCODE_WS", 1);
       
    46 define("BBCODE_EOI", 0);
       
    47 define("BBCODE_LEXSTATE_TEXT", 0);
       
    48 define("BBCODE_LEXSTATE_TAG", 1);
       
    49 define("BBCODE_MODE_SIMPLE", 0);
       
    50 define("BBCODE_MODE_CALLBACK", 1);
       
    51 define("BBCODE_MODE_INTERNAL", 2);
       
    52 define("BBCODE_MODE_LIBRARY", 3);
       
    53 define("BBCODE_MODE_ENHANCED", 4);
       
    54 define("BBCODE_STACK_TOKEN", 0);
       
    55 define("BBCODE_STACK_TEXT", 1);
       
    56 define("BBCODE_STACK_TAG", 2);
       
    57 define("BBCODE_STACK_CLASS", 3);
       
    58 if (!function_exists('str_split')) {
       
    59 function str_split($string, $split_length = 1) {
       
    60 $array = explode("\r\n", chunk_split($string, $split_length));
       
    61 array_pop($array);
       
    62 return $array;
       
    63 }
       
    64 }
       
    65 $BBCode_SourceDir = dirname(__FILE__);
       
    66 
       
    67 class BBCodeLexer {
       
    68 var $token;
       
    69 var $text;
       
    70 var $tag;
       
    71 var $state;
       
    72 var $input;
       
    73 var $ptr;
       
    74 var $unget;
       
    75 var $verbatim;
       
    76 var $debug;
       
    77 var $tagmarker;
       
    78 var $end_tagmarker;
       
    79 var $pat_main;
       
    80 var $pat_comment;
       
    81 var $pat_comment2;
       
    82 var $pat_wiki;
       
    83 function BBCodeLexer($string, $tagmarker = '[') {
       
    84 $regex_beginmarkers = Array( '[' => '\[', '<' => '<', '{' => '\{', '(' => '\(' );
       
    85 $regex_endmarkers = Array( '[' => '\]', '<' => '>', '{' => '\}', '(' => '\)' );
       
    86 $endmarkers = Array( '[' => ']', '<' => '>', '{' => '}', '(' => ')' );
       
    87 if (!isset($regex_endmarkers[$tagmarker])) $tagmarker = '[';
       
    88 $e = $regex_endmarkers[$tagmarker];
       
    89 $b = $regex_beginmarkers[$tagmarker];
       
    90 $this->tagmarker = $tagmarker;
       
    91 $this->end_tagmarker = $endmarkers[$tagmarker];
       
    92 $this->pat_main = "/( "
       
    93 . "{$b}"
       
    94 . "(?! -- | ' | !-- | {$b}{$b} )"
       
    95 . "(?: [^\\n\\r{$b}{$e}] | \\\" [^\\\"\\n\\r]* \\\" | \\' [^\\'\\n\\r]* \\' )*"
       
    96 . "{$e}"
       
    97 . "| {$b}{$b} (?: [^{$e}\\r\\n] | {$e}[^{$e}\\r\\n] )* {$e}{$e}"
       
    98 . "| {$b} (?: -- | ' ) (?: [^{$e}\\n\\r]* ) {$e}"
       
    99 . "| {$b}!-- (?: [^-] | -[^-] | --[^{$e}] )* --{$e}"
       
   100 . "| -----+"
       
   101 . "| \\x0D\\x0A | \\x0A\\x0D | \\x0D | \\x0A"
       
   102 . "| [\\x00-\\x09\\x0B-\\x0C\\x0E-\\x20]+(?=[\\x0D\\x0A{$b}]|-----|$)"
       
   103 . "| (?<=[\\x0D\\x0A{$e}]|-----|^)[\\x00-\\x09\\x0B-\\x0C\\x0E-\\x20]+"
       
   104 . " )/Dx";
       
   105 $this->input = preg_split($this->pat_main, $string, -1, PREG_SPLIT_DELIM_CAPTURE);
       
   106 $this->pat_comment = "/^ {$b} (?: -- | ' ) /Dx";
       
   107 $this->pat_comment2 = "/^ {$b}!-- (?: [^-] | -[^-] | --[^{$e}] )* --{$e} $/Dx";
       
   108 $this->pat_wiki = "/^ {$b}{$b} ([^\\|]*) (?:\\|(.*))? {$e}{$e} $/Dx";
       
   109 $this->ptr = 0;
       
   110 $this->unget = false;
       
   111 $this->state = BBCODE_LEXSTATE_TEXT;
       
   112 $this->verbatim = false;
       
   113 $this->token = BBCODE_EOI;
       
   114 $this->tag = false;
       
   115 $this->text = "";
       
   116 }
       
   117 function GuessTextLength() {
       
   118 $length = 0;
       
   119 $ptr = 0;
       
   120 $state = BBCODE_LEXSTATE_TEXT;
       
   121 while ($ptr < count($this->input)) {
       
   122 $text = $this->input[$ptr++];
       
   123 if ($state == BBCODE_LEXSTATE_TEXT) {
       
   124 $state = BBCODE_LEXSTATE_TAG;
       
   125 $length += strlen($text);
       
   126 }
       
   127 else {
       
   128 switch (ord(substr($this->text, 0, 1))) {
       
   129 case 10:
       
   130 case 13:
       
   131 $state = BBCODE_LEXSTATE_TEXT;
       
   132 $length++;
       
   133 break;
       
   134 default:
       
   135 $state = BBCODE_LEXSTATE_TEXT;
       
   136 $length += strlen($text);
       
   137 break;
       
   138 case 40:
       
   139 case 60:
       
   140 case 91:
       
   141 case 123:
       
   142 $state = BBCODE_LEXSTATE_TEXT;
       
   143 break;
       
   144 }
       
   145 }
       
   146 }
       
   147 return $length;
       
   148 }
       
   149 function NextToken() {
       
   150 if ($this->unget) {
       
   151 $this->unget = false;
       
   152 return $this->token;
       
   153 }
       
   154 while (true) {
       
   155 if ($this->ptr >= count($this->input)) {
       
   156 $this->text = "";
       
   157 $this->tag = false;
       
   158 return $this->token = BBCODE_EOI;
       
   159 }
       
   160 $this->text = preg_replace("/[\\x00-\\x08\\x0B-\\x0C\\x0E-\\x1F]/", "",
       
   161 $this->input[$this->ptr++]);
       
   162 if ($this->verbatim) {
       
   163 $this->tag = false;
       
   164 if ($this->state == BBCODE_LEXSTATE_TEXT) {
       
   165 $this->state = BBCODE_LEXSTATE_TAG;
       
   166 $token_type = BBCODE_TEXT;
       
   167 }
       
   168 else {
       
   169 $this->state = BBCODE_LEXSTATE_TEXT;
       
   170 switch (ord(substr($this->text, 0, 1))) {
       
   171 case 10:
       
   172 case 13:
       
   173 $token_type = BBCODE_NL;
       
   174 break;
       
   175 default:
       
   176 $token_type = BBCODE_WS;
       
   177 break;
       
   178 case 45:
       
   179 case 40:
       
   180 case 60:
       
   181 case 91:
       
   182 case 123:
       
   183 $token_type = BBCODE_TEXT;
       
   184 break;
       
   185 }
       
   186 }
       
   187 if (strlen($this->text) > 0)
       
   188 return $this->token = $token_type;
       
   189 }
       
   190 else if ($this->state == BBCODE_LEXSTATE_TEXT) {
       
   191 $this->state = BBCODE_LEXSTATE_TAG;
       
   192 $this->tag = false;
       
   193 if (strlen($this->text) > 0)
       
   194 return $this->token = BBCODE_TEXT;
       
   195 }
       
   196 else {
       
   197 switch (ord(substr($this->text, 0, 1))) {
       
   198 case 10:
       
   199 case 13:
       
   200 $this->tag = false;
       
   201 $this->state = BBCODE_LEXSTATE_TEXT;
       
   202 return $this->token = BBCODE_NL;
       
   203 case 45:
       
   204 if (preg_match("/^-----/", $this->text)) {
       
   205 $this->tag = Array('_name' => 'rule', '_endtag' => false, '_default' => '');
       
   206 $this->state = BBCODE_LEXSTATE_TEXT;
       
   207 return $this->token = BBCODE_TAG;
       
   208 }
       
   209 else {
       
   210 $this->tag = false;
       
   211 $this->state = BBCODE_LEXSTATE_TEXT;
       
   212 if (strlen($this->text) > 0)
       
   213 return $this->token = BBCODE_TEXT;
       
   214 continue;
       
   215 }
       
   216 default:
       
   217 $this->tag = false;
       
   218 $this->state = BBCODE_LEXSTATE_TEXT;
       
   219 return $this->token = BBCODE_WS;
       
   220 case 40:
       
   221 case 60:
       
   222 case 91:
       
   223 case 123:
       
   224 if (preg_match($this->pat_comment, $this->text)) {
       
   225 $this->state = BBCODE_LEXSTATE_TEXT;
       
   226 continue;
       
   227 }
       
   228 if (preg_match($this->pat_comment2, $this->text)) {
       
   229 $this->state = BBCODE_LEXSTATE_TEXT;
       
   230 continue;
       
   231 }
       
   232 if (preg_match($this->pat_wiki, $this->text, $matches)) {
       
   233 $this->tag = Array('_name' => 'wiki', '_endtag' => false,
       
   234 '_default' => @$matches[1], 'title' => @$matches[2]);
       
   235 $this->state = BBCODE_LEXSTATE_TEXT;
       
   236 return $this->token = BBCODE_TAG;
       
   237 }
       
   238 $this->tag = $this->Internal_DecodeTag($this->text);
       
   239 $this->state = BBCODE_LEXSTATE_TEXT;
       
   240 return $this->token = ($this->tag['_end'] ? BBCODE_ENDTAG : BBCODE_TAG);
       
   241 }
       
   242 }
       
   243 }
       
   244 }
       
   245 function UngetToken() {
       
   246 if ($this->token !== BBCODE_EOI)
       
   247 $this->unget = true;
       
   248 }
       
   249 function PeekToken() {
       
   250 $result = $this->NextToken();
       
   251 if ($this->token !== BBCODE_EOI)
       
   252 $this->unget = true;
       
   253 return $result;
       
   254 }
       
   255 function SaveState() {
       
   256 return Array(
       
   257 'token' => $this->token,
       
   258 'text' => $this->text,
       
   259 'tag' => $this->tag,
       
   260 'state' => $this->state,
       
   261 'input' => $this->input,
       
   262 'ptr' => $this->ptr,
       
   263 'unget' => $this->unget,
       
   264 'verbatim' => $this->verbatim
       
   265 );
       
   266 }
       
   267 function RestoreState($state) {
       
   268 if (!is_array($state)) return;
       
   269 $this->token = @$state['token'];
       
   270 $this->text = @$state['text'];
       
   271 $this->tag = @$state['tag'];
       
   272 $this->state = @$state['state'];
       
   273 $this->input = @$state['input'];
       
   274 $this->ptr = @$state['ptr'];
       
   275 $this->unget = @$state['unget'];
       
   276 $this->verbatim = @$state['verbatim'];
       
   277 }
       
   278 function Internal_StripQuotes($string) {
       
   279 if (preg_match("/^\\\"(.*)\\\"$/", $string, $matches))
       
   280 return $matches[1];
       
   281 else if (preg_match("/^\\'(.*)\\'$/", $string, $matches))
       
   282 return $matches[1];
       
   283 else return $string;
       
   284 }
       
   285 function Internal_ClassifyPiece($ptr, $pieces) {
       
   286 if ($ptr >= count($pieces)) return -1;
       
   287 $piece = $pieces[$ptr];
       
   288 if ($piece == '=') return '=';
       
   289 else if (preg_match("/^[\\'\\\"]/", $piece)) return '"';
       
   290 else if (preg_match("/^[\\x00-\\x20]+$/", $piece)) return ' ';
       
   291 else return 'A';
       
   292 }
       
   293 function Internal_DecodeTag($tag) {
       
   294 $result = Array('_tag' => $tag, '_endtag' => '', '_name' => '',
       
   295 '_hasend' => false, '_end' => false, '_default' => false);
       
   296 $tag = substr($tag, 1, strlen($tag)-2);
       
   297 $ch = ord(substr($tag, 0, 1));
       
   298 if ($ch >= 0 && $ch <= 32) return $result;
       
   299 $pieces = preg_split("/(\\\"[^\\\"]+\\\"|\\'[^\\']+\\'|=|[\\x00-\\x20]+)/",
       
   300 $tag, -1, PREG_SPLIT_DELIM_CAPTURE|PREG_SPLIT_NO_EMPTY);
       
   301 $ptr = 0;
       
   302 if (count($pieces) < 1) return $result;
       
   303 if (@substr($pieces[$ptr], 0, 1) == '/') {
       
   304 $result['_name'] = strtolower(substr($pieces[$ptr++], 1));
       
   305 $result['_end'] = true;
       
   306 }
       
   307 else {
       
   308 $result['_name'] = strtolower($pieces[$ptr++]);
       
   309 $result['_end'] = false;
       
   310 }
       
   311 while (($type = $this->Internal_ClassifyPiece($ptr, $pieces)) == ' ')
       
   312 $ptr++;
       
   313 $params = Array();
       
   314 if ($type != '=') {
       
   315 $result['_default'] = false;
       
   316 $params[] = Array('key' => '', 'value' => '');
       
   317 }
       
   318 else {
       
   319 $ptr++;
       
   320 while (($type = $this->Internal_ClassifyPiece($ptr, $pieces)) == ' ')
       
   321 $ptr++;
       
   322 if ($type == "\"")
       
   323 $value = $this->Internal_StripQuotes($pieces[$ptr++]);
       
   324 else {
       
   325 $after_space = false;
       
   326 $start = $ptr;
       
   327 while (($type = $this->Internal_ClassifyPiece($ptr, $pieces)) != -1) {
       
   328 if ($type == ' ') $after_space = true;
       
   329 if ($type == '=' && $after_space) break;
       
   330 $ptr++;
       
   331 }
       
   332 if ($type == -1) $ptr--;
       
   333 if ($type == '=') {
       
   334 $ptr--;
       
   335 while ($ptr > $start && $this->Internal_ClassifyPiece($ptr, $pieces) == ' ')
       
   336 $ptr--;
       
   337 while ($ptr > $start && $this->Internal_ClassifyPiece($ptr, $pieces) != ' ')
       
   338 $ptr--;
       
   339 }
       
   340 $value = "";
       
   341 for (; $start <= $ptr; $start++) {
       
   342 if ($this->Internal_ClassifyPiece($start, $pieces) == ' ')
       
   343 $value .= " ";
       
   344 else $value .= $this->Internal_StripQuotes($pieces[$start]);
       
   345 }
       
   346 $value = trim($value);
       
   347 $ptr++;
       
   348 }
       
   349 $result['_default'] = $value;
       
   350 $params[] = Array('key' => '', 'value' => $value);
       
   351 }
       
   352 while (($type = $this->Internal_ClassifyPiece($ptr, $pieces)) != -1) {
       
   353 while ($type == ' ') {
       
   354 $ptr++;
       
   355 $type = $this->Internal_ClassifyPiece($ptr, $pieces);
       
   356 }
       
   357 if ($type == 'A' || $type == '"')
       
   358 $key = strtolower($this->Internal_StripQuotes(@$pieces[$ptr++]));
       
   359 else if ($type == '=') {
       
   360 $ptr++;
       
   361 continue;
       
   362 }
       
   363 else if ($type == -1) break;
       
   364 while (($type = $this->Internal_ClassifyPiece($ptr, $pieces)) == ' ')
       
   365 $ptr++;
       
   366 if ($type != '=')
       
   367 $value = $this->Internal_StripQuotes($key);
       
   368 else {
       
   369 $ptr++;
       
   370 while (($type = $this->Internal_ClassifyPiece($ptr, $pieces)) == ' ')
       
   371 $ptr++;
       
   372 if ($type == '"') {
       
   373 $value = $this->Internal_StripQuotes($pieces[$ptr++]);
       
   374 }
       
   375 else if ($type != -1) {
       
   376 $value = $pieces[$ptr++];
       
   377 while (($type = $this->Internal_ClassifyPiece($ptr, $pieces)) != -1
       
   378 && $type != ' ')
       
   379 $value .= $pieces[$ptr++];
       
   380 }
       
   381 else $value = "";
       
   382 }
       
   383 if (substr($key, 0, 1) != '_')
       
   384 $result[$key] = $value;
       
   385 $params[] = Array('key' => $key, 'value' => $value);
       
   386 }
       
   387 $result['_params'] = $params;
       
   388 return $result;
       
   389 }
       
   390 }
       
   391 
       
   392 class BBCodeLibrary {
       
   393 var $default_smileys = Array(
       
   394 ':)' => 'smile.gif', ':-)' => 'smile.gif',
       
   395 '=)' => 'smile.gif', '=-)' => 'smile.gif',
       
   396 ':(' => 'frown.gif', ':-(' => 'frown.gif',
       
   397 '=(' => 'frown.gif', '=-(' => 'frown.gif',
       
   398 ':D' => 'bigsmile.gif', ':-D' => 'bigsmile.gif',
       
   399 '=D' => 'bigsmile.gif', '=-D' => 'bigsmile.gif',
       
   400 '>:('=> 'angry.gif', '>:-('=> 'angry.gif',
       
   401 '>=('=> 'angry.gif', '>=-('=> 'angry.gif',
       
   402 'D:' => 'angry.gif', 'D-:' => 'angry.gif',
       
   403 'D=' => 'angry.gif', 'D-=' => 'angry.gif',
       
   404 '>:)'=> 'evil.gif', '>:-)'=> 'evil.gif',
       
   405 '>=)'=> 'evil.gif', '>=-)'=> 'evil.gif',
       
   406 '>:D'=> 'evil.gif', '>:-D'=> 'evil.gif',
       
   407 '>=D'=> 'evil.gif', '>=-D'=> 'evil.gif',
       
   408 '>;)'=> 'sneaky.gif', '>;-)'=> 'sneaky.gif',
       
   409 '>;D'=> 'sneaky.gif', '>;-D'=> 'sneaky.gif',
       
   410 'O:)' => 'saint.gif', 'O:-)' => 'saint.gif',
       
   411 'O=)' => 'saint.gif', 'O=-)' => 'saint.gif',
       
   412 ':O' => 'surprise.gif', ':-O' => 'surprise.gif',
       
   413 '=O' => 'surprise.gif', '=-O' => 'surprise.gif',
       
   414 ':?' => 'confuse.gif', ':-?' => 'confuse.gif',
       
   415 '=?' => 'confuse.gif', '=-?' => 'confuse.gif',
       
   416 ':s' => 'worry.gif', ':-S' => 'worry.gif',
       
   417 '=s' => 'worry.gif', '=-S' => 'worry.gif',
       
   418 ':|' => 'neutral.gif', ':-|' => 'neutral.gif',
       
   419 '=|' => 'neutral.gif', '=-|' => 'neutral.gif',
       
   420 ':I' => 'neutral.gif', ':-I' => 'neutral.gif',
       
   421 '=I' => 'neutral.gif', '=-I' => 'neutral.gif',
       
   422 ':/' => 'irritated.gif', ':-/' => 'irritated.gif',
       
   423 '=/' => 'irritated.gif', '=-/' => 'irritated.gif',
       
   424 ':\\' => 'irritated.gif', ':-\\' => 'irritated.gif',
       
   425 '=\\' => 'irritated.gif', '=-\\' => 'irritated.gif',
       
   426 ':P' => 'tongue.gif', ':-P' => 'tongue.gif',
       
   427 '=P' => 'tongue.gif', '=-P' => 'tongue.gif',
       
   428 'X-P' => 'tongue.gif',
       
   429 '8)' => 'bigeyes.gif', '8-)' => 'bigeyes.gif',
       
   430 'B)' => 'cool.gif', 'B-)' => 'cool.gif',
       
   431 ';)' => 'wink.gif', ';-)' => 'wink.gif',
       
   432 ';D' => 'bigwink.gif', ';-D' => 'bigwink.gif',
       
   433 '^_^'=> 'anime.gif', '^^;' => 'sweatdrop.gif',
       
   434 '>_>'=> 'lookright.gif', '>.>' => 'lookright.gif',
       
   435 '<_<'=> 'lookleft.gif', '<.<' => 'lookleft.gif',
       
   436 'XD' => 'laugh.gif', 'X-D' => 'laugh.gif',
       
   437 ';D' => 'bigwink.gif', ';-D' => 'bigwink.gif',
       
   438 ':3' => 'smile3.gif', ':-3' => 'smile3.gif',
       
   439 '=3' => 'smile3.gif', '=-3' => 'smile3.gif',
       
   440 ';3' => 'wink3.gif', ';-3' => 'wink3.gif',
       
   441 '<g>' => 'teeth.gif', '<G>' => 'teeth.gif',
       
   442 'o.O' => 'boggle.gif', 'O.o' => 'boggle.gif',
       
   443 ':blue:' => 'blue.gif',
       
   444 ':zzz:' => 'sleepy.gif',
       
   445 '<3' => 'heart.gif',
       
   446 ':star:' => 'star.gif',
       
   447 );
       
   448 var $default_tag_rules = Array(
       
   449 'b' => Array(
       
   450 'simple_start' => "<b>",
       
   451 'simple_end' => "</b>",
       
   452 'class' => 'inline',
       
   453 'allow_in' => Array('listitem', 'block', 'columns', 'inline', 'link'),
       
   454 'plain_start' => "<b>",
       
   455 'plain_end' => "</b>",
       
   456 ),
       
   457 'i' => Array(
       
   458 'simple_start' => "<i>",
       
   459 'simple_end' => "</i>",
       
   460 'class' => 'inline',
       
   461 'allow_in' => Array('listitem', 'block', 'columns', 'inline', 'link'),
       
   462 'plain_start' => "<i>",
       
   463 'plain_end' => "</i>",
       
   464 ),
       
   465 'u' => Array(
       
   466 'simple_start' => "<u>",
       
   467 'simple_end' => "</u>",
       
   468 'class' => 'inline',
       
   469 'allow_in' => Array('listitem', 'block', 'columns', 'inline', 'link'),
       
   470 'plain_start' => "<u>",
       
   471 'plain_end' => "</u>",
       
   472 ),
       
   473 's' => Array(
       
   474 'simple_start' => "<strike>",
       
   475 'simple_end' => "</strike>",
       
   476 'class' => 'inline',
       
   477 'allow_in' => Array('listitem', 'block', 'columns', 'inline', 'link'),
       
   478 'plain_start' => "<i>",
       
   479 'plain_end' => "</i>",
       
   480 ),
       
   481 'font' => Array(
       
   482 'mode' => BBCODE_MODE_LIBRARY,
       
   483 'allow' => Array('_default' => '/^[a-zA-Z0-9._ -]+$/'),
       
   484 'method' => 'DoFont',
       
   485 'class' => 'inline',
       
   486 'allow_in' => Array('listitem', 'block', 'columns', 'inline', 'link'),
       
   487 ),
       
   488 'color' => Array(
       
   489 'mode' => BBCODE_MODE_ENHANCED,
       
   490 'allow' => Array('_default' => '/^#?[a-zA-Z0-9._ -]+$/'),
       
   491 'template' => '<span style="color:{$_default/tw}">{$_content/v}</span>',
       
   492 'class' => 'inline',
       
   493 'allow_in' => Array('listitem', 'block', 'columns', 'inline', 'link'),
       
   494 ),
       
   495 'size' => Array(
       
   496 'mode' => BBCODE_MODE_LIBRARY,
       
   497 'allow' => Array('_default' => '/^[0-9.]+$/D'),
       
   498 'method' => 'DoSize',
       
   499 'class' => 'inline',
       
   500 'allow_in' => Array('listitem', 'block', 'columns', 'inline', 'link'),
       
   501 ),
       
   502 'sup' => Array(
       
   503 'simple_start' => "<sup>",
       
   504 'simple_end' => "</sup>",
       
   505 'class' => 'inline',
       
   506 'allow_in' => Array('listitem', 'block', 'columns', 'inline', 'link'),
       
   507 ),
       
   508 'sub' => Array(
       
   509 'simple_start' => "<sub>",
       
   510 'simple_end' => "</sub>",
       
   511 'class' => 'inline',
       
   512 'allow_in' => Array('listitem', 'block', 'columns', 'inline', 'link'),
       
   513 ),
       
   514 'spoiler' => Array(
       
   515 'simple_start' => "<span class=\"bbcode_spoiler\">",
       
   516 'simple_end' => "</span>",
       
   517 'class' => 'inline',
       
   518 'allow_in' => Array('listitem', 'block', 'columns', 'inline', 'link'),
       
   519 ),
       
   520 'acronym' => Array(
       
   521 'mode' => BBCODE_MODE_ENHANCED,
       
   522 'template' => '<span class="bbcode_acronym" title="{$_default/e}">{$_content/v}</span>',
       
   523 'class' => 'inline',
       
   524 'allow_in' => Array('listitem', 'block', 'columns', 'inline', 'link'),
       
   525 ),
       
   526 'url' => Array(
       
   527 'mode' => BBCODE_MODE_LIBRARY,
       
   528 'method' => 'DoURL',
       
   529 'class' => 'link',
       
   530 'allow_in' => Array('listitem', 'block', 'columns', 'inline'),
       
   531 'content' => BBCODE_REQUIRED,
       
   532 'plain_start' => "<a href=\"{\$link}\">",
       
   533 'plain_end' => "</a>",
       
   534 'plain_content' => Array('_content', '_default'),
       
   535 'plain_link' => Array('_default', '_content'),
       
   536 ),
       
   537 'email' => Array(
       
   538 'mode' => BBCODE_MODE_LIBRARY,
       
   539 'method' => 'DoEmail',
       
   540 'class' => 'link',
       
   541 'allow_in' => Array('listitem', 'block', 'columns', 'inline'),
       
   542 'content' => BBCODE_REQUIRED,
       
   543 'plain_start' => "<a href=\"mailto:{\$link}\">",
       
   544 'plain_end' => "</a>",
       
   545 'plain_content' => Array('_content', '_default'),
       
   546 'plain_link' => Array('_default', '_content'),
       
   547 ),
       
   548 'wiki' => Array(
       
   549 'mode' => BBCODE_MODE_LIBRARY,
       
   550 'method' => "DoWiki",
       
   551 'class' => 'link',
       
   552 'allow_in' => Array('listitem', 'block', 'columns', 'inline'),
       
   553 'end_tag' => BBCODE_PROHIBIT,
       
   554 'content' => BBCODE_PROHIBIT,
       
   555 'plain_start' => "<b>[",
       
   556 'plain_end' => "]</b>",
       
   557 'plain_content' => Array('title', '_default'),
       
   558 'plain_link' => Array('_default', '_content'),
       
   559 ),
       
   560 'img' => Array(
       
   561 'mode' => BBCODE_MODE_LIBRARY,
       
   562 'method' => "DoImage",
       
   563 'class' => 'image',
       
   564 'allow_in' => Array('listitem', 'block', 'columns', 'inline', 'link'),
       
   565 'end_tag' => BBCODE_REQUIRED,
       
   566 'content' => BBCODE_REQUIRED,
       
   567 'plain_start' => "[image]",
       
   568 'plain_content' => Array(),
       
   569 ),
       
   570 'rule' => Array(
       
   571 'mode' => BBCODE_MODE_LIBRARY,
       
   572 'method' => "DoRule",
       
   573 'class' => 'block',
       
   574 'allow_in' => Array('listitem', 'block', 'columns'),
       
   575 'end_tag' => BBCODE_PROHIBIT,
       
   576 'content' => BBCODE_PROHIBIT,
       
   577 'before_tag' => "sns",
       
   578 'after_tag' => "sns",
       
   579 'plain_start' => "\n-----\n",
       
   580 'plain_end' => "",
       
   581 'plain_content' => Array(),
       
   582 ),
       
   583 'br' => Array(
       
   584 'mode' => BBCODE_MODE_SIMPLE,
       
   585 'simple_start' => "<br />\n",
       
   586 'simple_end' => "",
       
   587 'class' => 'inline',
       
   588 'allow_in' => Array('listitem', 'block', 'columns', 'inline', 'link'),
       
   589 'end_tag' => BBCODE_PROHIBIT,
       
   590 'content' => BBCODE_PROHIBIT,
       
   591 'before_tag' => "s",
       
   592 'after_tag' => "s",
       
   593 'plain_start' => "\n",
       
   594 'plain_end' => "",
       
   595 'plain_content' => Array(),
       
   596 ),
       
   597 'left' => Array(
       
   598 'simple_start' => "\n<div class=\"bbcode_left\" style=\"text-align:left\">\n",
       
   599 'simple_end' => "\n</div>\n",
       
   600 'allow_in' => Array('listitem', 'block', 'columns'),
       
   601 'before_tag' => "sns",
       
   602 'after_tag' => "sns",
       
   603 'before_endtag' => "sns",
       
   604 'after_endtag' => "sns",
       
   605 'plain_start' => "\n",
       
   606 'plain_end' => "\n",
       
   607 ),
       
   608 'right' => Array(
       
   609 'simple_start' => "\n<div class=\"bbcode_right\" style=\"text-align:right\">\n",
       
   610 'simple_end' => "\n</div>\n",
       
   611 'allow_in' => Array('listitem', 'block', 'columns'),
       
   612 'before_tag' => "sns",
       
   613 'after_tag' => "sns",
       
   614 'before_endtag' => "sns",
       
   615 'after_endtag' => "sns",
       
   616 'plain_start' => "\n",
       
   617 'plain_end' => "\n",
       
   618 ),
       
   619 'center' => Array(
       
   620 'simple_start' => "\n<div class=\"bbcode_center\" style=\"text-align:center\">\n",
       
   621 'simple_end' => "\n</div>\n",
       
   622 'allow_in' => Array('listitem', 'block', 'columns'),
       
   623 'before_tag' => "sns",
       
   624 'after_tag' => "sns",
       
   625 'before_endtag' => "sns",
       
   626 'after_endtag' => "sns",
       
   627 'plain_start' => "\n",
       
   628 'plain_end' => "\n",
       
   629 ),
       
   630 'indent' => Array(
       
   631 'simple_start' => "\n<div class=\"bbcode_indent\" style=\"margin-left:4em\">\n",
       
   632 'simple_end' => "\n</div>\n",
       
   633 'allow_in' => Array('listitem', 'block', 'columns'),
       
   634 'before_tag' => "sns",
       
   635 'after_tag' => "sns",
       
   636 'before_endtag' => "sns",
       
   637 'after_endtag' => "sns",
       
   638 'plain_start' => "\n",
       
   639 'plain_end' => "\n",
       
   640 ),
       
   641 'columns' => Array(
       
   642 'simple_start' => "\n<table class=\"bbcode_columns\"><tbody><tr><td class=\"bbcode_column bbcode_firstcolumn\">\n",
       
   643 'simple_end' => "\n</td></tr></tbody></table>\n",
       
   644 'class' => 'columns',
       
   645 'allow_in' => Array('listitem', 'block', 'columns'),
       
   646 'end_tag' => BBCODE_REQUIRED,
       
   647 'content' => BBCODE_REQUIRED,
       
   648 'before_tag' => "sns",
       
   649 'after_tag' => "sns",
       
   650 'before_endtag' => "sns",
       
   651 'after_endtag' => "sns",
       
   652 'plain_start' => "\n",
       
   653 'plain_end' => "\n",
       
   654 ),
       
   655 'nextcol' => Array(
       
   656 'simple_start' => "\n</td><td class=\"bbcode_column\">\n",
       
   657 'class' => 'nextcol',
       
   658 'allow_in' => Array('columns'),
       
   659 'end_tag' => BBCODE_PROHIBIT,
       
   660 'content' => BBCODE_PROHIBIT,
       
   661 'before_tag' => "sns",
       
   662 'after_tag' => "sns",
       
   663 'before_endtag' => "sns",
       
   664 'after_endtag' => "sns",
       
   665 'plain_start' => "\n",
       
   666 'plain_end' => "",
       
   667 ),
       
   668 'code' => Array(
       
   669 'mode' => BBCODE_MODE_ENHANCED,
       
   670 'template' => "\n<div class=\"bbcode_code\">\n<div class=\"bbcode_code_head\">Code:</div>\n<div class=\"bbcode_code_body\" style=\"white-space:pre\">{\$_content/v}</div>\n</div>\n",
       
   671 'class' => 'code',
       
   672 'allow_in' => Array('listitem', 'block', 'columns'),
       
   673 'content' => BBCODE_VERBATIM,
       
   674 'before_tag' => "sns",
       
   675 'after_tag' => "sn",
       
   676 'before_endtag' => "sn",
       
   677 'after_endtag' => "sns",
       
   678 'plain_start' => "\n<b>Code:</b>\n",
       
   679 'plain_end' => "\n",
       
   680 ),
       
   681 'quote' => Array(
       
   682 'mode' => BBCODE_MODE_LIBRARY,
       
   683 'method' => "DoQuote",
       
   684 'allow_in' => Array('listitem', 'block', 'columns'),
       
   685 'before_tag' => "sns",
       
   686 'after_tag' => "sns",
       
   687 'before_endtag' => "sns",
       
   688 'after_endtag' => "sns",
       
   689 'plain_start' => "\n<b>Quote:</b>\n",
       
   690 'plain_end' => "\n",
       
   691 ),
       
   692 'list' => Array(
       
   693 'mode' => BBCODE_MODE_LIBRARY,
       
   694 'method' => 'DoList',
       
   695 'class' => 'list',
       
   696 'allow_in' => Array('listitem', 'block', 'columns'),
       
   697 'before_tag' => "sns",
       
   698 'after_tag' => "sns",
       
   699 'before_endtag' => "sns",
       
   700 'after_endtag' => "sns",
       
   701 'plain_start' => "\n",
       
   702 'plain_end' => "\n",
       
   703 ),
       
   704 '*' => Array(
       
   705 'simple_start' => "<li>",
       
   706 'simple_end' => "</li>\n",
       
   707 'class' => 'listitem',
       
   708 'allow_in' => Array('list'),
       
   709 'end_tag' => BBCODE_OPTIONAL,
       
   710 'before_tag' => "s",
       
   711 'after_tag' => "s",
       
   712 'before_endtag' => "sns",
       
   713 'after_endtag' => "sns",
       
   714 'plain_start' => "\n * ",
       
   715 'plain_end' => "\n",
       
   716 ),
       
   717 );
       
   718 function DoURL($bbcode, $action, $name, $default, $params, $content) {
       
   719 if ($action == BBCODE_CHECK) return true;
       
   720 $url = is_string($default) ? $default : $bbcode->UnHTMLEncode(strip_tags($content));
       
   721 if ($bbcode->IsValidURL($url)) {
       
   722 if ($bbcode->debug)
       
   723 print "ISVALIDURL<br />";
       
   724 if ($bbcode->url_targetable !== false && isset($params['target']))
       
   725 $target = " target=\"" . htmlspecialchars($params['target']) . "\"";
       
   726 else $target = "";
       
   727 if ($bbcode->url_target !== false)
       
   728 if (!($bbcode->url_targetable == 'override' && isset($params['target'])))
       
   729 $target = " target=\"" . htmlspecialchars($bbcode->url_target) . "\"";
       
   730 return '<a href="' . htmlspecialchars($url) . '" class="bbcode_url"' . $target . '>' . $content . '</a>';
       
   731 }
       
   732 else return htmlspecialchars($params['_tag']) . $content . htmlspecialchars($params['_endtag']);
       
   733 }
       
   734 function DoEmail($bbcode, $action, $name, $default, $params, $content) {
       
   735 if ($action == BBCODE_CHECK) return true;
       
   736 $email = is_string($default) ? $default : $bbcode->UnHTMLEncode(strip_tags($content));
       
   737 if ($bbcode->IsValidEmail($email))
       
   738 return '<a href="mailto:' . htmlspecialchars($email) . '" class="bbcode_email">' . $content . '</a>';
       
   739 else return htmlspecialchars($params['_tag']) . $content . htmlspecialchars($params['_endtag']);
       
   740 }
       
   741 function DoSize($bbcode, $action, $name, $default, $params, $content) {
       
   742 switch ($default) {
       
   743 case '0': $size = '.5em'; break;
       
   744 case '1': $size = '.67em'; break;
       
   745 case '2': $size = '.83em'; break;
       
   746 default:
       
   747 case '3': $size = '1.0em'; break;
       
   748 case '4': $size = '1.17em'; break;
       
   749 case '5': $size = '1.5em'; break;
       
   750 case '6': $size = '2.0em'; break;
       
   751 case '7': $size = '2.5em'; break;
       
   752 }
       
   753 return "<span style=\"font-size:$size\">$content</span>";
       
   754 }
       
   755 function DoFont($bbcode, $action, $name, $default, $params, $content) {
       
   756 $fonts = explode(",", $default);
       
   757 $result = "";
       
   758 $special_fonts = Array(
       
   759 'serif' => 'serif',
       
   760 'sans-serif' => 'sans-serif',
       
   761 'sans serif' => 'sans-serif',
       
   762 'sansserif' => 'sans-serif',
       
   763 'sans' => 'sans-serif',
       
   764 'cursive' => 'cursive',
       
   765 'fantasy' => 'fantasy',
       
   766 'monospace' => 'monospace',
       
   767 'mono' => 'monospace',
       
   768 );
       
   769 foreach ($fonts as $font) {
       
   770 $font = trim($font);
       
   771 if (isset($special_fonts[$font])) {
       
   772 if (strlen($result) > 0) $result .= ",";
       
   773 $result .= $special_fonts[$font];
       
   774 }
       
   775 else if (strlen($font) > 0) {
       
   776 if (strlen($result) > 0) $result .= ",";
       
   777 $result .= "'$font'";
       
   778 }
       
   779 }
       
   780 return "<span style=\"font-family:$result\">$content</span>";
       
   781 }
       
   782 function DoWiki($bbcode, $action, $name, $default, $params, $content) {
       
   783 $name = $bbcode->Wikify($default);
       
   784 if ($action == BBCODE_CHECK)
       
   785 return strlen($name) > 0;
       
   786 $title = trim(@$params['title']);
       
   787 if (strlen($title) <= 0) $title = trim($default);
       
   788 return "<a href=\"{$bbcode->wiki_url}$name\" class=\"bbcode_wiki\">"
       
   789 . htmlspecialchars($title) . "</a>";
       
   790 }
       
   791 function DoImage($bbcode, $action, $name, $default, $params, $content) {
       
   792 if ($action == BBCODE_CHECK) return true;
       
   793 $content = trim($bbcode->UnHTMLEncode(strip_tags($content)));
       
   794 if (preg_match("/\\.(?:gif|jpeg|jpg|jpe|png)$/", $content)) {
       
   795 if (preg_match("/^[a-zA-Z0-9_][^:]+$/", $content)) {
       
   796 if (!preg_match("/(?:\\/\\.\\.\\/)|(?:^\\.\\.\\/)|(?:^\\/)/", $content)) {
       
   797 $info = @getimagesize("{$bbcode->local_img_dir}/{$content}");
       
   798 if ($info[2] == IMAGETYPE_GIF || $info[2] == IMAGETYPE_JPEG || $info[2] == IMAGETYPE_PNG) {
       
   799 return "<img src=\""
       
   800 . htmlspecialchars("{$bbcode->local_img_url}/{$content}") . "\" alt=\""
       
   801 . htmlspecialchars(basename($content)) . "\" width=\""
       
   802 . htmlspecialchars($info[0]) . "\" height=\""
       
   803 . htmlspecialchars($info[1]) . "\" class=\"bbcode_img\" />";
       
   804 }
       
   805 }
       
   806 }
       
   807 else if ($bbcode->IsValidURL($content, false)) {
       
   808 return "<img src=\"" . htmlspecialchars($content) . "\" alt=\""
       
   809 . htmlspecialchars(basename($content)) . "\" class=\"bbcode_img\" />";
       
   810 }
       
   811 }
       
   812 return htmlspecialchars($params['_tag']) . htmlspecialchars($content) . htmlspecialchars($params['_endtag']);
       
   813 }
       
   814 function DoRule($bbcode, $action, $name, $default, $params, $content) {
       
   815 if ($action == BBCODE_CHECK) return true;
       
   816 else return $bbcode->rule_html;
       
   817 }
       
   818 function DoQuote($bbcode, $action, $name, $default, $params, $content) {
       
   819 if ($action == BBCODE_CHECK) return true;
       
   820 if (isset($params['name'])) {
       
   821 $title = htmlspecialchars(trim($params['name'])) . " wrote";
       
   822 if (isset($params['date']))
       
   823 $title .= " on " . htmlspecialchars(trim($params['date']));
       
   824 $title .= ":";
       
   825 if (isset($params['url'])) {
       
   826 $url = trim($params['url']);
       
   827 if ($bbcode->IsValidURL($url))
       
   828 $title = "<a href=\"" . htmlspecialchars($params['url']) . "\">" . $title . "</a>";
       
   829 }
       
   830 }
       
   831 else if (!is_string($default))
       
   832 $title = "Quote:";
       
   833 else $title = htmlspecialchars(trim($default)) . " wrote:";
       
   834 return "\n<div class=\"bbcode_quote\">\n<div class=\"bbcode_quote_head\">"
       
   835 . $title . "</div>\n<div class=\"bbcode_quote_body\">"
       
   836 . $content . "</div>\n</div>\n";
       
   837 }
       
   838 function DoList($bbcode, $action, $name, $default, $params, $content) {
       
   839 $list_styles = Array(
       
   840 '1' => 'decimal',
       
   841 '01' => 'decimal-leading-zero',
       
   842 'i' => 'lower-roman',
       
   843 'I' => 'upper-roman',
       
   844 'a' => 'lower-alpha',
       
   845 'A' => 'upper-alpha',
       
   846 );
       
   847 $ci_list_styles = Array(
       
   848 'circle' => 'circle',
       
   849 'disc' => 'disc',
       
   850 'square' => 'square',
       
   851 'greek' => 'lower-greek',
       
   852 'armenian' => 'armenian',
       
   853 'georgian' => 'georgian',
       
   854 );
       
   855 $ul_types = Array(
       
   856 'circle' => 'circle',
       
   857 'disc' => 'disc',
       
   858 'square' => 'square',
       
   859 );
       
   860 $default = trim($default);
       
   861 if ($action == BBCODE_CHECK) {
       
   862 if (!is_string($default) || strlen($default) == "") return true;
       
   863 else if (isset($list_styles[$default])) return true;
       
   864 else if (isset($ci_list_styles[strtolower($default)])) return true;
       
   865 else return false;
       
   866 }
       
   867 if (!is_string($default) || strlen($default) == "") {
       
   868 $elem = 'ul';
       
   869 $type = '';
       
   870 }
       
   871 else if ($default == '1') {
       
   872 $elem = 'ol';
       
   873 $type = '';
       
   874 }
       
   875 else if (isset($list_styles[$default])) {
       
   876 $elem = 'ol';
       
   877 $type = $list_styles[$default];
       
   878 }
       
   879 else {
       
   880 $default = strtolower($default);
       
   881 if (isset($ul_types[$default])) {
       
   882 $elem = 'ul';
       
   883 $type = $ul_types[$default];
       
   884 }
       
   885 else if (isset($ci_list_styles[$default])) {
       
   886 $elem = 'ol';
       
   887 $type = $ci_list_styles[$default];
       
   888 }
       
   889 }
       
   890 if (strlen($type))
       
   891 return "\n<$elem class=\"bbcode_list\" style=\"list-style-type:$type\">\n$content</$elem>\n";
       
   892 else return "\n<$elem class=\"bbcode_list\">\n$content</$elem>\n";
       
   893 }
       
   894 }
       
   895 
       
   896 class BBCodeEmailAddressValidator {
       
   897 function check_email_address($strEmailAddress) {
       
   898 if (preg_match('/[\x00-\x1F\x7F-\xFF]/', $strEmailAddress)) {
       
   899 return false;
       
   900 }
       
   901 $intAtSymbol = strrpos($strEmailAddress, '@');
       
   902 if ($intAtSymbol === false) {
       
   903 return false;
       
   904 }
       
   905 $arrEmailAddress[0] = substr($strEmailAddress, 0, $intAtSymbol);
       
   906 $arrEmailAddress[1] = substr($strEmailAddress, $intAtSymbol + 1);
       
   907 $arrTempAddress[0] = preg_replace('/"[^"]+"/'
       
   908 ,''
       
   909 ,$arrEmailAddress[0]);
       
   910 $arrTempAddress[1] = $arrEmailAddress[1];
       
   911 $strTempAddress = $arrTempAddress[0] . $arrTempAddress[1];
       
   912 if (strrpos($strTempAddress, '@') !== false) {
       
   913 return false;
       
   914 }
       
   915 if (!$this->check_local_portion($arrEmailAddress[0])) {
       
   916 return false;
       
   917 }
       
   918 if (!$this->check_domain_portion($arrEmailAddress[1])) {
       
   919 return false;
       
   920 }
       
   921 return true;
       
   922 }
       
   923 function check_local_portion($strLocalPortion) {
       
   924 if (!$this->check_text_length($strLocalPortion, 1, 64)) {
       
   925 return false;
       
   926 }
       
   927 $arrLocalPortion = explode('.', $strLocalPortion);
       
   928 for ($i = 0, $max = sizeof($arrLocalPortion); $i < $max; $i++) {
       
   929 if (!preg_match('.^('
       
   930 . '([A-Za-z0-9!#$%&\'*+/=?^_`{|}~-]'
       
   931 . '[A-Za-z0-9!#$%&\'*+/=?^_`{|}~-]{0,63})'
       
   932 .'|'
       
   933 . '("[^\\\"]{0,62}")'
       
   934 .')$.'
       
   935 ,$arrLocalPortion[$i])) {
       
   936 return false;
       
   937 }
       
   938 }
       
   939 return true;
       
   940 }
       
   941 function check_domain_portion($strDomainPortion) {
       
   942 if (!$this->check_text_length($strDomainPortion, 1, 255)) {
       
   943 return false;
       
   944 }
       
   945 if (preg_match('/^(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])'
       
   946 .'(\.(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])){3}$/'
       
   947 ,$strDomainPortion) ||
       
   948 preg_match('/^\[(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])'
       
   949 .'(\.(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])){3}\]$/'
       
   950 ,$strDomainPortion)) {
       
   951 return true;
       
   952 } else {
       
   953 $arrDomainPortion = explode('.', $strDomainPortion);
       
   954 if (sizeof($arrDomainPortion) < 2) {
       
   955 return false;
       
   956 }
       
   957 for ($i = 0, $max = sizeof($arrDomainPortion); $i < $max; $i++) {
       
   958 if (!$this->check_text_length($arrDomainPortion[$i], 1, 63)) {
       
   959 return false;
       
   960 }
       
   961 if (!preg_match('/^(([A-Za-z0-9][A-Za-z0-9-]{0,61}[A-Za-z0-9])|'
       
   962 .'([A-Za-z0-9]+))$/', $arrDomainPortion[$i])) {
       
   963 return false;
       
   964 }
       
   965 }
       
   966 }
       
   967 return true;
       
   968 }
       
   969 function check_text_length($strText, $intMinimum, $intMaximum) {
       
   970 $intTextLength = strlen($strText);
       
   971 if (($intTextLength < $intMinimum) || ($intTextLength > $intMaximum)) {
       
   972 return false;
       
   973 } else {
       
   974 return true;
       
   975 }
       
   976 }
       
   977 }
       
   978 
       
   979 class BBCode {
       
   980 var $tag_rules;
       
   981 var $defaults;
       
   982 var $current_class;
       
   983 var $root_class;
       
   984 var $lost_start_tags;
       
   985 var $start_tags;
       
   986 var $allow_ampersand;
       
   987 var $tag_marker;
       
   988 var $ignore_newlines;
       
   989 var $plain_mode;
       
   990 var $detect_urls;
       
   991 var $url_pattern;
       
   992 var $output_limit;
       
   993 var $text_length;
       
   994 var $was_limited;
       
   995 var $limit_tail;
       
   996 var $limit_precision;
       
   997 var $smiley_dir;
       
   998 var $smiley_url;
       
   999 var $smileys;
       
  1000 var $smiley_regex;
       
  1001 var $enable_smileys;
       
  1002 var $wiki_url;
       
  1003 var $local_img_dir;
       
  1004 var $local_img_url;
       
  1005 var $url_targetable;
       
  1006 var $url_target;
       
  1007 var $rule_html;
       
  1008 var $pre_trim;
       
  1009 var $post_trim;
       
  1010 var $debug;
       
  1011 
       
  1012 
       
  1013 /* ADDED */
       
  1014 // singleton instance
       
  1015 private static $instance;
       
  1016 
       
  1017 // private constructor function
       
  1018 // to prevent external instantiation
       
  1019 private function __construct()
       
  1020 {
       
  1021 	$this->defaults = new BBCodeLibrary;
       
  1022 	$this->tag_rules = $this->defaults->default_tag_rules;
       
  1023 	$this->smileys = $this->defaults->default_smileys;
       
  1024 	$this->enable_smileys = true;
       
  1025 	$this->smiley_regex = false;
       
  1026 	$this->smiley_dir = $this->GetDefaultSmileyDir();
       
  1027 	$this->smiley_url = $this->GetDefaultSmileyURL();
       
  1028 	$this->wiki_url = $this->GetDefaultWikiURL();
       
  1029 	$this->local_img_dir = $this->GetDefaultLocalImgDir();
       
  1030 	$this->local_img_url = $this->GetDefaultLocalImgURL();
       
  1031 	$this->rule_html = $this->GetDefaultRuleHTML();
       
  1032 	$this->pre_trim = "";
       
  1033 	$this->post_trim = "";
       
  1034 	$this->root_class = 'block';
       
  1035 	$this->lost_start_tags = Array();
       
  1036 	$this->start_tags = Array();
       
  1037 	$this->tag_marker = '[';
       
  1038 	$this->allow_ampsersand = false;
       
  1039 	$this->current_class = $this->root_class;
       
  1040 	$this->debug = false;
       
  1041 	$this->ignore_newlines = false;
       
  1042 	$this->output_limit = 0;
       
  1043 	$this->plain_mode = false;
       
  1044 	$this->was_limited = false;
       
  1045 	$this->limit_tail = "...";
       
  1046 	$this->limit_precision = 0.15;
       
  1047 	$this->detect_urls = false;
       
  1048 	$this->url_pattern = '<a href="{$url/h}">{$text/h}</a>';
       
  1049 	$this->url_targetable = false;
       
  1050 	$this->url_target = false;
       
  1051 }
       
  1052 
       
  1053 // getInstance method
       
  1054 public static function getInstance()
       
  1055 {
       
  1056     if(!self::$instance)
       
  1057     {
       
  1058       self::$instance = new self();
       
  1059     }
       
  1060 
       
  1061     return self::$instance;
       
  1062 }
       
  1063 /* ADDED */
       
  1064 
       
  1065 
       
  1066 function SetPreTrim($trim = "a") { $this->pre_trim = $trim; }
       
  1067 function GetPreTrim() { return $this->pre_trim; }
       
  1068 function SetPostTrim($trim = "a") { $this->post_trim = $trim; }
       
  1069 function GetPostTrim() { return $this->post_trim; }
       
  1070 function SetRoot($class = 'block') { $this->root_class = $class; }
       
  1071 function SetRootInline() { $this->root_class = 'inline'; }
       
  1072 function SetRootBlock() { $this->root_class = 'block'; }
       
  1073 function GetRoot() { return $this->root_class; }
       
  1074 function SetDebug($enable = true) { $this->debug = $enable; }
       
  1075 function GetDebug() { return $this->debug; }
       
  1076 function SetAllowAmpersand($enable = true) { $this->allow_ampersand = $enable; }
       
  1077 function GetAllowAmpersand() { return $this->allow_ampersand; }
       
  1078 function SetTagMarker($marker = '[') { $this->tag_marker = $marker; }
       
  1079 function GetTagMarker() { return $this->tag_marker; }
       
  1080 function SetIgnoreNewlines($ignore = true) { $this->ignore_newlines = $ignore; }
       
  1081 function GetIgnoreNewlines() { return $this->ignore_newlines; }
       
  1082 function SetLimit($limit = 0) { $this->output_limit = $limit; }
       
  1083 function GetLimit() { return $this->output_limit; }
       
  1084 function SetLimitTail($tail = "...") { $this->limit_tail = $tail; }
       
  1085 function GetLimitTail() { return $this->limit_tail; }
       
  1086 function SetLimitPrecision($prec = 0.15) { $this->limit_precision = $prec; }
       
  1087 function GetLimitPrecision() { return $this->limit_precision; }
       
  1088 function WasLimited() { return $this->was_limited; }
       
  1089 function SetPlainMode($enable = true) { $this->plain_mode = $enable; }
       
  1090 function GetPlainMode() { return $this->plain_mode; }
       
  1091 function SetDetectURLs($enable = true) { $this->detect_urls = $enable; }
       
  1092 function GetDetectURLs() { return $this->detect_urls; }
       
  1093 function SetURLPattern($pattern) { $this->url_pattern = $pattern; }
       
  1094 function GetURLPattern() { return $this->url_pattern; }
       
  1095 function SetURLTargetable($enable) { $this->url_targetable = $enable; }
       
  1096 function GetURLTargetable() { return $this->url_targetable; }
       
  1097 function SetURLTarget($target) { $this->url_target = $target; }
       
  1098 function GetURLTarget() { return $this->url_target; }
       
  1099 function AddRule($name, $rule) { $this->tag_rules[$name] = $rule; }
       
  1100 function RemoveRule($name) { unset($this->tag_rules[$name]); }
       
  1101 function GetRule($name) { return isset($this->tag_rules[$name])
       
  1102 ? $this->tag_rules[$name] : false; }
       
  1103 function ClearRules() { $this->tag_rules = Array(); }
       
  1104 function GetDefaultRule($name) { return isset($this->defaults->default_tag_rules[$name])
       
  1105 ? $this->defaults->default_tag_rules[$name] : false; }
       
  1106 function SetDefaultRule($name) { if (isset($this->defaults->default_tag_rules[$name]))
       
  1107 $this->AddRule($name, $this->defaults->default_tag_rules[$name]);
       
  1108 else $this->RemoveRule($name); }
       
  1109 function GetDefaultRules() { return $this->defaults->default_tag_rules; }
       
  1110 function SetDefaultRules() { $this->tag_rules = $this->defaults->default_tag_rules; }
       
  1111 function SetWikiURL($url) { $this->wiki_url = $url; }
       
  1112 function GetWikiURL($url) { return $this->wiki_url; }
       
  1113 function GetDefaultWikiURL() { return '/?page='; }
       
  1114 function SetLocalImgDir($path) { $this->local_img_dir = $path; }
       
  1115 function GetLocalImgDir() { return $this->local_img_dir; }
       
  1116 function GetDefaultLocalImgDir() { return "img"; }
       
  1117 function SetLocalImgURL($path) { $this->local_img_url = $path; }
       
  1118 function GetLocalImgURL() { return $this->local_img_url; }
       
  1119 function GetDefaultLocalImgURL() { return "img"; }
       
  1120 function SetRuleHTML($html) { $this->rule_html = $html; }
       
  1121 function GetRuleHTML() { return $this->rule_html; }
       
  1122 function GetDefaultRuleHTML() { return "\n<hr class=\"bbcode_rule\" />\n"; }
       
  1123 function AddSmiley($code, $image) { $this->smileys[$code] = $image; $this->smiley_regex = false; }
       
  1124 function RemoveSmiley($code) { unset($this->smileys[$code]); $this->smiley_regex = false; }
       
  1125 function GetSmiley($code) { return isset($this->smileys[$code])
       
  1126 ? $this->smileys[$code] : false; }
       
  1127 function ClearSmileys() { $this->smileys = Array(); $this->smiley_regex = false; }
       
  1128 function GetDefaultSmiley($code) { return isset($this->defaults->default_smileys[$code])
       
  1129 ? $this->defaults->default_smileys[$code] : false; }
       
  1130 function SetDefaultSmiley($code) { $this->smileys[$code] = @$this->defaults->default_smileys[$code];
       
  1131 $this->smiley_regex = false; }
       
  1132 function GetDefaultSmileys() { return $this->defaults->default_smileys; }
       
  1133 function SetDefaultSmileys() { $this->smileys = $this->defaults->default_smileys;
       
  1134 $this->smiley_regex = false; }
       
  1135 function SetSmileyDir($path) { $this->smiley_dir = $path; }
       
  1136 function GetSmileyDir() { return $this->smiley_dir; }
       
  1137 function GetDefaultSmileyDir() { return "smileys"; }
       
  1138 function SetSmileyURL($path) { $this->smiley_url = $path; }
       
  1139 function GetSmileyURL() { return $this->smiley_url; }
       
  1140 function GetDefaultSmileyURL() { return "smileys"; }
       
  1141 function SetEnableSmileys($enable = true) { $this->enable_smileys = $enable; }
       
  1142 function GetEnableSmileys() { return $this->enable_smileys; }
       
  1143 function nl2br($string) {
       
  1144 return preg_replace("/\\x0A|\\x0D|\\x0A\\x0D|\\x0D\\x0A/", "<br />\n", $string);
       
  1145 }
       
  1146 function UnHTMLEncode($string) {
       
  1147 if (function_exists("html_entity_decode"))
       
  1148 return html_entity_decode($string);
       
  1149 $string = preg_replace('~&#x([0-9a-f]+);~ei', 'chr(hexdec("\\1"))', $string);
       
  1150 $string = preg_replace('~&#([0-9]+);~e', 'chr("\\1")', $string);
       
  1151 $trans_tbl = get_html_translation_table(HTML_ENTITIES);
       
  1152 $trans_tbl = array_flip($trans_tbl);
       
  1153 return strtr($string, $trans_tbl);
       
  1154 }
       
  1155 function Wikify($string) {
       
  1156 return rawurlencode(str_replace(" ", "_",
       
  1157 trim(preg_replace("/[!?;@#\$%\\^&*<>=+`~\\x00-\\x20_-]+/", " ", $string))));
       
  1158 }
       
  1159 function IsValidURL($string, $email_too = true) {
       
  1160 if (preg_match("/^
       
  1161 (?:https?|ftp):\\/\\/
       
  1162 (?:
       
  1163 (?:[a-zA-Z0-9](?:[a-zA-Z0-9-]*[a-zA-Z0-9])?\\.)+
       
  1164 [a-zA-Z0-9]
       
  1165 (?:[a-zA-Z0-9-]*[a-zA-Z0-9])?
       
  1166 |
       
  1167 \\[
       
  1168 (?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}
       
  1169 (?:
       
  1170 25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?|[a-zA-Z0-9-]*[a-zA-Z0-9]:
       
  1171 (?:[\\x01-\\x08\\x0B\\x0C\\x0E-\\x1F\\x21-\\x5A\\x53-\\x7F]
       
  1172 |\\\\[\\x01-\\x09\\x0B\\x0C\\x0E-\\x7F])+
       
  1173 )
       
  1174 \\]
       
  1175 )
       
  1176 (?::[0-9]{1,5})?
       
  1177 (?:[\\/\\?\\#][^\\n\\r]*)?
       
  1178 $/Dx", $string)) return true;
       
  1179 if (preg_match("/^[^:]+([\\/\\\\?#][^\\r\\n]*)?$/D", $string))
       
  1180 return true;
       
  1181 if ($email_too)
       
  1182 if (substr($string, 0, 7) == "mailto:")
       
  1183 return $this->IsValidEmail(substr($string, 7));
       
  1184 return false;
       
  1185 }
       
  1186 function IsValidEmail($string) {
       
  1187 $validator = new BBCodeEmailAddressValidator;
       
  1188 return $validator->check_email_address($string);
       
  1189 /*
       
  1190 return preg_match("/^
       
  1191 (?:
       
  1192 [a-z0-9\\!\\#\\\$\\%\\&\\'\\*\\+\\/=\\?\\^_`\\{\\|\\}~-]+
       
  1193 (?:\.[a-z0-9\\!\\#\\\$\\%\\&\\'\\*\\+\\/=\\?\\^_`\\{\\|\\}~-]+)*
       
  1194 |
       
  1195 \"(?:[\\x01-\\x08\\x0B\\x0C\\x0E-\\x1F\\x21\\x23-\\x5B\\x5D-\\x7F]
       
  1196 |\\\\[\\x01-\\x09\\x0B\\x0C\\x0E-\\x7F])*\"
       
  1197 )
       
  1198 @
       
  1199 (?:
       
  1200 (?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+
       
  1201 [a-z0-9]
       
  1202 (?:[a-z0-9-]*[a-z0-9])?
       
  1203 |
       
  1204 \\[
       
  1205 (?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}
       
  1206 (?:
       
  1207 25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?|[a-z0-9-]*[a-z0-9]:
       
  1208 (?:[\\x01-\\x08\\x0B\\x0C\\x0E-\\x1F\\x21-\\x5A\\x53-\\x7F]
       
  1209 |\\\\[\\x01-\\x09\\x0B\\x0C\\x0E-\\x7F])+
       
  1210 )
       
  1211 \\]
       
  1212 )
       
  1213 $/Dx", $string);
       
  1214 */
       
  1215 }
       
  1216 function HTMLEncode($string) {
       
  1217 if (!$this->allow_ampersand)
       
  1218 return htmlspecialchars($string);
       
  1219 else return str_replace(Array('<', '>', '"'),
       
  1220 Array('&lt;', '&gt;', '&quot;'), $string);
       
  1221 }
       
  1222 function FixupOutput($string) {
       
  1223 if (!$this->detect_urls) {
       
  1224 $output = $this->Internal_ProcessSmileys($string);
       
  1225 }
       
  1226 else {
       
  1227 $chunks = $this->Internal_AutoDetectURLs($string);
       
  1228 $output = Array();
       
  1229 if (count($chunks)) {
       
  1230 $is_a_url = false;
       
  1231 foreach ($chunks as $index => $chunk) {
       
  1232 if (!$is_a_url) {
       
  1233 $chunk = $this->Internal_ProcessSmileys($chunk);
       
  1234 }
       
  1235 $output[] = $chunk;
       
  1236 $is_a_url = !$is_a_url;
       
  1237 }
       
  1238 }
       
  1239 $output = implode("", $output);
       
  1240 }
       
  1241 return $output;
       
  1242 }
       
  1243 function Internal_ProcessSmileys($string) {
       
  1244 if (!$this->enable_smileys || $this->plain_mode) {
       
  1245 $output = $this->HTMLEncode($string);
       
  1246 }
       
  1247 else {
       
  1248 if ($this->smiley_regex === false) {
       
  1249 $this->Internal_RebuildSmileys();
       
  1250 }
       
  1251 $tokens = preg_split($this->smiley_regex, $string, -1, PREG_SPLIT_DELIM_CAPTURE);
       
  1252 if (count($tokens) <= 1) {
       
  1253 $output = $this->HTMLEncode($string);
       
  1254 }
       
  1255 else {
       
  1256 $output = "";
       
  1257 $is_a_smiley = false;
       
  1258 foreach ($tokens as $token) {
       
  1259 if (!$is_a_smiley) {
       
  1260 $output .= $this->HTMLEncode($token);
       
  1261 }
       
  1262 else {
       
  1263 if (isset($this->smiley_info[$token])) {
       
  1264 $info = $this->smiley_info[$token];
       
  1265 }
       
  1266 else {
       
  1267 $info = @getimagesize($this->smiley_dir . '/' . $this->smileys[$token]);
       
  1268 $this->smiley_info[$token] = $info;
       
  1269 }
       
  1270 $alt = htmlspecialchars($token);
       
  1271 $output .= "<img src=\"" . htmlspecialchars($this->smiley_url . '/' . $this->smileys[$token])
       
  1272 . "\" width=\"{$info[0]}\" height=\"{$info[1]}\""
       
  1273 . " alt=\"$alt\" title=\"$alt\" class=\"bbcode_smiley\" />";
       
  1274 }
       
  1275 $is_a_smiley = !$is_a_smiley;
       
  1276 }
       
  1277 }
       
  1278 }
       
  1279 return $output;
       
  1280 }
       
  1281 function Internal_RebuildSmileys() {
       
  1282 $regex = Array("/(?<![\\w])(");
       
  1283 $first = true;
       
  1284 foreach ($this->smileys as $code => $filename) {
       
  1285 if (!$first) $regex[] = "|";
       
  1286 $regex[] = preg_quote("$code", '/');
       
  1287 $first = false;
       
  1288 }
       
  1289 $regex[] = ")(?![\\w])/";
       
  1290 $this->smiley_regex = implode("", $regex);
       
  1291 }
       
  1292 function Internal_AutoDetectURLs($string) {
       
  1293 $output = preg_split("/( (?:
       
  1294 (?:https?|ftp) : \\/*
       
  1295 (?:
       
  1296 (?: (?: [a-zA-Z0-9-]{2,} \\. )+
       
  1297 (?: arpa | com | org | net | edu | gov | mil | int | [a-z]{2}
       
  1298 | aero | biz | coop | info | museum | name | pro
       
  1299 | example | invalid | localhost | test | local | onion | swift ) )
       
  1300 | (?: [0-9]{1,3} \\. [0-9]{1,3} \\. [0-9]{1,3} \\. [0-9]{1,3} )
       
  1301 | (?: [0-9A-Fa-f:]+ : [0-9A-Fa-f]{1,4} )
       
  1302 )
       
  1303 (?: : [0-9]+ )?
       
  1304 (?! [a-zA-Z0-9.:-] )
       
  1305 (?:
       
  1306 \\/
       
  1307 [^&?#\\(\\)\\[\\]\\{\\}<>\\'\\\"\\x00-\\x20\\x7F-\\xFF]*
       
  1308 )?
       
  1309 (?:
       
  1310 [?#]
       
  1311 [^\\(\\)\\[\\]\\{\\}<>\\'\\\"\\x00-\\x20\\x7F-\\xFF]+
       
  1312 )?
       
  1313 ) | (?:
       
  1314 (?:
       
  1315 (?: (?: [a-zA-Z0-9-]{2,} \\. )+
       
  1316 (?: arpa | com | org | net | edu | gov | mil | int | [a-z]{2}
       
  1317 | aero | biz | coop | info | museum | name | pro
       
  1318 | example | invalid | localhost | test | local | onion | swift ) )
       
  1319 | (?: [0-9]{1,3} \\. [0-9]{1,3} \\. [0-9]{1,3} \\. [0-9]{1,3} )
       
  1320 )
       
  1321 (?: : [0-9]+ )?
       
  1322 (?! [a-zA-Z0-9.:-] )
       
  1323 (?:
       
  1324 \\/
       
  1325 [^&?#\\(\\)\\[\\]\\{\\}<>\\'\\\"\\x00-\\x20\\x7F-\\xFF]*
       
  1326 )?
       
  1327 (?:
       
  1328 [?#]
       
  1329 [^\\(\\)\\[\\]\\{\\}<>\\'\\\"\\x00-\\x20\\x7F-\\xFF]+
       
  1330 )?
       
  1331 ) | (?:
       
  1332 [a-zA-Z0-9._-]{2,} @
       
  1333 (?:
       
  1334 (?: (?: [a-zA-Z0-9-]{2,} \\. )+
       
  1335 (?: arpa | com | org | net | edu | gov | mil | int | [a-z]{2}
       
  1336 | aero | biz | coop | info | museum | name | pro
       
  1337 | example | invalid | localhost | test | local | onion | swift ) )
       
  1338 | (?: [0-9]{1,3} \\. [0-9]{1,3} \\. [0-9]{1,3} \\. [0-9]{1,3} )
       
  1339 )
       
  1340 ) )/Dx", $string, -1, PREG_SPLIT_DELIM_CAPTURE);
       
  1341 if (count($output) > 1) {
       
  1342 $is_a_url = false;
       
  1343 foreach ($output as $index => $token) {
       
  1344 if ($is_a_url) {
       
  1345 if (preg_match("/^[a-zA-Z0-9._-]{2,}@/", $token)) {
       
  1346 $url = "mailto:" . $token;
       
  1347 }
       
  1348 else if (preg_match("/^(https?:|ftp:)\\/*([^\\/&?#]+)\\/*(.*)\$/", $token, $matches)) {
       
  1349 $url = $matches[1] . '/' . '/' . $matches[2] . "/" . $matches[3];
       
  1350 }
       
  1351 else {
       
  1352 preg_match("/^([^\\/&?#]+)\\/*(.*)\$/", $token, $matches);
       
  1353 $url = "http:/" . "/" . $matches[1] . "/" . $matches[2];
       
  1354 }
       
  1355 $params = @parse_url($url);
       
  1356 if (!is_array($params)) $params = Array();
       
  1357 $params['url'] = $url;
       
  1358 $params['link'] = $url;
       
  1359 $params['text'] = $token;
       
  1360 $output[$index] = $this->FillTemplate($this->url_pattern, $params);
       
  1361 }
       
  1362 $is_a_url = !$is_a_url;
       
  1363 }
       
  1364 }
       
  1365 return $output;
       
  1366 }
       
  1367 function FillTemplate($template, $insert_array, $default_array = Array()) {
       
  1368 $pieces = preg_split('/(\{\$[a-zA-Z0-9_.:\/-]+\})/', $template,
       
  1369 -1, PREG_SPLIT_DELIM_CAPTURE);
       
  1370 if (count($pieces) <= 1)
       
  1371 return $template;
       
  1372 $result = Array();
       
  1373 $is_an_insert = false;
       
  1374 foreach ($pieces as $piece) {
       
  1375 if (!$is_an_insert) {
       
  1376 $result[] = $piece;
       
  1377 }
       
  1378 else if (!preg_match('/\{\$([a-zA-Z0-9_:-]+)((?:\\.[a-zA-Z0-9_:-]+)*)(?:\/([a-zA-Z0-9_:-]+))?\}/', $piece, $matches)) {
       
  1379 $result[] = $piece;
       
  1380 }
       
  1381 else {
       
  1382 if (isset($insert_array[$matches[1]]))
       
  1383 $value = @$insert_array[$matches[1]];
       
  1384 else $value = @$default_array[$matches[1]];
       
  1385 if (strlen(@$matches[2])) {
       
  1386 foreach (split(".", substr($matches[2], 1)) as $index) {
       
  1387 if (is_array($value))
       
  1388 $value = @$value[$index];
       
  1389 else if (is_object($value)) {
       
  1390 $value = (array)$value;
       
  1391 $value = @$value[$index];
       
  1392 }
       
  1393 else $value = "";
       
  1394 }
       
  1395 }
       
  1396 switch (gettype($value)) {
       
  1397 case 'boolean': $value = $value ? "true" : "false"; break;
       
  1398 case 'integer': $value = (string)$value; break;
       
  1399 case 'double': $value = (string)$value; break;
       
  1400 case 'string': break;
       
  1401 default: $value = ""; break;
       
  1402 }
       
  1403 if (strlen(@$matches[3]))
       
  1404 $flags = array_flip(str_split($matches[3]));
       
  1405 else $flags = Array();
       
  1406 if (!isset($flags['v'])) {
       
  1407 if (isset($flags['w']))
       
  1408 $value = preg_replace("/[\\x00-\\x09\\x0B-\x0C\x0E-\\x20]+/", " ", $value);
       
  1409 if (isset($flags['t'])) $value = trim($value);
       
  1410 if (isset($flags['b'])) $value = basename($value);
       
  1411 if (isset($flags['e'])) $value = $this->HTMLEncode($value);
       
  1412 else if (isset($flags['k'])) $value = $this->Wikify($value);
       
  1413 else if (isset($flags['h'])) $value = htmlspecialchars($value);
       
  1414 else if (isset($flags['u'])) $value = urlencode($value);
       
  1415 if (isset($flags['n'])) $value = $this->nl2br($value);
       
  1416 }
       
  1417 $result[] = $value;
       
  1418 }
       
  1419 $is_an_insert = !$is_an_insert;
       
  1420 }
       
  1421 return implode("", $result);
       
  1422 }
       
  1423 function Internal_CollectText($array, $start = 0) {
       
  1424 ob_start();
       
  1425 for ($start = intval($start), $end = count($array); $start < $end; $start++)
       
  1426 print $array[$start][BBCODE_STACK_TEXT];
       
  1427 $output = ob_get_contents();
       
  1428 ob_end_clean();
       
  1429 return $output;
       
  1430 }
       
  1431 function Internal_CollectTextReverse($array, $start = 0, $end = 0) {
       
  1432 ob_start();
       
  1433 for ($start = intval($start); $start >= $end; $start--)
       
  1434 print $array[$start][BBCODE_STACK_TEXT];
       
  1435 $output = ob_get_contents();
       
  1436 ob_end_clean();
       
  1437 return $output;
       
  1438 }
       
  1439 function Internal_GenerateOutput($pos) {
       
  1440 $output = Array();
       
  1441 while (count($this->stack) > $pos) {
       
  1442 $token = array_pop($this->stack);
       
  1443 if ($token[BBCODE_STACK_TOKEN] != BBCODE_TAG) {
       
  1444 $output[] = $token;
       
  1445 }
       
  1446 else {
       
  1447 $name = @$token[BBCODE_STACK_TAG]['_name'];
       
  1448 $rule = @$this->tag_rules[$name];
       
  1449 $end_tag = @$rule['end_tag'];
       
  1450 if (!isset($rule['end_tag'])) $end_tag = BBCODE_REQUIRED;
       
  1451 else $end_tag = $rule['end_tag'];
       
  1452 array_pop($this->start_tags[$name]);
       
  1453 if ($end_tag == BBCODE_PROHIBIT) {
       
  1454 $output[] = Array(
       
  1455 BBCODE_STACK_TOKEN => BBCODE_TEXT,
       
  1456 BBCODE_STACK_TAG => false,
       
  1457 BBCODE_STACK_TEXT => $token[BBCODE_STACK_TEXT],
       
  1458 BBCODE_STACK_CLASS => $this->current_class,
       
  1459 );
       
  1460 }
       
  1461 else {
       
  1462 if ($end_tag == BBCODE_REQUIRED)
       
  1463 @$this->lost_start_tags[$name] += 1;
       
  1464 $end = $this->Internal_CleanupWSByIteratingPointer(@$rule['before_endtag'], 0, $output);
       
  1465 $this->Internal_CleanupWSByPoppingStack(@$rule['after_tag'], $output);
       
  1466 $tag_body = $this->Internal_CollectTextReverse($output, count($output)-1, $end);
       
  1467 $this->Internal_CleanupWSByPoppingStack(@$rule['before_tag'], $this->stack);
       
  1468 $this->Internal_UpdateParamsForMissingEndTag(@$token[BBCODE_STACK_TAG]);
       
  1469 $tag_output = $this->DoTag(BBCODE_OUTPUT, $name,
       
  1470 @$token[BBCODE_STACK_TAG]['_default'], @$token[BBCODE_STACK_TAG], $tag_body);
       
  1471 $output = Array(Array(
       
  1472 BBCODE_STACK_TOKEN => BBCODE_TEXT,
       
  1473 BBCODE_STACK_TAG => false,
       
  1474 BBCODE_STACK_TEXT => $tag_output,
       
  1475 BBCODE_STACK_CLASS => $this->current_class
       
  1476 ));
       
  1477 }
       
  1478 }
       
  1479 }
       
  1480 $this->Internal_ComputeCurrentClass();
       
  1481 return $output;
       
  1482 }
       
  1483 function Internal_RewindToClass($class_list) {
       
  1484 $pos = count($this->stack) - 1;
       
  1485 while ($pos >= 0 && !in_array($this->stack[$pos][BBCODE_STACK_CLASS], $class_list))
       
  1486 $pos--;
       
  1487 if ($pos < 0) {
       
  1488 if (!in_array($this->root_class, $class_list))
       
  1489 return false;
       
  1490 }
       
  1491 $output = $this->Internal_GenerateOutput($pos+1);
       
  1492 while (count($output)) {
       
  1493 $token = array_pop($output);
       
  1494 $token[BBCODE_STACK_CLASS] = $this->current_class;
       
  1495 $this->stack[] = $token;
       
  1496 }
       
  1497 return true;
       
  1498 }
       
  1499 function Internal_FinishTag($tag_name) {
       
  1500 if (strlen($tag_name) <= 0)
       
  1501 return false;
       
  1502 if (isset($this->start_tags[$tag_name])
       
  1503 && count($this->start_tags[$tag_name]))
       
  1504 $pos = array_pop($this->start_tags[$tag_name]);
       
  1505 else $pos = -1;
       
  1506 if ($pos < 0) return false;
       
  1507 $newpos = $this->Internal_CleanupWSByIteratingPointer(@$this->tag_rules[$tag_name]['after_tag'],
       
  1508 $pos+1, $this->stack);
       
  1509 $delta = $newpos - ($pos+1);
       
  1510 $output = $this->Internal_GenerateOutput($newpos);
       
  1511 $newend = $this->Internal_CleanupWSByIteratingPointer(@$this->tag_rules[$tag_name]['before_endtag'],
       
  1512 0, $output);
       
  1513 $output = $this->Internal_CollectTextReverse($output, count($output) - 1, $newend);
       
  1514 while ($delta-- > 0)
       
  1515 array_pop($this->stack);
       
  1516 $this->Internal_ComputeCurrentClass();
       
  1517 return $output;
       
  1518 }
       
  1519 function Internal_ComputeCurrentClass() {
       
  1520 if (count($this->stack) > 0)
       
  1521 $this->current_class = $this->stack[count($this->stack)-1][BBCODE_STACK_CLASS];
       
  1522 else $this->current_class = $this->root_class;
       
  1523 }
       
  1524 function Internal_DumpStack($array = false, $raw = false) {
       
  1525 if (!$raw) $string = "<span style='color: #00C;'>";
       
  1526 else $string = "";
       
  1527 if ($array === false)
       
  1528 $array = $this->stack;
       
  1529 foreach ($array as $item) {
       
  1530 switch (@$item[BBCODE_STACK_TOKEN]) {
       
  1531 case BBCODE_TEXT:
       
  1532 $string .= "\"" . htmlspecialchars(@$item[BBCODE_STACK_TEXT]) . "\" ";
       
  1533 break;
       
  1534 case BBCODE_WS:
       
  1535 $string .= "WS ";
       
  1536 break;
       
  1537 case BBCODE_NL:
       
  1538 $string .= "NL ";
       
  1539 break;
       
  1540 case BBCODE_TAG:
       
  1541 $string .= "[" . htmlspecialchars(@$item[BBCODE_STACK_TAG]['_name']) . "] ";
       
  1542 break;
       
  1543 default:
       
  1544 $string .= "unknown ";
       
  1545 break;
       
  1546 }
       
  1547 }
       
  1548 if (!$raw) $string .= "</span>";
       
  1549 return $string;
       
  1550 }
       
  1551 function Internal_CleanupWSByPoppingStack($pattern, &$array) {
       
  1552 if (strlen($pattern) <= 0) return;
       
  1553 $oldlen = count($array);
       
  1554 foreach (str_split($pattern) as $char) {
       
  1555 switch ($char) {
       
  1556 case 's':
       
  1557 while (count($array) > 0 && $array[count($array)-1][BBCODE_STACK_TOKEN] == BBCODE_WS)
       
  1558 array_pop($array);
       
  1559 break;
       
  1560 case 'n':
       
  1561 if (count($array) > 0 && $array[count($array)-1][BBCODE_STACK_TOKEN] == BBCODE_NL)
       
  1562 array_pop($array);
       
  1563 break;
       
  1564 case 'a':
       
  1565 while (count($array) > 0
       
  1566 && (($token = $array[count($array)-1][BBCODE_STACK_TOKEN]) == BBCODE_WS
       
  1567 || $token == BBCODE_NL))
       
  1568 array_pop($array);
       
  1569 break;
       
  1570 }
       
  1571 }
       
  1572 if (count($array) != $oldlen) {
       
  1573 $this->Internal_ComputeCurrentClass();
       
  1574 }
       
  1575 }
       
  1576 function Internal_CleanupWSByEatingInput($pattern) {
       
  1577 if (strlen($pattern) <= 0) return;
       
  1578 foreach (str_split($pattern) as $char) {
       
  1579 switch ($char) {
       
  1580 case 's':
       
  1581 $token_type = $this->lexer->NextToken();
       
  1582 while ($token_type == BBCODE_WS) {
       
  1583 $token_type = $this->lexer->NextToken();
       
  1584 }
       
  1585 $this->lexer->UngetToken();
       
  1586 break;
       
  1587 case 'n':
       
  1588 $token_type = $this->lexer->NextToken();
       
  1589 if ($token_type != BBCODE_NL)
       
  1590 $this->lexer->UngetToken();
       
  1591 break;
       
  1592 case 'a':
       
  1593 $token_type = $this->lexer->NextToken();
       
  1594 while ($token_type == BBCODE_WS || $token_type == BBCODE_NL) {
       
  1595 $token_type = $this->lexer->NextToken();
       
  1596 }
       
  1597 $this->lexer->UngetToken();
       
  1598 break;
       
  1599 }
       
  1600 }
       
  1601 }
       
  1602 function Internal_CleanupWSByIteratingPointer($pattern, $pos, $array) {
       
  1603 if (strlen($pattern) <= 0) return $pos;
       
  1604 foreach (str_split($pattern) as $char) {
       
  1605 switch ($char) {
       
  1606 case 's':
       
  1607 while ($pos < count($array) && $array[$pos][BBCODE_STACK_TOKEN] == BBCODE_WS)
       
  1608 $pos++;
       
  1609 break;
       
  1610 case 'n':
       
  1611 if ($pos < count($array) && $array[$pos][BBCODE_STACK_TOKEN] == BBCODE_NL)
       
  1612 $pos++;
       
  1613 break;
       
  1614 case 'a':
       
  1615 while ($pos < count($array)
       
  1616 && (($token = $array[$pos][BBCODE_STACK_TOKEN]) == BBCODE_WS || $token == BBCODE_NL))
       
  1617 $pos++;
       
  1618 break;
       
  1619 }
       
  1620 }
       
  1621 return $pos;
       
  1622 }
       
  1623 function Internal_LimitText($string, $limit) {
       
  1624 $chunks = preg_split("/([\\x00-\\x20]+)/", $string, -1, PREG_SPLIT_DELIM_CAPTURE);
       
  1625 $output = "";
       
  1626 foreach ($chunks as $chunk) {
       
  1627 if (strlen($output) + strlen($chunk) > $limit)
       
  1628 break;
       
  1629 $output .= $chunk;
       
  1630 }
       
  1631 $output = rtrim($output);
       
  1632 return $output;
       
  1633 }
       
  1634 function Internal_DoLimit() {
       
  1635 $this->Internal_CleanupWSByPoppingStack("a", $this->stack);
       
  1636 if (strlen($this->limit_tail) > 0) {
       
  1637 $this->stack[] = Array(
       
  1638 BBCODE_STACK_TOKEN => BBCODE_TEXT,
       
  1639 BBCODE_STACK_TEXT => $this->limit_tail,
       
  1640 BBCODE_STACK_TAG => false,
       
  1641 BBCODE_STACK_CLASS => $this->current_class,
       
  1642 );
       
  1643 }
       
  1644 $this->was_limited = true;
       
  1645 }
       
  1646 function DoTag($action, $tag_name, $default_value, $params, $contents) {
       
  1647 $tag_rule = @$this->tag_rules[$tag_name];
       
  1648 switch ($action) {
       
  1649 case BBCODE_CHECK:
       
  1650 if (isset($tag_rule['allow'])) {
       
  1651 foreach ($tag_rule['allow'] as $param => $pattern) {
       
  1652 if ($param == '_content') $value = $contents;
       
  1653 else if ($param == '_defaultcontent') {
       
  1654 if (strlen($default_value))
       
  1655 $value = $default_value;
       
  1656 else $value = $contents;
       
  1657 }
       
  1658 else {
       
  1659 if (isset($params[$param]))
       
  1660 $value = $params[$param];
       
  1661 else $value = @$tag_rule['default'][$param];
       
  1662 }
       
  1663 if (!preg_match($pattern, $value)) {
       
  1664 return false;
       
  1665 }
       
  1666 }
       
  1667 return true;
       
  1668 }
       
  1669 switch (@$tag_rule['mode']) {
       
  1670 default:
       
  1671 case BBCODE_MODE_SIMPLE:
       
  1672 $result = true;
       
  1673 break;
       
  1674 case BBCODE_MODE_ENHANCED:
       
  1675 $result = true;
       
  1676 break;
       
  1677 case BBCODE_MODE_INTERNAL:
       
  1678 $result = @call_user_func(Array($this, @$tag_rule['method']), BBCODE_CHECK,
       
  1679 $tag_name, $default_value, $params, $contents);
       
  1680 break;
       
  1681 case BBCODE_MODE_LIBRARY:
       
  1682 $result = @call_user_func(Array($this->defaults, @$tag_rule['method']), $this, BBCODE_CHECK,
       
  1683 $tag_name, $default_value, $params, $contents);
       
  1684 break;
       
  1685 case BBCODE_MODE_CALLBACK:
       
  1686 $result = @call_user_func(@$tag_rule['method'], $this, BBCODE_CHECK,
       
  1687 $tag_name, $default_value, $params, $contents);
       
  1688 break;
       
  1689 }
       
  1690 return $result;
       
  1691 case BBCODE_OUTPUT:
       
  1692 if ($this->plain_mode) {
       
  1693 if (!isset($tag_rule['plain_content']))
       
  1694 $plain_content = Array('_content');
       
  1695 else $plain_content = $tag_rule['plain_content'];
       
  1696 $result = $possible_content = "";
       
  1697 foreach ($plain_content as $possible_content) {
       
  1698 if ($possible_content == '_content'
       
  1699 && strlen($contents) > 0) {
       
  1700 $result = $contents;
       
  1701 break;
       
  1702 }
       
  1703 if (isset($params[$possible_content])
       
  1704 && strlen($params[$possible_content]) > 0) {
       
  1705 $result = htmlspecialchars($params[$possible_content]);
       
  1706 break;
       
  1707 }
       
  1708 }
       
  1709 $start = @$tag_rule['plain_start'];
       
  1710 $end = @$tag_rule['plain_end'];
       
  1711 if (isset($tag_rule['plain_link'])) {
       
  1712 $link = $possible_content = "";
       
  1713 foreach ($tag_rule['plain_link'] as $possible_content) {
       
  1714 if ($possible_content == '_content'
       
  1715 && strlen($contents) > 0) {
       
  1716 $link = $this->UnHTMLEncode(strip_tags($contents));
       
  1717 break;
       
  1718 }
       
  1719 if (isset($params[$possible_content])
       
  1720 && strlen($params[$possible_content]) > 0) {
       
  1721 $link = $params[$possible_content];
       
  1722 break;
       
  1723 }
       
  1724 }
       
  1725 $params = @parse_url($link);
       
  1726 if (!is_array($params)) $params = Array();
       
  1727 $params['link'] = $link;
       
  1728 $params['url'] = $link;
       
  1729 $start = $this->FillTemplate($start, $params);
       
  1730 $end = $this->FillTemplate($end, $params);
       
  1731 }
       
  1732 return $start . $result . $end;
       
  1733 }
       
  1734 switch (@$tag_rule['mode']) {
       
  1735 default:
       
  1736 case BBCODE_MODE_SIMPLE:
       
  1737 $result = @$tag_rule['simple_start'] . $contents . @$tag_rule['simple_end'];
       
  1738 break;
       
  1739 case BBCODE_MODE_ENHANCED:
       
  1740 $result = $this->Internal_DoEnhancedTag($tag_rule, $params, $contents);
       
  1741 break;
       
  1742 case BBCODE_MODE_INTERNAL:
       
  1743 $result = @call_user_func(Array($this, @$tag_rule['method']), BBCODE_OUTPUT,
       
  1744 $tag_name, $default_value, $params, $contents);
       
  1745 break;
       
  1746 case BBCODE_MODE_LIBRARY:
       
  1747 $result = @call_user_func(Array($this->defaults, @$tag_rule['method']), $this, BBCODE_OUTPUT,
       
  1748 $tag_name, $default_value, $params, $contents);
       
  1749 break;
       
  1750 case BBCODE_MODE_CALLBACK:
       
  1751 $result = @call_user_func(@$tag_rule['method'], $this, BBCODE_OUTPUT,
       
  1752 $tag_name, $default_value, $params, $contents);
       
  1753 break;
       
  1754 }
       
  1755 return $result;
       
  1756 default:
       
  1757 return false;
       
  1758 }
       
  1759 }
       
  1760 function Internal_DoEnhancedTag($tag_rule, $params, $contents) {
       
  1761 $params['_content'] = $contents;
       
  1762 $params['_defaultcontent'] = strlen(@$params['_default']) ? $params['_default'] : $contents;
       
  1763 return $this->FillTemplate(@$tag_rule['template'], $params, @$tag_rule['default']);
       
  1764 }
       
  1765 function Internal_UpdateParamsForMissingEndTag(&$params) {
       
  1766 switch ($this->tag_marker) {
       
  1767 case '[': $tail_marker = ']'; break;
       
  1768 case '<': $tail_marker = '>'; break;
       
  1769 case '{': $tail_marker = '}'; break;
       
  1770 case '(': $tail_marker = ')'; break;
       
  1771 default: $tail_marker = $this->tag_marker; break;
       
  1772 }
       
  1773 $params['_endtag'] = $this->tag_marker . '/' . $params['_name'] . $tail_marker;
       
  1774 }
       
  1775 function Internal_ProcessIsolatedTag($tag_name, $tag_params, $tag_rule) {
       
  1776 if (!$this->DoTag(BBCODE_CHECK, $tag_name, @$tag_params['_default'], $tag_params, "")) {
       
  1777 $this->stack[] = Array(
       
  1778 BBCODE_STACK_TOKEN => BBCODE_TEXT,
       
  1779 BBCODE_STACK_TEXT => $this->FixupOutput($this->lexer->text),
       
  1780 BBCODE_STACK_TAG => false,
       
  1781 BBCODE_STACK_CLASS => $this->current_class,
       
  1782 );
       
  1783 return;
       
  1784 }
       
  1785 $this->Internal_CleanupWSByPoppingStack(@$tag_rule['before_tag'], $this->stack);
       
  1786 $output = $this->DoTag(BBCODE_OUTPUT, $tag_name, @$tag_params['_default'], $tag_params, "");
       
  1787 $this->Internal_CleanupWSByEatingInput(@$tag_rule['after_tag']);
       
  1788 $this->stack[] = Array(
       
  1789 BBCODE_STACK_TOKEN => BBCODE_TEXT,
       
  1790 BBCODE_STACK_TEXT => $output,
       
  1791 BBCODE_STACK_TAG => false,
       
  1792 BBCODE_STACK_CLASS => $this->current_class,
       
  1793 );
       
  1794 }
       
  1795 function Internal_ProcessVerbatimTag($tag_name, $tag_params, $tag_rule) {
       
  1796 $state = $this->lexer->SaveState();
       
  1797 $end_tag = $this->lexer->tagmarker . "/" . $tag_name . $this->lexer->end_tagmarker;
       
  1798 $start = count($this->stack);
       
  1799 $this->lexer->verbatim = true;
       
  1800 while (($token_type = $this->lexer->NextToken()) != BBCODE_EOI) {
       
  1801 if ($this->lexer->text == $end_tag) {
       
  1802 $end_tag_params = $this->lexer->tag;
       
  1803 break;
       
  1804 }
       
  1805 if ($this->output_limit > 0
       
  1806 && $this->text_length + strlen($this->lexer->text) >= $this->output_limit) {
       
  1807 $text = $this->Internal_LimitText($this->lexer->text,
       
  1808 $this->output_limit - $this->text_length);
       
  1809 if (strlen($text) > 0) {
       
  1810 $this->text_length += strlen($text);
       
  1811 $this->stack[] = Array(
       
  1812 BBCODE_STACK_TOKEN => BBCODE_TEXT,
       
  1813 BBCODE_STACK_TEXT => $this->FixupOutput($text),
       
  1814 BBCODE_STACK_TAG => false,
       
  1815 BBCODE_STACK_CLASS => $this->current_class,
       
  1816 );
       
  1817 }
       
  1818 $this->Internal_DoLimit();
       
  1819 break;
       
  1820 }
       
  1821 $this->text_length += strlen($this->lexer->text);
       
  1822 $this->stack[] = Array(
       
  1823 BBCODE_STACK_TOKEN => $token_type,
       
  1824 BBCODE_STACK_TEXT => htmlspecialchars($this->lexer->text),
       
  1825 BBCODE_STACK_TAG => $this->lexer->tag,
       
  1826 BBCODE_STACK_CLASS => $this->current_class,
       
  1827 );
       
  1828 }
       
  1829 $this->lexer->verbatim = false;
       
  1830 if ($token_type == BBCODE_EOI) {
       
  1831 $this->lexer->RestoreState($state);
       
  1832 $this->stack[] = Array(
       
  1833 BBCODE_STACK_TOKEN => BBCODE_TEXT,
       
  1834 BBCODE_STACK_TEXT => $this->FixupOutput($this->lexer->text),
       
  1835 BBCODE_STACK_TAG => false,
       
  1836 BBCODE_STACK_CLASS => $this->current_class,
       
  1837 );
       
  1838 return;
       
  1839 }
       
  1840 $newstart = $this->Internal_CleanupWSByIteratingPointer(@$tag_rule['after_tag'], $start, $this->stack);
       
  1841 $this->Internal_CleanupWSByPoppingStack(@$tag_rule['before_endtag'], $this->stack);
       
  1842 $this->Internal_CleanupWSByEatingInput(@$tag_rule['after_endtag']);
       
  1843 $content = $this->Internal_CollectText($this->stack, $newstart);
       
  1844 array_splice($this->stack, $start);
       
  1845 $this->Internal_ComputeCurrentClass();
       
  1846 $this->Internal_CleanupWSByPoppingStack(@$tag_rule['before_tag'], $this->stack);
       
  1847 $tag_params['_endtag'] = $end_tag_params['_tag'];
       
  1848 $tag_params['_hasend'] = true;
       
  1849 $output = $this->DoTag(BBCODE_OUTPUT, $tag_name,
       
  1850 @$tag_params['_default'], $tag_params, $content);
       
  1851 $this->stack[] = Array(
       
  1852 BBCODE_STACK_TOKEN => BBCODE_TEXT,
       
  1853 BBCODE_STACK_TEXT => $output,
       
  1854 BBCODE_STACK_TAG => false,
       
  1855 BBCODE_STACK_CLASS => $this->current_class,
       
  1856 );
       
  1857 }
       
  1858 function Internal_ParseStartTagToken() {
       
  1859 $tag_params = $this->lexer->tag;
       
  1860 $tag_name = @$tag_params['_name'];
       
  1861 if (!isset($this->tag_rules[$tag_name])) {
       
  1862 $this->stack[] = Array(
       
  1863 BBCODE_STACK_TOKEN => BBCODE_TEXT,
       
  1864 BBCODE_STACK_TEXT => $this->FixupOutput($this->lexer->text),
       
  1865 BBCODE_STACK_TAG => false,
       
  1866 BBCODE_STACK_CLASS => $this->current_class,
       
  1867 );
       
  1868 return;
       
  1869 }
       
  1870 $tag_rule = $this->tag_rules[$tag_name];
       
  1871 $allow_in = is_array($tag_rule['allow_in'])
       
  1872 ? $tag_rule['allow_in'] : Array($this->root_class);
       
  1873 if (!in_array($this->current_class, $allow_in)) {
       
  1874 if (!$this->Internal_RewindToClass($allow_in)) {
       
  1875 $this->stack[] = Array(
       
  1876 BBCODE_STACK_TOKEN => BBCODE_TEXT,
       
  1877 BBCODE_STACK_TEXT => $this->FixupOutput($this->lexer->text),
       
  1878 BBCODE_STACK_TAG => false,
       
  1879 BBCODE_STACK_CLASS => $this->current_class,
       
  1880 );
       
  1881 return;
       
  1882 }
       
  1883 }
       
  1884 $end_tag = isset($tag_rule['end_tag']) ? $tag_rule['end_tag'] : BBCODE_REQUIRED;
       
  1885 if ($end_tag == BBCODE_PROHIBIT) {
       
  1886 $this->Internal_ProcessIsolatedTag($tag_name, $tag_params, $tag_rule);
       
  1887 return;
       
  1888 }
       
  1889 if (!$this->DoTag(BBCODE_CHECK, $tag_name, @$tag_params['_default'], $tag_params, "")) {
       
  1890 $this->stack[] = Array(
       
  1891 BBCODE_STACK_TOKEN => BBCODE_TEXT,
       
  1892 BBCODE_STACK_TEXT => $this->FixupOutput($this->lexer->text),
       
  1893 BBCODE_STACK_TAG => false,
       
  1894 BBCODE_STACK_CLASS => $this->current_class,
       
  1895 );
       
  1896 return;
       
  1897 }
       
  1898 if (@$tag_rule['content'] == BBCODE_VERBATIM) {
       
  1899 $this->Internal_ProcessVerbatimTag($tag_name, $tag_params, $tag_rule);
       
  1900 return;
       
  1901 }
       
  1902 if (isset($tag_rule['class']))
       
  1903 $newclass = $tag_rule['class'];
       
  1904 else $newclass = $this->root_class;
       
  1905 $this->stack[] = Array(
       
  1906 BBCODE_STACK_TOKEN => $this->lexer->token,
       
  1907 BBCODE_STACK_TEXT => $this->FixupOutput($this->lexer->text),
       
  1908 BBCODE_STACK_TAG => $this->lexer->tag,
       
  1909 BBCODE_STACK_CLASS => ($this->current_class = $newclass),
       
  1910 );
       
  1911 if (!isset($this->start_tags[$tag_name]))
       
  1912 $this->start_tags[$tag_name] = Array(count($this->stack)-1);
       
  1913 else $this->start_tags[$tag_name][] = count($this->stack)-1;
       
  1914 }
       
  1915 function Internal_ParseEndTagToken() {
       
  1916 $tag_params = $this->lexer->tag;
       
  1917 $tag_name = @$tag_params['_name'];
       
  1918 $contents = $this->Internal_FinishTag($tag_name);
       
  1919 if ($contents === false) {
       
  1920 if (@$this->lost_start_tags[$tag_name] > 0) {
       
  1921 $this->lost_start_tags[$tag_name]--;
       
  1922 }
       
  1923 else {
       
  1924 $this->stack[] = Array(
       
  1925 BBCODE_STACK_TOKEN => BBCODE_TEXT,
       
  1926 BBCODE_STACK_TEXT => $this->FixupOutput($this->lexer->text),
       
  1927 BBCODE_STACK_TAG => false,
       
  1928 BBCODE_STACK_CLASS => $this->current_class,
       
  1929 );
       
  1930 }
       
  1931 return;
       
  1932 }
       
  1933 $start_tag_node = array_pop($this->stack);
       
  1934 $start_tag_params = $start_tag_node[BBCODE_STACK_TAG];
       
  1935 $this->Internal_ComputeCurrentClass();
       
  1936 $this->Internal_CleanupWSByPoppingStack(@$this->tag_rules[$tag_name]['before_tag'], $this->stack);
       
  1937 $start_tag_params['_endtag'] = $tag_params['_tag'];
       
  1938 $start_tag_params['_hasend'] = true;
       
  1939 $output = $this->DoTag(BBCODE_OUTPUT, $tag_name, @$start_tag_params['_default'],
       
  1940 $start_tag_params, $contents);
       
  1941 $this->Internal_CleanupWSByEatingInput(@$this->tag_rules[$tag_name]['after_endtag']);
       
  1942 $this->stack[] = Array(
       
  1943 BBCODE_STACK_TOKEN => BBCODE_TEXT,
       
  1944 BBCODE_STACK_TEXT => $output,
       
  1945 BBCODE_STACK_TAG => false,
       
  1946 BBCODE_STACK_CLASS => $this->current_class,
       
  1947 );
       
  1948 }
       
  1949 function Parse($string) {
       
  1950 $this->lexer = new BBCodeLexer($string, $this->tag_marker);
       
  1951 $this->lexer->debug = $this->debug;
       
  1952 $old_output_limit = $this->output_limit;
       
  1953 if ($this->output_limit > 0) {
       
  1954 if (strlen($string) < $this->output_limit) {
       
  1955 $this->output_limit = 0;
       
  1956 }
       
  1957 else if ($this->limit_precision > 0) {
       
  1958 $guess_length = $this->lexer->GuessTextLength();
       
  1959 if ($guess_length < $this->output_limit * ($this->limit_precision + 1.0)) {
       
  1960 $this->output_limit = 0;
       
  1961 }
       
  1962 else {
       
  1963 }
       
  1964 }
       
  1965 }
       
  1966 $this->stack = Array();
       
  1967 $this->start_tags = Array();
       
  1968 $this->lost_start_tags = Array();
       
  1969 $this->text_length = 0;
       
  1970 $this->was_limited = false;
       
  1971 if (strlen($this->pre_trim) > 0)
       
  1972 $this->Internal_CleanupWSByEatingInput($this->pre_trim);
       
  1973 $newline = $this->plain_mode ? "\n" : "<br />\n";
       
  1974 while (true) {
       
  1975 if (($token_type = $this->lexer->NextToken()) == BBCODE_EOI) {
       
  1976 break;
       
  1977 }
       
  1978 switch ($token_type) {
       
  1979 case BBCODE_TEXT:
       
  1980 if ($this->output_limit > 0
       
  1981 && $this->text_length + strlen($this->lexer->text) >= $this->output_limit) {
       
  1982 $text = $this->Internal_LimitText($this->lexer->text,
       
  1983 $this->output_limit - $this->text_length);
       
  1984 if (strlen($text) > 0) {
       
  1985 $this->text_length += strlen($text);
       
  1986 $this->stack[] = Array(
       
  1987 BBCODE_STACK_TOKEN => BBCODE_TEXT,
       
  1988 BBCODE_STACK_TEXT => $this->FixupOutput($text),
       
  1989 BBCODE_STACK_TAG => false,
       
  1990 BBCODE_STACK_CLASS => $this->current_class,
       
  1991 );
       
  1992 }
       
  1993 $this->Internal_DoLimit();
       
  1994 break 2;
       
  1995 }
       
  1996 $this->text_length += strlen($this->lexer->text);
       
  1997 $this->stack[] = Array(
       
  1998 BBCODE_STACK_TOKEN => BBCODE_TEXT,
       
  1999 BBCODE_STACK_TEXT => $this->FixupOutput($this->lexer->text),
       
  2000 BBCODE_STACK_TAG => false,
       
  2001 BBCODE_STACK_CLASS => $this->current_class,
       
  2002 );
       
  2003 break;
       
  2004 case BBCODE_WS:
       
  2005 if ($this->output_limit > 0
       
  2006 && $this->text_length + strlen($this->lexer->text) >= $this->output_limit) {
       
  2007 $this->Internal_DoLimit();
       
  2008 break 2;
       
  2009 }
       
  2010 $this->text_length += strlen($this->lexer->text);
       
  2011 $this->stack[] = Array(
       
  2012 BBCODE_STACK_TOKEN => BBCODE_WS,
       
  2013 BBCODE_STACK_TEXT => $this->lexer->text,
       
  2014 BBCODE_STACK_TAG => false,
       
  2015 BBCODE_STACK_CLASS => $this->current_class,
       
  2016 );
       
  2017 break;
       
  2018 case BBCODE_NL:
       
  2019 if ($this->ignore_newlines) {
       
  2020 if ($this->output_limit > 0
       
  2021 && $this->text_length + 1 >= $this->output_limit) {
       
  2022 $this->Internal_DoLimit();
       
  2023 break 2;
       
  2024 }
       
  2025 $this->text_length += 1;
       
  2026 $this->stack[] = Array(
       
  2027 BBCODE_STACK_TOKEN => BBCODE_WS,
       
  2028 BBCODE_STACK_TEXT => "\n",
       
  2029 BBCODE_STACK_TAG => false,
       
  2030 BBCODE_STACK_CLASS => $this->current_class,
       
  2031 );
       
  2032 }
       
  2033 else {
       
  2034 $this->Internal_CleanupWSByPoppingStack("s", $this->stack);
       
  2035 if ($this->output_limit > 0
       
  2036 && $this->text_length + 1 >= $this->output_limit) {
       
  2037 $this->Internal_DoLimit();
       
  2038 break 2;
       
  2039 }
       
  2040 $this->text_length += 1;
       
  2041 $this->stack[] = Array(
       
  2042 BBCODE_STACK_TOKEN => BBCODE_NL,
       
  2043 BBCODE_STACK_TEXT => $newline,
       
  2044 BBCODE_STACK_TAG => false,
       
  2045 BBCODE_STACK_CLASS => $this->current_class,
       
  2046 );
       
  2047 $this->Internal_CleanupWSByEatingInput("s");
       
  2048 }
       
  2049 break;
       
  2050 case BBCODE_TAG:
       
  2051 $this->Internal_ParseStartTagToken();
       
  2052 break;
       
  2053 case BBCODE_ENDTAG:
       
  2054 $this->Internal_ParseEndTagToken();
       
  2055 break;
       
  2056 default:
       
  2057 break;
       
  2058 }
       
  2059 }
       
  2060 if (strlen($this->post_trim) > 0)
       
  2061 $this->Internal_CleanupWSByPoppingStack($this->post_trim, $this->stack);
       
  2062 $result = $this->Internal_GenerateOutput(0);
       
  2063 $result = $this->Internal_CollectTextReverse($result, count($result) - 1);
       
  2064 $this->output_limit = $old_output_limit;
       
  2065 if ($this->plain_mode) {
       
  2066 $result = preg_replace("/[\\x00-\\x09\\x0B-\\x20]+/", " ", $result);
       
  2067 $result = preg_replace("/(?:[\\x20]*\\n){2,}[\\x20]*/", "\n\n", $result);
       
  2068 $result = trim($result);
       
  2069 }
       
  2070 return $result;
       
  2071 }
       
  2072 }
       
  2073