File Coverage

lib/Archive/CAR/CID.pm
Criterion Covered Total %
statement 50 57 87.7
branch 11 18 61.1
condition 3 9 33.3
subroutine 5 6 83.3
pod 2 2 100.0
total 71 92 77.1


line stmt bran cond sub pod time code
1 2     2   414 use v5.40;
  2         6  
2 2     2   8 use feature 'class';
  2         3  
  2         249  
3 2     2   25 no warnings 'experimental::class';
  2         2  
  2         188  
4             #
5             class Archive::CAR::CID v0.0.3 {
6 2     2   8 use Archive::CAR::Utils qw[systell];
  2         2  
  2         2203  
7             #
8             field $version : param : reader;
9             field $codec : param : reader;
10             field $hash : param : reader;
11             field $digest : param : reader;
12             field $raw : param : reader;
13             #
14             method to_string() {
15              
16             # Minimal string conversion for debugging/display
17             # In a real IPFS context, this uses Multibase (base32 or base58)
18             return 'b' . $self->_encode_base32($raw) if $version == 1;
19             return unpack( 'H*', $raw );
20             }
21              
22             method _encode_base32 ($data) {
23             my @alphabet = split //, 'abcdefghijklmnopqrstuvwxyz234567';
24             my $bits = '';
25             for my $byte ( unpack 'C*', $data ) {
26             $bits .= sprintf '%08b', $byte;
27             }
28             my $out = '';
29             while ( $bits =~ s/^([01]{5})// ) {
30             $out .= $alphabet[ oct "0b$1" ];
31             }
32             if ( length $bits ) {
33             $bits .= '0' x ( 5 - length $bits );
34             $out .= $alphabet[ oct "0b$bits" ];
35             }
36             return $out;
37             }
38              
39 38     38 1 281361 sub decode ( $class, $fh ) {
  38         36  
  38         51  
  38         28  
40 38         48 my $pos_before = systell($fh);
41 38         36 my $first_byte;
42 38         47 my $fb_res = read( $fh, $first_byte, 1 );
43 38 50 33     117 return undef unless defined $fb_res && $fb_res == 1;
44 38         35 my $fb = ord($first_byte);
45 38 100       52 if ( $fb == 0x00 ) { # Optional leading zero
46 3         5 $pos_before = systell($fh);
47 3         3 $fb_res = read( $fh, $first_byte, 1 );
48 3 50 33     9 return undef unless defined $fb_res && $fb_res == 1;
49 3         4 $fb = ord($first_byte);
50             }
51 38 100       50 if ( $fb == 0x12 ) { # Likely CIDv0 in binary form
52 14         10 my $second_byte;
53 14         12 read( $fh, $second_byte, 1 );
54 14 50 33     29 if ( defined $second_byte && ord($second_byte) == 0x20 ) {
55 14         10 my $digest;
56 14         13 read( $fh, $digest, 32 );
57 14         14 my $raw = chr(0x12) . chr(0x20) . $digest;
58 14         128 return $class->new( version => 0, codec => 0x70, hash => 0x12, digest => $digest, raw => $raw );
59             }
60 0         0 seek( $fh, $pos_before + 1, 0 );
61             }
62 24         129 seek( $fh, $pos_before, 0 );
63 24         37 my ($version) = Archive::CAR::Utils::decode_varint($fh);
64 24 50       38 return undef if !defined $version;
65 24         31 my ($codec) = Archive::CAR::Utils::decode_varint($fh);
66 24 50       37 return undef unless defined $codec;
67 24         27 my ($mh_type) = Archive::CAR::Utils::decode_varint($fh);
68 24 50       32 return undef unless defined $mh_type;
69 24         31 my ($mh_len) = Archive::CAR::Utils::decode_varint($fh);
70 24 50       35 return undef unless defined $mh_len;
71 24         29 my $digest;
72 24         30 read( $fh, $digest, $mh_len );
73 24         81 my $pos_after = systell($fh);
74 24         101 seek( $fh, $pos_before, 0 );
75 24         31 my $raw;
76 24         72 read( $fh, $raw, $pos_after - $pos_before );
77 24         81 seek( $fh, $pos_after, 0 );
78 24         245 return $class->new( version => $version, codec => $codec, hash => $mh_type, digest => $digest, raw => $raw );
79             }
80              
81 0     0 1   sub from_raw ( $class, $raw ) {
  0            
  0            
  0            
82 0           open my $fh, '<:raw', \$raw;
83 0           return $class->decode($fh);
84             }
85             };
86             #
87             1;