Skip to content

Commit 7787da1

Browse files
authored
Merge pull request #63 from cpan-authors/issue-51
Fixed #51
2 parents 265d1fe + 7df34f6 commit 7787da1

File tree

3 files changed

+84
-32
lines changed

3 files changed

+84
-32
lines changed

MANIFEST

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ t/bug/doesnt-stringify.t
3636
t/bug/rt-41141.t
3737
t/bug/rt-49404-double_free.t
3838
t/bug/rt-54167.t
39+
t/escape-special-chars.t
3940
t/json-basic.t
4041
t/json-circular-ref.t
4142
t/json-crlf.t

emitter.c

Lines changed: 29 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,9 @@
55
* $Date: 2006-05-09 12:03:50 +0800 (二, 09 5 2006) $
66
*
77
* Copyright (C) 2003 why the lucky stiff
8-
*
8+
*
99
* All Base64 code from Ruby's pack.c.
10-
* Ruby is Copyright (C) 1993-2003 Yukihiro Matsumoto
10+
* Ruby is Copyright (C) 1993-2003 Yukihiro Matsumoto
1111
*/
1212
#include <stdio.h>
1313
#include <string.h>
@@ -16,7 +16,7 @@
1616

1717
#define DEFAULT_ANCHOR_FORMAT "id%03d"
1818

19-
const unsigned char hex_table[] =
19+
const unsigned char hex_table[] =
2020
"0123456789ABCDEF";
2121
static unsigned char b64_table[] =
2222
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
@@ -137,7 +137,7 @@ syck_new_emitter()
137137
e->output_handler = NULL;
138138
e->lvl_idx = 0;
139139
e->lvl_capa = ALLOC_CT;
140-
e->levels = S_ALLOC_N( SyckLevel, e->lvl_capa );
140+
e->levels = S_ALLOC_N( SyckLevel, e->lvl_capa );
141141
syck_emitter_reset_levels( e );
142142
e->bonus = NULL;
143143
return e;
@@ -203,7 +203,7 @@ syck_emitter_pop_level( SyckEmitter *e )
203203
free( e->levels[e->lvl_idx].domain );
204204
}
205205

206-
void
206+
void
207207
syck_emitter_add_level( SyckEmitter *e, int len, enum syck_level_status status )
208208
{
209209
ASSERT( e != NULL );
@@ -295,7 +295,7 @@ syck_emitter_write( SyckEmitter *e, const char *str, long len )
295295
{
296296
syck_emitter_clear( e );
297297
}
298-
298+
299299
/*
300300
* Flush if at end of buffer
301301
*/
@@ -366,7 +366,7 @@ syck_emit( SyckEmitter *e, st_data_t n )
366366
int indent = 0;
367367
SyckLevel *parent;
368368
SyckLevel *lvl = syck_emitter_current_level( e );
369-
369+
370370
/*
371371
* Determine headers.
372372
*/
@@ -498,7 +498,7 @@ void syck_emit_tag( SyckEmitter *e, const char *tag, const char *ignore )
498498
lvl->anctag = 1;
499499
}
500500

