Skip to content
This repository was archived by the owner on Jun 1, 2023. It is now read-only.

Commit e0f0e26

Browse files
committed
Cpanel-JSON-XS 4.09
1 parent c36bd43 commit e0f0e26

File tree

7 files changed

+139
-20
lines changed

7 files changed

+139
-20
lines changed

META.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -142,5 +142,5 @@
142142
}
143143
},
144144
"version" : "5.026005c",
145-
"x_serialization_backend" : "Cpanel::JSON::XS version 4.06"
145+
"x_serialization_backend" : "Cpanel::JSON::XS version 4.09"
146146
}

Porting/Maintainers.pl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -449,7 +449,7 @@ package Maintainers;
449449
},
450450

451451
'Cpanel::JSON::XS' => {
452-
'DISTRIBUTION' => 'RURBAN/Cpanel-JSON-XS-4.06.tar.gz',
452+
'DISTRIBUTION' => 'RURBAN/Cpanel-JSON-XS-4.09.tar.gz',
453453
'FILES' => q[cpan/Cpanel-JSON-XS],
454454
'EXCLUDED' => [
455455
'.appveyor.yml',

cpan/Cpanel-JSON-XS/XS.pm

Lines changed: 32 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
package Cpanel::JSON::XS;
2-
our $VERSION = '4.06';
2+
our $VERSION = '4.09';
33
our $XS_VERSION = $VERSION;
44
# $VERSION = eval $VERSION;
55

@@ -645,11 +645,12 @@ L</allow_barekey> option.
645645
646646
{ foo:"bar" }
647647
648-
=item * duplicate keys
648+
=item * allow_dupkeys
649649
650-
With relaxed decoding of duplicate keys does not error and are silently accepted.
650+
Allow decoding of duplicate keys in hashes. By default duplicate keys are forbidden.
651651
See L<http://seriot.ch/parsing_json.php#24>:
652652
RFC 7159 section 4: "The names within an object should be unique."
653+
See the L</allow_dupkeys> option.
653654
654655
=back
655656
@@ -701,6 +702,18 @@ C<"\/">.
701702
This setting has no effect when decoding JSON texts.
702703
703704
705+
=item $json = $json->unblessed_bool ([$enable])
706+
707+
=item $enabled = $json->get_unblessed_bool
708+
709+
$json = $json->unblessed_bool([$enable])
710+
711+
If C<$enable> is true (or missing), then C<decode> will return
712+
Perl non-object boolean variables (1 and 0) for JSON booleans
713+
(C<true> and C<false>). If C<$enable> is false, then C<decode>
714+
will return C<Cpanel::JSON::XS::Boolean> objects for JSON booleans.
715+
716+
704717
=item $json = $json->allow_singlequote ([$enable])
705718
706719
=item $enabled = $json->get_allow_singlequote
@@ -812,6 +825,22 @@ This option does not affect C<decode> in any way.
812825
This option is special to this module, it is not supported by other
813826
encoders. So it is not recommended to use it.
814827
828+
=item $json = $json->allow_dupkeys ([$enable])
829+
830+
=item $enabled = $json->get_allow_dupkeys
831+
832+
If C<$enable> is true (or missing), then the C<decode> method will not
833+
die when it encounters duplicate keys in a hash.
834+
C<allow_dupkeys> is also enabled in the C<relaxed> mode.
835+
836+
The JSON spec allows duplicate name in objects but recommends to
837+
disable it, however with Perl hashes they are impossible, parsing
838+
JSON in Perl silently ignores duplicate names, using the last value
839+
found.
840+
841+
See L<http://seriot.ch/parsing_json.php#24>:
842+
RFC 7159 section 4: "The names within an object should be unique."
843+
815844
=item $json = $json->allow_blessed ([$enable])
816845
817846
=item $enabled = $json->get_allow_blessed

cpan/Cpanel-JSON-XS/XS.xs

Lines changed: 30 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,14 @@
2424
# define snprintf _snprintf // C compilers have this in stdio.h
2525
#endif
2626

27+
#ifndef PERL_UNUSED_RESULT
28+
# if defined(__GNUC__) && defined(HASATTRIBUTE_WARN_UNUSED_RESULT)
29+
# define PERL_UNUSED_RESULT(v) STMT_START { __typeof__(v) z = (v); (void)sizeof(z); } STMT_END
30+
# else
31+
# define PERL_UNUSED_RESULT(v) ((void)(v))
32+
# endif
33+
#endif
34+
2735
#if defined(_AIX) && (!defined(HAS_LONG_DOUBLE) || AIX_WORKAROUND)
2836
#define HAVE_NO_POWL
2937
#endif
@@ -268,10 +276,12 @@ mingw_modfl(long double x, long double *ip)
268276
#define F_ESCAPE_SLASH 0x00080000UL
269277
#define F_SORT_BY 0x00100000UL
270278
#define F_ALLOW_STRINGIFY 0x00200000UL
279+
#define F_UNBLESSED_BOOL 0x00400000UL
280+
#define F_ALLOW_DUPKEYS 0x00800000UL
271281
#define F_HOOK 0x80000000UL /* some hooks exist, so slow-path processing */
272282

273283
#define F_PRETTY F_INDENT | F_SPACE_BEFORE | F_SPACE_AFTER
274-
#define SET_RELAXED (F_RELAXED | F_ALLOW_BAREKEY | F_ALLOW_SQUOTE)
284+
#define SET_RELAXED (F_RELAXED | F_ALLOW_BAREKEY | F_ALLOW_SQUOTE | F_ALLOW_DUPKEYS)
275285

276286
#define INIT_SIZE 32 /* initial scalar size to be allocated */
277287
#define INDENT_STEP 3 /* default spaces per indentation level */
@@ -1810,11 +1820,13 @@ encode_sv (pTHX_ enc_t *enc, SV *sv, SV *typesv)
18101820
# endif
18111821
}
18121822
#endif
1823+
18131824
#ifdef USE_QUADMATH
18141825
quadmath_snprintf(enc->cur, enc->end - enc->cur, "%.*Qg", (int)NV_DIG, nv);
18151826
#else
1816-
(void)Gconvert (nv, NV_DIG, 0, enc->cur);
1827+
PERL_UNUSED_RESULT(Gconvert (nv, NV_DIG, 0, enc->cur));
18171828
#endif
1829+
18181830
#ifdef NEED_NUMERIC_LOCALE_C
18191831
if (loc_changed) {
18201832
# ifdef HAS_USELOCALE
@@ -3243,7 +3255,7 @@ decode_hv (pTHX_ dec_t *dec, SV *typesv)
32433255
SV *typerv;
32443256
int allow_squote = dec->json.flags & F_ALLOW_SQUOTE;
32453257
int allow_barekey = dec->json.flags & F_ALLOW_BAREKEY;
3246-
int relaxed = dec->json.flags & F_RELAXED;
3258+
int allow_dupkeys = dec->json.flags & F_ALLOW_DUPKEYS;
32473259
char endstr = '"';
32483260

32493261
DEC_INC_DEPTH;
@@ -3303,14 +3315,16 @@ decode_hv (pTHX_ dec_t *dec, SV *typesv)
33033315
if (!key)
33043316
goto fail;
33053317

3318+
if (!allow_dupkeys && UNLIKELY(hv_exists_ent (hv, key, 0))) {
3319+
ERR ("Duplicate keys not allowed");
3320+
}
33063321
decode_ws (dec); EXPECT_CH (':');
3307-
33083322
decode_ws (dec);
33093323

33103324
if (typesv)
33113325
{
33123326
value_typesv = newSV (0);
3313-
hv_store_ent (typehv, key, value_typesv, 0);
3327+
(void)hv_store_ent (typehv, key, value_typesv, 0);
33143328
}
33153329

33163330
value = decode_sv (aTHX_ dec, value_typesv);
@@ -3320,7 +3334,7 @@ decode_hv (pTHX_ dec_t *dec, SV *typesv)
33203334
goto fail;
33213335
}
33223336

3323-
hv_store_ent (hv, key, value, 0);
3337+
(void)hv_store_ent (hv, key, value, 0);
33243338
SvREFCNT_dec (key);
33253339

33263340
break;
@@ -3340,14 +3354,12 @@ decode_hv (pTHX_ dec_t *dec, SV *typesv)
33403354
if (UNLIKELY(p - key > I32_MAX))
33413355
ERR ("Hash key too large");
33423356
#endif
3343-
if (!relaxed && UNLIKELY(hv_exists (hv, key, len))) {
3357+
if (!allow_dupkeys && UNLIKELY(hv_exists (hv, key, len))) {
33443358
ERR ("Duplicate keys not allowed");
33453359
}
33463360

33473361
dec->cur = p + 1;
3348-
33493362
decode_ws (dec); if (*p != ':') EXPECT_CH (':');
3350-
33513363
decode_ws (dec);
33523364

33533365
if (typesv)
@@ -3590,6 +3602,8 @@ decode_sv (pTHX_ dec_t *dec, SV *typesv)
35903602
dec->cur += 4;
35913603
if (typesv)
35923604
sv_setiv_mg (typesv, JSON_TYPE_BOOL);
3605+
if (dec->json.flags & F_UNBLESSED_BOOL)
3606+
return newSVsv (&PL_sv_yes);
35933607
return newSVsv(MY_CXT.json_true);
35943608
}
35953609
else
@@ -3604,6 +3618,8 @@ decode_sv (pTHX_ dec_t *dec, SV *typesv)
36043618
dec->cur += 5;
36053619
if (typesv)
36063620
sv_setiv_mg (typesv, JSON_TYPE_BOOL);
3621+
if (dec->json.flags & F_UNBLESSED_BOOL)
3622+
return newSVsv (&PL_sv_no);
36073623
return newSVsv(MY_CXT.json_false);
36083624
}
36093625
else
@@ -4093,6 +4109,8 @@ void ascii (JSON *self, int enable = 1)
40934109
allow_bignum = F_ALLOW_BIGNUM
40944110
escape_slash = F_ESCAPE_SLASH
40954111
allow_stringify = F_ALLOW_STRINGIFY
4112+
unblessed_bool = F_UNBLESSED_BOOL
4113+
allow_dupkeys = F_ALLOW_DUPKEYS
40964114
PPCODE:
40974115
if (enable)
40984116
self->flags |= ix;
@@ -4121,7 +4139,9 @@ void get_ascii (JSON *self)
41214139
get_allow_singlequote = F_ALLOW_SQUOTE
41224140
get_allow_bignum = F_ALLOW_BIGNUM
41234141
get_escape_slash = F_ESCAPE_SLASH
4124-
get_allow_stringify = F_ALLOW_STRINGIFY
4142+
get_allow_stringify = F_ALLOW_STRINGIFY
4143+
get_unblessed_bool = F_UNBLESSED_BOOL
4144+
get_allow_dupkeys = F_ALLOW_DUPKEYS
41254145
PPCODE:
41264146
XPUSHs (boolSV (self->flags & ix));
41274147

