dvadf
File manager - Edit - /home/centroca/public_html/html-api.zip
Back
PK �30] �Q�,A ,A class-wp-html-decoder.phpnu �[��� <?php /** * HTML API: WP_HTML_Decoder class * * Decodes spans of raw text found inside HTML content. * * @package WordPress * @subpackage HTML-API * @since 6.6.0 */ class WP_HTML_Decoder { /** * Indicates if an attribute value starts with a given raw string value. * * Use this method to determine if an attribute value starts with a given string, regardless * of how it might be encoded in HTML. For instance, `http:` could be represented as `http:` * or as `http:` or as `http:` or as `http:`, or in many other ways. * * Example: * * $value = 'http://wordpress.org/'; * true === WP_HTML_Decoder::attribute_starts_with( $value, 'http:', 'ascii-case-insensitive' ); * false === WP_HTML_Decoder::attribute_starts_with( $value, 'https:', 'ascii-case-insensitive' ); * * @since 6.6.0 * * @param string $haystack String containing the raw non-decoded attribute value. * @param string $search_text Does the attribute value start with this plain string. * @param string $case_sensitivity Optional. Pass 'ascii-case-insensitive' to ignore ASCII case when matching. * Default 'case-sensitive'. * @return bool Whether the attribute value starts with the given string. */ public static function attribute_starts_with( $haystack, $search_text, $case_sensitivity = 'case-sensitive' ): bool { $search_length = strlen( $search_text ); $loose_case = 'ascii-case-insensitive' === $case_sensitivity; $haystack_end = strlen( $haystack ); $search_at = 0; $haystack_at = 0; while ( $search_at < $search_length && $haystack_at < $haystack_end ) { $chars_match = $loose_case ? strtolower( $haystack[ $haystack_at ] ) === strtolower( $search_text[ $search_at ] ) : $haystack[ $haystack_at ] === $search_text[ $search_at ]; $is_introducer = '&' === $haystack[ $haystack_at ]; $next_chunk = $is_introducer ? self::read_character_reference( 'attribute', $haystack, $haystack_at, $token_length ) : null; // If there's no character reference and the characters don't match, the match fails. if ( null === $next_chunk && ! $chars_match ) { return false; } // If there's no character reference but the character do match, then it could still match. if ( null === $next_chunk && $chars_match ) { ++$haystack_at; ++$search_at; continue; } // If there is a character reference, then the decoded value must exactly match what follows in the search string. if ( 0 !== substr_compare( $search_text, $next_chunk, $search_at, strlen( $next_chunk ), $loose_case ) ) { return false; } // The character reference matched, so continue checking. $haystack_at += $token_length; $search_at += strlen( $next_chunk ); } return true; } /** * Returns a string containing the decoded value of a given HTML text node. * * Text nodes appear in HTML DATA sections, which are the text segments inside * and around tags, excepting SCRIPT and STYLE elements (and some others), * whose inner text is not decoded. Use this function to read the decoded * value of such a text span in an HTML document. * * Example: * * '“😄”' === WP_HTML_Decode::decode_text_node( '“😄”' ); * * @since 6.6.0 * * @param string $text Text containing raw and non-decoded text node to decode. * @return string Decoded UTF-8 value of given text node. */ public static function decode_text_node( $text ): string { return static::decode( 'data', $text ); } /** * Returns a string containing the decoded value of a given HTML attribute. * * Text found inside an HTML attribute has different parsing rules than for * text found inside other markup, or DATA segments. Use this function to * read the decoded value of an HTML string inside a quoted attribute. * * Example: * * '“😄”' === WP_HTML_Decode::decode_attribute( '“😄”' ); * * @since 6.6.0 * * @param string $text Text containing raw and non-decoded attribute value to decode. * @return string Decoded UTF-8 value of given attribute value. */ public static function decode_attribute( $text ): string { return static::decode( 'attribute', $text ); } /** * Decodes a span of HTML text, depending on the context in which it's found. * * This is a low-level method; prefer calling WP_HTML_Decoder::decode_attribute() or * WP_HTML_Decoder::decode_text_node() instead. It's provided for cases where this * may be difficult to do from calling code. * * Example: * * '©' = WP_HTML_Decoder::decode( 'data', '©' ); * * @since 6.6.0 * * @access private * * @param string $context `attribute` for decoding attribute values, `data` otherwise. * @param string $text Text document containing span of text to decode. * @return string Decoded UTF-8 string. */ public static function decode( $context, $text ): string { $decoded = ''; $end = strlen( $text ); $at = 0; $was_at = 0; while ( $at < $end ) { $next_character_reference_at = strpos( $text, '&', $at ); if ( false === $next_character_reference_at ) { break; } $character_reference = self::read_character_reference( $context, $text, $next_character_reference_at, $token_length ); if ( isset( $character_reference ) ) { $at = $next_character_reference_at; $decoded .= substr( $text, $was_at, $at - $was_at ); $decoded .= $character_reference; $at += $token_length; $was_at = $at; continue; } ++$at; } if ( 0 === $was_at ) { return $text; } if ( $was_at < $end ) { $decoded .= substr( $text, $was_at, $end - $was_at ); } return $decoded; } /** * Attempt to read a character reference at the given location in a given string, * depending on the context in which it's found. * * If a character reference is found, this function will return the translated value * that the reference maps to. It will then set `$match_byte_length` the * number of bytes of input it read while consuming the character reference. This * gives calling code the opportunity to advance its cursor when traversing a string * and decoding. * * Example: * * null === WP_HTML_Decoder::read_character_reference( 'attribute', 'Ships…', 0 ); * '…' === WP_HTML_Decoder::read_character_reference( 'attribute', 'Ships…', 5, $token_length ); * 8 === $token_length; // `…` * * null === WP_HTML_Decoder::read_character_reference( 'attribute', '¬in', 0 ); * '∉' === WP_HTML_Decoder::read_character_reference( 'attribute', '∉', 0, $token_length ); * 7 === $token_length; // `∉` * * '¬' === WP_HTML_Decoder::read_character_reference( 'data', '¬in', 0, $token_length ); * 4 === $token_length; // `¬` * '∉' === WP_HTML_Decoder::read_character_reference( 'data', '∉', 0, $token_length ); * 7 === $token_length; // `∉` * * @since 6.6.0 * * @global WP_Token_Map $html5_named_character_references Mappings for HTML5 named character references. * * @param string $context `attribute` for decoding attribute values, `data` otherwise. * @param string $text Text document containing span of text to decode. * @param int $at Optional. Byte offset into text where span begins, defaults to the beginning (0). * @param int &$match_byte_length Optional. Set to byte-length of character reference if provided and if a match * is found, otherwise not set. Default null. * @return ?string Decoded character reference in UTF-8 if found, otherwise null. */ public static function read_character_reference( $context, $text, $at = 0, &$match_byte_length = null ) { /** * Mappings for HTML5 named character references. * * @var WP_Token_Map $html5_named_character_references */ global $html5_named_character_references; $length = strlen( $text ); if ( $at + 1 >= $length ) { return null; } if ( '&' !== $text[ $at ] ) { return null; } /* * Numeric character references. * * When truncated, these will encode the code point found by parsing the * digits that are available. For example, when `🅰` is truncated * to `DZ` it will encode `DZ`. It does not: * - know how to parse the original `🅰`. * - fail to parse and return plaintext `DZ`. * - fail to parse and return the replacement character `�` */ if ( '#' === $text[ $at + 1 ] ) { if ( $at + 2 >= $length ) { return null; } /** Tracks inner parsing within the numeric character reference. */ $digits_at = $at + 2; if ( 'x' === $text[ $digits_at ] || 'X' === $text[ $digits_at ] ) { $numeric_base = 16; $numeric_digits = '0123456789abcdefABCDEF'; $max_digits = 6; //  ++$digits_at; } else { $numeric_base = 10; $numeric_digits = '0123456789'; $max_digits = 7; //  } // Cannot encode invalid Unicode code points. Max is to U+10FFFF. $zero_count = strspn( $text, '0', $digits_at ); $digit_count = strspn( $text, $numeric_digits, $digits_at + $zero_count ); $after_digits = $digits_at + $zero_count + $digit_count; $has_semicolon = $after_digits < $length && ';' === $text[ $after_digits ]; $end_of_span = $has_semicolon ? $after_digits + 1 : $after_digits; // `&#` or `&#x` without digits returns into plaintext. if ( 0 === $digit_count && 0 === $zero_count ) { return null; } // Whereas `&#` and only zeros is invalid. if ( 0 === $digit_count ) { $match_byte_length = $end_of_span - $at; return '�'; } // If there are too many digits then it's not worth parsing. It's invalid. if ( $digit_count > $max_digits ) { $match_byte_length = $end_of_span - $at; return '�'; } $digits = substr( $text, $digits_at + $zero_count, $digit_count ); $code_point = intval( $digits, $numeric_base ); /* * Noncharacters, 0x0D, and non-ASCII-whitespace control characters. * * > A noncharacter is a code point that is in the range U+FDD0 to U+FDEF, * > inclusive, or U+FFFE, U+FFFF, U+1FFFE, U+1FFFF, U+2FFFE, U+2FFFF, * > U+3FFFE, U+3FFFF, U+4FFFE, U+4FFFF, U+5FFFE, U+5FFFF, U+6FFFE, * > U+6FFFF, U+7FFFE, U+7FFFF, U+8FFFE, U+8FFFF, U+9FFFE, U+9FFFF, * > U+AFFFE, U+AFFFF, U+BFFFE, U+BFFFF, U+CFFFE, U+CFFFF, U+DFFFE, * > U+DFFFF, U+EFFFE, U+EFFFF, U+FFFFE, U+FFFFF, U+10FFFE, or U+10FFFF. * * A C0 control is a code point that is in the range of U+00 to U+1F, * but ASCII whitespace includes U+09, U+0A, U+0C, and U+0D. * * These characters are invalid but still decode as any valid character. * This comment is here to note and explain why there's no check to * remove these characters or replace them. * * @see https://infra.spec.whatwg.org/#noncharacter */ /* * Code points in the C1 controls area need to be remapped as if they * were stored in Windows-1252. Note! This transformation only happens * for numeric character references. The raw code points in the byte * stream are not translated. * * > If the number is one of the numbers in the first column of * > the following table, then find the row with that number in * > the first column, and set the character reference code to * > the number in the second column of that row. */ if ( $code_point >= 0x80 && $code_point <= 0x9F ) { $windows_1252_mapping = array( 0x20AC, // 0x80 -> EURO SIGN (€). 0x81, // 0x81 -> (no change). 0x201A, // 0x82 -> SINGLE LOW-9 QUOTATION MARK (‚). 0x0192, // 0x83 -> LATIN SMALL LETTER F WITH HOOK (ƒ). 0x201E, // 0x84 -> DOUBLE LOW-9 QUOTATION MARK („). 0x2026, // 0x85 -> HORIZONTAL ELLIPSIS (…). 0x2020, // 0x86 -> DAGGER (†). 0x2021, // 0x87 -> DOUBLE DAGGER (‡). 0x02C6, // 0x88 -> MODIFIER LETTER CIRCUMFLEX ACCENT (ˆ). 0x2030, // 0x89 -> PER MILLE SIGN (‰). 0x0160, // 0x8A -> LATIN CAPITAL LETTER S WITH CARON (Š). 0x2039, // 0x8B -> SINGLE LEFT-POINTING ANGLE QUOTATION MARK (‹). 0x0152, // 0x8C -> LATIN CAPITAL LIGATURE OE (Œ). 0x8D, // 0x8D -> (no change). 0x017D, // 0x8E -> LATIN CAPITAL LETTER Z WITH CARON (Ž). 0x8F, // 0x8F -> (no change). 0x90, // 0x90 -> (no change). 0x2018, // 0x91 -> LEFT SINGLE QUOTATION MARK (‘). 0x2019, // 0x92 -> RIGHT SINGLE QUOTATION MARK (’). 0x201C, // 0x93 -> LEFT DOUBLE QUOTATION MARK (“). 0x201D, // 0x94 -> RIGHT DOUBLE QUOTATION MARK (”). 0x2022, // 0x95 -> BULLET (•). 0x2013, // 0x96 -> EN DASH (–). 0x2014, // 0x97 -> EM DASH (—). 0x02DC, // 0x98 -> SMALL TILDE (˜). 0x2122, // 0x99 -> TRADE MARK SIGN (™). 0x0161, // 0x9A -> LATIN SMALL LETTER S WITH CARON (š). 0x203A, // 0x9B -> SINGLE RIGHT-POINTING ANGLE QUOTATION MARK (›). 0x0153, // 0x9C -> LATIN SMALL LIGATURE OE (œ). 0x9D, // 0x9D -> (no change). 0x017E, // 0x9E -> LATIN SMALL LETTER Z WITH CARON (ž). 0x0178, // 0x9F -> LATIN CAPITAL LETTER Y WITH DIAERESIS (Ÿ). ); $code_point = $windows_1252_mapping[ $code_point - 0x80 ]; } $match_byte_length = $end_of_span - $at; return self::code_point_to_utf8_bytes( $code_point ); } /** Tracks inner parsing within the named character reference. */ $name_at = $at + 1; // Minimum named character reference is two characters. E.g. `GT`. if ( $name_at + 2 > $length ) { return null; } $name_length = 0; $replacement = $html5_named_character_references->read_token( $text, $name_at, $name_length ); if ( false === $replacement ) { return null; } $after_name = $name_at + $name_length; // If the match ended with a semicolon then it should always be decoded. if ( ';' === $text[ $name_at + $name_length - 1 ] ) { $match_byte_length = $after_name - $at; return $replacement; } /* * At this point though there's a match for an entry in the named * character reference table but the match doesn't end in `;`. * It may be allowed if it's followed by something unambiguous. */ $ambiguous_follower = ( $after_name < $length && $name_at < $length && ( ctype_alnum( $text[ $after_name ] ) || '=' === $text[ $after_name ] ) ); // It's non-ambiguous, safe to leave it in. if ( ! $ambiguous_follower ) { $match_byte_length = $after_name - $at; return $replacement; } // It's ambiguous, which isn't allowed inside attributes. if ( 'attribute' === $context ) { return null; } $match_byte_length = $after_name - $at; return $replacement; } /** * Encode a code point number into the UTF-8 encoding. * * This encoder implements the UTF-8 encoding algorithm for converting * a code point into a byte sequence. If it receives an invalid code * point it will return the Unicode Replacement Character U+FFFD `�`. * * Example: * * '🅰' === WP_HTML_Decoder::code_point_to_utf8_bytes( 0x1f170 ); * * // Half of a surrogate pair is an invalid code point. * '�' === WP_HTML_Decoder::code_point_to_utf8_bytes( 0xd83c ); * * @since 6.6.0 * * @see https://www.rfc-editor.org/rfc/rfc3629 For the UTF-8 standard. * * @param int $code_point Which code point to convert. * @return string Converted code point, or `�` if invalid. */ public static function code_point_to_utf8_bytes( $code_point ): string { // Pre-check to ensure a valid code point. if ( $code_point <= 0 || ( $code_point >= 0xD800 && $code_point <= 0xDFFF ) || $code_point > 0x10FFFF ) { return '�'; } if ( $code_point <= 0x7F ) { return chr( $code_point ); } if ( $code_point <= 0x7FF ) { $byte1 = chr( ( $code_point >> 6 ) | 0xC0 ); $byte2 = chr( $code_point & 0x3F | 0x80 ); return "{$byte1}{$byte2}"; } if ( $code_point <= 0xFFFF ) { $byte1 = chr( ( $code_point >> 12 ) | 0xE0 ); $byte2 = chr( ( $code_point >> 6 ) & 0x3F | 0x80 ); $byte3 = chr( $code_point & 0x3F | 0x80 ); return "{$byte1}{$byte2}{$byte3}"; } // Any values above U+10FFFF are eliminated above in the pre-check. $byte1 = chr( ( $code_point >> 18 ) | 0xF0 ); $byte2 = chr( ( $code_point >> 12 ) & 0x3F | 0x80 ); $byte3 = chr( ( $code_point >> 6 ) & 0x3F | 0x80 ); $byte4 = chr( $code_point & 0x3F | 0x80 ); return "{$byte1}{$byte2}{$byte3}{$byte4}"; } } PK �30] �7�W �W class-wp-html-open-elements.phpnu �[��� <?php /** * HTML API: WP_HTML_Open_Elements class * * @package WordPress * @subpackage HTML-API * @since 6.4.0 */ /** * Core class used by the HTML processor during HTML parsing * for managing the stack of open elements. * * This class is designed for internal use by the HTML processor. * * > Initially, the stack of open elements is empty. The stack grows * > downwards; the topmost node on the stack is the first one added * > to the stack, and the bottommost node of the stack is the most * > recently added node in the stack (notwithstanding when the stack * > is manipulated in a random access fashion as part of the handling * > for misnested tags). * * @since 6.4.0 * * @access private * @ignore * * @see https://html.spec.whatwg.org/#stack-of-open-elements * @see WP_HTML_Processor */ class WP_HTML_Open_Elements { /** * Holds the stack of open element references. * * @since 6.4.0 * * @var WP_HTML_Token[] */ public $stack = array(); /** * Whether a P element is in button scope currently. * * This class optimizes scope lookup by pre-calculating * this value when elements are added and removed to the * stack of open elements which might change its value. * This avoids frequent iteration over the stack. * * @since 6.4.0 * * @var bool */ private $has_p_in_button_scope = false; /** * A function that will be called when an item is popped off the stack of open elements. * * The function will be called with the popped item as its argument. * * @since 6.6.0 * * @var Closure|null */ private $pop_handler = null; /** * A function that will be called when an item is pushed onto the stack of open elements. * * The function will be called with the pushed item as its argument. * * @since 6.6.0 * * @var Closure|null */ private $push_handler = null; /** * Sets a pop handler that will be called when an item is popped off the stack of * open elements. * * The function will be called with the pushed item as its argument. * * @since 6.6.0 * * @param Closure $handler The handler function. */ public function set_pop_handler( Closure $handler ): void { $this->pop_handler = $handler; } /** * Sets a push handler that will be called when an item is pushed onto the stack of * open elements. * * The function will be called with the pushed item as its argument. * * @since 6.6.0 * * @param Closure $handler The handler function. */ public function set_push_handler( Closure $handler ): void { $this->push_handler = $handler; } /** * Returns the name of the node at the nth position on the stack * of open elements, or `null` if no such position exists. * * Note that this uses a 1-based index, which represents the * "nth item" on the stack, counting from the top, where the * top-most element is the 1st, the second is the 2nd, etc... * * @since 6.7.0 * * @param int $nth Retrieve the nth item on the stack, with 1 being * the top element, 2 being the second, etc... * @return WP_HTML_Token|null Name of the node on the stack at the given location, * or `null` if the location isn't on the stack. */ public function at( int $nth ): ?WP_HTML_Token { foreach ( $this->walk_down() as $item ) { if ( 0 === --$nth ) { return $item; } } return null; } /** * Reports if a node of a given name is in the stack of open elements. * * @since 6.7.0 * * @param string $node_name Name of node for which to check. * @return bool Whether a node of the given name is in the stack of open elements. */ public function contains( string $node_name ): bool { foreach ( $this->walk_up() as $item ) { if ( $node_name === $item->node_name ) { return true; } } return false; } /** * Reports if a specific node is in the stack of open elements. * * @since 6.4.0 * * @param WP_HTML_Token $token Look for this node in the stack. * @return bool Whether the referenced node is in the stack of open elements. */ public function contains_node( WP_HTML_Token $token ): bool { foreach ( $this->walk_up() as $item ) { if ( $token === $item ) { return true; } } return false; } /** * Returns how many nodes are currently in the stack of open elements. * * @since 6.4.0 * * @return int How many node are in the stack of open elements. */ public function count(): int { return count( $this->stack ); } /** * Returns the node at the end of the stack of open elements, * if one exists. If the stack is empty, returns null. * * @since 6.4.0 * * @return WP_HTML_Token|null Last node in the stack of open elements, if one exists, otherwise null. */ public function current_node(): ?WP_HTML_Token { $current_node = end( $this->stack ); return $current_node ? $current_node : null; } /** * Indicates if the current node is of a given type or name. * * It's possible to pass either a node type or a node name to this function. * In the case there is no current element it will always return `false`. * * Example: * * // Is the current node a text node? * $stack->current_node_is( '#text' ); * * // Is the current node a DIV element? * $stack->current_node_is( 'DIV' ); * * // Is the current node any element/tag? * $stack->current_node_is( '#tag' ); * * @see WP_HTML_Tag_Processor::get_token_type * @see WP_HTML_Tag_Processor::get_token_name * * @since 6.7.0 * * @access private * * @param string $identity Check if the current node has this name or type (depending on what is provided). * @return bool Whether there is a current element that matches the given identity, whether a token name or type. */ public function current_node_is( string $identity ): bool { $current_node = end( $this->stack ); if ( false === $current_node ) { return false; } $current_node_name = $current_node->node_name; return ( $current_node_name === $identity || ( '#doctype' === $identity && 'html' === $current_node_name ) || ( '#tag' === $identity && ctype_upper( $current_node_name ) ) ); } /** * Returns whether an element is in a specific scope. * * @since 6.4.0 * * @see https://html.spec.whatwg.org/#has-an-element-in-the-specific-scope * * @param string $tag_name Name of tag check. * @param string[] $termination_list List of elements that terminate the search. * @return bool Whether the element was found in a specific scope. */ public function has_element_in_specific_scope( string $tag_name, $termination_list ): bool { foreach ( $this->walk_up() as $node ) { $namespaced_name = 'html' === $node->namespace ? $node->node_name : "{$node->namespace} {$node->node_name}"; if ( $namespaced_name === $tag_name ) { return true; } if ( '(internal: H1 through H6 - do not use)' === $tag_name && in_array( $namespaced_name, array( 'H1', 'H2', 'H3', 'H4', 'H5', 'H6' ), true ) ) { return true; } if ( in_array( $namespaced_name, $termination_list, true ) ) { return false; } } return false; } /** * Returns whether a particular element is in scope. * * > The stack of open elements is said to have a particular element in * > scope when it has that element in the specific scope consisting of * > the following element types: * > * > - applet * > - caption * > - html * > - table * > - td * > - th * > - marquee * > - object * > - template * > - MathML mi * > - MathML mo * > - MathML mn * > - MathML ms * > - MathML mtext * > - MathML annotation-xml * > - SVG foreignObject * > - SVG desc * > - SVG title * * @since 6.4.0 * @since 6.7.0 Full support. * * @see https://html.spec.whatwg.org/#has-an-element-in-scope * * @param string $tag_name Name of tag to check. * @return bool Whether given element is in scope. */ public function has_element_in_scope( string $tag_name ): bool { return $this->has_element_in_specific_scope( $tag_name, array( 'APPLET', 'CAPTION', 'HTML', 'TABLE', 'TD', 'TH', 'MARQUEE', 'OBJECT', 'TEMPLATE', 'math MI', 'math MO', 'math MN', 'math MS', 'math MTEXT', 'math ANNOTATION-XML', 'svg FOREIGNOBJECT', 'svg DESC', 'svg TITLE', ) ); } /** * Returns whether a particular element is in list item scope. * * > The stack of open elements is said to have a particular element * > in list item scope when it has that element in the specific scope * > consisting of the following element types: * > * > - All the element types listed above for the has an element in scope algorithm. * > - ol in the HTML namespace * > - ul in the HTML namespace * * @since 6.4.0 * @since 6.5.0 Implemented: no longer throws on every invocation. * @since 6.7.0 Supports all required HTML elements. * * @see https://html.spec.whatwg.org/#has-an-element-in-list-item-scope * * @param string $tag_name Name of tag to check. * @return bool Whether given element is in scope. */ public function has_element_in_list_item_scope( string $tag_name ): bool { return $this->has_element_in_specific_scope( $tag_name, array( 'APPLET', 'BUTTON', 'CAPTION', 'HTML', 'TABLE', 'TD', 'TH', 'MARQUEE', 'OBJECT', 'OL', 'TEMPLATE', 'UL', 'math MI', 'math MO', 'math MN', 'math MS', 'math MTEXT', 'math ANNOTATION-XML', 'svg FOREIGNOBJECT', 'svg DESC', 'svg TITLE', ) ); } /** * Returns whether a particular element is in button scope. * * > The stack of open elements is said to have a particular element * > in button scope when it has that element in the specific scope * > consisting of the following element types: * > * > - All the element types listed above for the has an element in scope algorithm. * > - button in the HTML namespace * * @since 6.4.0 * @since 6.7.0 Supports all required HTML elements. * * @see https://html.spec.whatwg.org/#has-an-element-in-button-scope * * @param string $tag_name Name of tag to check. * @return bool Whether given element is in scope. */ public function has_element_in_button_scope( string $tag_name ): bool { return $this->has_element_in_specific_scope( $tag_name, array( 'APPLET', 'BUTTON', 'CAPTION', 'HTML', 'TABLE', 'TD', 'TH', 'MARQUEE', 'OBJECT', 'TEMPLATE', 'math MI', 'math MO', 'math MN', 'math MS', 'math MTEXT', 'math ANNOTATION-XML', 'svg FOREIGNOBJECT', 'svg DESC', 'svg TITLE', ) ); } /** * Returns whether a particular element is in table scope. * * > The stack of open elements is said to have a particular element * > in table scope when it has that element in the specific scope * > consisting of the following element types: * > * > - html in the HTML namespace * > - table in the HTML namespace * > - template in the HTML namespace * * @since 6.4.0 * @since 6.7.0 Full implementation. * * @see https://html.spec.whatwg.org/#has-an-element-in-table-scope * * @param string $tag_name Name of tag to check. * @return bool Whether given element is in scope. */ public function has_element_in_table_scope( string $tag_name ): bool { return $this->has_element_in_specific_scope( $tag_name, array( 'HTML', 'TABLE', 'TEMPLATE', ) ); } /** * Returns whether a particular element is in select scope. * * This test differs from the others like it, in that its rules are inverted. * Instead of arriving at a match when one of any tag in a termination group * is reached, this one terminates if any other tag is reached. * * > The stack of open elements is said to have a particular element in select scope when it has * > that element in the specific scope consisting of all element types except the following: * > - optgroup in the HTML namespace * > - option in the HTML namespace * * @since 6.4.0 Stub implementation (throws). * @since 6.7.0 Full implementation. * * @see https://html.spec.whatwg.org/#has-an-element-in-select-scope * * @param string $tag_name Name of tag to check. * @return bool Whether the given element is in SELECT scope. */ public function has_element_in_select_scope( string $tag_name ): bool { foreach ( $this->walk_up() as $node ) { if ( $node->node_name === $tag_name ) { return true; } if ( 'OPTION' !== $node->node_name && 'OPTGROUP' !== $node->node_name ) { return false; } } return false; } /** * Returns whether a P is in BUTTON scope. * * @since 6.4.0 * * @see https://html.spec.whatwg.org/#has-an-element-in-button-scope * * @return bool Whether a P is in BUTTON scope. */ public function has_p_in_button_scope(): bool { return $this->has_p_in_button_scope; } /** * Pops a node off of the stack of open elements. * * @since 6.4.0 * * @see https://html.spec.whatwg.org/#stack-of-open-elements * * @return bool Whether a node was popped off of the stack. */ public function pop(): bool { $item = array_pop( $this->stack ); if ( null === $item ) { return false; } $this->after_element_pop( $item ); return true; } /** * Pops nodes off of the stack of open elements until an HTML tag with the given name has been popped. * * @since 6.4.0 * * @see WP_HTML_Open_Elements::pop * * @param string $html_tag_name Name of tag that needs to be popped off of the stack of open elements. * @return bool Whether a tag of the given name was found and popped off of the stack of open elements. */ public function pop_until( string $html_tag_name ): bool { foreach ( $this->walk_up() as $item ) { $this->pop(); if ( 'html' !== $item->namespace ) { continue; } if ( '(internal: H1 through H6 - do not use)' === $html_tag_name && in_array( $item->node_name, array( 'H1', 'H2', 'H3', 'H4', 'H5', 'H6' ), true ) ) { return true; } if ( $html_tag_name === $item->node_name ) { return true; } } return false; } /** * Pushes a node onto the stack of open elements. * * @since 6.4.0 * * @see https://html.spec.whatwg.org/#stack-of-open-elements * * @param WP_HTML_Token $stack_item Item to add onto stack. */ public function push( WP_HTML_Token $stack_item ): void { $this->stack[] = $stack_item; $this->after_element_push( $stack_item ); } /** * Removes a specific node from the stack of open elements. * * @since 6.4.0 * * @param WP_HTML_Token $token The node to remove from the stack of open elements. * @return bool Whether the node was found and removed from the stack of open elements. */ public function remove_node( WP_HTML_Token $token ): bool { foreach ( $this->walk_up() as $position_from_end => $item ) { if ( $token->bookmark_name !== $item->bookmark_name ) { continue; } $position_from_start = $this->count() - $position_from_end - 1; array_splice( $this->stack, $position_from_start, 1 ); $this->after_element_pop( $item ); return true; } return false; } /** * Steps through the stack of open elements, starting with the top element * (added first) and walking downwards to the one added last. * * This generator function is designed to be used inside a "foreach" loop. * * Example: * * $html = '<em><strong><a>We are here'; * foreach ( $stack->walk_down() as $node ) { * echo "{$node->node_name} -> "; * } * > EM -> STRONG -> A -> * * To start with the most-recently added element and walk towards the top, * see WP_HTML_Open_Elements::walk_up(). * * @since 6.4.0 */ public function walk_down() { $count = count( $this->stack ); for ( $i = 0; $i < $count; $i++ ) { yield $this->stack[ $i ]; } } /** * Steps through the stack of open elements, starting with the bottom element * (added last) and walking upwards to the one added first. * * This generator function is designed to be used inside a "foreach" loop. * * Example: * * $html = '<em><strong><a>We are here'; * foreach ( $stack->walk_up() as $node ) { * echo "{$node->node_name} -> "; * } * > A -> STRONG -> EM -> * * To start with the first added element and walk towards the bottom, * see WP_HTML_Open_Elements::walk_down(). * * @since 6.4.0 * @since 6.5.0 Accepts $above_this_node to start traversal above a given node, if it exists. * * @param WP_HTML_Token|null $above_this_node Optional. Start traversing above this node, * if provided and if the node exists. */ public function walk_up( ?WP_HTML_Token $above_this_node = null ) { $has_found_node = null === $above_this_node; for ( $i = count( $this->stack ) - 1; $i >= 0; $i-- ) { $node = $this->stack[ $i ]; if ( ! $has_found_node ) { $has_found_node = $node === $above_this_node; continue; } yield $node; } } /* * Internal helpers. */ /** * Updates internal flags after adding an element. * * Certain conditions (such as "has_p_in_button_scope") are maintained here as * flags that are only modified when adding and removing elements. This allows * the HTML Processor to quickly check for these conditions instead of iterating * over the open stack elements upon each new tag it encounters. These flags, * however, need to be maintained as items are added and removed from the stack. * * @since 6.4.0 * * @param WP_HTML_Token $item Element that was added to the stack of open elements. */ public function after_element_push( WP_HTML_Token $item ): void { $namespaced_name = 'html' === $item->namespace ? $item->node_name : "{$item->namespace} {$item->node_name}"; /* * When adding support for new elements, expand this switch to trap * cases where the precalculated value needs to change. */ switch ( $namespaced_name ) { case 'APPLET': case 'BUTTON': case 'CAPTION': case 'HTML': case 'TABLE': case 'TD': case 'TH': case 'MARQUEE': case 'OBJECT': case 'TEMPLATE': case 'math MI': case 'math MO': case 'math MN': case 'math MS': case 'math MTEXT': case 'math ANNOTATION-XML': case 'svg FOREIGNOBJECT': case 'svg DESC': case 'svg TITLE': $this->has_p_in_button_scope = false; break; case 'P': $this->has_p_in_button_scope = true; break; } if ( null !== $this->push_handler ) { call_user_func( $this->push_handler, $item ); } } /** * Updates internal flags after removing an element. * * Certain conditions (such as "has_p_in_button_scope") are maintained here as * flags that are only modified when adding and removing elements. This allows * the HTML Processor to quickly check for these conditions instead of iterating * over the open stack elements upon each new tag it encounters. These flags, * however, need to be maintained as items are added and removed from the stack. * * @since 6.4.0 * * @param WP_HTML_Token $item Element that was removed from the stack of open elements. */ public function after_element_pop( WP_HTML_Token $item ): void { /* * When adding support for new elements, expand this switch to trap * cases where the precalculated value needs to change. */ switch ( $item->node_name ) { case 'APPLET': case 'BUTTON': case 'CAPTION': case 'HTML': case 'P': case 'TABLE': case 'TD': case 'TH': case 'MARQUEE': case 'OBJECT': case 'TEMPLATE': case 'math MI': case 'math MO': case 'math MN': case 'math MS': case 'math MTEXT': case 'math ANNOTATION-XML': case 'svg FOREIGNOBJECT': case 'svg DESC': case 'svg TITLE': $this->has_p_in_button_scope = $this->has_element_in_button_scope( 'P' ); break; } if ( null !== $this->pop_handler ) { call_user_func( $this->pop_handler, $item ); } } /** * Clear the stack back to a table context. * * > When the steps above require the UA to clear the stack back to a table context, it means * > that the UA must, while the current node is not a table, template, or html element, pop * > elements from the stack of open elements. * * @see https://html.spec.whatwg.org/multipage/parsing.html#clear-the-stack-back-to-a-table-context * * @since 6.7.0 */ public function clear_to_table_context(): void { foreach ( $this->walk_up() as $item ) { if ( 'TABLE' === $item->node_name || 'TEMPLATE' === $item->node_name || 'HTML' === $item->node_name ) { break; } $this->pop(); } } /** * Clear the stack back to a table body context. * * > When the steps above require the UA to clear the stack back to a table body context, it * > means that the UA must, while the current node is not a tbody, tfoot, thead, template, or * > html element, pop elements from the stack of open elements. * * @see https://html.spec.whatwg.org/multipage/parsing.html#clear-the-stack-back-to-a-table-body-context * * @since 6.7.0 */ public function clear_to_table_body_context(): void { foreach ( $this->walk_up() as $item ) { if ( 'TBODY' === $item->node_name || 'TFOOT' === $item->node_name || 'THEAD' === $item->node_name || 'TEMPLATE' === $item->node_name || 'HTML' === $item->node_name ) { break; } $this->pop(); } } /** * Clear the stack back to a table row context. * * > When the steps above require the UA to clear the stack back to a table row context, it * > means that the UA must, while the current node is not a tr, template, or html element, pop * > elements from the stack of open elements. * * @see https://html.spec.whatwg.org/multipage/parsing.html#clear-the-stack-back-to-a-table-row-context * * @since 6.7.0 */ public function clear_to_table_row_context(): void { foreach ( $this->walk_up() as $item ) { if ( 'TR' === $item->node_name || 'TEMPLATE' === $item->node_name || 'HTML' === $item->node_name ) { break; } $this->pop(); } } /** * Wakeup magic method. * * @since 6.6.0 */ public function __wakeup() { throw new \LogicException( __CLASS__ . ' should never be unserialized' ); } } PK �30]K:'� � ! class-wp-html-attribute-token.phpnu �[��� <?php /** * HTML API: WP_HTML_Attribute_Token class * * @package WordPress * @subpackage HTML-API * @since 6.2.0 */ /** * Core class used by the HTML tag processor as a data structure for the attribute token, * allowing to drastically improve performance. * * This class is for internal usage of the WP_HTML_Tag_Processor class. * * @access private * @ignore * * @since 6.2.0 * @since 6.5.0 Replaced `end` with `length` to more closely match `substr()`. * * @see WP_HTML_Tag_Processor */ class WP_HTML_Attribute_Token { /** * Attribute name. * * @since 6.2.0 * * @var string */ public $name; /** * Attribute value. * * @since 6.2.0 * * @var int */ public $value_starts_at; /** * How many bytes the value occupies in the input HTML. * * @since 6.2.0 * * @var int */ public $value_length; /** * The string offset where the attribute name starts. * * @since 6.2.0 * * @var int */ public $start; /** * Byte length of text spanning the attribute inside a tag. * * This span starts at the first character of the attribute name * and it ends after one of three cases: * * - at the end of the attribute name for boolean attributes. * - at the end of the value for unquoted attributes. * - at the final single or double quote for quoted attributes. * * Example: * * <div class="post"> * ------------ length is 12, including quotes * * <input type="checked" checked id="selector"> * ------- length is 6 * * <a rel=noopener> * ------------ length is 11 * * @since 6.5.0 Replaced `end` with `length` to more closely match `substr()`. * * @var int */ public $length; /** * Whether the attribute is a boolean attribute with value `true`. * * @since 6.2.0 * * @var bool */ public $is_true; /** * Constructor. * * @since 6.2.0 * @since 6.5.0 Replaced `end` with `length` to more closely match `substr()`. * * @param string $name Attribute name. * @param int $value_start Attribute value. * @param int $value_length Number of bytes attribute value spans. * @param int $start The string offset where the attribute name starts. * @param int $length Byte length of the entire attribute name or name and value pair expression. * @param bool $is_true Whether the attribute is a boolean attribute with true value. */ public function __construct( $name, $value_start, $value_length, $start, $length, $is_true ) { $this->name = $name; $this->value_starts_at = $value_start; $this->value_length = $value_length; $this->start = $start; $this->length = $length; $this->is_true = $is_true; } } PK �30]�-z�R, R, ! class-wp-html-processor-state.phpnu �[��� <?php /** * HTML API: WP_HTML_Processor_State class * * @package WordPress * @subpackage HTML-API * @since 6.4.0 */ /** * Core class used by the HTML processor during HTML parsing * for managing the internal parsing state. * * This class is designed for internal use by the HTML processor. * * @since 6.4.0 * * @access private * @ignore * * @see WP_HTML_Processor */ class WP_HTML_Processor_State { /* * Insertion mode constants. * * These constants exist and are named to make it easier to * discover and recognize the supported insertion modes in * the parser. * * Out of all the possible insertion modes, only those * supported by the parser are listed here. As support * is added to the parser for more modes, add them here * following the same naming and value pattern. * * @see https://html.spec.whatwg.org/#the-insertion-mode */ /** * Initial insertion mode for full HTML parser. * * @since 6.4.0 * * @see https://html.spec.whatwg.org/#the-initial-insertion-mode * @see WP_HTML_Processor_State::$insertion_mode * * @var string */ const INSERTION_MODE_INITIAL = 'insertion-mode-initial'; /** * Before HTML insertion mode for full HTML parser. * * @since 6.7.0 * * @see https://html.spec.whatwg.org/#the-before-html-insertion-mode * @see WP_HTML_Processor_State::$insertion_mode * * @var string */ const INSERTION_MODE_BEFORE_HTML = 'insertion-mode-before-html'; /** * Before head insertion mode for full HTML parser. * * @since 6.7.0 * * @see https://html.spec.whatwg.org/#parsing-main-beforehead * @see WP_HTML_Processor_State::$insertion_mode * * @var string */ const INSERTION_MODE_BEFORE_HEAD = 'insertion-mode-before-head'; /** * In head insertion mode for full HTML parser. * * @since 6.7.0 * * @see https://html.spec.whatwg.org/#parsing-main-inhead * @see WP_HTML_Processor_State::$insertion_mode * * @var string */ const INSERTION_MODE_IN_HEAD = 'insertion-mode-in-head'; /** * In head noscript insertion mode for full HTML parser. * * @since 6.7.0 * * @see https://html.spec.whatwg.org/#parsing-main-inheadnoscript * @see WP_HTML_Processor_State::$insertion_mode * * @var string */ const INSERTION_MODE_IN_HEAD_NOSCRIPT = 'insertion-mode-in-head-noscript'; /** * After head insertion mode for full HTML parser. * * @since 6.7.0 * * @see https://html.spec.whatwg.org/#parsing-main-afterhead * @see WP_HTML_Processor_State::$insertion_mode * * @var string */ const INSERTION_MODE_AFTER_HEAD = 'insertion-mode-after-head'; /** * In body insertion mode for full HTML parser. * * @since 6.4.0 * * @see https://html.spec.whatwg.org/#parsing-main-inbody * @see WP_HTML_Processor_State::$insertion_mode * * @var string */ const INSERTION_MODE_IN_BODY = 'insertion-mode-in-body'; /** * In table insertion mode for full HTML parser. * * @since 6.7.0 * * @see https://html.spec.whatwg.org/#parsing-main-intable * @see WP_HTML_Processor_State::$insertion_mode * * @var string */ const INSERTION_MODE_IN_TABLE = 'insertion-mode-in-table'; /** * In table text insertion mode for full HTML parser. * * @since 6.7.0 * * @see https://html.spec.whatwg.org/#parsing-main-intabletext * @see WP_HTML_Processor_State::$insertion_mode * * @var string */ const INSERTION_MODE_IN_TABLE_TEXT = 'insertion-mode-in-table-text'; /** * In caption insertion mode for full HTML parser. * * @since 6.7.0 * * @see https://html.spec.whatwg.org/#parsing-main-incaption * @see WP_HTML_Processor_State::$insertion_mode * * @var string */ const INSERTION_MODE_IN_CAPTION = 'insertion-mode-in-caption'; /** * In column group insertion mode for full HTML parser. * * @since 6.7.0 * * @see https://html.spec.whatwg.org/#parsing-main-incolumngroup * @see WP_HTML_Processor_State::$insertion_mode * * @var string */ const INSERTION_MODE_IN_COLUMN_GROUP = 'insertion-mode-in-column-group'; /** * In table body insertion mode for full HTML parser. * * @since 6.7.0 * * @see https://html.spec.whatwg.org/#parsing-main-intablebody * @see WP_HTML_Processor_State::$insertion_mode * * @var string */ const INSERTION_MODE_IN_TABLE_BODY = 'insertion-mode-in-table-body'; /** * In row insertion mode for full HTML parser. * * @since 6.7.0 * * @see https://html.spec.whatwg.org/#parsing-main-inrow * @see WP_HTML_Processor_State::$insertion_mode * * @var string */ const INSERTION_MODE_IN_ROW = 'insertion-mode-in-row'; /** * In cell insertion mode for full HTML parser. * * @since 6.7.0 * * @see https://html.spec.whatwg.org/#parsing-main-incell * @see WP_HTML_Processor_State::$insertion_mode * * @var string */ const INSERTION_MODE_IN_CELL = 'insertion-mode-in-cell'; /** * In select insertion mode for full HTML parser. * * @since 6.7.0 * * @see https://html.spec.whatwg.org/#parsing-main-inselect * @see WP_HTML_Processor_State::$insertion_mode * * @var string */ const INSERTION_MODE_IN_SELECT = 'insertion-mode-in-select'; /** * In select in table insertion mode for full HTML parser. * * @since 6.7.0 * * @see https://html.spec.whatwg.org/#parsing-main-inselectintable * @see WP_HTML_Processor_State::$insertion_mode * * @var string */ const INSERTION_MODE_IN_SELECT_IN_TABLE = 'insertion-mode-in-select-in-table'; /** * In template insertion mode for full HTML parser. * * @since 6.7.0 * * @see https://html.spec.whatwg.org/#parsing-main-intemplate * @see WP_HTML_Processor_State::$insertion_mode * * @var string */ const INSERTION_MODE_IN_TEMPLATE = 'insertion-mode-in-template'; /** * After body insertion mode for full HTML parser. * * @since 6.7.0 * * @see https://html.spec.whatwg.org/#parsing-main-afterbody * @see WP_HTML_Processor_State::$insertion_mode * * @var string */ const INSERTION_MODE_AFTER_BODY = 'insertion-mode-after-body'; /** * In frameset insertion mode for full HTML parser. * * @since 6.7.0 * * @see https://html.spec.whatwg.org/#parsing-main-inframeset * @see WP_HTML_Processor_State::$insertion_mode * * @var string */ const INSERTION_MODE_IN_FRAMESET = 'insertion-mode-in-frameset'; /** * After frameset insertion mode for full HTML parser. * * @since 6.7.0 * * @see https://html.spec.whatwg.org/#parsing-main-afterframeset * @see WP_HTML_Processor_State::$insertion_mode * * @var string */ const INSERTION_MODE_AFTER_FRAMESET = 'insertion-mode-after-frameset'; /** * After after body insertion mode for full HTML parser. * * @since 6.7.0 * * @see https://html.spec.whatwg.org/#the-after-after-body-insertion-mode * @see WP_HTML_Processor_State::$insertion_mode * * @var string */ const INSERTION_MODE_AFTER_AFTER_BODY = 'insertion-mode-after-after-body'; /** * After after frameset insertion mode for full HTML parser. * * @since 6.7.0 * * @see https://html.spec.whatwg.org/#the-after-after-frameset-insertion-mode * @see WP_HTML_Processor_State::$insertion_mode * * @var string */ const INSERTION_MODE_AFTER_AFTER_FRAMESET = 'insertion-mode-after-after-frameset'; /** * The stack of template insertion modes. * * @since 6.7.0 * * @see https://html.spec.whatwg.org/#the-insertion-mode:stack-of-template-insertion-modes * * @var array<string> */ public $stack_of_template_insertion_modes = array(); /** * Tracks open elements while scanning HTML. * * This property is initialized in the constructor and never null. * * @since 6.4.0 * * @see https://html.spec.whatwg.org/#stack-of-open-elements * * @var WP_HTML_Open_Elements */ public $stack_of_open_elements; /** * Tracks open formatting elements, used to handle mis-nested formatting element tags. * * This property is initialized in the constructor and never null. * * @since 6.4.0 * * @see https://html.spec.whatwg.org/#list-of-active-formatting-elements * * @var WP_HTML_Active_Formatting_Elements */ public $active_formatting_elements; /** * Refers to the currently-matched tag, if any. * * @since 6.4.0 * * @var WP_HTML_Token|null */ public $current_token = null; /** * Tree construction insertion mode. * * @since 6.4.0 * * @see https://html.spec.whatwg.org/#insertion-mode * * @var string */ public $insertion_mode = self::INSERTION_MODE_INITIAL; /** * Context node initializing fragment parser, if created as a fragment parser. * * @since 6.4.0 * @deprecated 6.8.0 WP_HTML_Processor tracks the context_node internally. * * @var null */ public $context_node = null; /** * The recognized encoding of the input byte stream. * * > The stream of code points that comprises the input to the tokenization * > stage will be initially seen by the user agent as a stream of bytes * > (typically coming over the network or from the local file system). * > The bytes encode the actual characters according to a particular character * > encoding, which the user agent uses to decode the bytes into characters. * * @since 6.7.0 * * @var string|null */ public $encoding = null; /** * The parser's confidence in the input encoding. * * > When the HTML parser is decoding an input byte stream, it uses a character * > encoding and a confidence. The confidence is either tentative, certain, or * > irrelevant. The encoding used, and whether the confidence in that encoding * > is tentative or certain, is used during the parsing to determine whether to * > change the encoding. If no encoding is necessary, e.g. because the parser is * > operating on a Unicode stream and doesn't have to use a character encoding * > at all, then the confidence is irrelevant. * * @since 6.7.0 * * @var string */ public $encoding_confidence = 'tentative'; /** * HEAD element pointer. * * @since 6.7.0 * * @see https://html.spec.whatwg.org/multipage/parsing.html#head-element-pointer * * @var WP_HTML_Token|null */ public $head_element = null; /** * FORM element pointer. * * > points to the last form element that was opened and whose end tag has * > not yet been seen. It is used to make form controls associate with * > forms in the face of dramatically bad markup, for historical reasons. * > It is ignored inside template elements. * * @todo This may be invalidated by a seek operation. * * @see https://html.spec.whatwg.org/#form-element-pointer * * @since 6.7.0 * * @var WP_HTML_Token|null */ public $form_element = null; /** * The frameset-ok flag indicates if a `FRAMESET` element is allowed in the current state. * * > The frameset-ok flag is set to "ok" when the parser is created. It is set to "not ok" after certain tokens are seen. * * @since 6.4.0 * * @see https://html.spec.whatwg.org/#frameset-ok-flag * * @var bool */ public $frameset_ok = true; /** * Constructor - creates a new and empty state value. * * @since 6.4.0 * * @see WP_HTML_Processor */ public function __construct() { $this->stack_of_open_elements = new WP_HTML_Open_Elements(); $this->active_formatting_elements = new WP_HTML_Active_Formatting_Elements(); } } PK �30]$gh� � "