| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170 | <?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
 |