cpan/Cpanel-JSON-XS/t/25_boolean.t

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,16 @@
11
use strict;
2-
use Test::More tests => 32;
2+
use Test::More tests => 42;
33
use Cpanel::JSON::XS ();
44
use Config;
55

6+
my $have_blessed;
7+
BEGIN {
8+
if (eval { require Scalar::Util }) {
9+
Scalar::Util->import('blessed');
10+
$have_blessed = 1;
11+
}
12+
}
13+
614
my $booltrue = q({"is_true":true});
715
my $boolfalse = q({"is_false":false});
816
my $truefalse = "[true,false]";
@@ -11,6 +19,7 @@ my $true = Cpanel::JSON::XS::true;
1119
my $false = Cpanel::JSON::XS::false;
1220

1321
my $nonref_cjson = Cpanel::JSON::XS->new->allow_nonref;
22+
my $unblessed_bool_cjson = Cpanel::JSON::XS->new->unblessed_bool;
1423

1524
# from JSON::MaybeXS
1625
my $data = $cjson->decode('{"foo": true, "bar": false, "baz": 1}');
@@ -86,3 +95,27 @@ ok( Cpanel::JSON::XS::is_bool($js->[1]), "false is_bool");
8695

8796
# GH #53
8897
ok( !Cpanel::JSON::XS::is_bool( [] ), "[] !is_bool");
98+
99+
100+
$js = $unblessed_bool_cjson->decode($booltrue);
101+
SKIP: {
102+
skip "no Scalar::Util in $]", 1 unless $have_blessed;
103+
ok(!blessed($js->{is_true}), "->unblessed_bool for JSON true does not return blessed object");
104+
}
105+
cmp_ok($js->{is_true}, "==", 1, "->unblessed_bool for JSON true returns correct Perl bool value");
106+
cmp_ok($js->{is_true}, "eq", "1", "->unblessed_bool for JSON true returns correct Perl bool value");
107+
108+
$js = $unblessed_bool_cjson->decode($boolfalse);
109+
SKIP: {
110+
skip "no Scalar::Util in $]", 1 unless $have_blessed;
111+
ok(!blessed($js->{is_false}), "->unblessed_bool for JSON false does not return blessed object");
112+
}
113+
cmp_ok($js->{is_false}, "==", 0, "->unblessed_bool for JSON false returns correct Perl bool value");
114+
cmp_ok($js->{is_false}, "eq", "", "->unblessed_bool for JSON false returns correct Perl bool value");
115+
116+
is($unblessed_bool_cjson->encode(do { my $struct = $unblessed_bool_cjson->decode($truefalse, my $types); ($struct, $types) }), $truefalse, "encode(decode(boolean)) is identity with ->unblessed_bool");
117+
is($cjson->encode(do { my $struct = $unblessed_bool_cjson->decode($truefalse, my $types); ($struct, $types) }), $truefalse, "booleans decoded by ->unblessed_bool(1) are encoded by ->unblessed_bool(0) in the same way");
118+
119+
$js = $unblessed_bool_cjson->decode($truefalse);
120+
ok eval { $js->[0] = "new value 0" }, "decoded 'true' is modifiable" or diag($@);
121+
ok eval { $js->[1] = "new value 1" }, "decoded 'false' is modifiable" or diag($@);
Lines changed: 29 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,38 @@
1-
use Test::More tests => 4;
1+
use strict;
2+
use Test::More tests => 9;
23
use Cpanel::JSON::XS;
34

