File Coverage

blib/lib/Data/BISON/Encoder.pm
Criterion Covered Total %
statement 33 102 32.3
branch 0 32 0.0
condition 0 15 0.0
subroutine 11 20 55.0
pod 1 1 100.0
total 45 170 26.4


line stmt bran cond sub pod time code
1             package Data::BISON::Encoder;
2              
3 3     3   41860 use warnings;
  3         7  
  3         81  
4 3     3   14 use strict;
  3         5  
  3         79  
5 3     3   14 use Carp;
  3         4  
  3         231  
6 3     3   1918 use Data::BISON::Constants;
  3         8  
  3         388  
7 3     3   1726 use Data::BISON::yEnc qw(encode_yEnc);
  3         7  
  3         185  
8 3     3   21 use Scalar::Util qw(blessed);
  3         6  
  3         488  
9 3     3   2779 use Scalar::Util::Numeric qw(isnum isint isfloat);
  3         2849  
  3         240  
10 3     3   3871 use Encode qw();
  3         39424  
  3         73  
11 3     3   23 use Config;
  3         7  
  3         125  
12              
13 3     3   15 use version; our $VERSION = qv( '0.0.3' );
  3         9  
  3         25  
14              
15             our @ISA = qw(Data::BISON::Base);
16             use Data::BISON::Base {
17             yenc => { default => 0 },
18             double => { default => 0 },
19             version => {
20             default => MIN_VER,
21             set => sub {
22 0           my ( $self, $attr, $ver ) = @_;
23 0 0 0       if ( $ver < MIN_VER || $ver > CUR_VER ) {
24 0           my $desc = ( MIN_VER == CUR_VER )
25             ? MIN_VER
26             : 'between ' . MIN_VER . ' and ' . CUR_VER;
27 0           croak "Version must be $desc";
28             }
29 0           $self->{$attr} = $ver;
30             },
31             },
32 3         47 sort => { default => 0 },
33 3     3   13985 };
  3         8  
34              
35             my @INT_LEN = ( NULL, INT8, INT16, INT24, INT32 );
36              
37             sub _encode_size {
38 0     0     my $self = shift;
39 0           my $size = shift;
40              
41 0 0         if ( $size > 0xFFFF ) {
42 0           croak "Maximum array / hash size is 65535";
43             }
44              
45 0           return pack( 'v', $size );
46             }
47              
48             sub _encode_string {
49 0     0     my $self = shift;
50 0           my $str = shift;
51              
52 0           my $octets = Encode::encode( UTF8, $str );
53 0           $octets =~ s{(\\|\0)}{\\$1}g;
54              
55 0           return $octets . "\0";
56             }
57              
58             sub _encode_hash {
59 0     0     my $self = shift;
60 0           my $hash = shift;
61              
62 0           my @enc = ();
63              
64 0           my @keys = keys %$hash;
65 0 0         @keys = sort @keys if $self->sort;
66              
67 0           push @enc, $self->_encode_size( scalar @keys );
68              
69 0           for my $key ( @keys ) {
70 0           push @enc, $self->_encode_string( $key );
71 0           push @enc, $self->_encode_obj( $hash->{$key} );
72             }
73              
74 0           return join( '', @enc );
75             }
76              
77             sub _encode_array {
78 0     0     my $self = shift;
79 0           my $array = shift;
80              
81 0           my @enc = ();
82 0           push @enc, $self->_encode_size( scalar @$array );
83 0           push @enc, map { $self->_encode_obj( $_ ) } @$array;
  0            
84              
85 0           return join( '', @enc );
86             }
87              
88             # Unlike the above these return a serialized value /with/ the type byte
89             # prepended.
90              
91             sub _encode_int {
92 0     0     my $self = shift;
93 0           my $int = shift;
94              
95 0           my @rep = map { ord } split( //, pack( 'V', $int ) );
  0            
96              
97             # Trim extra bytes
98 0 0         if ( $int < 0 ) {
99 0           push @rep, 0xFF;
100 0   0       pop @rep while @rep > 1 && $rep[-1] == 0xFF && $rep[-2] >= 0x80;
      0        
101             }
102             else {
103 0           push @rep, 0x00;
104 0   0       pop @rep while @rep > 1 && $rep[-1] == 0x00 && $rep[-2] < 0x80;
      0        
105             }
106              
107 0           return chr( $INT_LEN[@rep] ) . pack( 'C*', @rep );
108             }
109              
110             sub _encode_float {
111 0     0     my $self = shift;
112 0           my $float = shift;
113              
114 0 0         my $rep = pack( $self->double ? 'd' : 'f', $float );
115              
116 0 0         if ( $Config{byteorder} eq '4321' ) {
117 0           $rep = join( '', reverse split( //, $rep ) );
118             }
119              
120 0 0         return chr( $self->double ? DOUBLE: FLOAT ) . $rep;
121             }
122              
123             sub _encode_obj {
124 0     0     my $self = shift;
125 0           my $obj = shift;
126              
127 0 0         if ( !defined $obj ) {
    0          
    0          
128 0           return chr( UNDEF );
129             }
130             elsif ( my $type = ref $obj ) {
131 0 0         if ( $type eq 'HASH' ) {
    0          
    0          
132 0           return chr( HASH ) . $self->_encode_hash( $obj );
133             }
134             elsif ( $type eq 'ARRAY' ) {
135 0           return chr( ARRAY ) . $self->_encode_array( $obj );
136             }
137             elsif ( blessed $obj ) {
138 0           croak "Can't serialize objects yet";
139             }
140             }
141             elsif ( isnum $obj) {
142 0 0         if ( isint $obj ) {
143 0           return $self->_encode_int( $obj );
144             }
145             else {
146 0           return $self->_encode_float( $obj );
147             }
148             }
149             else {
150 0           return chr( STRING ) . $self->_encode_string( $obj );
151             }
152             }
153              
154             sub _encode {
155 0     0     my $self = shift;
156              
157 0           return FMB . $self->_encode_obj( shift );
158             }
159              
160             sub encode {
161 0     0 1   my $self = shift;
162              
163 0 0         croak __PACKAGE__ . "->encode takes a single argument"
164             unless @_ == 1;
165              
166 0           my $obj = shift;
167              
168 0           my $enc_data = $self->_encode( $obj );
169              
170 0 0         if ( $self->yenc ) {
171 0           return encode_yEnc( $enc_data );
172             }
173              
174 0           return $enc_data;
175             }
176              
177             1;
178             __END__