1<?php
2
3class HTMLPurifier_DoctypeRegistry
4{
5
6    /**
7     * Hash of doctype names to doctype objects.
8     * @type array
9     */
10    protected $doctypes;
11
12    /**
13     * Lookup table of aliases to real doctype names.
14     * @type array
15     */
16    protected $aliases;
17
18    /**
19     * Registers a doctype to the registry
20     * @note Accepts a fully-formed doctype object, or the
21     *       parameters for constructing a doctype object
22     * @param string $doctype Name of doctype or literal doctype object
23     * @param bool $xml
24     * @param array $modules Modules doctype will load
25     * @param array $tidy_modules Modules doctype will load for certain modes
26     * @param array $aliases Alias names for doctype
27     * @param string $dtd_public
28     * @param string $dtd_system
29     * @return HTMLPurifier_Doctype Editable registered doctype
30     */
31    public function register(
32        $doctype,
33        $xml = true,
34        $modules = array(),
35        $tidy_modules = array(),
36        $aliases = array(),
37        $dtd_public = null,
38        $dtd_system = null
39    ) {
40        if (!is_array($modules)) {
41            $modules = array($modules);
42        }
43        if (!is_array($tidy_modules)) {
44            $tidy_modules = array($tidy_modules);
45        }
46        if (!is_array($aliases)) {
47            $aliases = array($aliases);
48        }
49        if (!is_object($doctype)) {
50            $doctype = new HTMLPurifier_Doctype(
51                $doctype,
52                $xml,
53                $modules,
54                $tidy_modules,
55                $aliases,
56                $dtd_public,
57                $dtd_system
58            );
59        }
60        $this->doctypes[$doctype->name] = $doctype;
61        $name = $doctype->name;
62        // hookup aliases
63        foreach ($doctype->aliases as $alias) {
64            if (isset($this->doctypes[$alias])) {
65                continue;
66            }
67            $this->aliases[$alias] = $name;
68        }
69        // remove old aliases
70        if (isset($this->aliases[$name])) {
71            unset($this->aliases[$name]);
72        }
73        return $doctype;
74    }
75
76    /**
77     * Retrieves reference to a doctype of a certain name
78     * @note This function resolves aliases
79     * @note When possible, use the more fully-featured make()
80     * @param string $doctype Name of doctype
81     * @return HTMLPurifier_Doctype Editable doctype object
82     */
83    public function get($doctype)
84    {
85        if (isset($this->aliases[$doctype])) {
86            $doctype = $this->aliases[$doctype];
87        }
88        if (!isset($this->doctypes[$doctype])) {
89            trigger_error('Doctype ' . htmlspecialchars($doctype) . ' does not exist', E_USER_ERROR);
90            $anon = new HTMLPurifier_Doctype($doctype);
91            return $anon;
92        }
93        return $this->doctypes[$doctype];
94    }
95
96    /**
97     * Creates a doctype based on a configuration object,
98     * will perform initialization on the doctype
99     * @note Use this function to get a copy of doctype that config
100     *       can hold on to (this is necessary in order to tell
101     *       Generator whether or not the current document is XML
102     *       based or not).
103     * @param HTMLPurifier_Config $config
104     * @return HTMLPurifier_Doctype
105     */
106    public function make($config)
107    {
108        return clone $this->get($this->getDoctypeFromConfig($config));
109    }
110
111    /**
112     * Retrieves the doctype from the configuration object
113     * @param HTMLPurifier_Config $config
114     * @return string
115     */
116    public function getDoctypeFromConfig($config)
117    {
118        // recommended test
119        $doctype = $config->get('HTML.Doctype');
120        if (!empty($doctype)) {
121            return $doctype;
122        }
123        $doctype = $config->get('HTML.CustomDoctype');
124        if (!empty($doctype)) {
125            return $doctype;
126        }
127        // backwards-compatibility
128        if ($config->get('HTML.XHTML')) {
129            $doctype = 'XHTML 1.0';
130        } else {
131            $doctype = 'HTML 4.01';
132        }
133        if ($config->get('HTML.Strict')) {
134            $doctype .= ' Strict';
135        } else {
136            $doctype .= ' Transitional';
137        }
138        return $doctype;
139    }
140}
141
142// vim: et sw=4 sts=4
143