File Coverage

blib/lib/GDPR/IAB/TCFv2/BitUtils.pm
Criterion Covered Total %
statement 76 82 92.6
branch 14 26 53.8
condition n/a
subroutine 21 21 100.0
pod 7 8 87.5
total 118 137 86.1


line stmt bran cond sub pod time code
1             package GDPR::IAB::TCFv2::BitUtils;
2 5     5   1355 use strict;
  5         11  
  5         193  
3 5     5   28 use warnings;
  5         9  
  5         299  
4 5     5   738 use integer;
  5         35  
  5         36  
5 5     5   595 use bytes;
  5         600  
  5         32  
6 5     5   11789 use Math::BigInt;
  5         308656  
  5         30  
7              
8 5     5   195304 use Carp qw(croak confess);
  5         16  
  5         895  
9              
10             require Exporter;
11 5     5   71 use base qw;
  5         13  
  5         1066  
12              
13 5     5   69 use constant ASCII_OFFSET => ord('A');
  5         10  
  5         751  
14              
15             my $CAN_PACK_QUADS;
16             my $CAN_FORCE_BIG_ENDIAN;
17              
18             BEGIN {
19 5     5   21 $CAN_PACK_QUADS = !!eval { my $f = pack 'Q>'; 1 };
  5         15  
  5         18  
20 5         12 $CAN_FORCE_BIG_ENDIAN = !!eval { my $f = pack 'S>'; 1 };
  5         41  
  5         6333  
21             }
22              
23             our @EXPORT_OK = qw
24             get_uint2
25             get_uint3
26             get_uint6
27             get_uint12
28             get_uint16
29             get_uint36
30             get_char6_pair
31             >;
32              
33             sub is_set {
34 2167     2167 1 3748 my ( $data, $offset ) = @_;
35              
36 2167         3158 my $data_size = length($data);
37              
38 2167 50       3895 croak
39             "index out of bounds on offset $offset: can't read 1, only has: $data_size"
40             if $offset + 1 > $data_size;
41              
42 2167         4148 my $r = substr( $data, $offset, 1 ) == 1;
43              
44 2167 100       8763 return wantarray ? ( $r, $offset + 1 ) : $r;
45             }
46              
47             sub get_uint2 {
48 24     24 1 92 my ( $data, $offset ) = @_;
49              
50 24         57 return _get_big_endian_octet_8bits( $data, $offset, 2 );
51             }
52              
53             sub get_uint3 {
54 14     14 0 33 my ( $data, $offset ) = @_;
55              
56 14         34 return _get_big_endian_octet_8bits( $data, $offset, 3 );
57             }
58              
59             sub get_uint6 {
60 181     181 1 334 my ( $data, $offset ) = @_;
61              
62 181         341 return _get_big_endian_octet_8bits( $data, $offset, 6 );
63             }
64              
65             sub get_char6_pair {
66 40     40 1 74 my ( $data, $offset ) = @_;
67              
68 40         55 my $pair;
69              
70 40         97 for ( 1 .. 2 ) {
71 80         137 my ( $byte, $next_offset ) = get_uint6( $data, $offset );
72              
73 80         160 $pair .= chr( ASCII_OFFSET + $byte );
74              
75 80         135 $offset = $next_offset;
76             }
77              
78 40 50       189 return wantarray ? ( $pair, $offset ) : $pair;
79             }
80              
81             sub get_uint12 {
82 157     157 1 298 my ( $data, $offset ) = @_;
83              
84 157         322 return _get_big_endian_short_16bits( $data, $offset, 12 );
85             }
86              
87             sub get_uint16 {
88 451     451 1 911 my ( $data, $offset ) = @_;
89              
90 451         840 return _get_big_endian_short_16bits( $data, $offset, 16 );
91             }
92              
93             sub _get_big_endian_octet_8bits {
94 219     219   356 my ( $data, $offset, $nbits ) = @_;
95              
96 219         392 my ( $bits_with_pading, $next_offset ) =
97             _get_bits_with_padding( $data, 8, $offset, $nbits );
98              
99 219         431 my $r = unpack(
100             "C",
101             $bits_with_pading
102             );
103              
104 219 100       676 return wantarray ? ( $r, $next_offset ) : $r;
105             }
106              
107             sub _get_big_endian_short_16bits {
108 608     608   1166 my ( $data, $offset, $nbits ) = @_;
109              
110 608 50       1311 if ($CAN_FORCE_BIG_ENDIAN) {
111 608         1144 my ( $bits_with_pading, $next_offset ) =
112             _get_bits_with_padding( $data, 16, $offset, $nbits );
113              
114 608         1336 my $r = unpack( "S>", $bits_with_pading );
115              
116 608 100       2001 return wantarray ? ( $r, $next_offset ) : $r;
117             }
118              
119 0         0 my ( $data_with_padding, $next_offset ) =
120             _add_padding( $data, 16, $offset, $nbits );
121              
122 0         0 my $r = Math::BigInt->new( "0b" . $data_with_padding );
123              
124 0 0       0 return wantarray ? ( $r, $next_offset ) : $r;
125             }
126              
127             sub get_uint36 {
128 44     44 1 93 my ( $data, $offset ) = @_;
129              
130 44 50       111 if ($CAN_PACK_QUADS) {
131 44         107 my ( $bits_with_pading, $next_offset ) =
132             _get_bits_with_padding( $data, 64, $offset, 36 );
133              
134 44         115 my $r = unpack( "Q>", $bits_with_pading );
135              
136 44 50       138 return wantarray ? ( $r, $next_offset ) : $r;
137             }
138              
139 0         0 my ( $data_with_padding, $next_offset ) =
140             _add_padding( $data, 64, $offset, 36 );
141              
142 0         0 my $r = Math::BigInt->new( "0b" . $data_with_padding );
143              
144 0 0       0 return wantarray ? ( $r, $next_offset ) : $r;
145             }
146              
147             sub _get_bits_with_padding {
148 871     871   1562 my ( $data, $bits, $offset, $nbits ) = @_;
149              
150 871         1715 my ( $data_with_padding, $next_offset ) =
151             _add_padding( $data, $bits, $offset, $nbits );
152              
153 871         2435 my $r = pack( "B${bits}", $data_with_padding );
154              
155 871 50       2253 return wantarray ? ( $r, $next_offset ) : $r;
156             }
157              
158             sub _add_padding {
159 871     871   1713 my ( $data, $bits, $offset, $nbits ) = @_;
160              
161 871         1337 my $data_size = length($data);
162              
163 871 50       1943 croak
164             "index out of bounds on offset $offset: can't read $nbits, only has: $data_size"
165             if $offset + $nbits > $data_size;
166              
167 871         1619 my $padding = "0" x ( $bits - $nbits );
168              
169 871         1725 my $r = $padding . substr( $data, $offset, $nbits );
170              
171 871 50       2756 return wantarray ? ( $r, $offset + $nbits ) : $r;
172             }
173              
174             1;
175             __END__