From a10fe823b2977010f82552f357bece578a8b2865 Mon Sep 17 00:00:00 2001 From: Owen Leibman Date: Sat, 16 Nov 2019 21:37:57 -0800 Subject: [PATCH 1/3] Errors in RTF Escaping 1. Codes meant to be in hex are specified in decimal. Consequently characters which don't need escaping are escaped. 2. Special handling (prepend backslash) needed for {, }, and \. RTF docs generated with those characters cannot be opened in Word. 3. Tab character needs to be escaped as \tab. RTF docs drop these characters. While running test suite, found that Writer/RTF/ElementTest was coded only for Unix line endings, and fails on Windows. Changed so that it would work on either. --- src/PhpWord/Escaper/Rtf.php | 12 +++- tests/PhpWord/Escaper/RtfEscaper2Test.php | 81 +++++++++++++++++++++++ tests/PhpWord/Writer/RTF/ElementTest.php | 11 +-- 3 files changed, 97 insertions(+), 7 deletions(-) create mode 100644 tests/PhpWord/Escaper/RtfEscaper2Test.php diff --git a/src/PhpWord/Escaper/Rtf.php b/src/PhpWord/Escaper/Rtf.php index b8e0b216..42eb22a7 100644 --- a/src/PhpWord/Escaper/Rtf.php +++ b/src/PhpWord/Escaper/Rtf.php @@ -26,8 +26,14 @@ class Rtf extends AbstractEscaper { protected function escapeAsciiCharacter($code) { - if (20 > $code || $code >= 80) { - return '{\u' . $code . '}'; + if ($code == 9) { + return '{\\tab}'; + } + if (0x20 > $code || $code >= 0x80) { + return '{\\u' . $code . '}'; + } + if ($code == 123 || $code == 125 || $code == 92) { // open or close brace or backslash + return '\\' . chr($code); } return chr($code); @@ -35,7 +41,7 @@ class Rtf extends AbstractEscaper protected function escapeMultibyteCharacter($code) { - return '\uc0{\u' . $code . '}'; + return '\\uc0{\\u' . $code . '}'; } /** diff --git a/tests/PhpWord/Escaper/RtfEscaper2Test.php b/tests/PhpWord/Escaper/RtfEscaper2Test.php new file mode 100644 index 00000000..b16dc469 --- /dev/null +++ b/tests/PhpWord/Escaper/RtfEscaper2Test.php @@ -0,0 +1,81 @@ +write()); + + return $txt2; + } + + public function expect($str) + { + return self::HEADER . $str . self::TRAILER; + } + + /** + * Test special characters which require escaping + */ + public function testSpecial() + { + $str = 'Special characters { open brace } close brace \\ backslash'; + $expect = $this->expect('Special characters \\{ open brace \\} close brace \\\\ backslash'); + $this->assertEquals($expect, $this->escapestring($str)); + } + + /** + * Test accented character + */ + public function testAccent() + { + $str = 'Voilà - string with accented char'; + $expect = $this->expect('Voil\\uc0{\\u224} - string with accented char'); + $this->assertEquals($expect, $this->escapestring($str)); + } + + /** + * Test Hebrew + */ + public function testHebrew() + { + $str = 'Hebrew - שלום'; + $expect = $this->expect('Hebrew - \\uc0{\\u1513}\\uc0{\\u1500}\\uc0{\\u1493}\\uc0{\\u1501}'); + $this->assertEquals($expect, $this->escapestring($str)); + } + + /** + * Test tab + */ + public function testTab() + { + $str = "Here's a tab\tfollowed by more characters."; + $expect = $this->expect("Here's a tab{\\tab}followed by more characters."); + $this->assertEquals($expect, $this->escapestring($str)); + } +} diff --git a/tests/PhpWord/Writer/RTF/ElementTest.php b/tests/PhpWord/Writer/RTF/ElementTest.php index 4b01bacf..4c9dfc5e 100644 --- a/tests/PhpWord/Writer/RTF/ElementTest.php +++ b/tests/PhpWord/Writer/RTF/ElementTest.php @@ -24,6 +24,9 @@ use PhpOffice\PhpWord\Writer\RTF; */ class ElementTest extends \PHPUnit\Framework\TestCase { + public function removeCr($field) { + return str_replace("\r\n", "\n", $field->write()); + } /** * Test unmatched elements */ @@ -46,7 +49,7 @@ class ElementTest extends \PHPUnit\Framework\TestCase $element = new \PhpOffice\PhpWord\Element\Field('PAGE'); $field = new \PhpOffice\PhpWord\Writer\RTF\Element\Field($parentWriter, $element); - $this->assertEquals("{\\field{\\*\\fldinst PAGE}{\\fldrslt}}\\par\n", $field->write()); + $this->assertEquals("{\\field{\\*\\fldinst PAGE}{\\fldrslt}}\\par\n", $this->removeCr($field)); } public function testNumpageField() @@ -55,7 +58,7 @@ class ElementTest extends \PHPUnit\Framework\TestCase $element = new \PhpOffice\PhpWord\Element\Field('NUMPAGES'); $field = new \PhpOffice\PhpWord\Writer\RTF\Element\Field($parentWriter, $element); - $this->assertEquals("{\\field{\\*\\fldinst NUMPAGES}{\\fldrslt}}\\par\n", $field->write()); + $this->assertEquals("{\\field{\\*\\fldinst NUMPAGES}{\\fldrslt}}\\par\n", $this->removeCr($field)); } public function testDateField() @@ -64,7 +67,7 @@ class ElementTest extends \PHPUnit\Framework\TestCase $element = new \PhpOffice\PhpWord\Element\Field('DATE', array('dateformat' => 'd MM yyyy H:mm:ss')); $field = new \PhpOffice\PhpWord\Writer\RTF\Element\Field($parentWriter, $element); - $this->assertEquals("{\\field{\\*\\fldinst DATE \\\\@ \"d MM yyyy H:mm:ss\"}{\\fldrslt}}\\par\n", $field->write()); + $this->assertEquals("{\\field{\\*\\fldinst DATE \\\\@ \"d MM yyyy H:mm:ss\"}{\\fldrslt}}\\par\n", $this->removeCr($field)); } public function testIndexField() @@ -73,6 +76,6 @@ class ElementTest extends \PHPUnit\Framework\TestCase $element = new \PhpOffice\PhpWord\Element\Field('INDEX'); $field = new \PhpOffice\PhpWord\Writer\RTF\Element\Field($parentWriter, $element); - $this->assertEquals("{}\\par\n", $field->write()); + $this->assertEquals("{}\\par\n", $this->removeCr($field)); } } From 2513e545406c81a117af7166cc3a053cc01f68e4 Mon Sep 17 00:00:00 2001 From: Owen Leibman Date: Sat, 16 Nov 2019 23:20:02 -0800 Subject: [PATCH 2/3] Errors in RTF Escaping 1. Codes meant to be in hex are specified in decimal. Consequently characters which don't need escaping are escaped. 2. Special handling (prepend backslash) needed for {, }, and . RTF docs generated with those characters cannot be opened in Word. 3. Tab character needs to be escaped as \tab. RTF docs drop these characters. While running test suite, found that Writer/RTF/ElementTest was coded only for Unix line endings, and fails on Windows. Changed so that it would work on either. --- tests/PhpWord/Escaper/RtfEscaper2Test.php | 4 +++- tests/PhpWord/Writer/RTF/ElementTest.php | 3 ++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/tests/PhpWord/Escaper/RtfEscaper2Test.php b/tests/PhpWord/Escaper/RtfEscaper2Test.php index b16dc469..27e8a985 100644 --- a/tests/PhpWord/Escaper/RtfEscaper2Test.php +++ b/tests/PhpWord/Escaper/RtfEscaper2Test.php @@ -15,8 +15,10 @@ * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ +namespace PhpOffice\PhpWord\Escaper; + /** - * Test class for PhpOffice\PhpWord\Writer\RTF\Style subnamespace + * Test class for PhpOffice\PhpWord\Escaper\RTF */ class RtfEscaperTest extends \PHPUnit\Framework\TestCase { diff --git a/tests/PhpWord/Writer/RTF/ElementTest.php b/tests/PhpWord/Writer/RTF/ElementTest.php index 4c9dfc5e..67a319e6 100644 --- a/tests/PhpWord/Writer/RTF/ElementTest.php +++ b/tests/PhpWord/Writer/RTF/ElementTest.php @@ -24,7 +24,8 @@ use PhpOffice\PhpWord\Writer\RTF; */ class ElementTest extends \PHPUnit\Framework\TestCase { - public function removeCr($field) { + public function removeCr($field) + { return str_replace("\r\n", "\n", $field->write()); } /** From 00f9bb5897b18c3507990cc34bc1c4d152e93db1 Mon Sep 17 00:00:00 2001 From: Owen Leibman Date: Sun, 17 Nov 2019 00:07:02 -0800 Subject: [PATCH 3/3] Formatting changes in source code. --- tests/PhpWord/Escaper/RtfEscaper2Test.php | 2 +- tests/PhpWord/Writer/RTF/ElementTest.php | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/PhpWord/Escaper/RtfEscaper2Test.php b/tests/PhpWord/Escaper/RtfEscaper2Test.php index 27e8a985..21c8a8c3 100644 --- a/tests/PhpWord/Escaper/RtfEscaper2Test.php +++ b/tests/PhpWord/Escaper/RtfEscaper2Test.php @@ -20,7 +20,7 @@ namespace PhpOffice\PhpWord\Escaper; /** * Test class for PhpOffice\PhpWord\Escaper\RTF */ -class RtfEscaperTest extends \PHPUnit\Framework\TestCase +class RtfEscaper2Test extends \PHPUnit\Framework\TestCase { const HEADER = '\\pard\\nowidctlpar {\\cf0\\f0 '; const TRAILER = '}\\par'; diff --git a/tests/PhpWord/Writer/RTF/ElementTest.php b/tests/PhpWord/Writer/RTF/ElementTest.php index 67a319e6..3e9c235d 100644 --- a/tests/PhpWord/Writer/RTF/ElementTest.php +++ b/tests/PhpWord/Writer/RTF/ElementTest.php @@ -28,6 +28,7 @@ class ElementTest extends \PHPUnit\Framework\TestCase { return str_replace("\r\n", "\n", $field->write()); } + /** * Test unmatched elements */