File Coverage

lib/Archive/CAR/v1.pm
Criterion Covered Total %
statement 18 18 100.0
branch 1 2 50.0
condition n/a
subroutine 7 7 100.0
pod n/a
total 26 27 96.3


line stmt bran cond sub pod time code
1 2     2   28 use v5.40;
  2         9  
2 2     2   13 use feature 'class';
  2         4  
  2         357  
3 2     2   17 no warnings 'experimental::class';
  2         4  
  2         265  
4             #
5             class Archive::CAR::v1 v0.0.3 {
6 2     2   846 use Archive::CAR::Utils qw[systell];
  2         6  
  2         122  
7 2     2   1723 use CBOR::Free;
  2         15496  
  2         77  
8 2     2   1096 use CBOR::Free::Decoder;
  2         1835  
  2         2631  
9             #
10             field $header : reader;
11             field $roots : reader;
12             field $blocks : reader;
13             #
14             method version () {1}
15             method to_file ($filename) { Archive::CAR->write( $filename, $self->roots, $self->blocks, 1 ) }
16              
17             method read ( $fh, $limit //= undef ) {
18             my $data_start = systell($fh);
19              
20             # Header
21             my ($header_len) = Archive::CAR::Utils::decode_varint($fh);
22             return undef unless defined $header_len;
23             my $header_raw;
24             read( $fh, $header_raw, $header_len );
25             $header = do {
26             local $SIG{__WARN__} = sub {
27 8 50   8   97 warn @_ unless $_[0] =~ /Ignoring unrecognized CBOR tag #42/;
28             };
29             CBOR::Free::decode($header_raw);
30             };
31             if ( $header->{roots} ) {
32             my @roots_list;
33             for my $root_data ( @{ $header->{roots} } ) {
34             my $raw_cid = $root_data;
35             open my $rfh, '<', \$raw_cid;
36             push @roots_list, Archive::CAR::Utils::decode_cid($rfh);
37             }
38             $roots = \@roots_list;
39             }
40             my @blocks_list;
41             while ( !defined $limit || systell($fh) < $data_start + $limit ) {
42             my $record_start = systell($fh);
43             my ( $block_len, $varint_len ) = Archive::CAR::Utils::decode_varint($fh);
44             last unless defined $block_len;
45             my $cid = Archive::CAR::Utils::decode_cid($fh);
46             if ( !defined $cid ) {
47             last;
48             }
49             my $cid_len = length( $cid->raw );
50             my $data_len = $block_len - $cid_len;
51             if ( $data_len < 0 ) {
52             last;
53             }
54             my $data;
55             read( $fh, $data, $data_len );
56             push @blocks_list,
57             {
58             cid => $cid,
59             data => $data,
60             offset => $record_start,
61             length => $block_len + $varint_len,
62             blockOffset => systell($fh) - $data_len,
63             blockLength => $data_len,
64             };
65             }
66             $blocks = \@blocks_list;
67             return $self;
68             }
69              
70             method write ( $fh, $roots, $blocks ) {
71              
72             # Write Header
73             # Transform CID objects to CBOR tags for the header
74             my @cbor_roots = map { CBOR::Free::tag( 42, $_->raw ) } @$roots;
75             my $header_data = { version => 1, roots => \@cbor_roots, };
76             my $header_encoded = CBOR::Free::encode($header_data);
77             print {$fh} Archive::CAR::Utils::encode_varint( length($header_encoded) );
78             print {$fh} $header_encoded;
79              
80             # Write Blocks
81             for my $block (@$blocks) {
82             my $cid_raw = $block->{cid}->raw;
83             my $data = $block->{data};
84             my $block_len = length($cid_raw) + length($data);
85             print {$fh} Archive::CAR::Utils::encode_varint($block_len);
86             print {$fh} $cid_raw;
87             print {$fh} $data;
88             }
89             }
90             };
91             #
92             1;