File Coverage

lib/Archive/CAR/v1.pm
Criterion Covered Total %
statement 17 17 100.0
branch n/a
condition n/a
subroutine 6 6 100.0
pod n/a
total 23 23 100.0


line stmt bran cond sub pod time code
1 2     2   26 use v5.40;
  2         11  
2 2     2   12 use feature 'class';
  2         4  
  2         308  
3 2     2   15 no warnings 'experimental::class';
  2         3  
  2         254  
4             #
5             class Archive::CAR::v1 v0.0.4 {
6 2     2   1034 use Archive::CAR::Utils qw[systell];
  2         7  
  2         140  
7 2     2   1299 use Codec::CBOR;
  2         9151  
  2         96  
8 2     2   1145 use Archive::CAR::CID;
  2         8  
  2         2773  
9             #
10             field $header : reader;
11             field $roots : reader;
12             field $blocks : reader;
13             field $codec;
14             #
15             ADJUST {
16             $codec = Codec::CBOR->new();
17             $codec->add_tag_handler(
18             42 => sub ($data) {
19              
20             # Codec::CBOR returns raw bytes for Major Type 2
21             return Archive::CAR::CID->from_raw( substr( $data, 1 ) ) if substr( $data, 0, 1 ) eq "\x00";
22             return Archive::CAR::CID->from_raw($data);
23             }
24             );
25             $codec->add_class_handler(
26             'Archive::CAR::CID' => sub ( $codec_obj, $item ) {
27             my $cid_raw = $item->raw;
28             return pack( 'C', 0xd8 ) . pack( 'C', 42 ) . $codec_obj->_encode_bytes( "\x00" . $cid_raw );
29             }
30             );
31             }
32             method version () {1}
33             method to_file ($filename) { Archive::CAR->write( $filename, $self->roots, $self->blocks, 1 ) }
34              
35             method read ( $fh, $limit //= undef ) {
36             my $data_start = systell($fh);
37              
38             # Header
39             my ($header_len) = Archive::CAR::Utils::decode_varint($fh);
40             return undef unless defined $header_len;
41             my $header_raw;
42             read( $fh, $header_raw, $header_len );
43             $header = $codec->decode($header_raw);
44              
45             # Ensure roots are CID objects.
46             # If they were decoded as Tag 42 with our handler, they already are.
47             $roots = $header->{roots} if $header->{roots};
48             my @blocks_list;
49             while ( !defined $limit || systell($fh) < $data_start + $limit ) {
50             my $record_start = systell($fh);
51             my ( $block_len, $varint_len ) = Archive::CAR::Utils::decode_varint($fh);
52             last unless defined $block_len;
53             my $cid = Archive::CAR::Utils::decode_cid($fh);
54             last unless defined $cid;
55             my $cid_len = length( $cid->raw );
56             my $data_len = $block_len - $cid_len;
57             last if $data_len < 0;
58             my $data;
59             read( $fh, $data, $data_len );
60             push @blocks_list,
61             {
62             cid => $cid,
63             data => $data,
64             offset => $record_start,
65             length => $block_len + $varint_len,
66             blockOffset => systell($fh) - $data_len,
67             blockLength => $data_len
68             };
69             }
70             $blocks = \@blocks_list;
71             return $self;
72             }
73              
74             method write ( $fh, $roots, $blocks ) {
75              
76             # Write header
77             # Transform CID objects to Tag 42 for the header via class handler
78             my $header_data = { version => 1, roots => $roots, };
79             my $header_encoded = $codec->encode($header_data);
80             print {$fh} Archive::CAR::Utils::encode_varint( length($header_encoded) );
81             print {$fh} $header_encoded;
82              
83             # Write blocks
84             for my $block (@$blocks) {
85             my $cid_raw = $block->{cid}->raw;
86             my $data = $block->{data};
87             my $block_len = length($cid_raw) + length($data);
88             print {$fh} Archive::CAR::Utils::encode_varint($block_len);
89             print {$fh} $cid_raw;
90             print {$fh} $data;
91             }
92             }
93             };
94             #
95             1;