45
my $json = Cpanel::JSON::XS->new;
56

6-
# disallow dupkeys:
7+
# disallow dupkeys
78
ok (!eval { $json->decode ('{"a":"b","a":"c"}') }); # y_object_duplicated_key.json
89
ok (!eval { $json->decode ('{"a":"b","a":"b"}') }); # y_object_duplicated_key_and_value.json
910

11+
# relaxed allows dupkeys
1012
$json->relaxed;
11-
is (encode_json ($json->decode ('{"a":"b","a":"c"}')), '{"a":"c"}'); # y_object_duplicated_key.json
12-
is (encode_json ($json->decode ('{"a":"b","a":"b"}')), '{"a":"b"}'); # y_object_duplicated_key_and_value.json
13+
# y_object_duplicated_key.json
14+
is (encode_json ($json->decode ('{"a":"b","a":"c"}')), '{"a":"c"}', 'relaxed');
15+
# y_object_duplicated_key_and_value.json
16+
is (encode_json ($json->decode ('{"a":"b","a":"b"}')), '{"a":"b"}', 'relaxed');
1317

18+
# turning off relaxed disallows dupkeys
19+
$json->relaxed(0);
20+
$json->allow_dupkeys; # but turn it on
21+
is (encode_json ($json->decode ('{"a":"b","a":"c"}')), '{"a":"c"}', 'allow_dupkeys');
22+
is (encode_json ($json->decode ('{"a":"b","a":"b"}')), '{"a":"b"}', 'allow_dupkeys');
23+
24+
# disallow dupkeys explicitly
25+
$json->allow_dupkeys(0);
26+
eval { $json->decode ('{"a":"b","a":"c"}') };
27+
like ($@, qr/^Duplicate keys not allowed/, 'allow_dupkeys(0)');
28+
29+
# disallow dupkeys explicitly with relaxed
30+
$json->relaxed;
31+
$json->allow_dupkeys(0);
32+
eval { $json->decode ('{"a":"b","a":"c"}') }; # the XS slow path
33+
like ($@, qr/^Duplicate keys not allowed/, 'relaxed and allow_dupkeys(0)');
34+
35+
$json->allow_dupkeys;
36+
$json->relaxed(0); # tuning off relaxed needs to turn off dupkeys
37+
eval { $json->decode ('{"a":"b","a":"c"}') };
38+
like ($@, qr/^Duplicate keys not allowed/, 'relaxed(0)');

pod/perlcdelta.pod

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,18 @@ L<perl5262cdelta>, which describes differences between v5.26.1c and v5.26.2c.
1818

1919
=over 4
2020

21+
=item L<Cpanel::JSON::XS> 4.09
22+
23+
Add seperate allow_dupkeys property, in relaxed (#122).
24+
Fixed allow_dupkeys for the XS slow path.
25+
Silence 2 -Wunused-value warnings.
26+
Fix ->unblessed_bool to produce modifiable perl structures (PR #121 by Pali).
27+
28+
Add unblessed_bool property (PR #118 by Pali).
29+
30+
Silence Gconvert -Wunused-result.
31+
gcvt returns a string, sprintf int, so suppress the retval.
32+
2133
=item L<ExtUtils::MakeMaker> 8.35_08
2234

2335
Added C<-flto> support for static libs (need the lto plugin) and D for

0 commit comments

Comments
 (0)