1<?php 2 3/** 4 * Converts a stream of HTMLPurifier_Token into an HTMLPurifier_Node, 5 * and back again. 6 * 7 * @note This transformation is not an equivalence. We mutate the input 8 * token stream to make it so; see all [MUT] markers in code. 9 */ 10class HTMLPurifier_Arborize 11{ 12 public static function arborize($tokens, $config, $context) { 13 $definition = $config->getHTMLDefinition(); 14 $parent = new HTMLPurifier_Token_Start($definition->info_parent); 15 $stack = array($parent->toNode()); 16 foreach ($tokens as $token) { 17 $token->skip = null; // [MUT] 18 $token->carryover = null; // [MUT] 19 if ($token instanceof HTMLPurifier_Token_End) { 20 $token->start = null; // [MUT] 21 $r = array_pop($stack); 22 //assert($r->name === $token->name); 23 //assert(empty($token->attr)); 24 $r->endCol = $token->col; 25 $r->endLine = $token->line; 26 $r->endArmor = $token->armor; 27 continue; 28 } 29 $node = $token->toNode(); 30 $stack[count($stack)-1]->children[] = $node; 31 if ($token instanceof HTMLPurifier_Token_Start) { 32 $stack[] = $node; 33 } 34 } 35 //assert(count($stack) == 1); 36 return $stack[0]; 37 } 38 39 public static function flatten($node, $config, $context) { 40 $level = 0; 41 $nodes = array($level => new HTMLPurifier_Queue(array($node))); 42 $closingTokens = array(); 43 $tokens = array(); 44 do { 45 while (!$nodes[$level]->isEmpty()) { 46 $node = $nodes[$level]->shift(); // FIFO 47 list($start, $end) = $node->toTokenPair(); 48 if ($level > 0) { 49 $tokens[] = $start; 50 } 51 if ($end !== NULL) { 52 $closingTokens[$level][] = $end; 53 } 54 if ($node instanceof HTMLPurifier_Node_Element) { 55 $level++; 56 $nodes[$level] = new HTMLPurifier_Queue(); 57 foreach ($node->children as $childNode) { 58 $nodes[$level]->push($childNode); 59 } 60 } 61 } 62 $level--; 63 if ($level && isset($closingTokens[$level])) { 64 while ($token = array_pop($closingTokens[$level])) { 65 $tokens[] = $token; 66 } 67 } 68 } while ($level > 0); 69 return $tokens; 70 } 71} 72