line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package Pcore::Util::Data; |
2
|
|
|
|
|
|
|
|
3
|
5
|
|
|
|
|
104
|
use Pcore -const, -export, |
4
|
|
|
|
|
|
|
{ ALL => [qw[encode_data decode_data]], |
5
|
|
|
|
|
|
|
PERL => [qw[to_perl from_perl]], |
6
|
|
|
|
|
|
|
JSON => [qw[to_json from_json]], |
7
|
|
|
|
|
|
|
CBOR => [qw[to_cbor from_cbor]], |
8
|
|
|
|
|
|
|
YAML => [qw[to_yaml from_yaml]], |
9
|
|
|
|
|
|
|
XML => [qw[to_xml from_xml]], |
10
|
|
|
|
|
|
|
INI => [qw[to_ini from_ini]], |
11
|
|
|
|
|
|
|
B64 => [qw[to_b64 to_b64_url from_b64 from_b64_url]], |
12
|
|
|
|
|
|
|
B85 => [qw[to_b85 from_b85]], |
13
|
|
|
|
|
|
|
URI => [qw[to_uri from_uri from_uri_query]], |
14
|
|
|
|
|
|
|
XOR => [qw[to_xor from_xor]], |
15
|
|
|
|
|
|
|
CONST => [qw[$DATA_ENC_B64 $DATA_ENC_HEX $DATA_ENC_B85 $DATA_COMPRESS_ZLIB $DATA_CIPHER_DES]], |
16
|
|
|
|
|
|
|
TYPE => [qw[$DATA_TYPE_PERL $DATA_TYPE_JSON $DATA_TYPE_CBOR $DATA_TYPE_YAML $DATA_TYPE_XML $DATA_TYPE_INI]], |
17
|
5
|
|
|
5
|
|
38
|
}; |
|
5
|
|
|
|
|
13
|
|
18
|
5
|
|
|
5
|
|
33
|
use Pcore::Util::Text qw[decode_utf8 encode_utf8 escape_scalar]; |
|
5
|
|
|
|
|
11
|
|
|
5
|
|
|
|
|
32
|
|
19
|
5
|
|
|
5
|
|
1586
|
use Pcore::Util::List qw[pairs]; |
|
5
|
|
|
|
|
13
|
|
|
5
|
|
|
|
|
37
|
|
20
|
5
|
|
|
5
|
|
35
|
use Sort::Naturally qw[nsort]; |
|
5
|
|
|
|
|
11
|
|
|
5
|
|
|
|
|
235
|
|
21
|
5
|
|
|
5
|
|
29
|
use Pcore::Util::Scalar qw[is_blessed_ref is_plain_arrayref]; |
|
5
|
|
|
|
|
10
|
|
|
5
|
|
|
|
|
31
|
|
22
|
5
|
|
|
5
|
|
32
|
use URI::Escape::XS qw[]; ## no critic qw[Modules::ProhibitEvilModules] |
|
5
|
|
|
|
|
9
|
|
|
5
|
|
|
|
|
2398
|
|
23
|
|
|
|
|
|
|
|
24
|
|
|
|
|
|
|
const our $DATA_TYPE_PERL => 1; |
25
|
|
|
|
|
|
|
const our $DATA_TYPE_JSON => 2; |
26
|
|
|
|
|
|
|
const our $DATA_TYPE_CBOR => 3; |
27
|
|
|
|
|
|
|
const our $DATA_TYPE_YAML => 4; |
28
|
|
|
|
|
|
|
const our $DATA_TYPE_XML => 5; |
29
|
|
|
|
|
|
|
const our $DATA_TYPE_INI => 6; |
30
|
|
|
|
|
|
|
|
31
|
|
|
|
|
|
|
const our $DATA_ENC_B64 => 1; |
32
|
|
|
|
|
|
|
const our $DATA_ENC_HEX => 2; |
33
|
|
|
|
|
|
|
const our $DATA_ENC_B85 => 3; |
34
|
|
|
|
|
|
|
|
35
|
|
|
|
|
|
|
const our $DATA_COMPRESS_ZLIB => 1; |
36
|
|
|
|
|
|
|
|
37
|
|
|
|
|
|
|
const our $DATA_CIPHER_DES => 1; |
38
|
|
|
|
|
|
|
|
39
|
|
|
|
|
|
|
const our $CIPHER_NAME => { # |
40
|
|
|
|
|
|
|
$DATA_CIPHER_DES => 'DES', |
41
|
|
|
|
|
|
|
}; |
42
|
|
|
|
|
|
|
|
43
|
|
|
|
|
|
|
our $JSON_CACHE; |
44
|
|
|
|
|
|
|
|
45
|
|
|
|
|
|
|
# JSON is used by default |
46
|
|
|
|
|
|
|
# JSON can't serialize ScalarRefs |
47
|
|
|
|
|
|
|
# objects should have TO_JSON method, otherwise object will be serialized as null |
48
|
|
|
|
|
|
|
# base64 encoder is used by default, it generates more compressed data |
49
|
0
|
|
|
0
|
0
|
0
|
sub encode_data ( $type, $data, @ ) { |
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
50
|
0
|
|
|
|
|
0
|
my %args = ( |
51
|
|
|
|
|
|
|
readable => undef, # make serialized data readable for humans |
52
|
|
|
|
|
|
|
compress => undef, # use compression |
53
|
|
|
|
|
|
|
secret => undef, # crypt data if defined, can be ArrayRef |
54
|
|
|
|
|
|
|
secret_index => 0, # index of secret to use in secret array, if secret is ArrayRef |
55
|
|
|
|
|
|
|
encode => undef, # 0 - disable |
56
|
|
|
|
|
|
|
token => undef, # attach informational token |
57
|
|
|
|
|
|
|
compress_threshold => 100, # min data length in bytes to perform compression, only if compress = 1 |
58
|
|
|
|
|
|
|
cipher => $DATA_CIPHER_DES, # cipher to use |
59
|
|
|
|
|
|
|
json => undef, # HashRef with additional params for Cpanel::JSON::XS |
60
|
|
|
|
|
|
|
splice @_, 2, |
61
|
|
|
|
|
|
|
); |
62
|
|
|
|
|
|
|
|
63
|
0
|
0
|
0
|
|
|
0
|
if ( $args{readable} && $type != $DATA_TYPE_CBOR ) { |
64
|
0
|
|
|
|
|
0
|
$args{compress} = undef; |
65
|
0
|
|
|
|
|
0
|
$args{secret} = undef; |
66
|
0
|
|
|
|
|
0
|
$args{encode} = undef; |
67
|
0
|
|
|
|
|
0
|
$args{token} = undef; |
68
|
|
|
|
|
|
|
} |
69
|
|
|
|
|
|
|
|
70
|
0
|
|
|
|
|
0
|
my $res; |
71
|
|
|
|
|
|
|
|
72
|
|
|
|
|
|
|
# encode |
73
|
0
|
0
|
|
|
|
0
|
if ( $type == $DATA_TYPE_PERL ) { |
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
74
|
0
|
|
|
|
|
0
|
state $init = !!require Data::Dumper; |
75
|
|
|
|
|
|
|
|
76
|
|
|
|
|
|
|
state $sort_keys = sub { |
77
|
0
|
|
|
0
|
|
0
|
return [ nsort keys $_[0]->%* ]; |
78
|
0
|
|
|
|
|
0
|
}; |
79
|
|
|
|
|
|
|
|
80
|
0
|
|
|
|
|
0
|
local $Data::Dumper::Indent = 0; |
81
|
0
|
|
|
|
|
0
|
local $Data::Dumper::Purity = 1; |
82
|
0
|
|
|
|
|
0
|
local $Data::Dumper::Pad = q[]; |
83
|
0
|
|
|
|
|
0
|
local $Data::Dumper::Terse = 1; |
84
|
0
|
|
|
|
|
0
|
local $Data::Dumper::Deepcopy = 0; |
85
|
0
|
|
|
|
|
0
|
local $Data::Dumper::Quotekeys = 0; |
86
|
0
|
|
|
|
|
0
|
local $Data::Dumper::Pair = '=>'; |
87
|
0
|
|
|
|
|
0
|
local $Data::Dumper::Maxdepth = 0; |
88
|
0
|
|
|
|
|
0
|
local $Data::Dumper::Deparse = 0; |
89
|
0
|
|
|
|
|
0
|
local $Data::Dumper::Sparseseen = 1; |
90
|
0
|
|
|
|
|
0
|
local $Data::Dumper::Useperl = 1; |
91
|
0
|
|
|
|
|
0
|
local $Data::Dumper::Useqq = 1; |
92
|
0
|
0
|
|
|
|
0
|
local $Data::Dumper::Sortkeys = $args{readable} ? $sort_keys : 0; |
93
|
|
|
|
|
|
|
|
94
|
0
|
0
|
|
|
|
0
|
if ( !defined $data ) { |
95
|
0
|
|
|
|
|
0
|
$res = \'undef'; |
96
|
|
|
|
|
|
|
} |
97
|
|
|
|
|
|
|
else { |
98
|
5
|
|
|
5
|
|
34
|
no warnings qw[redefine]; |
|
5
|
|
|
|
|
15
|
|
|
5
|
|
|
|
|
20087
|
|
99
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
local *Data::Dumper::qquote = sub { |
101
|
0
|
|
|
0
|
|
0
|
return q["] . encode_utf8( escape_scalar $_[0] ) . q["]; |
102
|
0
|
|
|
|
|
0
|
}; |
103
|
|
|
|
|
|
|
|
104
|
0
|
|
|
|
|
0
|
$res = \Data::Dumper->Dump( [$data] ); |
105
|
|
|
|
|
|
|
} |
106
|
|
|
|
|
|
|
|
107
|
0
|
0
|
|
|
|
0
|
if ( $args{readable} ) { |
108
|
0
|
|
|
|
|
0
|
state $init1 = !!require Pcore::Src::File; |
109
|
|
|
|
|
|
|
|
110
|
0
|
|
|
|
|
0
|
$res = Pcore::Src::File->new( |
111
|
|
|
|
|
|
|
{ action => $Pcore::Src::SRC_DECOMPRESS, |
112
|
|
|
|
|
|
|
path => 'config.perl', # mark file as perl config |
113
|
|
|
|
|
|
|
is_realpath => 0, |
114
|
|
|
|
|
|
|
in_buffer => $res, |
115
|
|
|
|
|
|
|
filter_args => { |
116
|
|
|
|
|
|
|
perl_tidy => '--comma-arrow-breakpoints=0', |
117
|
|
|
|
|
|
|
perl_critic => 0, |
118
|
|
|
|
|
|
|
}, |
119
|
|
|
|
|
|
|
} |
120
|
|
|
|
|
|
|
)->run->out_buffer; |
121
|
|
|
|
|
|
|
} |
122
|
|
|
|
|
|
|
} |
123
|
|
|
|
|
|
|
elsif ( $type == $DATA_TYPE_JSON ) { |
124
|
0
|
0
|
|
|
|
0
|
if ( $args{json} ) { |
|
|
0
|
|
|
|
|
|
125
|
0
|
|
|
|
|
0
|
my $json = _get_json_obj( $args{json}->%* ); |
126
|
|
|
|
|
|
|
|
127
|
0
|
|
|
|
|
0
|
$res = \$json->encode($data); |
128
|
|
|
|
|
|
|
} |
129
|
|
|
|
|
|
|
elsif ( $args{readable} ) { |
130
|
0
|
|
|
|
|
0
|
state $json = _get_json_obj( ascii => 0, latin1 => 0, utf8 => 1, canonical => 1, indent => 1, space_before => 0, space_after => 1 ); |
131
|
|
|
|
|
|
|
|
132
|
0
|
|
|
|
|
0
|
$res = \$json->encode($data); |
133
|
|
|
|
|
|
|
} |
134
|
|
|
|
|
|
|
else { |
135
|
0
|
|
|
|
|
0
|
state $json = _get_json_obj( ascii => 1, latin1 => 0, utf8 => 1, pretty => 0 ); |
136
|
|
|
|
|
|
|
|
137
|
0
|
|
|
|
|
0
|
$res = \$json->encode($data); |
138
|
|
|
|
|
|
|
} |
139
|
|
|
|
|
|
|
} |
140
|
|
|
|
|
|
|
elsif ( $type == $DATA_TYPE_CBOR ) { |
141
|
0
|
|
|
|
|
0
|
state $cbor = _get_cbor_obj(); |
142
|
|
|
|
|
|
|
|
143
|
0
|
|
|
|
|
0
|
$res = \$cbor->encode($data); |
144
|
|
|
|
|
|
|
} |
145
|
|
|
|
|
|
|
elsif ( $type == $DATA_TYPE_YAML ) { |
146
|
0
|
|
|
|
|
0
|
state $init = !!require YAML::XS; |
147
|
|
|
|
|
|
|
|
148
|
0
|
|
|
|
|
0
|
local $YAML::XS::UseCode = 0; |
149
|
0
|
|
|
|
|
0
|
local $YAML::XS::DumpCode = 0; |
150
|
0
|
|
|
|
|
0
|
local $YAML::XS::LoadCode = 0; |
151
|
|
|
|
|
|
|
|
152
|
0
|
|
|
|
|
0
|
$res = \YAML::XS::Dump($data); |
153
|
|
|
|
|
|
|
} |
154
|
|
|
|
|
|
|
elsif ( $type == $DATA_TYPE_XML ) { |
155
|
0
|
|
|
|
|
0
|
state $init = !!require XML::Hash::XS; |
156
|
|
|
|
|
|
|
|
157
|
0
|
|
|
|
|
0
|
state $xml_args = { |
158
|
|
|
|
|
|
|
root => 'root', |
159
|
|
|
|
|
|
|
version => '1.0', |
160
|
|
|
|
|
|
|
encode => 'UTF-8', |
161
|
|
|
|
|
|
|
output => undef, |
162
|
|
|
|
|
|
|
canonical => 0, # sort hash keys |
163
|
|
|
|
|
|
|
use_attr => 1, |
164
|
|
|
|
|
|
|
content => 'content', # if defined that the key name for the text content(used only if use_attr=1) |
165
|
|
|
|
|
|
|
xml_decl => 1, |
166
|
|
|
|
|
|
|
trim => 1, |
167
|
|
|
|
|
|
|
utf8 => 0, |
168
|
|
|
|
|
|
|
buf_size => 4096, |
169
|
|
|
|
|
|
|
method => 'NATIVE', |
170
|
|
|
|
|
|
|
}; |
171
|
|
|
|
|
|
|
|
172
|
0
|
|
|
|
|
0
|
state $xml_obj = XML::Hash::XS->new( $xml_args->%* ); |
173
|
|
|
|
|
|
|
|
174
|
0
|
|
|
|
|
0
|
my $root = [ keys $data->%* ]->[0]; |
175
|
|
|
|
|
|
|
|
176
|
0
|
0
|
|
|
|
0
|
$res = \$xml_obj->hash2xml( $data->{$root}, root => $root, indent => $args{readable} ? 4 : 0 ); |
177
|
|
|
|
|
|
|
} |
178
|
|
|
|
|
|
|
elsif ( $type == $DATA_TYPE_INI ) { |
179
|
0
|
|
|
|
|
0
|
state $init = !!require Pcore::Util::Config::INI; |
180
|
|
|
|
|
|
|
|
181
|
0
|
|
|
|
|
0
|
$res = Pcore::Util::Config::INI::to_ini($data); |
182
|
|
|
|
|
|
|
} |
183
|
|
|
|
|
|
|
else { |
184
|
0
|
|
|
|
|
0
|
die qq[Unknown serializer "$type"]; |
185
|
|
|
|
|
|
|
} |
186
|
|
|
|
|
|
|
|
187
|
|
|
|
|
|
|
# compress |
188
|
0
|
0
|
|
|
|
0
|
if ( $args{compress} ) { |
189
|
0
|
0
|
|
|
|
0
|
if ( bytes::length $res->$* >= $args{compress_threshold} ) { |
190
|
0
|
0
|
|
|
|
0
|
if ( $args{compress} == $DATA_COMPRESS_ZLIB ) { |
191
|
0
|
|
|
|
|
0
|
state $init = !!require Compress::Zlib; |
192
|
|
|
|
|
|
|
|
193
|
0
|
|
|
|
|
0
|
$res = \Compress::Zlib::compress( $res->$* ); |
194
|
|
|
|
|
|
|
} |
195
|
|
|
|
|
|
|
else { |
196
|
0
|
|
|
|
|
0
|
die qq[Unknown compressor type "$args{compress}"]; |
197
|
|
|
|
|
|
|
} |
198
|
|
|
|
|
|
|
} |
199
|
|
|
|
|
|
|
else { |
200
|
0
|
|
|
|
|
0
|
$args{compress} = 0; |
201
|
|
|
|
|
|
|
} |
202
|
|
|
|
|
|
|
} |
203
|
|
|
|
|
|
|
|
204
|
|
|
|
|
|
|
# encrypt |
205
|
0
|
0
|
|
|
|
0
|
if ( defined $args{secret} ) { |
206
|
0
|
|
|
|
|
0
|
my $secret; |
207
|
|
|
|
|
|
|
|
208
|
0
|
0
|
|
|
|
0
|
if ( is_plain_arrayref $args{secret} ) { |
209
|
0
|
|
|
|
|
0
|
$secret = $args{secret}->[ $args{secret_index} ]; |
210
|
|
|
|
|
|
|
} |
211
|
|
|
|
|
|
|
else { |
212
|
0
|
|
|
|
|
0
|
$secret = $args{secret}; |
213
|
|
|
|
|
|
|
} |
214
|
|
|
|
|
|
|
|
215
|
0
|
0
|
|
|
|
0
|
if ( defined $secret ) { |
216
|
0
|
|
|
|
|
0
|
state $init = !!require Crypt::CBC; |
217
|
|
|
|
|
|
|
|
218
|
|
|
|
|
|
|
$res = \Crypt::CBC->new( |
219
|
|
|
|
|
|
|
-key => $secret, |
220
|
|
|
|
|
|
|
-cipher => $CIPHER_NAME->{ $args{cipher} }, |
221
|
0
|
|
|
|
|
0
|
)->encrypt( $res->$* ); |
222
|
|
|
|
|
|
|
} |
223
|
|
|
|
|
|
|
else { |
224
|
0
|
|
|
|
|
0
|
$args{secret} = undef; |
225
|
|
|
|
|
|
|
} |
226
|
|
|
|
|
|
|
} |
227
|
|
|
|
|
|
|
|
228
|
|
|
|
|
|
|
# encode |
229
|
0
|
0
|
|
|
|
0
|
if ( $args{encode} ) { |
230
|
0
|
0
|
|
|
|
0
|
if ( $args{encode} == $DATA_ENC_B64 ) { |
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
231
|
0
|
|
|
|
|
0
|
$res = \to_b64_url( $res->$* ); |
232
|
|
|
|
|
|
|
} |
233
|
|
|
|
|
|
|
elsif ( $args{encode} == $DATA_ENC_HEX ) { |
234
|
0
|
|
|
|
|
0
|
$res = \unpack 'H*', $res->$*; |
235
|
|
|
|
|
|
|
} |
236
|
|
|
|
|
|
|
elsif ( $args{encode} == $DATA_ENC_B85 ) { |
237
|
0
|
|
|
|
|
0
|
$res = \to_b85( $res->$* ); |
238
|
|
|
|
|
|
|
} |
239
|
|
|
|
|
|
|
else { |
240
|
0
|
|
|
|
|
0
|
die qq[Unknown encoder "$args{encode}"]; |
241
|
|
|
|
|
|
|
} |
242
|
|
|
|
|
|
|
} |
243
|
|
|
|
|
|
|
|
244
|
|
|
|
|
|
|
# add token |
245
|
0
|
0
|
|
|
|
0
|
if ( $args{token} ) { |
246
|
0
|
0
|
0
|
|
|
0
|
$res->$* .= sprintf( '#%x', ( $args{compress} // 0 ) . ( defined $args{secret} ? $args{cipher} : 0 ) . ( $args{secret_index} // 0 ) . ( $args{encode} // 0 ) . $type ) . sprintf '#%x', bytes::length $res->$*; |
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
247
|
|
|
|
|
|
|
} |
248
|
|
|
|
|
|
|
|
249
|
0
|
|
|
|
|
0
|
return $res; |
250
|
|
|
|
|
|
|
} |
251
|
|
|
|
|
|
|
|
252
|
|
|
|
|
|
|
# JSON data should be without UTF8 flag |
253
|
|
|
|
|
|
|
# objects isn't deserialized automatically from JSON |
254
|
8
|
|
|
8
|
0
|
20
|
sub decode_data ( $type, @ ) { |
|
8
|
|
|
|
|
18
|
|
|
8
|
|
|
|
|
14
|
|
255
|
8
|
50
|
|
|
|
39
|
my $data_ref = ref $_[1] ? $_[1] : \$_[1]; |
256
|
|
|
|
|
|
|
|
257
|
8
|
|
|
|
|
94
|
my %args = ( |
258
|
|
|
|
|
|
|
compress => undef, |
259
|
|
|
|
|
|
|
secret => undef, # can be ArrayRef |
260
|
|
|
|
|
|
|
secret_index => 0, |
261
|
|
|
|
|
|
|
cipher => $DATA_CIPHER_DES, |
262
|
|
|
|
|
|
|
encode => undef, # 0, 1 = 'hex', 'hex', 'b64' |
263
|
|
|
|
|
|
|
perl_ns => undef, # for PERL only, namespace for data evaluation |
264
|
|
|
|
|
|
|
json => undef, # HashRef with additional params for Cpanel::JSON::XS |
265
|
|
|
|
|
|
|
return_token => 0, # return token |
266
|
|
|
|
|
|
|
splice( @_, 2 ), |
267
|
|
|
|
|
|
|
type => $type, |
268
|
|
|
|
|
|
|
); |
269
|
|
|
|
|
|
|
|
270
|
|
|
|
|
|
|
# parse token |
271
|
8
|
50
|
|
|
|
54
|
if ( $data_ref->$* =~ /#([[:xdigit:]]{1,8})#([[:xdigit:]]{1,16})\z/sm ) { |
272
|
0
|
|
|
|
|
0
|
my $token_len = 2 + length($1) + length $2; |
273
|
|
|
|
|
|
|
|
274
|
0
|
0
|
|
|
|
0
|
if ( bytes::length( $data_ref->$* ) - $token_len == hex $2 ) { |
275
|
0
|
|
|
|
|
0
|
$args{has_token} = 1; |
276
|
|
|
|
|
|
|
|
277
|
0
|
|
|
|
|
0
|
substr $data_ref->$*, -$token_len, $token_len, q[]; |
278
|
|
|
|
|
|
|
|
279
|
0
|
|
|
|
|
0
|
( $args{compress}, $args{cipher}, $args{secret_index}, $args{encode}, $type ) = split //sm, sprintf '%05s', hex $1; |
280
|
|
|
|
|
|
|
|
281
|
0
|
|
|
|
|
0
|
$args{type} = $type; |
282
|
|
|
|
|
|
|
} |
283
|
|
|
|
|
|
|
} |
284
|
|
|
|
|
|
|
|
285
|
|
|
|
|
|
|
# decode |
286
|
8
|
50
|
|
|
|
32
|
if ( $args{encode} ) { |
287
|
0
|
0
|
|
|
|
0
|
if ( $args{encode} == $DATA_ENC_B64 ) { |
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
288
|
0
|
|
|
|
|
0
|
$data_ref = \from_b64_url( $data_ref->$* ); |
289
|
|
|
|
|
|
|
} |
290
|
|
|
|
|
|
|
elsif ( $args{encode} == $DATA_ENC_HEX ) { |
291
|
0
|
|
|
|
|
0
|
$data_ref = \pack 'H*', $data_ref->$*; |
292
|
|
|
|
|
|
|
} |
293
|
|
|
|
|
|
|
elsif ( $args{encode} == $DATA_ENC_B85 ) { |
294
|
0
|
|
|
|
|
0
|
$data_ref = \from_b85( $data_ref->$* ); |
295
|
|
|
|
|
|
|
} |
296
|
|
|
|
|
|
|
else { |
297
|
0
|
|
|
|
|
0
|
die qq[Unknown encoder "$args{encode}"]; |
298
|
|
|
|
|
|
|
} |
299
|
|
|
|
|
|
|
} |
300
|
|
|
|
|
|
|
|
301
|
|
|
|
|
|
|
# decrypt |
302
|
8
|
50
|
33
|
|
|
68
|
if ( $args{cipher} && defined $args{secret} ) { |
303
|
0
|
|
|
|
|
0
|
my $secret; |
304
|
|
|
|
|
|
|
|
305
|
0
|
0
|
|
|
|
0
|
if ( is_plain_arrayref $args{secret} ) { |
306
|
0
|
|
|
|
|
0
|
$secret = $args{secret}->[ $args{secret_index} ]; |
307
|
|
|
|
|
|
|
} |
308
|
|
|
|
|
|
|
else { |
309
|
0
|
|
|
|
|
0
|
$secret = $args{secret}; |
310
|
|
|
|
|
|
|
} |
311
|
|
|
|
|
|
|
|
312
|
0
|
0
|
|
|
|
0
|
if ( defined $secret ) { |
313
|
0
|
|
|
|
|
0
|
state $init = !!require Crypt::CBC; |
314
|
|
|
|
|
|
|
|
315
|
|
|
|
|
|
|
$data_ref = \Crypt::CBC->new( |
316
|
|
|
|
|
|
|
-key => $secret, |
317
|
|
|
|
|
|
|
-cipher => $CIPHER_NAME->{ $args{cipher} }, |
318
|
0
|
|
|
|
|
0
|
)->decrypt( $data_ref->$* ); |
319
|
|
|
|
|
|
|
|
320
|
|
|
|
|
|
|
} |
321
|
|
|
|
|
|
|
} |
322
|
|
|
|
|
|
|
|
323
|
|
|
|
|
|
|
# decompress |
324
|
8
|
50
|
|
|
|
32
|
if ( $args{compress} ) { |
325
|
0
|
0
|
|
|
|
0
|
if ( $args{compress} == $DATA_COMPRESS_ZLIB ) { |
326
|
0
|
|
|
|
|
0
|
state $init = !!require Compress::Zlib; |
327
|
|
|
|
|
|
|
|
328
|
0
|
|
|
|
|
0
|
$data_ref = \Compress::Zlib::uncompress($data_ref); |
329
|
|
|
|
|
|
|
|
330
|
0
|
0
|
|
|
|
0
|
die if !defined $data_ref->$*; |
331
|
|
|
|
|
|
|
} |
332
|
|
|
|
|
|
|
else { |
333
|
0
|
|
|
|
|
0
|
die qq[Unknown compressor "$args{compressor}"]; |
334
|
|
|
|
|
|
|
} |
335
|
|
|
|
|
|
|
} |
336
|
|
|
|
|
|
|
|
337
|
|
|
|
|
|
|
# decode |
338
|
8
|
|
|
|
|
19
|
my $res; |
339
|
|
|
|
|
|
|
|
340
|
8
|
100
|
|
|
|
56
|
if ( $type == $DATA_TYPE_PERL ) { |
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
341
|
5
|
|
50
|
|
|
30
|
my $ns = $args{perl_ns} || '_Pcore::CONFIG::SANDBOX'; |
342
|
|
|
|
|
|
|
|
343
|
5
|
|
|
|
|
158
|
decode_utf8 $data_ref->$*; |
344
|
|
|
|
|
|
|
|
345
|
|
|
|
|
|
|
## no critic qw[BuiltinFunctions::ProhibitStringyEval] |
346
|
5
|
|
|
5
|
|
40
|
$res = eval <<"CODE"; |
|
5
|
|
|
|
|
12
|
|
|
5
|
|
|
|
|
38
|
|
|
5
|
|
|
|
|
588
|
|
347
|
|
|
|
|
|
|
package $ns; |
348
|
|
|
|
|
|
|
|
349
|
|
|
|
|
|
|
use Pcore -config; |
350
|
|
|
|
|
|
|
|
351
|
|
|
|
|
|
|
$data_ref->$* |
352
|
|
|
|
|
|
|
CODE |
353
|
5
|
50
|
|
|
|
43
|
die $@ if $@; |
354
|
|
|
|
|
|
|
|
355
|
5
|
50
|
|
|
|
22
|
die q[Config must return value] unless $res; |
356
|
|
|
|
|
|
|
} |
357
|
|
|
|
|
|
|
elsif ( $type == $DATA_TYPE_JSON ) { |
358
|
0
|
0
|
|
|
|
0
|
if ( $args{json} ) { |
359
|
0
|
|
|
|
|
0
|
my $json = _get_json_obj( $args{json}->%* ); |
360
|
|
|
|
|
|
|
|
361
|
0
|
|
|
|
|
0
|
$res = $json->decode( $data_ref->$* ); |
362
|
|
|
|
|
|
|
} |
363
|
|
|
|
|
|
|
else { |
364
|
0
|
|
|
|
|
0
|
state $json = _get_json_obj( utf8 => 1 ); |
365
|
|
|
|
|
|
|
|
366
|
|
|
|
|
|
|
# $res = $json->decode_prefix( $data_ref->$* ); |
367
|
|
|
|
|
|
|
|
368
|
0
|
|
|
|
|
0
|
$res = $json->decode( $data_ref->$* ); |
369
|
|
|
|
|
|
|
} |
370
|
|
|
|
|
|
|
} |
371
|
|
|
|
|
|
|
elsif ( $type == $DATA_TYPE_CBOR ) { |
372
|
0
|
|
|
|
|
0
|
state $cbor = _get_cbor_obj(); |
373
|
|
|
|
|
|
|
|
374
|
0
|
|
|
|
|
0
|
$res = $cbor->decode( $data_ref->$* ); |
375
|
|
|
|
|
|
|
} |
376
|
|
|
|
|
|
|
elsif ( $type == $DATA_TYPE_YAML ) { |
377
|
0
|
|
|
|
|
0
|
state $init = !!require YAML::XS; |
378
|
|
|
|
|
|
|
|
379
|
0
|
|
|
|
|
0
|
local $YAML::XS::UseCode = 0; |
380
|
0
|
|
|
|
|
0
|
local $YAML::XS::DumpCode = 0; |
381
|
0
|
|
|
|
|
0
|
local $YAML::XS::LoadCode = 0; |
382
|
|
|
|
|
|
|
|
383
|
0
|
|
|
|
|
0
|
$res = YAML::XS::Load( $data_ref->$* ); |
384
|
|
|
|
|
|
|
} |
385
|
|
|
|
|
|
|
elsif ( $type == $DATA_TYPE_XML ) { |
386
|
0
|
|
|
|
|
0
|
state $init = !!require XML::Hash::XS; |
387
|
|
|
|
|
|
|
|
388
|
0
|
|
|
|
|
0
|
state $xml_args = { |
389
|
|
|
|
|
|
|
encoding => 'UTF-8', |
390
|
|
|
|
|
|
|
utf8 => 1, |
391
|
|
|
|
|
|
|
max_depth => 1024, |
392
|
|
|
|
|
|
|
buf_size => 4096, |
393
|
|
|
|
|
|
|
force_array => 1, |
394
|
|
|
|
|
|
|
force_content => 1, |
395
|
|
|
|
|
|
|
merge_text => 1, |
396
|
|
|
|
|
|
|
keep_root => 1, |
397
|
|
|
|
|
|
|
}; |
398
|
|
|
|
|
|
|
|
399
|
0
|
|
|
|
|
0
|
state $xml_obj = XML::Hash::XS->new( $xml_args->%* ); |
400
|
|
|
|
|
|
|
|
401
|
0
|
|
|
|
|
0
|
$res = $xml_obj->xml2hash($data_ref); |
402
|
|
|
|
|
|
|
} |
403
|
|
|
|
|
|
|
elsif ( $type == $DATA_TYPE_INI ) { |
404
|
3
|
|
|
|
|
1204
|
state $init = !!require Pcore::Util::Config::INI; |
405
|
|
|
|
|
|
|
|
406
|
3
|
|
|
|
|
16
|
$res = Pcore::Util::Config::INI::from_ini( $data_ref->$* ); |
407
|
|
|
|
|
|
|
} |
408
|
|
|
|
|
|
|
else { |
409
|
0
|
|
|
|
|
0
|
die qq[Unknown serializer "$type"]; |
410
|
|
|
|
|
|
|
} |
411
|
|
|
|
|
|
|
|
412
|
8
|
50
|
33
|
|
|
37
|
if ( wantarray && $args{return_token} ) { |
413
|
0
|
|
|
|
|
0
|
return $res, \%args; |
414
|
|
|
|
|
|
|
} |
415
|
|
|
|
|
|
|
else { |
416
|
8
|
|
|
|
|
168
|
return $res; |
417
|
|
|
|
|
|
|
} |
418
|
|
|
|
|
|
|
} |
419
|
|
|
|
|
|
|
|
420
|
|
|
|
|
|
|
# PERL |
421
|
|
|
|
|
|
|
sub to_perl { |
422
|
0
|
|
|
0
|
0
|
|
return encode_data( $DATA_TYPE_PERL, @_ ); |
423
|
|
|
|
|
|
|
} |
424
|
|
|
|
|
|
|
|
425
|
|
|
|
|
|
|
sub from_perl { |
426
|
0
|
|
|
0
|
0
|
|
return decode_data( $DATA_TYPE_PERL, @_ ); |
427
|
|
|
|
|
|
|
} |
428
|
|
|
|
|
|
|
|
429
|
|
|
|
|
|
|
# JSON |
430
|
|
|
|
|
|
|
sub _get_json_obj { |
431
|
0
|
|
|
0
|
|
|
my %args = ( |
432
|
|
|
|
|
|
|
|
433
|
|
|
|
|
|
|
# COMMON |
434
|
|
|
|
|
|
|
utf8 => 1, |
435
|
|
|
|
|
|
|
allow_nonref => 1, # allow scalars |
436
|
|
|
|
|
|
|
allow_tags => 0, # use FREEZE / THAW, we don't use this, because non-standard JSON will be generated, use CBOR instead to serialize objects |
437
|
|
|
|
|
|
|
|
438
|
|
|
|
|
|
|
# shrink => 0, |
439
|
|
|
|
|
|
|
# max_depth => 512, |
440
|
|
|
|
|
|
|
|
441
|
|
|
|
|
|
|
# DECODE |
442
|
|
|
|
|
|
|
relaxed => 1, # allows commas and # - style comments |
443
|
|
|
|
|
|
|
|
444
|
|
|
|
|
|
|
# filter_json_object => undef, |
445
|
|
|
|
|
|
|
# filter_json_single_key_object => undef, |
446
|
|
|
|
|
|
|
# max_size => 0, |
447
|
|
|
|
|
|
|
|
448
|
|
|
|
|
|
|
# ENCODE |
449
|
|
|
|
|
|
|
ascii => 1, |
450
|
|
|
|
|
|
|
latin1 => 0, |
451
|
|
|
|
|
|
|
|
452
|
|
|
|
|
|
|
# pretty => 0, # set indent, space_before, space_after |
453
|
|
|
|
|
|
|
canonical => 0, # sort hash keys, slow |
454
|
|
|
|
|
|
|
indent => 0, |
455
|
|
|
|
|
|
|
space_before => 0, # put a space before the ":" separating key from values |
456
|
|
|
|
|
|
|
space_after => 0, # put a space after the ":" separating key from values, and after "," separating key-value pairs |
457
|
|
|
|
|
|
|
|
458
|
|
|
|
|
|
|
allow_unknown => 0, # throw exception if can't encode item |
459
|
|
|
|
|
|
|
allow_blessed => 1, # allow blessed objects |
460
|
|
|
|
|
|
|
convert_blessed => 1, # use TO_JSON method of blessed objects |
461
|
|
|
|
|
|
|
|
462
|
|
|
|
|
|
|
@_, |
463
|
|
|
|
|
|
|
); |
464
|
|
|
|
|
|
|
|
465
|
0
|
|
|
|
|
|
state $init = !!require Cpanel::JSON::XS; |
466
|
|
|
|
|
|
|
|
467
|
0
|
|
|
|
|
|
my $json = Cpanel::JSON::XS->new; |
468
|
|
|
|
|
|
|
|
469
|
0
|
|
|
|
|
|
for ( keys %args ) { |
470
|
0
|
|
|
|
|
|
$json->$_( $args{$_} ); |
471
|
|
|
|
|
|
|
} |
472
|
|
|
|
|
|
|
|
473
|
0
|
|
|
|
|
|
return $json; |
474
|
|
|
|
|
|
|
} |
475
|
|
|
|
|
|
|
|
476
|
0
|
|
|
0
|
0
|
|
sub to_json ( $data, @ ) { |
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
477
|
0
|
|
|
|
|
|
return encode_data( $DATA_TYPE_JSON, @_ ); |
478
|
|
|
|
|
|
|
} |
479
|
|
|
|
|
|
|
|
480
|
0
|
|
|
0
|
0
|
|
sub from_json ( $data, @ ) { |
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
481
|
0
|
|
|
|
|
|
return decode_data( $DATA_TYPE_JSON, @_ ); |
482
|
|
|
|
|
|
|
} |
483
|
|
|
|
|
|
|
|
484
|
|
|
|
|
|
|
# CBOR |
485
|
|
|
|
|
|
|
sub _get_cbor_obj { |
486
|
0
|
|
|
0
|
|
|
state $init = !!require CBOR::XS; |
487
|
|
|
|
|
|
|
|
488
|
0
|
|
|
|
|
|
my $cbor = CBOR::XS->new; |
489
|
|
|
|
|
|
|
|
490
|
0
|
|
|
|
|
|
$cbor->max_depth(512); |
491
|
0
|
|
|
|
|
|
$cbor->max_size(0); # max. string size is unlimited |
492
|
0
|
|
|
|
|
|
$cbor->allow_unknown(0); |
493
|
0
|
|
|
|
|
|
$cbor->allow_sharing(1); |
494
|
0
|
|
|
|
|
|
$cbor->allow_cycles(1); |
495
|
0
|
|
|
|
|
|
$cbor->pack_strings(0); # set to 1 affect speed, but makes size smaller |
496
|
0
|
|
|
|
|
|
$cbor->validate_utf8(0); |
497
|
0
|
|
|
|
|
|
$cbor->filter(undef); |
498
|
|
|
|
|
|
|
|
499
|
0
|
|
|
|
|
|
return $cbor; |
500
|
|
|
|
|
|
|
} |
501
|
|
|
|
|
|
|
|
502
|
|
|
|
|
|
|
sub to_cbor { |
503
|
0
|
|
|
0
|
0
|
|
return encode_data( $DATA_TYPE_CBOR, @_ ); |
504
|
|
|
|
|
|
|
} |
505
|
|
|
|
|
|
|
|
506
|
|
|
|
|
|
|
sub from_cbor { |
507
|
0
|
|
|
0
|
0
|
|
return decode_data( $DATA_TYPE_CBOR, @_ ); |
508
|
|
|
|
|
|
|
} |
509
|
|
|
|
|
|
|
|
510
|
|
|
|
|
|
|
# YAML |
511
|
|
|
|
|
|
|
sub to_yaml { |
512
|
0
|
|
|
0
|
0
|
|
return encode_data( $DATA_TYPE_YAML, @_ ); |
513
|
|
|
|
|
|
|
} |
514
|
|
|
|
|
|
|
|
515
|
|
|
|
|
|
|
sub from_yaml { |
516
|
0
|
|
|
0
|
0
|
|
return decode_data( $DATA_TYPE_YAML, @_ ); |
517
|
|
|
|
|
|
|
} |
518
|
|
|
|
|
|
|
|
519
|
|
|
|
|
|
|
# XML |
520
|
|
|
|
|
|
|
sub to_xml { |
521
|
0
|
|
|
0
|
0
|
|
return encode_data( $DATA_TYPE_XML, @_ ); |
522
|
|
|
|
|
|
|
} |
523
|
|
|
|
|
|
|
|
524
|
|
|
|
|
|
|
sub from_xml { |
525
|
0
|
|
|
0
|
0
|
|
return decode_data( $DATA_TYPE_XML, @_ ); |
526
|
|
|
|
|
|
|
} |
527
|
|
|
|
|
|
|
|
528
|
|
|
|
|
|
|
# INI |
529
|
|
|
|
|
|
|
sub to_ini { |
530
|
0
|
|
|
0
|
0
|
|
return encode_data( $DATA_TYPE_INI, @_ ); |
531
|
|
|
|
|
|
|
} |
532
|
|
|
|
|
|
|
|
533
|
|
|
|
|
|
|
sub from_ini { |
534
|
0
|
|
|
0
|
0
|
|
return decode_data( $DATA_TYPE_INI, @_ ); |
535
|
|
|
|
|
|
|
} |
536
|
|
|
|
|
|
|
|
537
|
|
|
|
|
|
|
# BASE64 |
538
|
|
|
|
|
|
|
sub to_b64 { |
539
|
0
|
|
|
0
|
0
|
|
state $init = !!require MIME::Base64; |
540
|
|
|
|
|
|
|
|
541
|
0
|
|
|
|
|
|
return &MIME::Base64::encode_base64; ## no critic qw[Subroutines::ProhibitAmpersandSigils] |
542
|
|
|
|
|
|
|
} |
543
|
|
|
|
|
|
|
|
544
|
|
|
|
|
|
|
sub to_b64_url { |
545
|
0
|
|
|
0
|
0
|
|
state $init = !!require MIME::Base64; |
546
|
|
|
|
|
|
|
|
547
|
0
|
|
|
|
|
|
return &MIME::Base64::encode_base64url; ## no critic qw[Subroutines::ProhibitAmpersandSigils] |
548
|
|
|
|
|
|
|
} |
549
|
|
|
|
|
|
|
|
550
|
|
|
|
|
|
|
sub from_b64 { |
551
|
0
|
|
|
0
|
0
|
|
state $init = !!require MIME::Base64; |
552
|
|
|
|
|
|
|
|
553
|
0
|
|
|
|
|
|
return &MIME::Base64::decode_base64; ## no critic qw[Subroutines::ProhibitAmpersandSigils] |
554
|
|
|
|
|
|
|
} |
555
|
|
|
|
|
|
|
|
556
|
|
|
|
|
|
|
sub from_b64_url { |
557
|
0
|
|
|
0
|
0
|
|
state $init = !!require MIME::Base64; |
558
|
|
|
|
|
|
|
|
559
|
0
|
|
|
|
|
|
return &MIME::Base64::decode_base64url; ## no critic qw[Subroutines::ProhibitAmpersandSigils] |
560
|
|
|
|
|
|
|
} |
561
|
|
|
|
|
|
|
|
562
|
|
|
|
|
|
|
# BASE85 |
563
|
|
|
|
|
|
|
sub to_b85 { |
564
|
0
|
|
|
0
|
0
|
|
state $init = !!require Convert::Ascii85; |
565
|
|
|
|
|
|
|
|
566
|
0
|
|
|
|
|
|
state $args = { compress_zero => 1, compress_space => 1 }; |
567
|
|
|
|
|
|
|
|
568
|
0
|
|
|
|
|
|
return Convert::Ascii85::ascii85_encode( $_[0], $args ); |
569
|
|
|
|
|
|
|
} |
570
|
|
|
|
|
|
|
|
571
|
|
|
|
|
|
|
sub from_b85 { |
572
|
0
|
|
|
0
|
0
|
|
state $init = !!require Convert::Ascii85; |
573
|
|
|
|
|
|
|
|
574
|
0
|
|
|
|
|
|
return &Convert::Ascii85::ascii85_decode; ## no critic qw[Subroutines::ProhibitAmpersandSigils] |
575
|
|
|
|
|
|
|
} |
576
|
|
|
|
|
|
|
|
577
|
|
|
|
|
|
|
# URI |
578
|
|
|
|
|
|
|
sub to_uri { |
579
|
0
|
0
|
|
0
|
0
|
|
if ( ref $_[0] ) { |
580
|
0
|
0
|
0
|
|
|
|
my $data = is_blessed_ref $_[0] && $_[0]->isa('Pcore::Util::Hash::Multivalue') ? $_[0]->get_hash : $_[0]; |
581
|
|
|
|
|
|
|
|
582
|
0
|
|
|
|
|
|
my @res; |
583
|
|
|
|
|
|
|
|
584
|
0
|
0
|
|
|
|
|
if ( is_plain_arrayref $data ) { |
585
|
0
|
|
|
|
|
|
for ( my $i = 0; $i <= $data->$#*; $i += 2 ) { |
586
|
0
|
0
|
|
|
|
|
push @res, join q[=], defined $data->[$i] ? URI::Escape::XS::encodeURIComponent( $data->[$i] ) : q[], defined $data->[ $i + 1 ] ? URI::Escape::XS::encodeURIComponent( $data->[ $i + 1 ] ) : (); |
|
|
0
|
|
|
|
|
|
587
|
|
|
|
|
|
|
} |
588
|
|
|
|
|
|
|
} |
589
|
|
|
|
|
|
|
else { |
590
|
0
|
|
|
|
|
|
while ( my ( $k, $v ) = each $data->%* ) { |
591
|
0
|
|
|
|
|
|
$k = URI::Escape::XS::encodeURIComponent($k); |
592
|
|
|
|
|
|
|
|
593
|
0
|
0
|
|
|
|
|
if ( ref $v ) { |
594
|
|
|
|
|
|
|
|
595
|
|
|
|
|
|
|
# value is ArrayRef |
596
|
0
|
|
|
|
|
|
for my $v1 ( $v->@* ) { |
597
|
0
|
0
|
|
|
|
|
push @res, join q[=], $k, defined $v1 ? URI::Escape::XS::encodeURIComponent($v1) : (); |
598
|
|
|
|
|
|
|
} |
599
|
|
|
|
|
|
|
} |
600
|
|
|
|
|
|
|
else { |
601
|
0
|
0
|
|
|
|
|
push @res, join q[=], $k, defined $v ? URI::Escape::XS::encodeURIComponent($v) : (); |
602
|
|
|
|
|
|
|
} |
603
|
|
|
|
|
|
|
} |
604
|
|
|
|
|
|
|
} |
605
|
|
|
|
|
|
|
|
606
|
0
|
|
|
|
|
|
return join q[&], @res; |
607
|
|
|
|
|
|
|
} |
608
|
|
|
|
|
|
|
else { |
609
|
0
|
|
|
|
|
|
return URI::Escape::XS::encodeURIComponent( $_[0] ); |
610
|
|
|
|
|
|
|
} |
611
|
|
|
|
|
|
|
} |
612
|
|
|
|
|
|
|
|
613
|
|
|
|
|
|
|
# always return scalar string |
614
|
|
|
|
|
|
|
sub from_uri { |
615
|
0
|
|
|
0
|
0
|
|
my %args = ( |
616
|
|
|
|
|
|
|
encoding => 'UTF-8', |
617
|
|
|
|
|
|
|
splice @_, 1, |
618
|
|
|
|
|
|
|
); |
619
|
|
|
|
|
|
|
|
620
|
0
|
|
|
|
|
|
my $u = URI::Escape::XS::decodeURIComponent( $_[0] ); |
621
|
|
|
|
|
|
|
|
622
|
0
|
0
|
|
|
|
|
if ( $args{encoding} ) { |
623
|
0
|
|
|
|
|
|
state $encoding = {}; |
624
|
|
|
|
|
|
|
|
625
|
0
|
|
0
|
|
|
|
$encoding->{ $args{encoding} } //= Encode::find_encoding( $args{encoding} ); |
626
|
|
|
|
|
|
|
|
627
|
0
|
0
|
|
|
|
|
eval { $u = $encoding->{ $args{encoding} }->decode( $u, Encode::FB_CROAK | Encode::LEAVE_SRC ); 1; } or do { |
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
628
|
0
|
0
|
|
|
|
|
utf8::upgrade($u) if $@; |
629
|
|
|
|
|
|
|
}; |
630
|
|
|
|
|
|
|
} |
631
|
|
|
|
|
|
|
|
632
|
0
|
0
|
|
|
|
|
if ( defined wantarray ) { |
633
|
0
|
|
|
|
|
|
return $u; |
634
|
|
|
|
|
|
|
} |
635
|
|
|
|
|
|
|
else { |
636
|
0
|
|
|
|
|
|
$_[0] = $u; |
637
|
|
|
|
|
|
|
|
638
|
0
|
|
|
|
|
|
return; |
639
|
|
|
|
|
|
|
} |
640
|
|
|
|
|
|
|
} |
641
|
|
|
|
|
|
|
|
642
|
|
|
|
|
|
|
# always return HashMultivalue |
643
|
|
|
|
|
|
|
sub from_uri_query { |
644
|
0
|
|
|
0
|
0
|
|
my %args = ( |
645
|
|
|
|
|
|
|
encoding => 'UTF-8', |
646
|
|
|
|
|
|
|
splice @_, 1, |
647
|
|
|
|
|
|
|
); |
648
|
|
|
|
|
|
|
|
649
|
0
|
|
|
|
|
|
my $enc; |
650
|
|
|
|
|
|
|
|
651
|
0
|
0
|
|
|
|
|
if ( $args{encoding} ) { |
652
|
0
|
|
|
|
|
|
state $encoding = {}; |
653
|
|
|
|
|
|
|
|
654
|
0
|
|
0
|
|
|
|
$encoding->{ $args{encoding} } //= Encode::find_encoding( $args{encoding} ); |
655
|
|
|
|
|
|
|
|
656
|
0
|
|
|
|
|
|
$enc = $encoding->{ $args{encoding} }; |
657
|
|
|
|
|
|
|
} |
658
|
|
|
|
|
|
|
|
659
|
0
|
|
|
|
|
|
my $res = P->hash->multivalue; |
660
|
|
|
|
|
|
|
|
661
|
0
|
|
|
|
|
|
my $hash = $res->get_hash; |
662
|
|
|
|
|
|
|
|
663
|
0
|
|
|
|
|
|
for my $key ( split /&/sm, $_[0] ) { |
664
|
0
|
|
|
|
|
|
my $val; |
665
|
|
|
|
|
|
|
|
666
|
0
|
0
|
|
|
|
|
if ( ( my $idx = index $key, q[=] ) != -1 ) { |
667
|
0
|
|
|
|
|
|
$val = substr $key, $idx, length $key, q[]; |
668
|
|
|
|
|
|
|
|
669
|
0
|
|
|
|
|
|
substr $val, 0, 1, q[]; |
670
|
|
|
|
|
|
|
|
671
|
0
|
|
|
|
|
|
$val = URI::Escape::XS::decodeURIComponent($val); |
672
|
|
|
|
|
|
|
} |
673
|
|
|
|
|
|
|
|
674
|
0
|
|
|
|
|
|
$key = URI::Escape::XS::decodeURIComponent($key); |
675
|
|
|
|
|
|
|
|
676
|
0
|
0
|
|
|
|
|
if ($enc) { |
677
|
|
|
|
|
|
|
|
678
|
|
|
|
|
|
|
# decode key |
679
|
0
|
0
|
|
|
|
|
eval { $key = $enc->decode( $key, Encode::FB_CROAK | Encode::LEAVE_SRC ); 1; } or do { |
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
680
|
0
|
0
|
|
|
|
|
utf8::upgrade($key) if $@; |
681
|
|
|
|
|
|
|
}; |
682
|
|
|
|
|
|
|
|
683
|
|
|
|
|
|
|
# decode value |
684
|
0
|
0
|
|
|
|
|
if ( defined $val ) { |
685
|
0
|
0
|
|
|
|
|
eval { $val = $enc->decode( $val, Encode::FB_CROAK | Encode::LEAVE_SRC ); 1; } or do { |
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
686
|
0
|
0
|
|
|
|
|
utf8::upgrade($val) if $@; |
687
|
|
|
|
|
|
|
}; |
688
|
|
|
|
|
|
|
} |
689
|
|
|
|
|
|
|
} |
690
|
|
|
|
|
|
|
|
691
|
0
|
|
|
|
|
|
push $hash->{$key}->@*, $val; |
692
|
|
|
|
|
|
|
} |
693
|
|
|
|
|
|
|
|
694
|
0
|
0
|
|
|
|
|
if ( defined wantarray ) { |
695
|
0
|
|
|
|
|
|
return $res; |
696
|
|
|
|
|
|
|
} |
697
|
|
|
|
|
|
|
else { |
698
|
0
|
|
|
|
|
|
$_[0] = $res; |
699
|
|
|
|
|
|
|
|
700
|
0
|
|
|
|
|
|
return; |
701
|
|
|
|
|
|
|
} |
702
|
|
|
|
|
|
|
} |
703
|
|
|
|
|
|
|
|
704
|
|
|
|
|
|
|
# XOR |
705
|
0
|
|
|
0
|
0
|
|
sub to_xor ( $buf, $mask ) { |
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
706
|
5
|
|
|
5
|
|
52
|
no feature qw[bitwise]; |
|
5
|
|
|
|
|
11
|
|
|
5
|
|
|
|
|
1089
|
|
707
|
|
|
|
|
|
|
|
708
|
0
|
|
|
|
|
|
my $mlen = length $mask; |
709
|
|
|
|
|
|
|
|
710
|
|
|
|
|
|
|
# select mask length, max. mask length is 1K |
711
|
0
|
|
|
|
|
|
state $max_mlen = 1024; |
712
|
|
|
|
|
|
|
|
713
|
0
|
0
|
0
|
|
|
|
if ( length $buf > $max_mlen && $mlen < $max_mlen ) { |
714
|
0
|
|
|
|
|
|
$mask = $mask x int $max_mlen / $mlen; |
715
|
|
|
|
|
|
|
|
716
|
0
|
|
|
|
|
|
$mlen = length $mask; |
717
|
|
|
|
|
|
|
} |
718
|
|
|
|
|
|
|
|
719
|
0
|
|
|
|
|
|
my $tmp_buf = my $out = q[]; |
720
|
|
|
|
|
|
|
|
721
|
0
|
|
|
|
|
|
$out .= $tmp_buf ^ $mask while length( $tmp_buf = substr $buf, 0, $mlen, q[] ) == $mlen; |
722
|
|
|
|
|
|
|
|
723
|
0
|
|
|
|
|
|
$out .= $tmp_buf ^ substr $mask, 0, length $tmp_buf; |
724
|
|
|
|
|
|
|
|
725
|
0
|
|
|
|
|
|
return $out; |
726
|
|
|
|
|
|
|
} |
727
|
|
|
|
|
|
|
|
728
|
|
|
|
|
|
|
*from_xor = \&to_xor; |
729
|
|
|
|
|
|
|
|
730
|
|
|
|
|
|
|
1; |
731
|
|
|
|
|
|
|
## -----SOURCE FILTER LOG BEGIN----- |
732
|
|
|
|
|
|
|
## |
733
|
|
|
|
|
|
|
## PerlCritic profile "pcore-script" policy violations: |
734
|
|
|
|
|
|
|
## +------+----------------------+----------------------------------------------------------------------------------------------------------------+ |
735
|
|
|
|
|
|
|
## | Sev. | Lines | Policy | |
736
|
|
|
|
|
|
|
## |======+======================+================================================================================================================| |
737
|
|
|
|
|
|
|
## | 3 | | Subroutines::ProhibitExcessComplexity | |
738
|
|
|
|
|
|
|
## | | 49 | * Subroutine "encode_data" with high complexity score (35) | |
739
|
|
|
|
|
|
|
## | | 254 | * Subroutine "decode_data" with high complexity score (33) | |
740
|
|
|
|
|
|
|
## |------+----------------------+----------------------------------------------------------------------------------------------------------------| |
741
|
|
|
|
|
|
|
## | 2 | 585 | ControlStructures::ProhibitCStyleForLoops - C-style "for" loop used | |
742
|
|
|
|
|
|
|
## |------+----------------------+----------------------------------------------------------------------------------------------------------------| |
743
|
|
|
|
|
|
|
## | 2 | 721 | ControlStructures::ProhibitPostfixControls - Postfix control "while" used | |
744
|
|
|
|
|
|
|
## +------+----------------------+----------------------------------------------------------------------------------------------------------------+ |
745
|
|
|
|
|
|
|
## |
746
|
|
|
|
|
|
|
## -----SOURCE FILTER LOG END----- |
747
|
|
|
|
|
|
|
__END__ |
748
|
|
|
|
|
|
|
=pod |
749
|
|
|
|
|
|
|
|
750
|
|
|
|
|
|
|
=encoding utf8 |
751
|
|
|
|
|
|
|
|
752
|
|
|
|
|
|
|
=head1 NAME |
753
|
|
|
|
|
|
|
|
754
|
|
|
|
|
|
|
Pcore::Util::Data |
755
|
|
|
|
|
|
|
|
756
|
|
|
|
|
|
|
=head1 SYNOPSIS |
757
|
|
|
|
|
|
|
|
758
|
|
|
|
|
|
|
=head1 DESCRIPTION |
759
|
|
|
|
|
|
|
|
760
|
|
|
|
|
|
|
JSON SERIALIZE |
761
|
|
|
|
|
|
|
|
762
|
|
|
|
|
|
|
ascii(1): |
763
|
|
|
|
|
|
|
- qq[\xA3] -> \u00A3, upgrded and encoded to UTF-8 character; |
764
|
|
|
|
|
|
|
- qq[£] -> \u00A3, UTF-8 character; |
765
|
|
|
|
|
|
|
- qq[á¾¥] -> \u1FA5, UTF-8 character; |
766
|
|
|
|
|
|
|
|
767
|
|
|
|
|
|
|
latin1(1): |
768
|
|
|
|
|
|
|
- qq[\xA3] -> qq[\xA3], encoded as bytes; |
769
|
|
|
|
|
|
|
- qq[£] -> qq[\xA3], downgraded and encoded as bytes; |
770
|
|
|
|
|
|
|
- qq[á¾¥] -> \u1FA5, downgrade impossible, encoded as UTF-8 character; |
771
|
|
|
|
|
|
|
|
772
|
|
|
|
|
|
|
utf8 - used only when ascii(0) and latin1(0); |
773
|
|
|
|
|
|
|
utf8(0) - upgrade scalar, UTF8 on, DO NOT USE, SERIALIZED DATA SHOULD ALWAYS BY WITHOUT UTF8 FLAG!!!!!!!!!!!!!!!!!!; |
774
|
|
|
|
|
|
|
- qq[\xA3] -> "£" (UTF8, multi-byte, len = 1, bytes::len = 2); |
775
|
|
|
|
|
|
|
- qq[£] -> "£" (UTF8, multi-byte, len = 1, bytes::len = 2); |
776
|
|
|
|
|
|
|
- qq[á¾¥] -> "á¾¥" (UTF8, multi-byte, len = 1, bytes::len = 3); |
777
|
|
|
|
|
|
|
|
778
|
|
|
|
|
|
|
utf8(1) - upgrade, encode scalar, UTF8 off; |
779
|
|
|
|
|
|
|
- qq[\xA3] -> "\xC2\xA3" (latin1, bytes::len = 2); |
780
|
|
|
|
|
|
|
- qq[£] -> "\xC2\xA3" (latin1, bytes::len = 2); |
781
|
|
|
|
|
|
|
- qq[á¾¥] -> "\xE1\xBE\xA5" (latin1, bytes::len = 3); |
782
|
|
|
|
|
|
|
|
783
|
|
|
|
|
|
|
So, |
784
|
|
|
|
|
|
|
- don't use latin1(1); |
785
|
|
|
|
|
|
|
- don't use utf8(0); |
786
|
|
|
|
|
|
|
|
787
|
|
|
|
|
|
|
JSON DESERIALIZE |
788
|
|
|
|
|
|
|
|
789
|
|
|
|
|
|
|
utf8(0): |
790
|
|
|
|
|
|
|
- qq[\xA3] -> "£", upgrade; |
791
|
|
|
|
|
|
|
- qq[£] -> "£", as is; |
792
|
|
|
|
|
|
|
- qq[\xC2\xA3] -> "£", upgrade each byte, invalid; |
793
|
|
|
|
|
|
|
- qq[á¾¥] -> error; |
794
|
|
|
|
|
|
|
|
795
|
|
|
|
|
|
|
utf8(1): |
796
|
|
|
|
|
|
|
- qq[\xA3] -> "£", error, can't decode utf8; |
797
|
|
|
|
|
|
|
- qq[£] -> "£", error, can't decode utf8; |
798
|
|
|
|
|
|
|
- qq[\xC2\xA3] -> "£", decode utf8; |
799
|
|
|
|
|
|
|
- qq[á¾¥] -> error, can't decode utf8; |
800
|
|
|
|
|
|
|
|
801
|
|
|
|
|
|
|
So, |
802
|
|
|
|
|
|
|
- if data was encoded with utf8(0) - use utf8(0) to decode; |
803
|
|
|
|
|
|
|
- if data was encoded with utf8(1) - use utf8(1) to decode; |
804
|
|
|
|
|
|
|
|
805
|
|
|
|
|
|
|
=cut |