/includes/Opl/Opt/Compiler/Class.php
PHP | 3663 lines | 2679 code | 193 blank | 791 comment | 484 complexity | 251f002e7a1918a53f611464877d43de MD5 | raw file
Possible License(s): GPL-3.0, MIT
Large files files are truncated, but you can click here to view the full file
- <?php
- /*
- * OPEN POWER LIBS <http://www.invenzzia.org>
- *
- * This file is subject to the new BSD license that is bundled
- * with this package in the file LICENSE. It is also available through
- * WWW at this URL: <http://www.invenzzia.org/license/new-bsd>
- *
- * Copyright (c) Invenzzia Group <http://www.invenzzia.org>
- * and other contributors. See website for details.
- *
- * $Id: Class.php 274 2009-12-29 10:17:48Z zyxist $
- */
-
- class Opt_Compiler_Class
- {
- // Opcodes
- const OP_VARIABLE = 1;
- const OP_LANGUAGE_VAR = 2;
- const OP_STRING = 4;
- const OP_NUMBER = 8;
- const OP_ARRAY = 16;
- const OP_OBJECT = 32;
- const OP_IDENTIFIER = 64;
- const OP_OPERATOR = 128;
- const OP_POST_OPERATOR = 256;
- const OP_PRE_OPERATOR = 512;
- const OP_ASSIGN = 1024;
- const OP_NULL = 2048;
- const OP_SQ_BRACKET = 4096;
- const OP_SQ_BRACKET_E = 8192;
- const OP_FUNCTION = 16384;
- const OP_METHOD = 32768;
- const OP_BRACKET = 65536;
- const OP_CLASS = 131072;
- const OP_CALL = 262144;
- const OP_FIELD = 524288;
- const OP_EXPRESSION = 1048576;
- const OP_OBJMAN = 2097152;
- const OP_BRACKET_E = 4194304;
- const OP_TU = 8388608;
- const OP_CURLY_BRACKET = 16777216;
-
- const ESCAPE_ON = true;
- const ESCAPE_OFF = false;
- const ESCAPE_BOTH = 2;
-
-
- // Current compilation
- protected $_template = NULL;
- protected $_attr = array();
- protected $_stack = NULL;
- protected $_node = NULL;
-
- static protected $_recursionDetector = NULL;
-
- // Compiler info
- protected $_tags = array();
- protected $_attributes = array();
- protected $_conversions = array();
- protected $_processors = array();
- protected $_dependencies = array();
-
- // OPT parser info
- protected $_tpl;
- protected $_instructions;
- protected $_namespaces;
- protected $_functions;
- protected $_classes;
- protected $_blocks;
- protected $_components;
- protected $_tf;
- protected $_entities;
- protected $_formnatInfo;
- protected $_formats = array();
- protected $_formatObj = array();
- protected $_inheritance;
-
- // Regular expressions
- private $_rCDataExpression = '/(\<\!\[CDATA\[|\]\]\>)/msi';
- private $_rCommentExpression = '/(\<\!\-\-|\-\-\>)/si';
- private $_rCommentSplitExpression = '/(\<\!\-\-(.*?)\-\-\>)/si';
- private $_rOpeningChar = '[a-zA-Z\:\_]';
- private $_rNameChar = '[a-zA-Z0-9\:\.\_\-]';
- private $_rNameExpression;
- private $_rXmlTagExpression;
- private $_rTagExpandExpression;
- private $_rQuirksTagExpression = '';
- private $_rExpressionTag = '/(\{([^\}]*)\})/msi';
- private $_rAttributeTokens = '/(?:[^\=\"\'\s]+|\=|\"|\'|\s)/x';
- private $_rPrologTokens = '/(?:[^\=\"\'\s]+|\=|\'|\"|\s)/x';
- private $_rModifiers = 'si';
- private $_rXmlHeader = '/(\<\?xml.+\?\>)/msi';
- private $_rProlog = '/\<\?xml(.+)\?\>|/msi';
- private $_rEncodingName = '/[A-Za-z]([A-Za-z0-9.\_]|\-)*/si';
-
- private $_rBacktickString = '`[^`\\\\]*(?:\\\\.[^`\\\\]*)*`';
- private $_rSingleQuoteString = '\'[^\'\\\\]*(?:\\\\.[^\'\\\\]*)*\'';
- private $_rHexadecimalNumber = '\-?0[xX][0-9a-fA-F]+';
- private $_rDecimalNumber = '[0-9]+\.?[0-9]*';
- private $_rLanguageVar = '\$[a-zA-Z0-9\_]+@[a-zA-Z0-9\_]+';
- private $_rVariable = '(\$|@)[a-zA-Z0-9\_\.]*';
- private $_rOperators = '\-\>|!==|===|==|!=|\=\>|<>|<<|>>|<=|>=|\&\&|\|\||\(|\)|,|\!|\^|=|\&|\~|<|>|\||\%|\+\+|\-\-|\+|\-|\*|\/|\[|\]|\.|\:\:|\{|\}|\'|\"|';
- private $_rIdentifier = '[a-zA-Z\_]{1}[a-zA-Z0-9\_\.]*';
- private $_rLanguageVarExtract = '\$([a-zA-Z0-9\_]+)@([a-zA-Z0-9\_]+)';
-
- // Help fields
- private $_charset = null;
- private $_translationConversion = null;
- private $_initialMemory = null;
- private $_comments = 0;
- private $_standalone = false;
- private $_dynamicBlocks = null;
-
- static private $_templates = array();
-
- /**
- * Creates a new instance of the template compiler. The compiler can
- * be created, using the settings from the main OPT class or another
- * compiler.
- *
- * @param Opt_Class|Opt_Compiler_Class $tpl The initial object.
- */
- public function __construct($tpl)
- {
- if($tpl instanceof Opt_Class)
- {
- $this->_tpl = $tpl;
- $this->_namespaces = $tpl->_getList('_namespaces');
- $this->_classes = $tpl->_getList('_classes');
- $this->_functions = $tpl->_getList('_functions');
- $this->_components = $tpl->_getList('_components');
- $this->_blocks = $tpl->_getList('_blocks');
- $this->_phpFunctions = $tpl->_getList('_phpFunctions');
- $this->_formats = $tpl->_getList('_formats');
- $this->_tf = $tpl->_getList('_tf');
- $this->_entities = $tpl->_getList('_entities');
- $this->_charset = strtoupper($tpl->charset);
-
- // Create the processors and call their configuration method in the constructors.
- $instructions = $tpl->_getList('_instructions');
- foreach($instructions as $instructionClass)
- {
- $obj = new $instructionClass($this, $tpl);
- $this->_processors[$obj->getName()] = $obj;
-
- // Add the tags and attributes registered by this processor.
- foreach($obj->getInstructions() as $item)
- {
- $this->_instructions[$item] = $obj;
- }
- foreach($obj->getAttributes() as $item)
- {
- $this->_attributes[$item] = $obj;
- }
- }
- }
- elseif($tpl instanceof Opt_Compiler_Class)
- {
- // Simply import the data structures from that compiler.
- $this->_tpl = $tpl->_tpl;
- $this->_namespaces = $tpl->_namespaces;
- $this->_classes = $tpl->_classes;
- $this->_functions = $tpl->_functions;
- $this->_components = $tpl->_components;
- $this->_blocks = $tpl->_blocks;
- $this->_inheritance = $tpl->_inheritance;
- $this->_formatInfo = $tpl->_formatInfo;
- $this->_formats = $tpl->_formats;
- $this->_tf = $tpl->_tf;
- $this->_processor = $tpl->_processors;
- $this->_instructions = $tpl->_instructions;
- $this->_attributes = $tpl->_attributes;
- $this->_charset = $tpl->_charset;
- $this->_entities = $tpl->_entities;
- $tpl = $this->_tpl;
- }
-
- if($tpl->unicodeNames)
- {
- // Register unicode name regular expressions
- $this->_rOpeningChar = '(\p{Lu}|\p{Ll}|\p{Ll}|\p{Lt}|\p{Lm}|\p{Nl}|\_|\:)';
- $this->_rNameChar = '(\p{Lu}|\p{Ll}|\p{Ll}|\p{Lt}|\p{Lm}|\p{Nl}|\p{Mc}|\p{Me}|\p{Mn}|\p{Lm}|\p{Nd}|\_|\:|\.|\-)';
- $this->_rModifiers = 'msiu';
- }
-
- // Register the rest of the expressions
- $this->_rNameExpression = '/('.$this->_rOpeningChar.'?'.$this->_rNameChar.'*)/'.$this->_rModifiers;
- $this->_rXmlTagExpression = '/(\<((\/)?('.$this->_rOpeningChar.'?'.$this->_rNameChar.'*)( [^\<\>]*)?(\/)?)\>)/'.$this->_rModifiers;
- $this->_rTagExpandExpression = '/^(\/)?('.$this->_rOpeningChar.'?'.$this->_rNameChar.'*)( [^\<\>]*)?(\/)?$/'.$this->_rModifiers;
-
-
- $this->_rQuirksTagExpression = '/(\<((\/)?(('.implode('|', $this->_namespaces).')\:'.$this->_rNameChar.'*)( [^\<\>]+)?(\/)?)\>)/'.$this->_rModifiers;
- // We've just thrown the performance away by loading the compiler, so this won't make things worse
- // but the user may be happy :). However, don't show this message, if we are in the performance mode.
- if(!is_writable($tpl->compileDir) && $tpl->_compileMode != Opt_Class::CM_PERFORMANCE)
- {
- throw new Opt_FilesystemAccess_Exception('compilation', 'writeable');
- }
-
- // If the debug console is active, preload the XML tree classes.
- // Without it, the debug console would show crazy things about the memory usage.
- if($this->_tpl->debugConsole && !class_exists('Opt_Xml_Root'))
- {
- Opl_Loader::load('Opt_Xml_Root');
- Opl_Loader::load('Opt_Xml_Text');
- Opl_Loader::load('Opt_Xml_Cdata');
- Opl_Loader::load('Opt_Xml_Element');
- Opl_Loader::load('Opt_Xml_Attribute');
- Opl_Loader::load('Opt_Xml_Expression');
- Opl_Loader::load('Opt_Xml_Prolog');
- Opl_Loader::load('Opt_Xml_Dtd');
- Opl_Loader::load('Opt_Format_Array');
- }
- } // end __construct();
-
- /**
- * Allows to clone the original compiler, creating new instruction
- * processors for the new instance.
- */
- public function __clone()
- {
- $this->_processors = array();
- $this->_tags = array();
- $this->_attributes = array();
- $this->_conversions = array();
- $instructions = $this->_tpl->_getList('_instructions');
- $cnt = sizeof($instructions);
- for($i = 0; $i < $cnt; $i++)
- {
- $obj = new $instructions[$i]($this, $tpl);
- $this->_processors[$obj->getName()] = $obj;
- }
- } // end __clone();
-
- /*
- * General purpose tools and utilities
- */
-
- /**
- * Returns the currently processed template file name.
- *
- * @static
- * @return String The currently processed template name
- */
- static public function getCurrentTemplate()
- {
- return end(self::$_templates);
- } // end getCurrentTemplate();
-
- /**
- * Cleans the compiler state after the template compilation.
- * It is necessary in the exception processing - if the exception
- * is thrown in the middle of the compilation, the compiler becomes
- * useless, because it is locked. The compilation algorithm automatically
- * filters the exceptions, cleans the compiler state and throws the captured
- * exceptions again, to the script.
- *
- * @static
- */
- static public function cleanCompiler()
- {
- self::$_recursionDetector = null;
- self::$_templates = array();
- } // end cleanCompiler();
-
- /**
- * Returns the value of the compiler state variable or
- * NULL if the variable is not set.
- *
- * @param String $name Compiler variable name
- * @return Mixed The compiler variable value.
- */
- public function get($name)
- {
- if(!isset($this->_attr[$name]))
- {
- return NULL;
- }
- return $this->_attr[$name];
- } // end get();
-
- /**
- * Creates or modifies the compiler state variable.
- *
- * @param String $name The name
- * @param Mixed $value The value
- */
- public function set($name, $value)
- {
- $this->_attr[$name] = $value;
- } // end set();
-
- /**
- * Adds the escaping formula to the specified expression using the current escaping
- * rules:
- *
- * 1. The $status variable.
- * 2. The current template settings.
- * 3. The OPT settings.
- *
- * @param String $expression The PHP expression to be escaped.
- * @param Boolean $status The status of escaping for this expression or NULL, if not set.
- * @return String The expression with the escaping formula added, if necessary.
- */
- public function escape($expression, $status = null)
- {
- // OPT Configuration
- $escape = $this->_tpl->escape;
-
- // Template configuration
- if(!is_null($this->get('escaping')))
- {
- $escape = ($this->get('escaping') == true ? true : false);
- }
-
- // Expression settings
- if(!is_null($status))
- {
- $escape = ($status == true ? true : false);
- }
-
- if($escape)
- {
- // The user may define a custom escaping function
- if($this->isFunction('escape'))
- {
- if(strpos($this->_functions['escape'], '#', 0) !== false)
- {
- throw new Opt_InvalidArgumentFormat_Exception('escape', 'escape');
- }
- return $this->_functions['escape'].'('.$expression.')';
- }
- return 'htmlspecialchars('.$expression.')';
- }
- return $expression;
- } // end escape();
-
- /**
- * Returns the format object for the specified variable.
- *
- * @param String $variable The variable identifier.
- * @param Boolean $restore optional Whether to load a previously created format object (false) or to create a new one.
- * @return Opt_Compiler_Format The format object.
- */
- public function getFormat($variable, $restore = false)
- {
- $hc = $this->_tpl->defaultFormat;
- if(isset($this->_formatInfo[$variable]))
- {
- $hc = $this->_formatInfo[$variable];
- }
- if($restore && isset($this->_formatObj[$hc]))
- {
- return $this->_formatObj[$hc];
- }
-
- $top = $this->createFormat($variable, $hc);
- if($restore)
- {
- $this->_formatObj[$hc] = $top;
- }
- return $top;
- } // end getFormat();
-
- /**
- * Creates a format object for the specified description string.
- *
- * @param String $variable The variable name (for debug purposes)
- * @param String $hc The description string.
- * @return Opt_Compiler_Format The newly created format object.
- */
- public function createFormat($variable, $hc)
- {
- // Decorate the objects, if necessary
- $expanded = explode('/', $hc);
- $obj = null;
- foreach($expanded as $class)
- {
- if(!isset($this->_formats[$class]))
- {
- throw new Opt_FormatNotFound_Exception($variable, $class);
- }
- $hcName = $this->_formats[$class];
- if(!is_null($obj))
- {
- $obj->decorate($obj2 = new $hcName($this->_tpl, $this));
- $obj = $obj2;
- }
- else
- {
- $top = $obj = new $hcName($this->_tpl, $this, $hc);
- }
- }
- return $top;
- } // end createFormat();
-
- /**
- * Allows to export the list of variables and their data formats to
- * the template compiler.
- *
- * @param Array $list An associative array of pairs "variable => format description"
- */
- public function setFormatList(Array $list)
- {
- $this->_formatInfo = $list;
- } // end setFormatList();
-
- /**
- * Converts the specified item into another string using one of the
- * registered patterns. If the pattern is not found, the method returns
- * the original item unmodified.
- *
- * @param String $item The item to be converted.
- * @return String
- */
- public function convert($item)
- {
- // the converter allows to convert one name into another and keep it, if there is no
- // conversion pattern. Used in connection with sections + snippets.
- if(isset($this->_conversions[$item]))
- {
- return $this->_conversions[$item];
- }
- return $item;
- } // end convert();
-
- /**
- * Creates a new conversion pattern. The string $from will be converted
- * into $to.
- *
- * @param String $from The original string
- * @param String $to The new string
- */
- public function setConversion($from, $to)
- {
- $this->_conversions[$from] = $to;
- } // end setConversion();
-
- /**
- * Removes the conversion pattern from the compiler memory.
- *
- * @param String $from The original string.
- * @return Boolean
- */
- public function unsetConversion($from)
- {
- if(isset($this->_conversions[$from]))
- {
- unset($this->_conversions[$from]);
- return true;
- }
- return false;
- } // end unsetConversion();
-
- /**
- * Registers the dynamic inheritance rules for the templates. The
- * array taken as a parameter must be an associative array of pairs
- * 'extending' => 'extended' file names.
- *
- * @param Array $inheritance The list of inheritance rules.
- */
- public function setInheritance(Array $inheritance)
- {
- $this->_inheritance = $inheritance;
- } // end setInheritance();
-
- /**
- * Parses the entities in the specified text.
- *
- * @param String $text The original text
- * @return String
- */
- public function parseEntities($text)
- {
- return preg_replace_callback('/\&(([a-zA-Z\_\:]{1}[a-zA-Z0-9\_\:\-\.]*)|(\#((x[a-fA-F0-9]+)|([0-9]+))))\;/', array($this, '_decodeEntity'), $text);
- // return htmlspecialchars_decode(str_replace(array_keys($this->_entities), array_values($this->_entities), $text));
- } // end parseEntities();
-
- /**
- * Replaces only OPT-specific entities &lb; and &rb; to the corresponding
- * characters.
- *
- * @param String $text Input text
- * @return String output text
- */
- public function parseShortEntities($text)
- {
- return str_replace(array('&lb;', '&rb;'), array('{', '}'), $text);
- } // end parseShortEntities();
-
- /**
- * Replaces the XML special characters back to entities with smart ommiting of &
- * that already creates an entity.
- *
- * @param String $text Input text.
- * @return String Output text.
- */
- public function parseSpecialChars($text)
- {
- return htmlspecialchars($text);
- return preg_replace_callback('/(\&\#?[a-zA-Z0-9]*\;)|\<|\>|\"|\&/', array($this, '_entitize'), $text);
- } // end parseSpecialChars();
-
- /**
- * Returns 'true', if the argument is a valid identifier. An identifier
- * must begin with a letter or underscore, and later, the numbers are also
- * allowed.
- *
- * @param String $id The tested string
- * @return Boolean
- */
- public function isIdentifier($id)
- {
- return preg_match($this->_rEncodingName, $id);
- } // end isIdentifier();
-
- /**
- * Checks whether the specified tag name is registered as an instruction.
- * Returns its processor in case of success or NULL.
- *
- * @param String $tag The tag name (with the namespace)
- * @return Opt_Compiler_Processor|NULL The processor that registered this tag.
- */
- public function isInstruction($tag)
- {
- if(isset($this->_instructions[$tag]))
- {
- return $this->_instructions[$tag];
- }
- return NULL;
- } // end isInstruction();
-
- /**
- * Returns true, if the argument is the name of an OPT attribute.
- *
- * @param String $tag The attribute name
- * @return Boolean
- */
- public function isOptAttribute($tag)
- {
- if(isset($this->_attributes[$tag]))
- {
- return $this->_attributes[$tag];
- }
- return NULL;
- } // end isOptAttribute();
-
- /**
- * Returns true, if the argument is the OPT function name.
- *
- * @param String $name The function name
- * @return Boolean
- */
- public function isFunction($name)
- {
- if(isset($this->_functions[$name]))
- {
- return $this->_functions[$name];
- }
- return NULL;
- } // end isFunction();
-
- /**
- * Returns true, if the argument is the name of the class
- * accepted by OPT.
- *
- * @param String $id The class name.
- * @return Boolean
- */
- public function isClass($id)
- {
- if(isset($this->_classes[$id]))
- {
- return $this->_classes[$id];
- }
- return NULL;
- } // end isClass();
-
- /**
- * Returns true, if the argument is the name of the namespace
- * processed by OPT.
- *
- * @param String $ns The namespace name
- * @return Boolean
- */
- public function isNamespace($ns)
- {
- return in_array($ns, $this->_namespaces);
- } // end isNamespace();
-
- /**
- * Returns true, if the argument is the name of the component tag.
- * @param String $component The component tag name
- * @return Boolean
- */
- public function isComponent($component)
- {
- return isset($this->_components[$component]);
- } // end isComponent();
-
- /**
- * Returns true, if the argument is the name of the block tag.
- * @param String $block The block tag name.
- * @return Boolean
- */
- public function isBlock($block)
- {
- return isset($this->_blocks[$block]);
- } // end isComponent();
-
- /**
- * Returns true, if the argument is the processor name.
- *
- * @param String $name The instruction processor name
- * @return Boolean
- */
- public function isProcessor($name)
- {
- if(!isset($this->_processors[$name]))
- {
- return NULL;
- }
- return $this->_processors[$name];
- } // end isProcessor();
-
- /**
- * Returns the processor object with the specified name. If
- * the processor does not exist, it generates an exception.
- *
- * @param String $name The processor name
- * @return Opt_Compiler_Processor
- */
- public function processor($name)
- {
- if(!isset($this->_processors[$name]))
- {
- throw new Opt_ObjectNotExists_Exception('processor', $name);
- }
- return $this->_processors[$name];
- } // end processor();
-
- /**
- * Returns the component class name assigned to the specified
- * XML tag. If the component class is not registered, it throws
- * an exception.
- *
- * @param String $name The component XML tag name.
- * @return Opt_Component_Interface
- */
- public function component($name)
- {
- if(!isset($this->_components[$name]))
- {
- throw new Opt_ObjectNotExists_Exception('component', $name);
- }
- return $this->_components[$name];
- } // end component();
-
- /**
- * Returns the block class name assigned to the specified
- * XML tag. If the block class is not registered, it throws
- * an exception.
- *
- * @param String $name The block XML tag name.
- * @return Opt_Block_Interface
- */
- public function block($name)
- {
- if(!isset($this->_blocks[$name]))
- {
- throw new Opt_ObjectNotExists_Exception('block', $name);
- }
- return $this->_blocks[$name];
- } // end block();
-
- /**
- * Returns the template name that is inherited by the template '$name'
- *
- * @param String $name The "current" template file name
- * @return String
- */
- public function inherits($name)
- {
- if(isset($this->_inheritance[$name]))
- {
- return $this->_inheritance[$name];
- }
- return NULL;
- } // end inherits();
-
- /**
- * Adds the template file name to the dependency list of the currently
- * compiled file, so that it could be checked for modifications during
- * the execution.
- *
- * @param String $template The template file name.
- */
- public function addDependantTemplate($template)
- {
- if(in_array($template, $this->_dependencies))
- {
- $exception = new Opt_InheritanceRecursion_Exception($template);
- $exception->setData($this->_dependencies);
- throw $exception;
- }
-
- $this->_dependencies[] = $template;
- } // end addDependantTemplate();
-
- /**
- * Imports the dependencies from another compiler object and adds them
- * to the actual dependency list.
- *
- * @param Opt_Compiler_Class $compiler Another compiler object.
- */
- public function importDependencies(Opt_Compiler_Class $compiler)
- {
- $this->_dependencies = array_merge($this->_dependencies, $compiler->_dependencies);
- } // end importDependencies();
-
- /*
- * Internal tools and utilities
- */
-
- /**
- * Compiles the attribute part of the opening tag and extracts the tag
- * attributes to an array. Moreover, it performs the entity conversion
- * to the corresponding characters.
- *
- * @internal
- * @param String $attrList The attribute list string
- * @param string $tagName The tag name for debug purposes
- * @return Array The list of attributes with the values.
- */
- protected function _compileAttributes($attrList, $tagName = '')
- {
- // Tokenize the list
- preg_match_all($this->_rAttributeTokens, $attrList, $match, PREG_SET_ORDER);
-
- $size = sizeof($match);
- $result = array();
- for($i = 0; $i < $size; $i++)
- {
- /**
- * The algorithm scans the tokens on the list and determines, where
- * the beginning and the end of the attribute is. We do not use the
- * regular expressions, because they are not able to capture the
- * invalid content between the expressions.
- *
- * The sub-loops can modify the iteration variable to skip the found
- * elements, white characters etc. This means that the main loop
- * does only a few iteration number, equal approximately the number
- * of attributes.
- */
- if(!ctype_space($match[$i][0]))
- {
-
- if(!preg_match($this->_rNameExpression, $match[$i][0]))
- {
- return false;
- }
-
- $vret = false;
- $name = $match[$i][0];
-
- if(substr_count($name, ':') > 1)
- {
- throw new Opt_InvalidNamespace_Exception($name);
- }
-
- $value = null;
- for($i++; ctype_space($match[$i][0]) && $i < $size; $i++){}
-
- if($match[$i][0] != '=')
- {
- if($this->_tpl->htmlAttributes)
- {
- $result[$name] = $name;
- continue;
- }
- else
- {
- return false;
- }
- }
- // Look for the attribute value start
- for($i++; ctype_space($match[$i][0]) && $i < $size; $i++){}
-
- if($match[$i][0] != '"' && $match[$i][0] != '\'')
- {
- return false;
- }
-
- // Save the delimiter, because we will use it to make the error checking
- $delimiter = $match[$i][0];
-
- $value = '';
- for($i++; $i < $size; $i++)
- {
- if($match[$i][0] == $delimiter)
- {
- break;
- }
- $value .= $match[$i][0];
- }
- if(!isset($match[$i][0]))
- {
- return false;
- }
- if($match[$i][0] != $delimiter)
- {
- return false;
- }
- // We return the decoded attribute values, because they are
- // stored without the entities.
- if(isset($result[$name]))
- {
- throw new Opt_XmlDuplicatedAttribute_Exception($name, $tagName);
- }
- $result[$name] = htmlspecialchars_decode($value);
- }
- }
- return $result;
- } // end _compileAttributes();
-
- /**
- * Parses the XML prolog and returns its attributes as an array. The parsing
- * algorith is the same, as in _compileAttributes().
- *
- * @internal
- * @param String $prolog The prolog string.
- * @return Array
- */
- protected function _compileProlog($prolog)
- {
- // Tokenize the list
- preg_match_all($this->_rPrologTokens, $prolog, $match, PREG_SET_ORDER);
-
- $size = sizeof($match);
- $result = array();
- for($i = 0; $i < $size; $i++)
- {
- if(!ctype_space($match[$i][0]))
- {
- // Traverse through a single attribute
- if(!preg_match($this->_rNameExpression, $match[$i][0]))
- {
- throw new Opt_XmlInvalidProlog_Exception('invalid attribute format');
- }
-
- $vret = false;
- $name = $match[$i][0];
- $value = null;
- for($i++; $i < $size && ctype_space($match[$i][0]); $i++){}
-
- if($i >= $size || $match[$i][0] != '=')
- {
- throw new Opt_XmlInvalidProlog_Exception('invalid attribute format');
- }
- for($i++; ctype_space($match[$i][0]) && $i < $size; $i++){}
-
- if($match[$i][0] != '"' && $match[$i][0] != '\'')
- {
- throw new Opt_XmlInvalidProlog_Exception('invalid attribute format');
- }
- $opening = $match[$i][0];
- $value = '';
- for($i++; $i < $size; $i++)
- {
- if($match[$i][0] == $opening)
- {
- break;
- }
- $value .= $match[$i][0];
- }
- if(!isset($match[$i][0]) || $match[$i][0] != $opening)
- {
- throw new Opt_XmlInvalidProlog_Exception('invalid attribute format');
- }
- // If we are here, the attribute is correct. No shit on the way detected.
- $result[$name] = $value;
- }
- }
- $returnedResult = $result;
- // Check, whether the arguments are correct.
- if(isset($result['version']))
- {
- // There is no other version so far, so report a warning. For 99,9% this is a mistake.
- if($result['version'] != '1.0')
- {
- $this->_tpl->debugConsole and Opt_Support::warning('OPT', 'XML prolog warning: strange XML version: '.$result['version']);
- }
- unset($result['version']);
- }
- if(isset($result['encoding']))
- {
- if(!preg_match($this->_rEncodingName, $result['encoding']))
- {
- throw new Opt_XmlInvalidProlog_Exception('invalid encoding name format');
- }
- // The encoding should match the value we mentioned in the OPT configuration and sent to the browser.
- $result['encoding'] = strtolower($result['encoding']);
- $charset = is_null($this->_tpl->charset) ? null : strtolower($this->_tpl->charset);
- if($result['encoding'] != $charset && !is_null($charset))
- {
- $this->_tpl->debugConsole and Opt_Support::warning('OPT', 'XML prolog warning: the declared encoding: "'.$result['encoding'].'" differs from setContentType() setting: "'.$charset.'"');
- }
- unset($result['encoding']);
- }
- else
- {
- $this->_tpl->debugConsole and Opt_Support::warning('XML prolog warning: no encoding information. Remember your content must be pure UTF-8 or UTF-16 then.');
- }
- if(isset($result['standalone']))
- {
- if($result['standalone'] != 'yes' && $result['standalone'] != 'no')
- {
- throw new Opt_XmlInvalidProlog_Exception('invalid value for "standalone" attribute: "'.$result['standalone'].'"; expected: "yes", "no".');
- }
- unset($result['standalone']);
- }
- if(sizeof($result) > 0)
- {
- throw new Opt_XmlInvalidProlog_Exception('invalid attributes in prolog.');
- }
- return $returnedResult;
- } // end _compileProlog();
-
- /**
- * Adds the PHP code with dependencies to the code buffers in the tree
- * root node.
- *
- * @internal
- * @param Opt_Xml_Node $tree The tree root node.
- */
- protected function _addDependencies($tree)
- {
- // OK, there is really some info to include!
- $list = '';
- foreach($this->_dependencies as $a)
- {
- $list .= '\''.$a.'\',';
- }
-
- $tree->addBefore(Opt_Xml_Buffer::TAG_BEFORE, 'if(!$this->_massPreprocess($compileTime, array('.$list.'))){ ');
- $tree->addAfter(Opt_Xml_Buffer::TAG_AFTER, ' }else{ $compileTime = $this->_compile($this->_template); require(__FILE__); } ');
- } // end _addDependencies();
-
- /**
- * Compiles the current text block between two XML tags, creating a
- * complete Opt_Xml_Text node. It looks for the expressions in the
- * curly brackets, extracts them and packs as separate nodes.
- *
- * Moreover, it replaces the entities with the corresponding characters.
- *
- * @internal
- * @param Opt_Xml_Node $current The current XML node.
- * @param String $text The text block between two tags.
- * @param Boolean $noExpressions=false If true, do not look for the expressions.
- * @return Opt_Xml_Node The current XML node.
- */
- protected function _treeTextCompile($current, $text, $noExpressions = false)
- {
- // Yes, we parse entities, but the text itself should not contain
- // any special characters.
- if(strcspn($text, '<>') != strlen($text))
- {
- throw new Opt_XmlInvalidCharacter_Exception(htmlspecialchars($text));
- }
-
- if($noExpressions)
- {
- $current = $this->_treeTextAppend($current, $this->parseEntities($text));
- }
-
- preg_match_all($this->_rExpressionTag, $text, $result, PREG_SET_ORDER);
-
- $resultSize = sizeof($result);
- $offset = 0;
- for($i = 0; $i < $resultSize; $i++)
- {
- $id = strpos($text, $result[$i][0], $offset);
- if($id > $offset)
- {
- $current = $this->_treeTextAppend($current, $this->parseEntities(substr($text, $offset, $id - $offset)));
- }
- $offset = $id + strlen($result[$i][0]);
-
- $current = $this->_treeTextAppend($current, new Opt_Xml_Expression($this->parseEntities($result[$i][2])));
- }
-
- $i--;
- // Now the remaining content of the file
- if(strlen($text) > $offset)
- {
- $current = $this->_treeTextAppend($current, $this->parseEntities(substr($text, $offset, strlen($text) - $offset)));
- }
- return $current;
- } // end _treeTextCompile();
-
- /**
- * An utility method that simplifies inserting the text to the XML
- * tree. Depending on the last child type, it can create a new text
- * node or add the text to the existing one.
- *
- * @internal
- * @param Opt_Xml_Node $current The currently built XML node.
- * @param String|Opt_Xml_Node $text The text or the expression node.
- * @return Opt_Xml_Node The current XML node.
- */
- protected function _treeTextAppend($current, $text)
- {
- $last = $current->getLastChild();
- if(!is_object($last) || !($last instanceof Opt_Xml_Text))
- {
- if(!is_object($text))
- {
- $node = new Opt_Xml_Text($text);
- }
- else
- {
- $node = new Opt_Xml_Text();
- $node->appendChild($text);
- }
- $current->appendChild($node);
- }
- else
- {
- if(!is_object($text))
- {
- $last->appendData($text);
- }
- else
- {
- $last->appendChild($text);
- }
- }
- return $current;
- } // end _treeTextAppend();
-
- /**
- * A helper method for building the XML tree. It appends the
- * node to the current node and returns the new node that should
- * become the new current node.
- *
- * @internal
- * @param Opt_Xml_Node $current The current node.
- * @param Opt_Xml_Node $node The newly created node.
- * @param Boolean $goInto Whether we visit the new node.
- * @return Opt_Xml_Node
- */
- protected function _treeNodeAppend($current, $node, $goInto)
- {
- $current->appendChild($node);
- if($goInto)
- {
- return $node;
- }
- return $current;
- } // end _treeNodeAppend();
-
- /**
- * A helper method for building the XML tree. It jumps out of the
- * current node to the parent and switches to it.
- *
- * @internal
- * @param Opt_Xml_Node $current The current node.
- * @return Opt_Xml_Node
- */
- protected function _treeJumpOut($current)
- {
- $parent = $current->getParent();
-
- if(!is_null($parent))
- {
- return $parent;
- }
- return $current;
- } // end _treeJumpOut();
-
- /**
- * Looks for special OPT attributes in the element attribute list and
- * processes them. Returns the list of nodes that need to be postprocessed.
- *
- * @internal
- * @param Opt_Xml_Element $node The scanned element.
- * @param Boolean $specialNs Do we recognize "parse" and "str" namespaces?
- * @return Array
- */
- protected function _processXml(Opt_Xml_Element $node, $specialNs = true)
- {
- if(!$node->hasAttributes())
- {
- return array();
- }
- $attributes = $node->getAttributes();
- $pp = array();
-
- // Look for special OPT attributes
- foreach($attributes as $attr)
- {
- if($this->isNamespace($attr->getNamespace()))
- {
- $xml = $attr->getXmlName();
- // Check the namespace we found
- switch($attr->getNamespace())
- {
- case 'parse':
- if($specialNs)
- {
- $result = $this->compileExpression((string)$attr, false, Opt_Compiler_Class::ESCAPE_BOTH);
- $attr->addAfter(Opt_Xml_Buffer::ATTRIBUTE_VALUE, ' echo '.$result[0].'; ');
- $attr->setNamespace(null);
- }
- break;
- case 'str':
- if($specialNs)
- {
- $attr->setNamespace(null);
- }
- break;
- default:
- if(isset($this->_attributes[$xml]))
- {
- $this->_attributes[$xml]->processAttribute($node, $attr);
- if($attr->get('postprocess'))
- {
- $pp[] = array($this->_attributes[$xml], $attr);
- }
- }
- $node->removeAttribute($xml);
- }
- }
- }
- return $pp;
- } // end _processXml();
-
- /**
- * Runs the postprocessors for the specified attributes.
- *
- * @internal
- * @param Opt_Xml_Node $node The scanned node.
- * @param Array $list The list of XML attribute processors that need to be postprocessed.
- */
- protected function _postprocessXml(Opt_Xml_Node $node, Array $list)
- {
- $cnt = sizeof($list);
- for($i = 0; $i < $cnt; $i++)
- {
- $list[$i][0]->postprocessAttribute($node, $list[$i][1]);
- }
- } // end _postprocessXml();
-
- /**
- * An utility method for the stage 2 and 3 of the compilation. It is
- * used to create a non-recursive depth-first search algorithm. The
- * current queue is sent to a stack, and the new queue if initialized,
- * if $item contains children.
- *
- * @internal
- * @param SplStack $stack The processing stack.
- * @param SplQueue $queue The processing queue.
- * @param Opt_Xml_Scannable $item The item, where to import the nodes from.
- * @param Boolean $pp The postprocess flag.
- * @return SplQueue The new queue (or the old one, if none has been created).
- */
- protected function _pushQueue($stack, $queue, $item, $pp)
- {
- if($item->hasChildren())
- {
- $stack->push(array($item, $queue, $pp));
- $pp = NULL;
- $queue = new SplQueue;
- foreach($item as $child)
- {
- $queue->enqueue($child);
- }
- }
-
- return $queue;
- } // end _pushQueue();
-
- /**
- * Does the postprocessing in the second stage of compilation.
- *
- * @internal
- * @param Opt_Xml_Node|Null $item The postprocessed node.
- * @param Array $pp The list of postprocessed attributes.
- */
- protected function _doPostprocess($item, $pp)
- {
- // Postprocess code for the compilation stage 2
- // Packed into a method, because it is used twice.
- if(is_null($item))
- {
- return;
- }
- if(sizeof($pp) > 0)
- {
- $this->_postprocessXml($item, $pp);
- }
- if($item->get('postprocess'))
- {
- if(!is_null($processor = $this->isInstruction($item->getXmlName())))
- {
- $processor->postprocessNode($item);
- }
- elseif($this->isComponent($item->getXmlName()))
- {
- $processor = $this->processor('component');
- $processor->postprocessComponent($item);
- }
- elseif($this->isBlock($item->getXmlName()))
- {
- $processor = $this->processor('block');
- $processor->postprocessBlock($item);
- }
- else
- {
- throw new Opt_UnknownProcessor_Exception($item->getXmlName());
- }
- }
- } // end _doPostprocess();
-
- /**
- * Does the post-linking for the third stage of the compilation and returns
- * the linked code.
- *
- * @internal
- * @param Opt_Xml_Node $item The linked item.
- * @return String
- */
- protected function _doPostlinking($item)
- {
- // Post code
- if(is_null($item))
- {
- return '';
- }
-
- // This prevents from displaying </> if the HTML node was hidden.
- if($item->get('hidden') !== false)
- {
- return '';
- }
- if($item->get('_skip_postlinking') == true)
- {
- return '';
- }
-
- $output = '';
- switch($item->getType())
- {
- case 'Opt_Xml_Text':
- $output .= $item->buildCode(Opt_Xml_Buffer::TAG_AFTER);
- break;
- case 'Opt_Xml_Element':
- if($this->isNamespace($item->getNamespace()))
- {
- if($item->get('single'))
- {
- $output .= $item->buildCode(Opt_Xml_Buffer::TAG_SINGLE_AFTER, Opt_Xml_Buffer::TAG_AFTER);
- }
- else
- {
- $output .= $item->buildCode(Opt_Xml_Buffer::TAG_CONTENT_AFTER, Opt_Xml_Buffer::TAG_CLOSING_BEFORE,
- Opt_Xml_Buffer::TAG_CLOSING_AFTER, Opt_Xml_Buffer::TAG_AFTER);
- }
- }
- else
- {
- $output .= $item->buildCode(Opt_Xml_Buffer::TAG_CONTENT_AFTER, Opt_Xml_Buffer::TAG_CLOSING_BEFORE).'</'.$item->get('_name').'>'.$item->buildCode(Opt_Xml_Buffer::TAG_CLOSING_AFTER, Opt_Xml_Buffer::TAG_AFTER);
- $item->set('_name', NULL);
- }
- break;
- case 'Opt_Xml_Root':
- $output .= $item->buildCode(Opt_Xml_Buffer::TAG_AFTER);
- break;
- }
- $this->_closeComments($item, $output);
- return $output;
- } // end _doPostlinking();
-
- /**
- * Closes the XML comment for the commented item.
- *
- * @internal
- * @param Opt_Xml_Node $item The commented item.
- * @param String &$output The reference to the output buffer.
- */
- protected function _closeComments($item, &$output)
- {
- if($item->get('commented'))
- {
- $this->_comments--;
- if($this->_comments == 0)
- {
- // According to the XML grammar, the construct "--->" is not allowed.
- if(strlen($output) > 0 && $output[strlen($output)-1] == '-')
- {
- throw new Opt_XmlComment_Exception('--->');
- }
-
- $output .= '-->';
- }
- }
- } // end _closeComments();
-
- /**
- * Links the element attributes into a valid XML code and returns
- * the output code.
- *
- * @internal
- * @param Opt_Xml_Element $subitem The XML element.
- * @return String
- */
- protected function _linkAttributes($subitem)
- {
- // Links the attributes into the PHP code
- if($subitem->hasAttributes() || $subitem->bufferSize(Opt_Xml_Buffer::TAG_BEGINNING_ATTRIBUTES) > 0 || $subitem->bufferSize(Opt_Xml_Buffer::TAG_ENDING_ATTRIBUTES) > 0)
- {
-
- $code = $subitem->buildCode(Opt_Xml_Buffer::TAG_ATTRIBUTES_BEFORE, Opt_Xml_Buffer::TAG_BEGINNING_ATTRIBUTES);
- $attrList = $subitem->getAttributes();
- // Link attributes into a string
- foreach($attrList as $attribute)
- {
- $s = $attribute->bufferSize(Opt_Xml_Buffer::ATTRIBUTE_NAME);
- switch($s)
- {
- case 0:
- $code .= $attribute->buildCode(Opt_Xml_Buffer::ATTRIBUTE_BEGIN).' '.$attribute->getXmlName();
- break;
- case 1:
- $code .= ($attribute->bufferSize(Opt_Xml_Buffer::ATTRIBUTE_BEGIN) == 0 ? ' ' : '').$attribute->buildCode(Opt_Xml_Buffer::ATTRIBUTE_BEGIN, ' ', Opt_Xml_Buffer::ATTRIBUTE_NAME);
- break;
- default:
- throw new Opt_CompilerCodeBufferConflict_Exception(1, 'ATTRIBUTE_NAME', $subitem->getXmlName());
- }
-
- if($attribute->bufferSize(Opt_Xml_Buffer::ATTRIBUTE_VALUE) == 0)
- {
- // Static value
- if(!($this->_tpl->htmlAttributes && $attribute->getValue() == $attribute->getName()))
- {
- $code .= '="'.htmlspecialchars($attribute->getValue()).'"';
- }
- }
- else
- {
- $code .= '="'.$attribute->buildCode(Opt_Xml_Buffer::ATTRIBUTE_VALUE).'"';
- }
- $code .= $attribute->buildCode(Opt_Xml_Buffer::ATTRIBUTE_END);
- }
- return $code.$subitem->buildCode(Opt_Xml_Buffer::TAG_ENDING_ATTRIBUTES, Opt_Xml_Buffer::TAG_ATTRIBUTES_AFTER);
- }
- return '';
- } // end _linkAttributes();
-
- /*
- * Main compilation methods
- */
-
- /**
- * The compilation launcher. It executes the proper compilation steps
- * according to the inheritance rules etc.
- *
- * @param String $code The source code to be compiled.
- * @param String $filename The source template filename.
- * @param String $compiledFilename The output template filename.
- * @param Int $mode The compilation mode.
- */
- public function compile($code, $filename, $compiledFilename, $mode)
- {
- try
- {
- // We cannot compile two templates at the same time
- if(!is_null($this->_template))
- {
- throw new Opt_CompilerLocked_Exception($filename, $this->_template);
- }
-
- // Detecting recursive inclusion
- if(is_null(self::$_recursionDetector))
- {
- self::$_recursionDetector = array(0 => $filename);
- $weFree = true;
- }
- else
- {
- if(in_array($filename, self::$_recursionDetector))
- {
- $exception = new Opt_CompilerRecursion_Exception($filename);
- $exception->setData(self::$_recursionDetector);
- throw $exception;
- }
- self::$_recursionDetector[] = $filename;
- $weFree = false;
- }
- // Cleaning up the processors
- foreach($this->_processors as $proc)
- {
- $proc->reset();
- }
- // Initializing the template launcher
- $this->set('template', $this->_template = $filename);
- $this->set('mode', $mode);
- $this->set('currentTemplate', $this->_template);
- array_push(self::$_templates, $filename);
- $this->_stack = new SplStack;
- $i = 0;
- $extend = $filename;
-
- $memory = 0;
-
- // The inheritance loop
- do
- {
- // Stage 1 - code compilation
- if($this->_tpl->debugConsole)
- {
- $initial = memory_get_usage();
- $tree = $this->_stage1($code, $extend, $mode);
- // Stage 2 - PHP tree processing
- $this->_stack = array();
- $this->_stage2($tree);
- $this->set('escape', NULL);
- unset($this->_stack);
- $memory += (memory_get_usage() - $initial);
- unset($code);
- }
- else
- {
- $tree = $this->_stage1($code, $extend, $mode);
- unset($code);
- // Stage 2 - PHP tree processing
- $this->_stack = array();
- $this->_stage2($tree);
- $this->set('escape', NULL);
- unset($this->_stack);
- }
-
-
- // if the template extends something, load it and also process
- if(isset($extend) && $extend != $filename)
- {
- $this->addDependantTemplate($extend);
- }
-
- if(!is_null($snippet = $tree->get('snippet')))
- {
- $tree->dispose();
- unset($tree);
-
- // Change the specified snippet into a root node.
- $tree = new Opt_Xml_Root;
- $attribute = new Opt_Xml_Attribute('opt:use', $snippet);
- $this->processor('snippet')->processAttribute($tree, $attribute);
- $this->processor('snippet')->postprocessAttribute($tree, $attribute);
-
- $this->_stage2($tree, true);
- break;
- }
- if(!is_null($extend = $tree->get('extend')))
- {
- $tree->dispose();
- unset($tree);
-
- $this->set('currentTemplate', $extend);
- array_pop(self::$_templates);
- array_push(self::$_templates, $extend);
- $code = $this->_tpl->_getSource($extend);
- }
- $i++;
- }
- while(!is_null($extend));
- // There are some dependant templates. We must add a suitable PHP code
- // to the output.
-
- if(sizeof($this->_dependencies) > 0)
- {
- $this->_addDependencies($tree);
- }
-
- if($this->_tpl->debugConsole)
- {
- Opt_Support::addCompiledTemplate($this->_template, $memory);
- }
-
- // Stage 3 - linking the last tree
- if(!is_null($compiledFilename))
- {
- $output = '';
- $this->_dynamicBlocks = array();
-
- $this->_stage3($output, $tree);
- $tree->dispose();
- unset($tree);
-
- $output = str_replace('?><'.'?php', '', $output);
-
- // Build the directories, if needed.
- if(($pos = strrpos($compiledFilename, '/')) !== false)
- {
- $path = $this->_tpl->compileDir.substr($compiledFilename, 0, $pos);
- if(!is_dir($path))
- {
- mkdir($path, 0750, true);
- }
- }
-
- // Save the file
- if(sizeof($this->_dynamicBlocks) > 0)
- {
- file_put_contents($this->_tpl->compileDir.$compiledFilename.'.dyn', serialize($this->_dynamicBlocks));
- }
- file_put_contents($this->_tpl->compileDir.$compiledFilename, $output);
- }
- else
- {
- $tree->dispose();
- }
- array_pop(self::$_templates);
- $this->_inheritance = array();
- if($weFree)
- {
- // Do the cleanup.
- $this->_dependencies = array();
- self::$_recursionDetector = NULL;
- foreach($this->_processors as $processor)
- {
- $processor->reset();
- }
- }
- $this->_template = NULL;
-
- // Run the new garbage collector, if it is available.
- /* if(version_compare(PHP_VERSION, '5.3.0', '>='))
- {
- gc_collect_cycles();
- }*/
- }
- catch(Exception $e)
- {
- // Free the memory
- if(isset($tree))
- {
- $tree->dispose();
- }
- // Clean the compiler state in case of exception
- $this->_template = NULL;
- $this->_dependencies = array();
- self::$_recursionDetector = NULL;
- foreach($this->_processors as $processor)
- {
- $processor->reset();
- }
- // Run the new garbage collector, if it is available.
- /* if(version_compare(PHP_VERSION, '5.3.0', '>='))
- {
- gc_collect_cycles();
- }*/
- // And throw it forward.
- throw $e;
- }
- } // end compile();
-
- /**
- * Compilation - stage 1 - parsing the input template and
- * building an XML tree.
- *
- * @internal
- * @param String &$code The code to be parsed
- * @param String $filename Currently unused.
- * @param Int $mode The compilation mode.
- * @return Opt_Xml_Root The root node of the new tree.
- */
- protected function _stage1(&$code, $filename, $mode)
- {
- $current = $tree = new Opt_Xml_Root;
- $codeSize = strlen($code);
- $encoding = $this->_tpl->charset;
-
- // First we have to find the prolog and DTD. Then we will be able to parse tags.
- if($mode != Opt_Class::QUIRKS_MODE)
- {
- // Find and parse XML prolog
- $endProlog = 0;
- $endDoctype = 0;
- if(substr($code, 0, 5) == '<?xml')
- {
- $endProlog = strpos($code, '?>', 5);
-
- if($endProlog === false)
- {
- throw new Opt_XmlInvalidProlog_Exception('prolog ending is missing');
- }
- $values = $this->_compileProlog(substr($code, 5, $endProlog - 5));
- $endProlog += 2;
- if(!$this->_tpl->prologRequired)
- {
- // The prolog must be displayed
- $tree->setProlog(new Opt_Xml_Prolog($values));
- }
- }
- // Skip white spaces
- for($i = $endProlog; $i < $codeSize; $i++)
- {
- if($code[$i] != ' ' && $code[$i] != ' ' && $code[$i] != "\r" && $code[$i] != "\n")
- {
- break;
- }
- }
- // Try to find doctype at the new position.
- $possibleDoctype = substr($code, $i, 9);
-
- if($possibleDoctype == '<!doctype' || $possibleDoctype == '<!DOCTYPE')
- {
- // OK, we've found it, now determine the doctype end.
- $bracketCounter = 0;
- $doctypeStart = $i;
- for($i += 9; $i < $codeSize; $i++)
- {
- if($code[$i] == '<')
- {
- $bracketCounter++;
- }
- else if($code[$i] == '>')
- {
- if($bracketCounter == 0)
- {
- $endDoctype = $i;
- break;
- }
- $bracketCounter--;
- }
- }
- if($endDoctype == 0)
- {
- throw new Opt_XmlInvalidDoctype_Exception('doctype ending is missing');
- }
-
- if(!$this->_tpl->prologRequired)
- {
- $tree->setDtd(new Opt_Xml_Dtd(substr($code, $doctypeStart, $i - $doctypeStart + 1)));
- }
- $endDoctype++;
- }
- else
- {
- $endDoctype = $endProlog;
- }
- // OK, now skip that part.
- $code = substr($code, $endDoctype, $codeSize);
- // In the quirks mode, some results from the regular expression parser are
- // moved by one position, so we must add some dynamics here.
- $attributeCell = 5;
- $endingSlashCell = 6;
- $tagExpression = $this->_rXmlTagExpression;
- }
- else
- {
- $tagExpression = $this->_rQuirksTagExpression;
- $attributeCell = 6;
- $endingSlashCell = 7;
- }
-
- // Split through the general groups (cdata-content)
- $groups = preg_split($this->_rCDataExpression, $code, …
Large files files are truncated, but you can click here to view the full file