You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
170 lines
5.5 KiB
170 lines
5.5 KiB
<?php |
|
|
|
/** |
|
* @todo Unit test |
|
*/ |
|
class HTMLPurifier_ContentSets |
|
{ |
|
|
|
/** |
|
* List of content set strings (pipe separators) indexed by name. |
|
* @type array |
|
*/ |
|
public $info = array(); |
|
|
|
/** |
|
* List of content set lookups (element => true) indexed by name. |
|
* @type array |
|
* @note This is in HTMLPurifier_HTMLDefinition->info_content_sets |
|
*/ |
|
public $lookup = array(); |
|
|
|
/** |
|
* Synchronized list of defined content sets (keys of info). |
|
* @type array |
|
*/ |
|
protected $keys = array(); |
|
/** |
|
* Synchronized list of defined content values (values of info). |
|
* @type array |
|
*/ |
|
protected $values = array(); |
|
|
|
/** |
|
* Merges in module's content sets, expands identifiers in the content |
|
* sets and populates the keys, values and lookup member variables. |
|
* @param HTMLPurifier_HTMLModule[] $modules List of HTMLPurifier_HTMLModule |
|
*/ |
|
public function __construct($modules) |
|
{ |
|
if (!is_array($modules)) { |
|
$modules = array($modules); |
|
} |
|
// populate content_sets based on module hints |
|
// sorry, no way of overloading |
|
foreach ($modules as $module) { |
|
foreach ($module->content_sets as $key => $value) { |
|
$temp = $this->convertToLookup($value); |
|
if (isset($this->lookup[$key])) { |
|
// add it into the existing content set |
|
$this->lookup[$key] = array_merge($this->lookup[$key], $temp); |
|
} else { |
|
$this->lookup[$key] = $temp; |
|
} |
|
} |
|
} |
|
$old_lookup = false; |
|
while ($old_lookup !== $this->lookup) { |
|
$old_lookup = $this->lookup; |
|
foreach ($this->lookup as $i => $set) { |
|
$add = array(); |
|
foreach ($set as $element => $x) { |
|
if (isset($this->lookup[$element])) { |
|
$add += $this->lookup[$element]; |
|
unset($this->lookup[$i][$element]); |
|
} |
|
} |
|
$this->lookup[$i] += $add; |
|
} |
|
} |
|
|
|
foreach ($this->lookup as $key => $lookup) { |
|
$this->info[$key] = implode(' | ', array_keys($lookup)); |
|
} |
|
$this->keys = array_keys($this->info); |
|
$this->values = array_values($this->info); |
|
} |
|
|
|
/** |
|
* Accepts a definition; generates and assigns a ChildDef for it |
|
* @param HTMLPurifier_ElementDef $def HTMLPurifier_ElementDef reference |
|
* @param HTMLPurifier_HTMLModule $module Module that defined the ElementDef |
|
*/ |
|
public function generateChildDef(&$def, $module) |
|
{ |
|
if (!empty($def->child)) { // already done! |
|
return; |
|
} |
|
$content_model = $def->content_model; |
|
if (is_string($content_model)) { |
|
// Assume that $this->keys is alphanumeric |
|
$def->content_model = preg_replace_callback( |
|
'/\b(' . implode('|', $this->keys) . ')\b/', |
|
array($this, 'generateChildDefCallback'), |
|
$content_model |
|
); |
|
//$def->content_model = str_replace( |
|
// $this->keys, $this->values, $content_model); |
|
} |
|
$def->child = $this->getChildDef($def, $module); |
|
} |
|
|
|
public function generateChildDefCallback($matches) |
|
{ |
|
return $this->info[$matches[0]]; |
|
} |
|
|
|
/** |
|
* Instantiates a ChildDef based on content_model and content_model_type |
|
* member variables in HTMLPurifier_ElementDef |
|
* @note This will also defer to modules for custom HTMLPurifier_ChildDef |
|
* subclasses that need content set expansion |
|
* @param HTMLPurifier_ElementDef $def HTMLPurifier_ElementDef to have ChildDef extracted |
|
* @param HTMLPurifier_HTMLModule $module Module that defined the ElementDef |
|
* @return HTMLPurifier_ChildDef corresponding to ElementDef |
|
*/ |
|
public function getChildDef($def, $module) |
|
{ |
|
$value = $def->content_model; |
|
if (is_object($value)) { |
|
trigger_error( |
|
'Literal object child definitions should be stored in '. |
|
'ElementDef->child not ElementDef->content_model', |
|
E_USER_NOTICE |
|
); |
|
return $value; |
|
} |
|
switch ($def->content_model_type) { |
|
case 'required': |
|
return new HTMLPurifier_ChildDef_Required($value); |
|
case 'optional': |
|
return new HTMLPurifier_ChildDef_Optional($value); |
|
case 'empty': |
|
return new HTMLPurifier_ChildDef_Empty(); |
|
case 'custom': |
|
return new HTMLPurifier_ChildDef_Custom($value); |
|
} |
|
// defer to its module |
|
$return = false; |
|
if ($module->defines_child_def) { // save a func call |
|
$return = $module->getChildDef($def); |
|
} |
|
if ($return !== false) { |
|
return $return; |
|
} |
|
// error-out |
|
trigger_error( |
|
'Could not determine which ChildDef class to instantiate', |
|
E_USER_ERROR |
|
); |
|
return false; |
|
} |
|
|
|
/** |
|
* Converts a string list of elements separated by pipes into |
|
* a lookup array. |
|
* @param string $string List of elements |
|
* @return array Lookup array of elements |
|
*/ |
|
protected function convertToLookup($string) |
|
{ |
|
$array = explode('|', str_replace(' ', '', $string)); |
|
$ret = array(); |
|
foreach ($array as $k) { |
|
$ret[$k] = true; |
|
} |
|
return $ret; |
|
} |
|
} |
|
|
|
// vim: et sw=4 sts=4
|
|
|