| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
|
|
|
|
|
|
########################################################### |
|
2
|
|
|
|
|
|
|
# A Perl package for showing/modifying JPEG (meta)data. # |
|
3
|
|
|
|
|
|
|
# Copyright (C) 2004,2005,2006 Stefano Bettelli # |
|
4
|
|
|
|
|
|
|
# See the COPYING and LICENSE files for license terms. # |
|
5
|
|
|
|
|
|
|
########################################################### |
|
6
|
|
|
|
|
|
|
#use Image::MetaData::JPEG::data::Tables qw(); |
|
7
|
15
|
|
|
15
|
|
65
|
no integer; |
|
|
15
|
|
|
|
|
19
|
|
|
|
15
|
|
|
|
|
69
|
|
|
8
|
15
|
|
|
15
|
|
374
|
use strict; |
|
|
15
|
|
|
|
|
21
|
|
|
|
15
|
|
|
|
|
397
|
|
|
9
|
15
|
|
|
15
|
|
54
|
use warnings; |
|
|
15
|
|
|
|
|
17
|
|
|
|
15
|
|
|
|
|
5387
|
|
|
10
|
|
|
|
|
|
|
|
|
11
|
|
|
|
|
|
|
########################################################### |
|
12
|
|
|
|
|
|
|
# This method parses an APP12 segment; this segment was # |
|
13
|
|
|
|
|
|
|
# used around 1998 by at least Olympus, Agfa and Epson # |
|
14
|
|
|
|
|
|
|
# as a non standard replacement for EXIF. Information is # |
|
15
|
|
|
|
|
|
|
# semi-readeable (mainly ascii text), but the format is # |
|
16
|
|
|
|
|
|
|
# undocument (let me know if you have any documentation!) # |
|
17
|
|
|
|
|
|
|
#=========================================================# |
|
18
|
|
|
|
|
|
|
# From the few examples I was able to find, my interpre- # |
|
19
|
|
|
|
|
|
|
# tation of the APP12 format is the following: # |
|
20
|
|
|
|
|
|
|
#---------------------------------------------------------# |
|
21
|
|
|
|
|
|
|
# 1 line identification (maker info?) # |
|
22
|
|
|
|
|
|
|
#----- multiple times ------------------------------------# |
|
23
|
|
|
|
|
|
|
# 1 line group (a string in square brackets) # |
|
24
|
|
|
|
|
|
|
# multiple lines records (key-value separated by '=') # |
|
25
|
|
|
|
|
|
|
#----- multiple times ------------------------------------# |
|
26
|
|
|
|
|
|
|
# characters group (a string in square brackets) # |
|
27
|
|
|
|
|
|
|
# characters unintelligible data # |
|
28
|
|
|
|
|
|
|
#=========================================================# |
|
29
|
|
|
|
|
|
|
# Well, this description looks a mess, I know. It means # |
|
30
|
|
|
|
|
|
|
# that after the identification line, there is some plain # |
|
31
|
|
|
|
|
|
|
# ascii information (divided in groups, each group starts # |
|
32
|
|
|
|
|
|
|
# with a line like "[picture info]", each key-value pair # |
|
33
|
|
|
|
|
|
|
# span one line) followed by groups containing binary # |
|
34
|
|
|
|
|
|
|
# data (so that splitting on line ends does not work!). # |
|
35
|
|
|
|
|
|
|
# Line terminations are marked by '\r\n' = 0x0d0a. # |
|
36
|
|
|
|
|
|
|
#=========================================================# |
|
37
|
|
|
|
|
|
|
# Ref: ... ??? # |
|
38
|
|
|
|
|
|
|
########################################################### |
|
39
|
|
|
|
|
|
|
sub parse_app12 { |
|
40
|
2
|
|
|
2
|
0
|
4
|
my ($this) = @_; |
|
41
|
|
|
|
|
|
|
# compile once and for all the following regular expression, |
|
42
|
|
|
|
|
|
|
# which captures a [groupname]; the name can contain alphanumeric |
|
43
|
|
|
|
|
|
|
# characters, underscores and spaces (this is a guess ...) |
|
44
|
2
|
|
|
|
|
7
|
my $groupname = qr/^\[([ \w]*)\]/; |
|
45
|
|
|
|
|
|
|
# search the string "[user]" in the data area; it seems to |
|
46
|
|
|
|
|
|
|
# separate the ascii data area from the binary data area. |
|
47
|
|
|
|
|
|
|
# If the string is not there ($limit = -1), convert this value |
|
48
|
|
|
|
|
|
|
# to the past-the-end character. |
|
49
|
2
|
|
|
|
|
6
|
my $limit = index $this->data(0, $this->size()), "[user]"; |
|
50
|
2
|
100
|
|
|
|
7
|
$limit = $this->size() if $limit == -1; |
|
51
|
|
|
|
|
|
|
# get all segment data up to the $limit and split in lines |
|
52
|
|
|
|
|
|
|
# (each line is terminated by carriage-return + line-feed) |
|
53
|
2
|
|
|
|
|
6
|
my @lines = split /\r\n/, $this->data(0, $limit); |
|
54
|
|
|
|
|
|
|
# extract the first line out of @lines, because it must be |
|
55
|
|
|
|
|
|
|
# treated differently. It seems that this line contains some |
|
56
|
|
|
|
|
|
|
# null characters, but I don't want to split it further ... |
|
57
|
2
|
|
|
|
|
6
|
my $preamble = shift @lines; |
|
58
|
2
|
|
|
|
|
6
|
$this->store_record('MakerInfo', $ASCII, \ $preamble, length $preamble); |
|
59
|
|
|
|
|
|
|
# each group will be written to a different subdirectory |
|
60
|
2
|
|
|
|
|
2
|
my $dirref = undef; |
|
61
|
|
|
|
|
|
|
# for each line in the ascii data area, except the first ... |
|
62
|
2
|
|
|
|
|
5
|
for (@lines) { |
|
63
|
|
|
|
|
|
|
# if the line is like "[groupname]", extract the group name |
|
64
|
|
|
|
|
|
|
# from the square brackets and create a new subdirectory |
|
65
|
25
|
100
|
|
|
|
120
|
if (/^$groupname$/) { $dirref = $this->provide_subdirectory($1); } |
|
|
3
|
|
|
|
|
8
|
|
|
66
|
|
|
|
|
|
|
# otherwise, split the line on "="; on the left we find the |
|
67
|
|
|
|
|
|
|
# tag name, on the right the ascii value(s). Store, in the |
|
68
|
|
|
|
|
|
|
# appropriate subdirectory, a non-numeric record. |
|
69
|
22
|
|
|
|
|
39
|
else { my ($tag, $vals) = split /=/, $_; |
|
70
|
22
|
|
|
|
|
47
|
$this->store_record($dirref,$tag,$ASCII,\$vals,length $vals); } |
|
71
|
|
|
|
|
|
|
} |
|
72
|
|
|
|
|
|
|
# it's time to take care of the binary data area. We can't rely |
|
73
|
|
|
|
|
|
|
# on line terminations here, so a different strategy is necessary. |
|
74
|
|
|
|
|
|
|
# First, the remainig of the data area is copied in a variable ... |
|
75
|
2
|
|
|
|
|
6
|
my $binary = $this->data($limit, $this->size() - $limit); |
|
76
|
|
|
|
|
|
|
# ... then this variable is slowly consumed |
|
77
|
2
|
|
|
|
|
8
|
while (0 != length $binary) { |
|
78
|
|
|
|
|
|
|
# match the [groupname] string. It must be at the beginning |
|
79
|
|
|
|
|
|
|
# of $$binary_ref, otherwise something is going wrong ... |
|
80
|
1
|
|
|
|
|
5
|
$binary =~ /$groupname/; |
|
81
|
1
|
50
|
|
|
|
6
|
$this->die('Error while decoding binary data') if $-[0] != 0; |
|
82
|
|
|
|
|
|
|
# the subgroup matches the groupname (without the square |
|
83
|
|
|
|
|
|
|
# brackets); assume the rest, up to the end, is the value |
|
84
|
1
|
|
|
|
|
3
|
my $tag = $1; |
|
85
|
1
|
|
|
|
|
3
|
my $val = substr $binary, $+[0]; |
|
86
|
|
|
|
|
|
|
# but if we find another [groupname], |
|
87
|
|
|
|
|
|
|
# we change our mind on where the value ends |
|
88
|
1
|
50
|
|
|
|
11
|
$val = substr($val, 0, $-[0]) if $val =~ /$groupname/; |
|
89
|
|
|
|
|
|
|
# take out the group name and the value from binary, then |
|
90
|
|
|
|
|
|
|
# save them in a non-numeric record as undefined bytes (add |
|
91
|
|
|
|
|
|
|
# 2 to the length sum, this counts the two square brackets) |
|
92
|
1
|
|
|
|
|
3
|
$binary = substr($binary, length($tag) + length($val) + 2); |
|
93
|
1
|
|
|
|
|
4
|
$this->store_record($tag, $UNDEF, \$val, length $val); |
|
94
|
|
|
|
|
|
|
} |
|
95
|
|
|
|
|
|
|
} |
|
96
|
|
|
|
|
|
|
|
|
97
|
|
|
|
|
|
|
# successful load |
|
98
|
|
|
|
|
|
|
1; |