7 my ($class, @args) = @_;
9 return $wrap->encode(@args);
13 my ($class, $dump) = @_;
16 return $wrap->decode($dump);
23 sub true
{ $wrap->true };
24 sub false
{ $wrap->false };
27 my ( $class, $what ) = @_;
28 return $what ?
$wrap->true : $wrap->false;
32 my ( $class, $what ) = @_;
34 # not using int deliberately because we may be handling floats here
38 foreach my $class (qw(LJ::JSON::XS LJ::JSON::JSONv2 LJ::JSON::JSONv1)) {
39 if ($class->can_load) {
48 package LJ
::JSON
::Wrapper
;
53 my ($class, $what, $sub) = @_;
63 if ($type eq 'HASH') {
65 foreach my $k (keys %$what) {
66 $ret{$sub->($k)} = $class->traverse($what->{$k}, $sub);
72 if ($type eq 'ARRAY') {
74 foreach my $v (@
$what) {
75 push @ret, $class->traverse($v, $sub);
80 # unknown type; let the subclass decode it to a scalar
81 # (base class function defaults to plain stringification)
82 return $sub->($class->decode_unknown_type($what));
85 sub traverse_fix_encoding
{
86 my ($class, $what) = @_;
88 return $class->traverse($what, sub {
91 return $scalar unless Encode
::is_utf8
($scalar);
93 # if the string does indeed contain wide characters (which happens
94 # in case the source string literals contained chars specified as
95 # '\u041c'), encode stuff as utf8
96 if ($scalar =~ /[^\x01-\xff]/) {
97 return Encode
::encode
("utf8", $scalar);
100 return Encode
::encode
("iso-8859-1", $scalar);
104 sub decode_unknown_type
{
105 my ($class, $what) = @_;
110 sub clean_after_encode
{
111 my ($class, $encoded) = @_;
113 unless (Encode
::is_utf8
($encoded)) {
114 $encoded = Encode
::decode
('utf8', $encoded);
117 # Perl 5.10 do not understand \x{00ad} sequence as Unicode char in the regexp s/...|\x{00ad}|.../, therefore we used char class.
118 # Dangerous symbols, that were tested on the Chrome and were a reason of its crush: \r \n \x{2028} \x{2029}
119 $encoded =~ s/[\r\n\x{0000}\x{0085}\x{00ad}\x{2028}\x{2029}\x{0600}-\x{0604}\x{070f}\x{17b4}\x{17b5}\x{200c}-\x{200f}\x{202a}-\x{202f}\x{2060}-\x{206f}\x{feff}\x{fff0}-\x{ffff}]//gs;
121 return Encode
::encode
('utf8', $encoded);
124 package LJ
::JSON
::XS
;
127 BEGIN { @ISA = qw(LJ::JSON::Wrapper JSON::XS); }
130 eval { require JSON
::XS
; JSON
::XS
->import; };
136 return $class->SUPER::new
->latin1;
141 my $encoded = $class->SUPER::encode
(@_);
142 return $class->clean_after_encode($encoded);
146 my ($class, $dump) = @_;
148 my $decoded = $class->SUPER::decode
($dump);
149 $decoded = $class->traverse_fix_encoding($decoded);
153 sub decode_unknown_type
{
154 my ($class, $what) = @_;
156 # booleans get converted to undef for false and 1 for true
157 return $what ?
1 : undef if JSON
::XS
::is_bool
($what);
159 # otherwise, stringify
165 package LJ
::JSON
::JSONv2
;
168 BEGIN { @ISA = qw(LJ::JSON::Wrapper JSON); }
171 eval { require JSON
};
172 return !$@
&& $JSON::VERSION
ge 2;
177 return $class->SUPER::new
->latin1;
181 my ($class, $dump) = @_;
183 my $decoded = $class->SUPER::decode
($dump);
184 $decoded = $class->traverse_fix_encoding($decoded);
188 sub decode_unknown_type
{
189 my ($class, $what) = @_;
191 # booleans get converted to undef for false and 1 for true
192 return $what ?
1 : undef if JSON
::is_bool
($what);
194 # otherwise, stringify
200 package LJ
::JSON
::JSONv1
;
203 BEGIN { @ISA = qw(LJ::JSON::Wrapper JSON); }
206 eval { require JSON
};
207 return !$@
&& $JSON::VERSION
ge 1;
210 *encode
= \
&JSON
::objToJson
;
211 *decode
= \
&JSON
::jsonToObj
;