| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
|
|
|
|
|
|
#------------------------------------------------------------------------------ |
|
2
|
|
|
|
|
|
|
# File: Torrent.pm |
|
3
|
|
|
|
|
|
|
# |
|
4
|
|
|
|
|
|
|
# Description: Read information from BitTorrent file |
|
5
|
|
|
|
|
|
|
# |
|
6
|
|
|
|
|
|
|
# Revisions: 2013/08/27 - P. Harvey Created |
|
7
|
|
|
|
|
|
|
# |
|
8
|
|
|
|
|
|
|
# References: 1) https://wiki.theory.org/BitTorrentSpecification |
|
9
|
|
|
|
|
|
|
#------------------------------------------------------------------------------ |
|
10
|
|
|
|
|
|
|
|
|
11
|
|
|
|
|
|
|
package Image::ExifTool::Torrent; |
|
12
|
|
|
|
|
|
|
|
|
13
|
1
|
|
|
1
|
|
4483
|
use strict; |
|
|
1
|
|
|
|
|
4
|
|
|
|
1
|
|
|
|
|
33
|
|
|
14
|
1
|
|
|
1
|
|
6
|
use vars qw($VERSION); |
|
|
1
|
|
|
|
|
2
|
|
|
|
1
|
|
|
|
|
39
|
|
|
15
|
1
|
|
|
1
|
|
17
|
use Image::ExifTool qw(:DataAccess :Utils); |
|
|
1
|
|
|
|
|
2
|
|
|
|
1
|
|
|
|
|
6120
|
|
|
16
|
|
|
|
|
|
|
|
|
17
|
|
|
|
|
|
|
$VERSION = '1.06'; |
|
18
|
|
|
|
|
|
|
|
|
19
|
|
|
|
|
|
|
sub ReadBencode($$$); |
|
20
|
|
|
|
|
|
|
sub ExtractTags($$$;$$@); |
|
21
|
|
|
|
|
|
|
|
|
22
|
|
|
|
|
|
|
# tags extracted from BitTorrent files |
|
23
|
|
|
|
|
|
|
%Image::ExifTool::Torrent::Main = ( |
|
24
|
|
|
|
|
|
|
GROUPS => { 2 => 'Document' }, |
|
25
|
|
|
|
|
|
|
NOTES => q{ |
|
26
|
|
|
|
|
|
|
Below are tags commonly found in BitTorrent files. As well as these tags, |
|
27
|
|
|
|
|
|
|
any other existing tags will be extracted. For convenience, list items are |
|
28
|
|
|
|
|
|
|
expanded into individual tags with an index in the tag name, but only the |
|
29
|
|
|
|
|
|
|
tags with index "1" are listed in the tables below. See |
|
30
|
|
|
|
|
|
|
L for the BitTorrent |
|
31
|
|
|
|
|
|
|
specification. |
|
32
|
|
|
|
|
|
|
}, |
|
33
|
|
|
|
|
|
|
'announce' => { }, |
|
34
|
|
|
|
|
|
|
'announce-list' => { Name => 'AnnounceList1' }, |
|
35
|
|
|
|
|
|
|
'comment' => { }, |
|
36
|
|
|
|
|
|
|
'created by' => { Name => 'Creator' }, # software used to create the torrent |
|
37
|
|
|
|
|
|
|
'creation date' => { |
|
38
|
|
|
|
|
|
|
Name => 'CreateDate', |
|
39
|
|
|
|
|
|
|
Groups => { 2 => 'Time' }, |
|
40
|
|
|
|
|
|
|
ValueConv => 'ConvertUnixTime($val,1)', |
|
41
|
|
|
|
|
|
|
PrintConv => '$self->ConvertDateTime($val)', |
|
42
|
|
|
|
|
|
|
}, |
|
43
|
|
|
|
|
|
|
'encoding' => { }, |
|
44
|
|
|
|
|
|
|
'info' => { |
|
45
|
|
|
|
|
|
|
SubDirectory => { TagTable => 'Image::ExifTool::Torrent::Info' }, |
|
46
|
|
|
|
|
|
|
Notes => 'extracted as a structure with the Struct option', |
|
47
|
|
|
|
|
|
|
}, |
|
48
|
|
|
|
|
|
|
'url-list' => { Name => 'URLList1' }, |
|
49
|
|
|
|
|
|
|
); |
|
50
|
|
|
|
|
|
|
|
|
51
|
|
|
|
|
|
|
%Image::ExifTool::Torrent::Info = ( |
|
52
|
|
|
|
|
|
|
GROUPS => { 2 => 'Document' }, |
|
53
|
|
|
|
|
|
|
'file-duration' => { Name => 'File1Duration' }, |
|
54
|
|
|
|
|
|
|
'file-media' => { Name => 'File1Media' }, |
|
55
|
|
|
|
|
|
|
'files' => { SubDirectory => { TagTable => 'Image::ExifTool::Torrent::Files' } }, |
|
56
|
|
|
|
|
|
|
'length' => { }, |
|
57
|
|
|
|
|
|
|
'md5sum' => { Name => 'MD5Sum' }, |
|
58
|
|
|
|
|
|
|
'name' => { }, |
|
59
|
|
|
|
|
|
|
'name.utf-8' => { Name => 'NameUTF-8' }, |
|
60
|
|
|
|
|
|
|
'piece length' => { Name => 'PieceLength' }, |
|
61
|
|
|
|
|
|
|
'pieces' => { |
|
62
|
|
|
|
|
|
|
Name => 'Pieces', |
|
63
|
|
|
|
|
|
|
Notes => 'concatenation of 20-byte SHA-1 digests for each piece', |
|
64
|
|
|
|
|
|
|
}, |
|
65
|
|
|
|
|
|
|
'private' => { }, |
|
66
|
|
|
|
|
|
|
'profiles' => { SubDirectory => { TagTable => 'Image::ExifTool::Torrent::Profiles' } }, |
|
67
|
|
|
|
|
|
|
); |
|
68
|
|
|
|
|
|
|
|
|
69
|
|
|
|
|
|
|
%Image::ExifTool::Torrent::Profiles = ( |
|
70
|
|
|
|
|
|
|
GROUPS => { 2 => 'Document' }, |
|
71
|
|
|
|
|
|
|
'width' => { Name => 'Profile1Width' }, |
|
72
|
|
|
|
|
|
|
'height' => { Name => 'Profile1Height' }, |
|
73
|
|
|
|
|
|
|
'acodec' => { Name => 'Profile1AudioCodec' }, |
|
74
|
|
|
|
|
|
|
'vcodec' => { Name => 'Profile1VideoCodec' }, |
|
75
|
|
|
|
|
|
|
); |
|
76
|
|
|
|
|
|
|
|
|
77
|
|
|
|
|
|
|
%Image::ExifTool::Torrent::Files = ( |
|
78
|
|
|
|
|
|
|
GROUPS => { 2 => 'Document' }, |
|
79
|
|
|
|
|
|
|
'length' => { Name => 'File1Length', PrintConv => 'ConvertFileSize($val)' }, |
|
80
|
|
|
|
|
|
|
'md5sum' => { Name => 'File1MD5Sum' }, |
|
81
|
|
|
|
|
|
|
'path' => { Name => 'File1Path', JoinPath => 1 }, |
|
82
|
|
|
|
|
|
|
'path.utf-8' => { Name => 'File1PathUTF-8', JoinPath => 1 }, |
|
83
|
|
|
|
|
|
|
); |
|
84
|
|
|
|
|
|
|
|
|
85
|
|
|
|
|
|
|
#------------------------------------------------------------------------------ |
|
86
|
|
|
|
|
|
|
# Read 64kB more data into buffer |
|
87
|
|
|
|
|
|
|
# Inputs: 0) RAF ref, 1) buffer ref |
|
88
|
|
|
|
|
|
|
# Returns: number of bytes read |
|
89
|
|
|
|
|
|
|
# Notes: Sets BencodeEOF element of RAF on end of file |
|
90
|
|
|
|
|
|
|
sub ReadMore($$) |
|
91
|
|
|
|
|
|
|
{ |
|
92
|
1
|
|
|
1
|
0
|
3
|
my ($raf, $dataPt) = @_; |
|
93
|
1
|
|
|
|
|
2
|
my $buf2; |
|
94
|
1
|
|
|
|
|
3
|
my $n = $raf->Read($buf2, 65536); |
|
95
|
1
|
50
|
|
|
|
6
|
$$raf{BencodeEOF} = 1 if $n != 65536; |
|
96
|
1
|
50
|
|
|
|
9
|
$$dataPt = substr($$dataPt, pos($$dataPt)) . $buf2 if $n; |
|
97
|
1
|
|
|
|
|
3
|
return $n; |
|
98
|
|
|
|
|
|
|
} |
|
99
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
#------------------------------------------------------------------------------ |
|
101
|
|
|
|
|
|
|
# Read bencoded value |
|
102
|
|
|
|
|
|
|
# Inputs: 0) ExifTool ref, 1) input file, 2) buffer (pos must be set to current position) |
|
103
|
|
|
|
|
|
|
# Returns: HASH ref, ARRAY ref, SCALAR ref, SCALAR, or undef on error or end of data |
|
104
|
|
|
|
|
|
|
# Notes: Sets BencodeError element of RAF on any error |
|
105
|
|
|
|
|
|
|
sub ReadBencode($$$) |
|
106
|
|
|
|
|
|
|
{ |
|
107
|
70
|
|
|
70
|
0
|
103
|
my ($et, $raf, $dataPt) = @_; |
|
108
|
|
|
|
|
|
|
|
|
109
|
|
|
|
|
|
|
# read more if necessary (keep a minimum of 64 bytes in the buffer) |
|
110
|
70
|
|
|
|
|
98
|
my $pos = pos($$dataPt); |
|
111
|
70
|
50
|
|
|
|
117
|
return undef unless defined $pos; |
|
112
|
70
|
|
|
|
|
91
|
my $remaining = length($$dataPt) - $pos; |
|
113
|
70
|
100
|
100
|
|
|
141
|
ReadMore($raf, $dataPt) if $remaining < 64 and not $$raf{BencodeEOF}; |
|
114
|
|
|
|
|
|
|
|
|
115
|
|
|
|
|
|
|
# read next token |
|
116
|
70
|
50
|
|
|
|
176
|
$$dataPt =~ /(.)/sg or return undef; |
|
117
|
|
|
|
|
|
|
|
|
118
|
70
|
|
|
|
|
100
|
my $val; |
|
119
|
70
|
|
|
|
|
117
|
my $tok = $1; |
|
120
|
70
|
100
|
33
|
|
|
300
|
if ($tok eq 'i') { # integer |
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
121
|
6
|
50
|
|
|
|
31
|
$$dataPt =~ /\G(-?\d+)e/g or return $val; |
|
122
|
6
|
|
|
|
|
12
|
$val = $1; |
|
123
|
|
|
|
|
|
|
} elsif ($tok eq 'd') { # dictionary |
|
124
|
6
|
|
|
|
|
11
|
$val = { }; |
|
125
|
6
|
|
|
|
|
11
|
for (;;) { |
|
126
|
26
|
|
|
|
|
56
|
my $k = ReadBencode($et, $raf, $dataPt); |
|
127
|
26
|
100
|
|
|
|
52
|
last unless defined $k; |
|
128
|
|
|
|
|
|
|
# the key must be a byte string |
|
129
|
20
|
50
|
|
|
|
38
|
if (ref $k) { |
|
130
|
0
|
0
|
|
|
|
0
|
ref $k ne 'SCALAR' and $$raf{BencodeError} = 'Bad dictionary key', last; |
|
131
|
0
|
|
|
|
|
0
|
$k = $$k; |
|
132
|
|
|
|
|
|
|
} |
|
133
|
20
|
|
|
|
|
34
|
my $v = ReadBencode($et, $raf, $dataPt); |
|
134
|
20
|
50
|
|
|
|
47
|
last unless defined $v; |
|
135
|
20
|
|
|
|
|
58
|
$$val{$k} = $v; |
|
136
|
|
|
|
|
|
|
} |
|
137
|
|
|
|
|
|
|
} elsif ($tok eq 'l') { # list |
|
138
|
8
|
|
|
|
|
13
|
$val = [ ]; |
|
139
|
8
|
|
|
|
|
12
|
for (;;) { |
|
140
|
23
|
|
|
|
|
56
|
my $v = ReadBencode($et, $raf, $dataPt); |
|
141
|
23
|
100
|
|
|
|
43
|
last unless defined $v; |
|
142
|
15
|
|
|
|
|
30
|
push @$val, $v; |
|
143
|
|
|
|
|
|
|
} |
|
144
|
|
|
|
|
|
|
} elsif ($tok eq 'e') { # end of dictionary or list |
|
145
|
|
|
|
|
|
|
# return undef (no error) |
|
146
|
|
|
|
|
|
|
} elsif ($tok =~ /^\d$/ and $$dataPt =~ /\G(\d*):/g) { # byte string |
|
147
|
36
|
|
|
|
|
80
|
my $len = $tok . $1; |
|
148
|
36
|
|
|
|
|
68
|
my $more = $len - (length($$dataPt) - pos($$dataPt)); |
|
149
|
36
|
|
|
|
|
44
|
my $value; |
|
150
|
36
|
50
|
|
|
|
56
|
if ($more <= 0) { |
|
|
|
0
|
|
|
|
|
|
|
151
|
36
|
|
|
|
|
70
|
$value = substr($$dataPt,pos($$dataPt),$len); |
|
152
|
36
|
|
|
|
|
73
|
pos($$dataPt) = pos($$dataPt) + $len; |
|
153
|
|
|
|
|
|
|
} elsif ($more > 10000000) { |
|
154
|
|
|
|
|
|
|
# just skip over really long values |
|
155
|
0
|
0
|
|
|
|
0
|
$val = \ "(Binary data $len bytes)" if $raf->Seek($more, 1); |
|
156
|
|
|
|
|
|
|
} else { |
|
157
|
|
|
|
|
|
|
# need to read more from file |
|
158
|
0
|
|
|
|
|
0
|
my $buff; |
|
159
|
0
|
|
|
|
|
0
|
my $n = $raf->Read($buff, $more); |
|
160
|
0
|
0
|
|
|
|
0
|
if ($n == $more) { |
|
161
|
0
|
|
|
|
|
0
|
$value = substr($$dataPt,pos($$dataPt)) . $buff; |
|
162
|
0
|
|
|
|
|
0
|
$$dataPt = ''; |
|
163
|
0
|
|
|
|
|
0
|
pos($$dataPt) = 0; |
|
164
|
|
|
|
|
|
|
} |
|
165
|
|
|
|
|
|
|
} |
|
166
|
36
|
50
|
|
|
|
71
|
if (defined $value) { |
|
|
|
0
|
|
|
|
|
|
|
167
|
|
|
|
|
|
|
# return as binary data unless it is a reasonable-length ASCII string |
|
168
|
36
|
50
|
|
|
|
82
|
if (length($value) > 256) { |
|
|
|
100
|
|
|
|
|
|
|
169
|
0
|
|
|
|
|
0
|
$val = \$value; |
|
170
|
|
|
|
|
|
|
} elsif ($value =~ /[^\t\x20-\x7e]/) { |
|
171
|
1
|
50
|
|
|
|
11
|
if (Image::ExifTool::IsUTF8(\$value) >= 0) { |
|
172
|
0
|
|
|
|
|
0
|
$val = $et->Decode($value, 'UTF8'); |
|
173
|
|
|
|
|
|
|
} else { |
|
174
|
1
|
|
|
|
|
4
|
$val = \$value; |
|
175
|
|
|
|
|
|
|
} |
|
176
|
|
|
|
|
|
|
} else { |
|
177
|
35
|
|
|
|
|
59
|
$val = $value; |
|
178
|
|
|
|
|
|
|
} |
|
179
|
|
|
|
|
|
|
} elsif (not defined $val) { |
|
180
|
0
|
|
|
|
|
0
|
$$raf{BencodeError} = 'Truncated byte string'; |
|
181
|
|
|
|
|
|
|
} |
|
182
|
|
|
|
|
|
|
} else { |
|
183
|
0
|
|
|
|
|
0
|
$$raf{BencodeError} = 'Bad format'; |
|
184
|
|
|
|
|
|
|
} |
|
185
|
70
|
|
|
|
|
128
|
return $val; |
|
186
|
|
|
|
|
|
|
} |
|
187
|
|
|
|
|
|
|
|
|
188
|
|
|
|
|
|
|
#------------------------------------------------------------------------------ |
|
189
|
|
|
|
|
|
|
# Extract tags from dictionary hash |
|
190
|
|
|
|
|
|
|
# Inputs: 0) ExifTool ref, 1) dictionary hash reference, 2) tag table ref, |
|
191
|
|
|
|
|
|
|
# 3) parent hash ID, 4) parent hash name, 5-N) list indices |
|
192
|
|
|
|
|
|
|
# Returns: number of tags extracted |
|
193
|
|
|
|
|
|
|
sub ExtractTags($$$;$$@) |
|
194
|
|
|
|
|
|
|
{ |
|
195
|
6
|
|
|
6
|
0
|
17
|
my ($et, $hashPtr, $tagTablePtr, $baseID, $baseName, @index) = @_; |
|
196
|
6
|
|
|
|
|
8
|
my $count = 0; |
|
197
|
6
|
|
|
|
|
11
|
my $tag; |
|
198
|
6
|
|
|
|
|
40
|
foreach $tag (sort keys %$hashPtr) { |
|
199
|
20
|
|
|
|
|
36
|
my $val = $$hashPtr{$tag}; |
|
200
|
20
|
|
|
|
|
30
|
my ($i, $j, @more); |
|
201
|
20
|
|
|
|
|
38
|
for (; defined $val; $val = shift @more) { |
|
202
|
27
|
50
|
|
|
|
52
|
my $id = defined $baseID ? "$baseID/$tag" : $tag; |
|
203
|
27
|
50
|
|
|
|
58
|
unless ($$tagTablePtr{$id}) { |
|
204
|
0
|
|
|
|
|
0
|
my $name = ucfirst $tag; |
|
205
|
|
|
|
|
|
|
# capitalize all words in tag name and remove illegal characters |
|
206
|
0
|
|
|
|
|
0
|
$name =~ s/[^-_a-zA-Z0-9]+(.?)/\U$1/g; |
|
207
|
0
|
0
|
0
|
|
|
0
|
$name = "Tag$name" if length($name) < 2 or $name !~ /^[A-Z]/; |
|
208
|
0
|
0
|
|
|
|
0
|
$name = $baseName . $name if defined $baseName; # add base name if necessary |
|
209
|
0
|
|
|
|
|
0
|
AddTagToTable($tagTablePtr, $id, { Name => $name }); |
|
210
|
0
|
|
|
|
|
0
|
$et->VPrint(0, " [adding $id '${name}']\n"); |
|
211
|
|
|
|
|
|
|
} |
|
212
|
27
|
50
|
|
|
|
68
|
my $tagInfo = $et->GetTagInfo($tagTablePtr, $id) or next; |
|
213
|
27
|
100
|
|
|
|
65
|
if (ref $val eq 'ARRAY') { |
|
214
|
8
|
100
|
|
|
|
18
|
if ($$tagInfo{JoinPath}) { |
|
215
|
4
|
50
|
|
|
|
10
|
$val = join '/', map { ref $_ ? '(Binary data)' : $_ } @$val; |
|
|
5
|
|
|
|
|
23
|
|
|
216
|
|
|
|
|
|
|
} else { |
|
217
|
4
|
|
|
|
|
11
|
push @more, @$val; |
|
218
|
4
|
100
|
|
|
|
11
|
next if ref $more[0] eq 'ARRAY'; # continue expanding nested lists |
|
219
|
3
|
|
|
|
|
5
|
$val = shift @more; |
|
220
|
3
|
50
|
|
|
|
10
|
$i or $i = 0, push(@index, $i); |
|
221
|
|
|
|
|
|
|
} |
|
222
|
|
|
|
|
|
|
} |
|
223
|
26
|
100
|
|
|
|
56
|
$index[-1] = ++$i if defined $i; |
|
224
|
26
|
100
|
|
|
|
50
|
if (@index) { |
|
225
|
17
|
|
|
|
|
48
|
$id .= join '_', @index; # add instance number(s) to tag ID |
|
226
|
17
|
50
|
|
|
|
37
|
unless ($$tagTablePtr{$id}) { |
|
227
|
17
|
|
|
|
|
41
|
my $name = $$tagInfo{Name}; |
|
228
|
|
|
|
|
|
|
# embed indices at position of '1' in tag name |
|
229
|
17
|
|
|
|
|
30
|
my $n = ($name =~ tr/1/#/); |
|
230
|
17
|
|
|
|
|
39
|
for ($j=0; $j<$n; ++$j) { |
|
231
|
13
|
|
50
|
|
|
34
|
my $idx = $index[$j] || ''; |
|
232
|
13
|
|
|
|
|
62
|
$name =~ s/#/$idx/; |
|
233
|
|
|
|
|
|
|
} |
|
234
|
|
|
|
|
|
|
# put remaining indices at end of tag name |
|
235
|
17
|
|
|
|
|
37
|
for (; $j<@index; ++$j) { |
|
236
|
4
|
50
|
|
|
|
19
|
$name .= '_' if $name =~ /\d$/; |
|
237
|
4
|
|
|
|
|
11
|
$name .= $index[$j]; |
|
238
|
|
|
|
|
|
|
} |
|
239
|
17
|
|
|
|
|
95
|
AddTagToTable($tagTablePtr, $id, { %$tagInfo, Name => $name }); |
|
240
|
|
|
|
|
|
|
} |
|
241
|
17
|
50
|
|
|
|
46
|
$tagInfo = $et->GetTagInfo($tagTablePtr, $id) or next; |
|
242
|
|
|
|
|
|
|
} |
|
243
|
26
|
100
|
|
|
|
50
|
if (ref $val eq 'HASH') { |
|
244
|
5
|
0
|
33
|
|
|
14
|
if ($et->Options('Struct') and $tagInfo and $$tagInfo{Name} eq 'Info') { |
|
|
|
|
33
|
|
|
|
|
|
245
|
0
|
|
|
|
|
0
|
$et->FoundTag($tagInfo, $val); |
|
246
|
0
|
|
|
|
|
0
|
++$count; |
|
247
|
0
|
|
|
|
|
0
|
next; |
|
248
|
|
|
|
|
|
|
} |
|
249
|
|
|
|
|
|
|
# extract tags from this dictionary |
|
250
|
5
|
|
|
|
|
10
|
my ($table, $rootID, $rootName); |
|
251
|
5
|
50
|
|
|
|
11
|
if ($$tagInfo{SubDirectory}) { |
|
252
|
5
|
|
|
|
|
14
|
$table = GetTagTable($$tagInfo{SubDirectory}{TagTable}); |
|
253
|
|
|
|
|
|
|
} else { |
|
254
|
0
|
|
|
|
|
0
|
$table = $tagTablePtr; |
|
255
|
|
|
|
|
|
|
# use hash ID and Name as base for contained tags to avoid conflicts |
|
256
|
0
|
|
|
|
|
0
|
$rootID = $id; |
|
257
|
0
|
|
|
|
|
0
|
$rootName = $$tagInfo{Name}; |
|
258
|
|
|
|
|
|
|
} |
|
259
|
5
|
|
|
|
|
21
|
$count += ExtractTags($et, $val, $table, $rootID, $rootName, @index); |
|
260
|
|
|
|
|
|
|
} else { |
|
261
|
|
|
|
|
|
|
# handle this simple tag value |
|
262
|
21
|
|
|
|
|
59
|
$et->HandleTag($tagTablePtr, $id, $val); |
|
263
|
21
|
|
|
|
|
60
|
++$count; |
|
264
|
|
|
|
|
|
|
} |
|
265
|
|
|
|
|
|
|
} |
|
266
|
20
|
100
|
|
|
|
46
|
pop @index if defined $i; |
|
267
|
|
|
|
|
|
|
} |
|
268
|
6
|
|
|
|
|
24
|
return $count; |
|
269
|
|
|
|
|
|
|
} |
|
270
|
|
|
|
|
|
|
|
|
271
|
|
|
|
|
|
|
#------------------------------------------------------------------------------ |
|
272
|
|
|
|
|
|
|
# Process BitTorrent file |
|
273
|
|
|
|
|
|
|
# Inputs: 0) ExifTool object reference, 1) dirInfo reference (with RAF set) |
|
274
|
|
|
|
|
|
|
# Returns: 1 on success, 0 if this wasn't a valid BitTorrent file |
|
275
|
|
|
|
|
|
|
sub ProcessTorrent($$) |
|
276
|
|
|
|
|
|
|
{ |
|
277
|
1
|
|
|
1
|
0
|
4
|
my ($et, $dirInfo) = @_; |
|
278
|
1
|
|
|
|
|
3
|
my $success = 0; |
|
279
|
1
|
|
|
|
|
3
|
my $raf = $$dirInfo{RAF}; |
|
280
|
1
|
|
|
|
|
3
|
my $buff = ''; |
|
281
|
1
|
|
|
|
|
6
|
pos($buff) = 0; |
|
282
|
1
|
|
|
|
|
6
|
my $dict = ReadBencode($et, $raf, \$buff); |
|
283
|
1
|
|
|
|
|
3
|
my $err = $$raf{BencodeError}; |
|
284
|
1
|
50
|
|
|
|
3
|
$et->Warn("Bencode error: $err") if $err; |
|
285
|
1
|
50
|
33
|
|
|
8
|
if (ref $dict eq 'HASH' and ($$dict{announce} or $$dict{'created by'})) { |
|
|
|
|
33
|
|
|
|
|
|
286
|
1
|
|
|
|
|
7
|
$et->SetFileType(); |
|
287
|
1
|
|
|
|
|
5
|
my $tagTablePtr = GetTagTable('Image::ExifTool::Torrent::Main'); |
|
288
|
1
|
50
|
|
|
|
5
|
ExtractTags($et, $dict, $tagTablePtr) and $success = 1; |
|
289
|
|
|
|
|
|
|
} |
|
290
|
1
|
|
|
|
|
16
|
return $success; |
|
291
|
|
|
|
|
|
|
} |
|
292
|
|
|
|
|
|
|
|
|
293
|
|
|
|
|
|
|
1; # end |
|
294
|
|
|
|
|
|
|
|
|
295
|
|
|
|
|
|
|
__END__ |