| 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 | 15 |  |  | 15 |  | 87 | use Image::MetaData::JPEG::data::Tables qw(:TagsAPP1_Exif); | 
|  | 15 |  |  |  |  | 33 |  | 
|  | 15 |  |  |  |  | 3020 |  | 
| 7 | 15 |  |  | 15 |  | 96 | no  integer; | 
|  | 15 |  |  |  |  | 1304 |  | 
|  | 15 |  |  |  |  | 98 |  | 
| 8 | 15 |  |  | 15 |  | 406 | use strict; | 
|  | 15 |  |  |  |  | 25 |  | 
|  | 15 |  |  |  |  | 457 |  | 
| 9 | 15 |  |  | 15 |  | 76 | use warnings; | 
|  | 15 |  |  |  |  | 27 |  | 
|  | 15 |  |  |  |  | 39557 |  | 
| 10 |  |  |  |  |  |  |  | 
| 11 |  |  |  |  |  |  | ########################################################### | 
| 12 |  |  |  |  |  |  | # This method dumps an Exif APP1 segment. Basically, it   # | 
| 13 |  |  |  |  |  |  | # dumps the identifier, the two IFDs and the thumbnail.   # | 
| 14 |  |  |  |  |  |  | ########################################################### | 
| 15 |  |  |  |  |  |  | sub dump_app1_exif { | 
| 16 | 161 |  |  | 161 | 0 | 365 | my ($this) = @_; | 
| 17 |  |  |  |  |  |  | # dump the identifier (not part of the TIFF header) | 
| 18 | 161 |  |  |  |  | 669 | my $identifier = $this->search_record('Identifier')->get(); | 
| 19 | 161 |  |  |  |  | 757 | $this->set_data($identifier); | 
| 20 |  |  |  |  |  |  | # dump the TIFF header; note that the offset returned by | 
| 21 |  |  |  |  |  |  | # dump_TIFF_header is the current position in the newly written | 
| 22 |  |  |  |  |  |  | # data area AFTER the identifier (i.e., the base is the base | 
| 23 |  |  |  |  |  |  | # of the TIFF header), so it does not start from zero but from the | 
| 24 |  |  |  |  |  |  | # value of $ifd0_link. Be aware that its meaning is slightly | 
| 25 |  |  |  |  |  |  | # different from $offset in the parser. | 
| 26 | 161 |  |  |  |  | 612 | my ($header, $offset, $endianness) = $this->dump_TIFF_header(); | 
| 27 | 161 |  |  |  |  | 631 | $this->set_data($header); | 
| 28 |  |  |  |  |  |  | # locally set the current endianness to what we have found. | 
| 29 | 161 |  |  |  |  | 544 | local $this->{endianness} = $endianness; | 
| 30 |  |  |  |  |  |  | # dump all the records of the 0th IFD, and update $offset to | 
| 31 |  |  |  |  |  |  | # point after the end of the current data area (with respect | 
| 32 |  |  |  |  |  |  | # to the TIFF header base). This must be done even if the IFD | 
| 33 |  |  |  |  |  |  | # itself is empty (in order to find the next one). | 
| 34 | 161 | 100 |  |  |  | 584 | my $ifd1_link = defined $this->search_record('IFD1') ? 0 : 1; | 
| 35 | 161 |  |  |  |  | 705 | $offset += $this->set_data($this->dump_ifd('IFD0', $offset, $ifd1_link)); | 
| 36 |  |  |  |  |  |  | # same thing with the 1st IFD. We don't have to worry if this | 
| 37 |  |  |  |  |  |  | # IFD is not there, because dump_ifd tests for this case. | 
| 38 | 161 |  |  |  |  | 753 | $offset += $this->set_data($this->dump_ifd('IFD1', $offset, 1)); | 
| 39 |  |  |  |  |  |  | # if there is thumbnail data in the main directory of this | 
| 40 |  |  |  |  |  |  | # segment, it is time to dump it. Use the reference, because | 
| 41 |  |  |  |  |  |  | # this can be quite large (some tens of kilobytes ....) | 
| 42 | 161 | 100 |  |  |  | 699 | if (my $th_record = $this->search_record('ThumbnailData')) { | 
| 43 | 82 |  |  |  |  | 465 | (undef, undef, undef, my $tdataref) = $th_record->get(); | 
| 44 | 82 |  |  |  |  | 339 | $this->set_data($tdataref); } | 
| 45 |  |  |  |  |  |  | } | 
| 46 |  |  |  |  |  |  |  | 
| 47 |  |  |  |  |  |  | ########################################################### | 
| 48 |  |  |  |  |  |  | # This method reconstructs a TIFF header and returns a    # | 
| 49 |  |  |  |  |  |  | # list with all the relevant values. Nothing is written   # | 
| 50 |  |  |  |  |  |  | # to the data area. Records are searched for in the       # | 
| 51 |  |  |  |  |  |  | # directory specified by the second argument.             # | 
| 52 |  |  |  |  |  |  | ########################################################### | 
| 53 |  |  |  |  |  |  | sub dump_TIFF_header { | 
| 54 | 162 |  |  | 162 | 0 | 461 | my ($this, $dirref) = @_; | 
| 55 |  |  |  |  |  |  | # retrieve the endianness, and signature. It is not worth | 
| 56 |  |  |  |  |  |  | # setting the temporary segment endianness here, do it later. | 
| 57 | 162 |  |  |  |  | 563 | my $endianness=$this->search_record('Endianness',$dirref)->get(); | 
| 58 | 162 |  |  |  |  | 663 | my $signature =$this->search_record('Signature',$dirref)->get($endianness); | 
| 59 |  |  |  |  |  |  | # create a string containing the TIFF header (we always | 
| 60 |  |  |  |  |  |  | # choose the offset of the 0th IFD must to be 8 here). | 
| 61 | 162 |  |  |  |  | 393 | my $ifd0_len  = 8; | 
| 62 | 162 | 100 |  |  |  | 756 | my $ifd0_link = pack $endianness eq $BIG_ENDIAN ? "N" : "V", $ifd0_len; | 
| 63 | 162 |  |  |  |  | 391 | my $header = $endianness . $signature . $ifd0_link; | 
| 64 |  |  |  |  |  |  | # return all relevant values in a list | 
| 65 | 162 |  |  |  |  | 621 | return ($header, $ifd0_len, $endianness); | 
| 66 |  |  |  |  |  |  | } | 
| 67 |  |  |  |  |  |  |  | 
| 68 |  |  |  |  |  |  | ########################################################### | 
| 69 |  |  |  |  |  |  | # This is the core of the Exif APP1 dumping method. It    # | 
| 70 |  |  |  |  |  |  | # takes care to dump a whole IFD, including a special     # | 
| 71 |  |  |  |  |  |  | # treatement for thumbnails and makernotes. No action is  # | 
| 72 |  |  |  |  |  |  | # taken unless there is already a directory for this IFD  # | 
| 73 |  |  |  |  |  |  | # in the structured data area of the segment.             # | 
| 74 |  |  |  |  |  |  | # ------------------------------------------------------- # | 
| 75 |  |  |  |  |  |  | # Special treatement for tags holding an IFD offset (this # | 
| 76 |  |  |  |  |  |  | # includes makernotes); these tags are regenerated on the # | 
| 77 |  |  |  |  |  |  | # fly (since they are no more stored) and their value is  # | 
| 78 |  |  |  |  |  |  | # recalculated and written to the raw data area.          # | 
| 79 |  |  |  |  |  |  | # ------------------------------------------------------- # | 
| 80 |  |  |  |  |  |  | # New argument ($next), which specifies how the next_link # | 
| 81 |  |  |  |  |  |  | # pointer is to be treated: '0' --> the pointer is dumped # | 
| 82 |  |  |  |  |  |  | # with a non zero value; '1' --> the pointer is dumped    # | 
| 83 |  |  |  |  |  |  | # with value set to zero; '2' -->: the pointer is ignored # | 
| 84 |  |  |  |  |  |  | ########################################################### | 
| 85 |  |  |  |  |  |  | sub dump_ifd { | 
| 86 | 630 |  |  | 630 | 0 | 1297 | my ($this, $dirnames, $offset, $next) = @_; | 
| 87 |  |  |  |  |  |  | # set the next link flag to zero if it is undefined | 
| 88 | 630 | 50 |  |  |  | 1486 | $next = 0 unless defined $next; | 
| 89 |  |  |  |  |  |  | # retrieve the appropriate record list (specified by a '@' separated | 
| 90 |  |  |  |  |  |  | # list of dir names in $dirnames to be interpreted in sequence). If | 
| 91 |  |  |  |  |  |  | # this fails, return immediately with a reference to an empty string | 
| 92 | 630 |  |  |  |  | 3226 | my $dirref = $this->search_record_value($dirnames); | 
| 93 | 630 | 100 |  |  |  | 2108 | return \ (my $ns = '') unless $dirref; | 
| 94 |  |  |  |  |  |  | # $short and $long are two useful format strings correctly taking | 
| 95 |  |  |  |  |  |  | # into account the IFD endianness. $format is a format string for | 
| 96 |  |  |  |  |  |  | # packing an Interoperability array | 
| 97 | 575 | 100 |  |  |  | 2087 | my $short   = $this->{endianness} eq $BIG_ENDIAN ? 'n' : 'v'; | 
| 98 | 575 | 100 |  |  |  | 1395 | my $long    = $this->{endianness} eq $BIG_ENDIAN ? 'N' : 'V'; | 
| 99 | 575 |  |  |  |  | 1518 | my $format  = $short. $short . $long; | 
| 100 |  |  |  |  |  |  | # retrieve the record list for this IFD, then eliminate the REFERENCE | 
| 101 |  |  |  |  |  |  | # records (added by the parser routine, they were not in the JPEG file). | 
| 102 | 575 |  |  |  |  | 1100 | my @records = grep { $_->{type} != $REFERENCE } @$dirref; | 
|  | 7246 |  |  |  |  | 19946 |  | 
| 103 |  |  |  |  |  |  | # for each reference record with a non-undef extra field, regenerate | 
| 104 |  |  |  |  |  |  | # the corresponding offset record (which can be retraced from the | 
| 105 |  |  |  |  |  |  | # "extra" field) and insert it into the @records list with a dummy | 
| 106 |  |  |  |  |  |  | # value (0). We can safely use $LONG as record type (new-style offsets). | 
| 107 | 392 |  |  |  |  | 1797 | push @records, map { | 
| 108 | 7246 | 100 |  |  |  | 21713 | my $nt = JPEG_lookup($this->{name}, $dirnames, $_->{extra}); | 
| 109 | 392 |  |  |  |  | 16454 | new Image::MetaData::JPEG::Record($nt, $LONG, \ pack($long, 0)) } | 
| 110 | 575 |  |  |  |  | 1171 | grep { $_->{type} == $REFERENCE && $_->{extra} } @$dirref; | 
| 111 |  |  |  |  |  |  | # sort the accumulated records with respect to their tags (numeric). | 
| 112 |  |  |  |  |  |  | # This is not, strictly speaking mandatory, but the file looks more | 
| 113 |  |  |  |  |  |  | # polished after this (am I introducing any gratuitous incompatibility?) | 
| 114 | 575 |  |  |  |  | 3084 | @records = sort { $a->{key} <=> $b->{key} } @records; | 
|  | 10965 |  |  |  |  | 18997 |  | 
| 115 |  |  |  |  |  |  | # the IFD data area is to be initialised with two bytes specifying | 
| 116 |  |  |  |  |  |  | # the number of Interoperability arrays. | 
| 117 | 575 |  |  |  |  | 1992 | my $ifd_content = pack $short, scalar @records; | 
| 118 |  |  |  |  |  |  | # Data areas too large for the Interop array will be saved in $extra; | 
| 119 |  |  |  |  |  |  | # $remote should point to its beginning (from TIFF header base), so we | 
| 120 |  |  |  |  |  |  | # must skip 12 bytes for each Interop. array, 2 bytes for the initial | 
| 121 |  |  |  |  |  |  | # count (and 4 bytes for the next IFD link, unless $next is two). | 
| 122 | 575 |  |  |  |  | 2079 | my ($remote, $extra) = ($offset + 2 + 12*@records, ''); | 
| 123 | 575 | 50 |  |  |  | 1781 | $remote += 4 unless $next == 2; | 
| 124 |  |  |  |  |  |  | # managing the thumbnail is not trivial. We want to be sure that | 
| 125 |  |  |  |  |  |  | # its declared size corresponds to the reality and correct if | 
| 126 |  |  |  |  |  |  | # this is not the case (is this a stupid idea?) | 
| 127 | 575 | 100 | 100 |  |  | 2103 | if ($dirnames eq 'IFD1' && | 
| 128 |  |  |  |  |  |  | (my $th_record = $this->search_record('ThumbnailData'))) { | 
| 129 | 82 |  |  |  |  | 314 | (undef, undef, undef, my $tdataref) = $th_record->get(); | 
| 130 | 82 |  |  |  |  | 304 | for ($THTIFF_LENGTH, $THJPEG_LENGTH) { | 
| 131 | 164 |  |  |  |  | 567 | my $th_len = $this->search_record($_, $dirref); | 
| 132 | 164 | 100 |  |  |  | 816 | $th_len->set_value(length $$tdataref) if $th_len; } } | 
| 133 |  |  |  |  |  |  | # the following tags can be found only in IFD1 in APP1, and concern | 
| 134 |  |  |  |  |  |  | # the thumbnail location. They must be dealt with in a special way. | 
| 135 | 575 |  |  |  |  | 2658 | my %th_tags = ($THTIFF_OFFSET => undef, $THJPEG_OFFSET => undef); | 
| 136 |  |  |  |  |  |  | # determine weather this IFD can have subidrectories or not; if so, | 
| 137 |  |  |  |  |  |  | # get a special mapping table from %IFD_SUBDIRS (avoid autovivification) | 
| 138 | 575 |  |  |  |  | 2048 | my $path = join '@', $this->{name}, $dirnames; | 
| 139 | 575 | 100 |  |  |  | 2072 | my $mapping = exists $IFD_SUBDIRS{$path} ? $IFD_SUBDIRS{$path} : undef; | 
| 140 |  |  |  |  |  |  | # loop on all selected records and dump them | 
| 141 | 575 |  |  |  |  | 1145 | for my $record (@records) { | 
| 142 |  |  |  |  |  |  | # extract all necessary information about this | 
| 143 |  |  |  |  |  |  | # Interoperability array, with the correct endianness. | 
| 144 | 7243 |  |  |  |  | 31069 | my ($tag, $type, $count, $dataref) = $record->get($this->{endianness}); | 
| 145 |  |  |  |  |  |  | # calculate the length of the array data, and correct $count | 
| 146 |  |  |  |  |  |  | # for string-like records (it had been set to 1 during the | 
| 147 |  |  |  |  |  |  | # parsing, it must be the data length in this case). | 
| 148 | 7243 |  |  |  |  | 15661 | my $length = length $$dataref; | 
| 149 | 7243 | 100 |  |  |  | 19894 | $count = $length if $record->get_category() eq 'S'; | 
| 150 |  |  |  |  |  |  | # the last four bytes in an interoperability array are either | 
| 151 |  |  |  |  |  |  | # data or an address; prepare a variable for holding this value | 
| 152 | 7243 |  |  |  |  | 10550 | my $record_end = ''; | 
| 153 |  |  |  |  |  |  | # if this IFD1 record specifies the thumbnail location, it needs | 
| 154 |  |  |  |  |  |  | # a special treatment, since we cannot yet know where the thumbnail | 
| 155 |  |  |  |  |  |  | # will be located. Write a bogus offset now and overwrite it later. | 
| 156 | 7243 | 100 | 100 |  |  | 53043 | if ($dirnames eq 'IFD1' && exists $th_tags{$tag}) { | 
|  |  | 100 | 100 |  |  |  |  | 
|  |  | 100 |  |  |  |  |  | 
| 157 | 72 |  |  |  |  | 213 | $th_tags{$tag} = 8 + length $ifd_content; | 
| 158 | 72 |  |  |  |  | 138 | $record_end = "\000\000\000\000"; } | 
| 159 |  |  |  |  |  |  | # if this Interop array is known to correspond to a subdirectory | 
| 160 |  |  |  |  |  |  | # (use %$mapping for this), the subdirectory content is calculated | 
| 161 |  |  |  |  |  |  | # on the fly, and stored in this IFD's remote data area. Its offset | 
| 162 |  |  |  |  |  |  | # instead is saved at the end of the Interoperability array. | 
| 163 |  |  |  |  |  |  | elsif ($mapping && exists $$mapping{$tag}) { | 
| 164 | 392 |  |  |  |  | 1782 | my $is_makernote = ($tag =~ $MAKERNOTE_TAG); | 
| 165 | 392 |  |  |  |  | 1118 | my $extended_dirnames = $dirnames.'@'.$$mapping{$tag}; | 
| 166 |  |  |  |  |  |  | # MakerNotes require a special treatment, including rewriting | 
| 167 |  |  |  |  |  |  | # type and count (one LONG is really many UNDEF bytes); other | 
| 168 |  |  |  |  |  |  | # subIFD's are written by a recursive dump_ifd (next link is 0). | 
| 169 | 392 | 100 |  |  |  | 1877 | my $subifd = $is_makernote ? | 
| 170 |  |  |  |  |  |  | $this->dump_makernote($extended_dirnames, $remote) : | 
| 171 |  |  |  |  |  |  | $this->dump_ifd($extended_dirnames, $remote, 1); | 
| 172 | 392 | 100 |  |  |  | 1148 | $type = $UNDEF, $count = length($$subifd) if $is_makernote; | 
| 173 | 392 |  |  |  |  | 1688 | $record_end = pack $long, $remote; | 
| 174 | 392 |  |  |  |  | 1285 | $extra .= $$subifd; $remote += length $$subifd; } | 
|  | 392 |  |  |  |  | 975 |  | 
| 175 |  |  |  |  |  |  | # if the data length is not larger than four bytes, we are ok. | 
| 176 |  |  |  |  |  |  | # $$dataref is simply appended (with padding up to 4 bytes, | 
| 177 |  |  |  |  |  |  | # AFTER $$dataref, independently of the IFD endianness). | 
| 178 | 3485 |  |  |  |  | 7589 | elsif ($length <= 4) { $record_end = $$dataref . "\000"x(4-$length); } | 
| 179 |  |  |  |  |  |  | # if $$dataref is too big, it must be packed in the $extra | 
| 180 |  |  |  |  |  |  | # section, and its pointer appended here. Remember to update | 
| 181 |  |  |  |  |  |  | # $remote for the next record of this type. | 
| 182 | 3294 |  |  |  |  | 7228 | else { $record_end = pack $long, $remote; | 
| 183 | 3294 |  |  |  |  | 4121 | $remote += $length; $extra .= $$dataref; } | 
|  | 3294 |  |  |  |  | 5442 |  | 
| 184 |  |  |  |  |  |  | # the interoperability array starts with tag, type and count, | 
| 185 |  |  |  |  |  |  | # followed by $record_end (4 bytes): dump into the ifd data area | 
| 186 | 7243 |  |  |  |  | 30859 | $ifd_content .= (pack $format, $tag, $type, $count) . $record_end; } | 
| 187 |  |  |  |  |  |  | # after the Interop. arrays there can be a link to the next IFD | 
| 188 |  |  |  |  |  |  | # (this takes 4 bytes). $next = 0 --> write the next IFD offset, | 
| 189 |  |  |  |  |  |  | # = 1 --> write zero, 2 --> do not write these four bytes. | 
| 190 | 575 | 100 |  |  |  | 1779 | $ifd_content .= pack $long, $remote if $next == 0; | 
| 191 | 575 | 100 |  |  |  | 1899 | $ifd_content .= pack $long, 0       if $next == 1; | 
| 192 |  |  |  |  |  |  | # then, we save the remote data area | 
| 193 | 575 |  |  |  |  | 3310 | $ifd_content .= $extra; | 
| 194 |  |  |  |  |  |  | # if the thumbnail offset tags were found during the scan, we | 
| 195 |  |  |  |  |  |  | # need to overwrite their values with a meaningful offset now. | 
| 196 | 575 |  |  |  |  | 2034 | for (keys %th_tags) { | 
| 197 | 1150 | 100 |  |  |  | 3633 | next unless my $overwrite = $th_tags{$_}; | 
| 198 | 72 |  |  |  |  | 321 | my $tag_record = $this->search_record($_, $dirref); | 
| 199 | 72 |  |  |  |  | 270 | $tag_record->set_value($remote); | 
| 200 | 72 |  |  |  |  | 287 | my $new_offset = $tag_record->get($this->{endianness}); | 
| 201 | 72 |  |  |  |  | 264 | substr($ifd_content, $overwrite, length $new_offset) = $new_offset; } | 
| 202 |  |  |  |  |  |  | # return a reference to the scalar which holds the binary dump | 
| 203 |  |  |  |  |  |  | # of this IFD (to be saved in the caller routine, I think). | 
| 204 | 575 |  |  |  |  | 5923 | return \$ifd_content; | 
| 205 |  |  |  |  |  |  | } | 
| 206 |  |  |  |  |  |  |  | 
| 207 |  |  |  |  |  |  | ########################################################### | 
| 208 |  |  |  |  |  |  | # This routine dumps all kinds of makernotes. Have a look # | 
| 209 |  |  |  |  |  |  | # at parse_makernote() for further details.               # | 
| 210 |  |  |  |  |  |  | ########################################################### | 
| 211 |  |  |  |  |  |  | sub dump_makernote { | 
| 212 | 87 |  |  | 87 | 0 | 191 | my ($this, $dirnames, $offset) = @_; | 
| 213 |  |  |  |  |  |  | # look for a MakerNote subdirectory beginning with $dirnames: the | 
| 214 |  |  |  |  |  |  | # actual name has the format appended, e.g., MakerNoteData_Canon. | 
| 215 | 87 |  |  |  |  | 970 | $dirnames =~ s/(.*@|)([^@]*)/$1/; | 
| 216 | 87 |  |  |  |  | 391 | my $dirref = $this->search_record_value($dirnames); | 
| 217 | 2201 |  |  |  |  | 9412 | $dirnames .= $_->{key}, $dirref = $_->get_value(), last | 
| 218 | 87 |  |  |  |  | 231 | for (grep{$_->{key}=~/^$2/} @$dirref); | 
| 219 |  |  |  |  |  |  | # Also look for the subdir with special information. | 
| 220 | 87 |  |  |  |  | 433 | my $spcref = $this->search_record_value($dirnames.'@special'); | 
| 221 |  |  |  |  |  |  | # entering here without the dir and its subdir being present is an error | 
| 222 | 87 | 50 | 33 |  |  | 559 | $this->die('MakerNote subdirs not found') unless $dirref && $spcref; | 
| 223 |  |  |  |  |  |  | # read all MakerNote special values (added by the parser routine) | 
| 224 | 435 |  |  |  |  | 1262 | my ($data, $signature, $endianness, $format, $error) = | 
| 225 | 87 |  |  |  |  | 265 | map { $this->search_record_value($_, $spcref) } | 
| 226 |  |  |  |  |  |  | ('ORIGINAL', 'SIGNATURE', 'ENDIANNESS', 'FORMAT', 'ERROR'); | 
| 227 |  |  |  |  |  |  | # die and debug if the format record is not present | 
| 228 | 87 | 50 |  |  |  | 332 | $this->die('FORMAT not found') unless $format; | 
| 229 |  |  |  |  |  |  | # if the format is unknown or there was an error at parse time, it | 
| 230 |  |  |  |  |  |  | # is wiser to return the original, unparsed content of the MakerNote | 
| 231 | 87 | 100 | 100 |  |  | 567 | if ($format =~ /unknown/ || defined $error) { | 
| 232 | 2 | 50 |  |  |  | 9 | $this->die('ORIGINAL data not found') unless $data; return \$data; }; | 
|  | 2 |  |  |  |  | 8 |  | 
| 233 |  |  |  |  |  |  | # also extract the property table for this MakerNote format | 
| 234 | 85 |  |  |  |  | 307 | my $hash = $$HASH_MAKERNOTES{$format}; | 
| 235 |  |  |  |  |  |  | # now, die if the signature or endianness is still undefined | 
| 236 | 85 | 50 | 33 |  |  | 472 | $this->die('Properties not found')unless defined $signature && $endianness; | 
| 237 |  |  |  |  |  |  | # in general, the MakerNote's next-IFD link is zero, but some | 
| 238 |  |  |  |  |  |  | # MakerNotes do not even have these four bytes: prepare the flag | 
| 239 | 85 | 50 |  |  |  | 330 | my $next_flag = exists $$hash{nonext} ? 2 : 1; | 
| 240 |  |  |  |  |  |  | # in general, MakerNote's offsets are computed from the APP1 segment | 
| 241 |  |  |  |  |  |  | # TIFF base; however, some formats compute offsets from the beginning | 
| 242 |  |  |  |  |  |  | # of the MakerNote itself: setup the offset base as required. | 
| 243 | 85 | 100 |  |  |  | 288 | $offset = length($signature) + (exists $$hash{mkntstart} ? 0 : $offset); | 
| 244 |  |  |  |  |  |  | # initialise the data area with the detected signature | 
| 245 | 85 |  |  |  |  | 183 | $data = $signature; | 
| 246 |  |  |  |  |  |  | # some MakerNotes have a TIFF header on their own, freeing them | 
| 247 |  |  |  |  |  |  | # from the relocation problem; values from this header overwrite | 
| 248 |  |  |  |  |  |  | # the previously assigned values; records are saved in $mknt_dir. | 
| 249 | 85 | 100 |  |  |  | 329 | if (exists $$hash{mkntTIFF}) { | 
| 250 | 1 |  |  |  |  | 5 | my ($TIFF_header, $TIFF_offset, $TIFF_endianness) | 
| 251 |  |  |  |  |  |  | = $this->dump_TIFF_header($spcref); | 
| 252 | 1 | 50 |  |  |  | 5 | $this->die('Endianness mismatch') if $endianness ne $TIFF_endianness; | 
| 253 | 1 |  |  |  |  | 4 | $data .= $TIFF_header; $offset = $TIFF_offset; } | 
|  | 1 |  |  |  |  | 2 |  | 
| 254 |  |  |  |  |  |  | # Unstructured case: the content of the MakerNote is simply | 
| 255 |  |  |  |  |  |  | # a sequence of bytes, which must be encoded using $$hash{tags} | 
| 256 | 85 | 100 |  |  |  | 286 | if (exists $$hash{nonIFD}) { | 
| 257 | 3608 |  |  |  |  | 7093 | $data .= $this->search_record($$_[0], $dirref)->get($endianness) | 
| 258 | 82 |  |  |  |  | 160 | for map {$$hash{tags}{$_}} sort {$a <=> $b} keys %{$$hash{tags}}; } | 
|  | 15440 |  |  |  |  | 16100 |  | 
|  | 82 |  |  |  |  | 1627 |  | 
| 259 |  |  |  |  |  |  | # Structured case: the content of the MakerNote can be dumped | 
| 260 |  |  |  |  |  |  | # with dump_ifd (change locally the endianness value). | 
| 261 | 3 |  |  |  |  | 7 | else { local $this->{endianness} = $endianness; | 
| 262 | 3 |  |  |  |  | 5 | $data .= ${$this->dump_ifd($dirnames, $offset, $next_flag)} }; | 
|  | 3 |  |  |  |  | 32 |  | 
| 263 |  |  |  |  |  |  | # return the MakerNote as a binary object | 
| 264 | 85 |  |  |  |  | 1786 | return \$data; | 
| 265 |  |  |  |  |  |  | } | 
| 266 |  |  |  |  |  |  |  | 
| 267 |  |  |  |  |  |  | # successful load | 
| 268 |  |  |  |  |  |  | 1; |