| 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; |