diff --git a/lib/Excel/Writer/XLSX/Package/XMLwriter.pm b/lib/Excel/Writer/XLSX/Package/XMLwriter.pm index c76bcbea..aa246972 100644 --- a/lib/Excel/Writer/XLSX/Package/XMLwriter.pm +++ b/lib/Excel/Writer/XLSX/Package/XMLwriter.pm @@ -232,6 +232,7 @@ sub xml_data_element { } $data = _escape_data( $data ); + $data = _escape_control_characters( $data ); local $\ = undef; print { $self->{_fh} } "<$tag>$data"; @@ -494,6 +495,29 @@ sub _escape_data { } +############################################################################### +# +# _escape_control_characters() +# +# Excel escapes control characters with _xHHHH_ and also escapes any +# literal strings of that type by encoding the leading underscore. So +# "\0" -> _x0000_ and "_x0000_" -> _x005F_x0000_. +# The following substitutions deal with those cases. +# +sub _escape_control_characters { + + my $str = $_[0]; + + # Escape the escape. + $str =~ s/(_x[0-9a-fA-F]{4}_)/_x005F$1/g; + + # Convert control character to the _xHHHH_ escape. + $str =~ s/([\x00-\x08\x0B-\x1F])/sprintf "_x%04X_", ord($1)/eg; + + return $str; +} + + 1; diff --git a/t/regression/escapes09.t b/t/regression/escapes09.t new file mode 100644 index 00000000..7ae159e4 --- /dev/null +++ b/t/regression/escapes09.t @@ -0,0 +1,90 @@ +############################################################################### +# +# Tests the output of Excel::Writer::XLSX against Excel generated files. +# +# Copyright 2000-2023, John McNamara, jmcnamara@cpan.org +# +# SPDX-License-Identifier: Artistic-1.0-Perl OR GPL-1.0-or-later +# + +use lib 't/lib'; +use TestFunctions qw(_compare_xlsx_files _is_deep_diff); +use strict; +use warnings; + +use Test::More tests => 1; + +############################################################################### +# +# Tests setup. +# +my $filename = 'escapes09.xlsx'; +my $dir = 't/regression/'; +my $got_filename = $dir . "ewx_$filename"; +my $exp_filename = $dir . 'xlsx_files/' . $filename; + +my $ignore_members = []; + +my $ignore_elements = {}; + + +############################################################################### +# +# Test the creation of a simple Excel::Writer::XLSX file. +# +use Excel::Writer::XLSX; + +my $workbook = Excel::Writer::XLSX->new( $got_filename ); +my $worksheet = $workbook->add_worksheet(); +my $chart = $workbook->add_chart( type => 'line', embedded => 1 ); + +# For testing, copy the randomly generated axis ids in the target xlsx file. +$chart->{_axis_ids} = [ 52721920, 53133312 ]; + + +$worksheet->write( 0, 0, "Data\x1b[32m1" ); +$worksheet->write( 1, 0, "Data\x1b[32m2" ); +$worksheet->write( 2, 0, "Data\x1b[32m3" ); +$worksheet->write( 3, 0, "Data\x1b[32m4" ); + +$worksheet->write( 0, 1, 10 ); +$worksheet->write( 1, 1, 20 ); +$worksheet->write( 2, 1, 10 ); +$worksheet->write( 3, 1, 30 ); + +$chart->add_series( + categories => '=Sheet1!$A$1:$A$4', + values => '=Sheet1!$B$1:$B$4' +); + +$worksheet->insert_chart( 'E9', $chart ); + +$workbook->close(); + + +############################################################################### +# +# Compare the generated and existing Excel files. +# + +my ( $got, $expected, $caption ) = _compare_xlsx_files( + + $got_filename, + $exp_filename, + $ignore_members, + $ignore_elements, +); + +_is_deep_diff( $got, $expected, $caption ); + + +############################################################################### +# +# Cleanup. +# +unlink $got_filename; + +__END__ + + + diff --git a/t/regression/xlsx_files/escapes09.xlsx b/t/regression/xlsx_files/escapes09.xlsx new file mode 100644 index 00000000..c8895578 Binary files /dev/null and b/t/regression/xlsx_files/escapes09.xlsx differ