use
Carp
qw(croak confess carp)
;
use
vars
qw/$VERSION @ISA @EXPORT_OK/
;
$VERSION
=
'0.34'
;
@ISA
=
qw(Exporter)
;
@EXPORT_OK
=
qw(unserialize serialize)
;
Hide Show 12 lines of Pod
Hide Show 8 lines of Pod
sub
new {
my
(
$class
) =
shift
;
my
$self
=
bless
{}, blessed(
$class
) ? blessed(
$class
) :
$class
;
return
$self
;
}
Hide Show 20 lines of Pod
sub
serialize {
return
__PACKAGE__->new->encode(
@_
);
}
Hide Show 12 lines of Pod
sub
unserialize {
return
__PACKAGE__->new->decode(
@_
);
}
Hide Show 18 lines of Pod
my
$sorthash
;
sub
decode {
my
(
$self
,
$string
,
$class
,
$shash
) =
@_
;
$sorthash
=
$shash
if
defined
(
$shash
);
my
$cursor
= 0;
$self
->{string} = \
$string
;
$self
->{cursor} = \
$cursor
;
$self
->{strlen} =
length
(
$string
);
if
(
defined
$class
) {
$self
->{class} =
$class
;
}
else
{
$self
->{class} =
'PHP::Serialization::Object'
;
}
my
@values
=
$self
->_parse();
if
(
$#values
== -1 ) {
return
;
}
elsif
(
$#values
== 0 ) {
return
$values
[0];
}
else
{
return
\
@values
;
}
}
my
%type_table
= (
O
=>
'object'
,
s
=>
'scalar'
,
a
=>
'array'
,
i
=>
'integer'
,
d
=>
'float'
,
b
=>
'boolean'
,
N
=>
'undef'
,
);
sub
_parse_array {
my
$self
=
shift
;
my
$elemcount
=
shift
;
my
$cursor
=
$self
->{cursor};
my
$string
=
$self
->{string};
my
$strlen
=
$self
->{strlen};
confess(
"No cursor"
)
unless
$cursor
;
confess(
"No string"
)
unless
$string
;
confess(
"No strlen"
)
unless
$strlen
;
my
@elems
= ();
my
@shash_arr
= (
'some'
)
if
((
$sorthash
) and (
ref
(
$sorthash
) eq
'HASH'
));
$self
->_skipchar(
'{'
);
foreach
my
$i
(1..
$elemcount
*2) {
push
(
@elems
,
$self
->_parse_elem);
if
((
$i
% 2) and (
@shash_arr
)) {
$shash_arr
[0]= (((
$i
-1)/2) eq
$elems
[
$#elems
])?
'array'
:
'hash'
unless
(
$shash_arr
[0] eq
'hash'
);
push
(
@shash_arr
,
$elems
[
$#elems
]);
}
}
$self
->_skipchar(
'}'
);
push
(
@elems
,\
@shash_arr
)
if
(
@shash_arr
);
return
@elems
;
}
sub
_parse_elem {
my
$self
=
shift
;
my
$cursor
=
$self
->{cursor};
my
$string
=
$self
->{string};
my
$strlen
=
$self
->{strlen};
my
@elems
;
my
$type_c
=
$self
->_readchar();
my
$type
=
$type_table
{
$type_c
};
if
(!
defined
$type
) {
croak(
"ERROR: Unknown type $type_c."
);
}
if
(
$type
eq
'object'
) {
$self
->_skipchar(
':'
);
my
$namelen
=
$self
->_readnum();
$self
->_skipchar(
':'
);
$self
->_skipchar(
'"'
);
my
$name
=
$self
->_readstr(
$namelen
);
$self
->_skipchar(
'"'
);
$self
->_skipchar(
':'
);
my
$elemcount
=
$self
->_readnum();
$self
->_skipchar(
':'
);
my
%value
=
$self
->_parse_array(
$elemcount
);
return
bless
(\
%value
,
$self
->{class} .
'::'
.
$name
);
}
elsif
(
$type
eq
'array'
) {
$self
->_skipchar(
':'
);
my
$elemcount
=
$self
->_readnum();
$self
->_skipchar(
':'
);
my
@values
=
$self
->_parse_array(
$elemcount
);
my
$subtype
=
'array'
;
my
@newlist
;
my
@shash_arr
=@{
pop
(
@values
)}
if
(
ref
(
$sorthash
) eq
'HASH'
);
foreach
( 0..
$#values
) {
if
( (
$_
% 2) ) {
push
(
@newlist
,
$values
[
$_
]);
next
;
}
elsif
((
$_
/ 2) ne
$values
[
$_
]) {
$subtype
=
'hash'
;
last
;
}
if
(
$values
[
$_
] !~ /^\d+$/ ) {
$subtype
=
'hash'
;
last
;
}
}
if
(
$subtype
eq
'array'
) {
return
\
@newlist
;
}
else
{
my
%hash
=
@values
;
${
$sorthash
}{\
%hash
}=
@shash_arr
if
((
ref
(
$sorthash
) eq
'HASH'
) and
@shash_arr
and (
shift
(
@shash_arr
) ne
'array'
));
return
\
%hash
;
}
}
elsif
(
$type
eq
'scalar'
) {
$self
->_skipchar(
':'
);
my
$strlen
=
$self
->_readnum;
$self
->_skipchar(
':'
);
$self
->_skipchar(
'"'
);
my
$string
=
$self
->_readstr(
$strlen
);
$self
->_skipchar(
'"'
);
$self
->_skipchar(
';'
);
return
$string
;
}
elsif
(
$type
eq
'integer'
||
$type
eq
'float'
) {
$self
->_skipchar(
':'
);
my
$val
=
$self
->_readnum;
if
(
$type
eq
'integer'
) {
$val
=
int
(
$val
); }
$self
->_skipchar(
';'
);
return
$val
;
}
elsif
(
$type
eq
'boolean'
) {
$self
->_skipchar(
':'
);
my
$bool
=
$self
->_readchar;
$self
->_skipchar;
if
(
$bool
eq
'0'
) {
$bool
=
undef
;
}
return
$bool
;
}
elsif
(
$type
eq
'undef'
) {
$self
->_skipchar(
';'
);
return
undef
;
}
else
{
confess
"Unknown element type '$type' found! (cursor $$cursor)"
;
}
}
sub
_parse {
my
(
$self
) =
@_
;
my
$cursor
=
$self
->{cursor};
my
$string
=
$self
->{string};
my
$strlen
=
$self
->{strlen};
confess(
"No cursor"
)
unless
$cursor
;
confess(
"No string"
)
unless
$string
;
confess(
"No strlen"
)
unless
$strlen
;
my
@elems
;
push
(
@elems
,
$self
->_parse_elem);
if
(
$$cursor
!=
$strlen
) {
carp(
"WARN: Unused characters in string after $$cursor."
);
}
return
@elems
;
}
sub
_readstr {
my
(
$self
,
$length
) =
@_
;
my
$string
=
$self
->{string};
my
$cursor
=
$self
->{cursor};
if
(
$$cursor
+
$length
>
length
(
$$string
)) {
croak(
"ERROR: Read past end of string. Want $length after $$cursor. ("
.
$$string
.
")"
);
}
my
$str
=
substr
(
$$string
,
$$cursor
,
$length
);
$$cursor
+=
$length
;
return
$str
;
}
sub
_readchar {
my
(
$self
) =
@_
;
return
$self
->_readstr(1);
}
sub
_readnum {
my
(
$self
) =
@_
;
my
$cursor
=
$self
->{cursor};
my
$string
;
while
( 1 ) {
my
$char
=
$self
->_readchar;
if
(
$char
!~ /^[\d\.-]+$/ ) {
$$cursor
--;
last
;
}
$string
.=
$char
;
}
return
$string
;
}
sub
_skipchar {
my
$self
=
shift
;
my
$want
=
shift
;
my
$c
=
$self
->_readchar();
if
((
$want
)&&(
$c
ne
$want
)) {
my
$cursor
=
$self
->{cursor};
my
$str
=
$self
->{string};
croak(
"ERROR: Wrong char $c, expected $want at position "
.
$$cursor
.
" ("
.
$$str
.
")"
);
}
print
"_skipchar: WRONG char $c ($want)\n"
if
((
$want
)&&(
$c
ne
$want
));
}
Hide Show 14 lines of Pod
sub
encode {
my
(
$self
,
$val
,
$iskey
,
$shash
) =
@_
;
$iskey
=0
unless
defined
$iskey
;
$sorthash
=
$shash
if
defined
$shash
;
if
( !
defined
$val
) {
return
$self
->_encode(
'null'
,
$val
);
}
elsif
( blessed
$val
) {
return
$self
->_encode(
'obj'
,
$val
);
}
elsif
( !
ref
(
$val
) ) {
if
(
$val
=~ /^-?(?:[0-9]|[1-9]\d{1,10})$/ &&
abs
(
$val
) < 2**31 ) {
return
$self
->_encode(
'int'
,
$val
);
}
elsif
(
$val
=~ /^-?\d+\.\d*$/ && !
$iskey
) {
return
$self
->_encode(
'float'
,
$val
);
}
else
{
return
$self
->_encode(
'string'
,
$val
);
}
}
else
{
my
$type
=
ref
(
$val
);
if
(
$type
eq
'HASH'
||
$type
eq
'ARRAY'
) {
return
$self
->_sort_hash_encode(
$val
)
if
((
$sorthash
) and (
$type
eq
'HASH'
));
return
$self
->_encode(
'array'
,
$val
);
}
else
{
confess
"I can't serialize data of type '$type'!"
;
}
}
}
sub
_sort_hash_encode {
my
(
$self
,
$val
) =
@_
;
my
$buffer
=
''
;
my
@hsort
= ((
ref
(
$sorthash
) eq
'HASH'
) and (
ref
(${
$sorthash
}{
$val
}) eq
'ARRAY'
)) ? ${
$sorthash
}{
$val
} :
sort
keys
%{
$val
};
$buffer
.=
sprintf
(
'a:%d:'
,
scalar
(
@hsort
)) .
'{'
;
for
(
@hsort
) {
$buffer
.=
$self
->encode(
$_
,1);
$buffer
.=
$self
->encode(
$$val
{
$_
});
}
$buffer
.=
'}'
;
return
$buffer
;
}
sub
_encode {
my
(
$self
,
$type
,
$val
) =
@_
;
my
$buffer
=
''
;
if
(
$type
eq
'null'
) {
$buffer
.=
'N;'
;
}
elsif
(
$type
eq
'int'
) {
$buffer
.=
sprintf
(
'i:%d;'
,
$val
);
}
elsif
(
$type
eq
'float'
) {
$buffer
.=
sprintf
(
'd:%s;'
,
$val
);
}
elsif
(
$type
eq
'string'
) {
$buffer
.=
sprintf
(
's:%d:"%s";'
,
length
(
$val
),
$val
);
}
elsif
(
$type
eq
'array'
) {
if
(
ref
(
$val
) eq
'ARRAY'
) {
$buffer
.=
sprintf
(
'a:%d:'
,($
map
{
$buffer
.=
$self
->encode(
$_
);
$buffer
.=
$self
->encode(
$$val
[
$_
]);
} 0..$
$buffer
.=
'}'
;
}
else
{
$buffer
.=
sprintf
(
'a:%d:'
,
scalar
(
keys
(%{
$val
}))) .
'{'
;
while
(
my
(
$key
,
$value
) =
each
(%{
$val
}) ) {
$buffer
.=
$self
->encode(
$key
,1);
$buffer
.=
$self
->encode(
$value
);
}
$buffer
.=
'}'
;
}
}
elsif
(
$type
eq
'obj'
) {
my
$class
=
ref
(
$val
);
$class
=~ /(\w+)$/;
my
$subclass
= $1;
$buffer
.=
sprintf
(
'O:%d:"%s":%d:'
,
length
(
$subclass
),
$subclass
,
scalar
(
keys
%{
$val
})) .
'{'
;
foreach
( %{
$val
} ) {
$buffer
.=
$self
->encode(
$_
);
}
$buffer
.=
'}'
;
}
else
{
confess
"Unknown encode type!"
;
}
return
$buffer
;
}
Hide Show 17 lines of Pod
1;