Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 0 additions & 9 deletions components/XML/Tests/W3CXMLConformanceTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -58,15 +58,6 @@ public function test_w3c_xml_test_case($test_id, $test_type, $test_file, $descri
return;
}

if (in_array($test_id, [
"not-sa04",
"sa04",
"ibm-valid-P01-ibm01v01.xml",
])) {
$this->markTestSkipped("Skipping test case: {$test_id} – XMLProcessor does not support custom processing directive targets (e.g. <?music ... ?>)");
return;
}

if (in_array($test_id, [
"ibm-1-1-valid-P02-ibm02v01.xml",
"ibm-1-1-valid-P02-ibm02v02.xml",
Expand Down
13 changes: 13 additions & 0 deletions components/XML/Tests/XMLProcessorTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -1501,6 +1501,19 @@ public function test_processor_instructions() {
'The modifiable text was not correctly captured.' );
}

public function test_custom_processing_instruction_target() {
$processor = XMLProcessor::create_from_string( '<?music "notes"?><post/>' );
$this->assertTrue( $processor->next_token(), 'The custom processing instruction was not found.' );
$this->assertEquals(
'#processing-instructions',
$processor->get_token_type(),
'The custom processing instruction was not correctly identified.'
);
$this->assertSame( ' "notes"', $processor->get_modifiable_text() );
$this->assertTrue( $processor->next_token(), 'The element following the processing instruction was not found.' );
$this->assertSame( 'post', $processor->get_token_name(), 'The element following the processing instruction was not parsed correctly.' );
}

/**
* Ensures that updates which are enqueued in front of the cursor
* are applied before moving forward in the document.
Expand Down
29 changes: 14 additions & 15 deletions components/XML/class-xmlprocessor.php
Original file line number Diff line number Diff line change
Expand Up @@ -2106,27 +2106,26 @@ private function parse_next_tag() {
* `<?` denotes a processing instruction.
* See https://www.w3.org/TR/xml/#sec-pi
*/
if (
! $this->is_closing_tag &&
'?' === $xml[ $at + 1 ]
) {
if ( $at + 4 >= $doc_length ) {
if ( ! $this->is_closing_tag && '?' === $xml[ $at + 1 ] ) {
if ( $at + 2 >= $doc_length ) {
$this->mark_incomplete_input();

return false;
}

if ( ! (
( 'x' === $xml[ $at + 2 ] || 'X' === $xml[ $at + 2 ] ) &&
( 'm' === $xml[ $at + 3 ] || 'M' === $xml[ $at + 3 ] ) &&
( 'l' === $xml[ $at + 4 ] || 'L' === $xml[ $at + 4 ] )
) ) {
$target_length = $this->parse_name( $at + 2 );
if ( false === $target_length ) {
return false;
}

if ( 0 === $target_length ) {
$this->bail( 'Invalid processing instruction target.', self::ERROR_SYNTAX );
}

$at += 5;
$target_ends_at = $at + 2 + $target_length;
$this->bytes_already_parsed = $target_ends_at;

// Skip whitespace.
// Skip whitespace after the target, if any.
$this->skip_whitespace();

/*
Expand All @@ -2141,16 +2140,16 @@ private function parse_next_tag() {
* closing ?> is found. Some failures may pass unnoticed. That may not be a problem in practice,
* but if it is then this code path will require a stricter implementation.
*/
$closer_at = strpos( $xml, '?>', $at );
$closer_at = strpos( $xml, '?>', $this->bytes_already_parsed );
if ( false === $closer_at ) {
$this->mark_incomplete_input();

return false;
}

$this->parser_state = self::STATE_PI_NODE;
$this->token_length = $closer_at + 5 - $this->token_starts_at;
$this->text_starts_at = $this->token_starts_at + 5;
$this->token_length = $closer_at + 2 - $this->token_starts_at;
$this->text_starts_at = $target_ends_at;
$this->text_length = $closer_at - $this->text_starts_at;
$this->bytes_already_parsed = $closer_at + 2;

Expand Down