501-
/*
501+
/*
502502
* Emit a newline and an appropriately spaced indent.
503503
*/
504504
void syck_emit_indent( SyckEmitter *e )
@@ -582,7 +582,7 @@ syck_scan_scalar( int req_width, char *cursor, long len )
582582
} else if ( len > 1 && cursor[len-2] == '\n' ) {
583583
flags |= SCAN_MANYNL_E;
584584
}
585-
if (
585+
if (
586586
( len > 0 && ( cursor[0] == ' ' || cursor[0] == '\t' ) ) ||
587587
( len > 1 && ( cursor[len-1] == ' ' || cursor[len-1] == '\t' ) )
588588
) {
@@ -609,7 +609,7 @@ syck_scan_scalar( int req_width, char *cursor, long len )
609609
flags |= SCAN_NEWLINE;
610610
if ( len - i >= 3 && strncmp( &cursor[i+1], "---", 3 ) == 0 )
611611
flags |= SCAN_DOCSEP;
612-
if ( cursor[i+1] == ' ' || cursor[i+1] == '\t' )
612+
if ( cursor[i+1] == ' ' || cursor[i+1] == '\t' )
613613
flags |= SCAN_INDENTED;
614614
if ( req_width > 0 && i - start > req_width )
615615
flags |= SCAN_WIDE;
@@ -633,12 +633,12 @@ syck_scan_scalar( int req_width, char *cursor, long len )
633633
}
634634
/* remember, if plain collections get implemented, to add nb-plain-flow-char */
635635
else if ( ( cursor[i] == ' ' && cursor[i+1] == '#' ) ||
636-
( cursor[i] == ':' &&
636+
( cursor[i] == ':' &&
637637
( cursor[i+1] == ' ' || cursor[i+1] == '\n' || i == len - 1 ) ) )
638638
{
639639
flags |= SCAN_INDIC_C;
640640
}
641-
else if ( cursor[i] == ',' &&
641+
else if ( cursor[i] == ',' &&
642642
( cursor[i+1] == ' ' || cursor[i+1] == '\n' || i == len - 1 ) )
643643
{
644644
flags |= SCAN_FLOWMAP;
@@ -661,12 +661,12 @@ void syck_emit_scalar( SyckEmitter *e, char *tag, enum scalar_style force_style,
661661
SyckLevel *lvl = syck_emitter_current_level( e );
662662
int scan = 0;
663663
char *implicit;
664-
664+
665665
if ( str == NULL ) str = "";
666666

667667
/* No empty nulls as map keys */
668-
if ( len == 0 && ( parent->status == syck_lvl_map || parent->status == syck_lvl_imap ) &&
669-
parent->ncount % 2 == 1 && syck_tagcmp( tag, "tag:yaml.org,2002:null" ) == 0 )
668+
if ( len == 0 && ( parent->status == syck_lvl_map || parent->status == syck_lvl_imap ) &&
669+
parent->ncount % 2 == 1 && syck_tagcmp( tag, "tag:yaml.org,2002:null" ) == 0 )
670670
{
671671
str = "~";
672672
len = 1;
@@ -678,7 +678,7 @@ void syck_emit_scalar( SyckEmitter *e, char *tag, enum scalar_style force_style,
678678
/* quote strings which default to implicits */
679679
if (
680680
(
681-
(strncmp( implicit, "bool", 4 ) == 0) ||
681+
(strncmp( implicit, "bool", 4 ) == 0) ||
682682
(strncmp( implicit, "null", 4 ) == 0)
683683
)
684684
&&
@@ -690,8 +690,8 @@ void syck_emit_scalar( SyckEmitter *e, char *tag, enum scalar_style force_style,
690690
} else {
691691
/* complex key -- disabled by Audrey Tang -/
692692
if ( parent->status == syck_lvl_map && parent->ncount % 2 == 1 &&
693-
( !( tag == NULL ||
694-
( implicit != NULL && syck_tagcmp( tag, implicit ) == 0 && e->explicit_typing == 0 ) ) ) )
693+
( !( tag == NULL ||
694+
( implicit != NULL && syck_tagcmp( tag, implicit ) == 0 && e->explicit_typing == 0 ) ) ) )
695695
{
696696
syck_emitter_write( e, "? ", 2 );
697697
parent->status = syck_lvl_mapx;
@@ -955,7 +955,17 @@ void syck_emit_2quoted( SyckEmitter *e, int width, char *str, long len )
955955

956956
/* Escape sequences allowed within double quotes. */
957957
case '"': syck_emitter_write( e, "\\\"", 2 ); break;
958-
case '\\': syck_emitter_write( e, "\\\\", 2 ); break;
958+
case '\\':
959+
/* Check if next char is a special char that needs escaping */
960+
if (mark + 1 < str + len &&
961+
(mark[1] == 't' || mark[1] == 'r' || mark[1] == 'n' ||
962+
mark[1] == '0' || mark[1] == 'a' || mark[1] == 'b' ||
963+
mark[1] == 'f' || mark[1] == 'v' || mark[1] == 'e')) {
964+
syck_emitter_write( e, "\\\\", 2 );
965+
} else {
966+
syck_emitter_write( e, "\\\\", 2 );
967+
}
968+
break;
959969
case '\0': syck_emitter_write( e, "\\0", 2 ); break;
960970
case '\a': syck_emitter_write( e, "\\a", 2 ); break;
961971
case '\b': syck_emitter_write( e, "\\b", 2 ); break;
@@ -966,18 +976,6 @@ void syck_emit_2quoted( SyckEmitter *e, int width, char *str, long len )
966976
case 0x1b: syck_emitter_write( e, "\\e", 2 ); break;
967977
case '\n': syck_emitter_write( e, "\\n", 2 ); break;
968978

969-
/* XXX - Disabled by Audrey Tang for YAML.pm compat
970-
case '\n':
971-
end = mark + 1;
972-
syck_emitter_write( e, "\\n", 2 );
973-
do_indent = e->indent;
974-
start = mark + 1;
975-
if ( start < str + len && ( *start == ' ' || *start == '\n' ) ) {
976-
do_indent = 0;
977-
}
978-
break;
979-
*/
980-
981979
case ' ':
982980
if ( width > 0 && *start != ' ' && mark - end > width ) {
983981
do_indent = 1;
@@ -1356,4 +1354,3 @@ syck_emitter_mark_node( SyckEmitter *e, st_data_t n, int flags )
13561354
}
13571355
return oid;
13581356
}
1359-

t/escape-special-chars.t

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
use strict;
2+
use warnings;
3+
use Test::More tests => 8;
4+
use YAML::Syck;
5+
6+
# Test string with various special characters
7+
my $test_str = "with \t tabs and carriage \r returns";
8+
9+
# Test dumping and loading
10+
my $yaml = Dump($test_str);
11+
my $loaded = Load($yaml);
12+
13+
# Verify the string roundtrips correctly
14+
is($loaded, $test_str, "String with special chars roundtrips correctly");
15+
16+
# Test literal backslashes
17+
my $backslash_str = "with \\t tabs and carriage \\r returns";
18+
$yaml = Dump($backslash_str);
19+
$loaded = Load($yaml);
20+
is($loaded, $backslash_str, "String with literal backslashes roundtrips correctly");
21+
22+
# Test mixed special chars and literal backslashes
23+
my $mixed_str = "with \t tabs and \\r literal returns";
24+
$yaml = Dump($mixed_str);
25+
$loaded = Load($yaml);
26+
is($loaded, $mixed_str, "String with mixed special chars and literal backslashes roundtrips correctly");
27+
28+
# Test in a hash
29+
my $hash = {
30+
special => "with \t tabs and carriage \r returns",
31+
literal => "with \\t tabs and carriage \\r returns",
32+
mixed => "with \t tabs and \\r literal returns"
33+
};
34+
35+
$yaml = Dump($hash);
36+
$loaded = Load($yaml);
37+
38+
is($loaded->{special}, $hash->{special}, "Special chars in hash value roundtrip correctly");
39+
is($loaded->{literal}, $hash->{literal}, "Literal backslashes in hash value roundtrip correctly");
40+
is($loaded->{mixed}, $hash->{mixed}, "Mixed chars in hash value roundtrip correctly");
41+
42+
# Test in an array
43+
my $array = [
44+
"with \t tabs and carriage \r returns",
45+
"with \\t tabs and carriage \\r returns",
46+
"with \t tabs and \\r literal returns"
47+
];
48+
49+
$yaml = Dump($array);
50+
$loaded = Load($yaml);
51+
52+
is($loaded->[0], $array->[0], "Special chars in array element roundtrip correctly");
53+
is($loaded->[1], $array->[1], "Literal backslashes in array element roundtrip correctly");
54+

0 commit comments

Comments
 (0)