1#------------------------------------------------------------------------------
2# File:         Rawzor.pm
3#
4# Description:  Read meta information from Rawzor compressed images
5#
6# Revisions:    09/09/2008 - P. Harvey Created
7#
8# References:   1) http://www.rawzor.com/
9#------------------------------------------------------------------------------
10
11package Image::ExifTool::Rawzor;
12
13use strict;
14use vars qw($VERSION);
15use Image::ExifTool qw(:DataAccess :Utils);
16
17$VERSION = '1.05';
18
19# currently support this version Rawzor images
20my $implementedRawzorVersion = 199; # (up to version 1.99)
21
22# Rawzor-specific tags
23%Image::ExifTool::Rawzor::Main = (
24    GROUPS => { 2 => 'Other' },
25    VARS => { NO_ID => 1 },
26    NOTES => q{
27        Rawzor files store compressed images of other formats. As well as the
28        information listed below, exiftool uncompresses and extracts the meta
29        information from the original image.
30    },
31    OriginalFileType => { },
32    OriginalFileSize => {
33        PrintConv => $Image::ExifTool::Extra{FileSize}->{PrintConv},
34    },
35    RawzorRequiredVersion => {
36        ValueConv => '$val / 100',
37        PrintConv => 'sprintf("%.2f", $val)',
38    },
39    RawzorCreatorVersion => {
40        ValueConv => '$val / 100',
41        PrintConv => 'sprintf("%.2f", $val)',
42    },
43    # compression factor is originalSize/compressedSize (and compression
44    # ratio is the inverse - ref "Data Compression" by David Salomon)
45    CompressionFactor => { PrintConv => 'sprintf("%.2f", $val)' },
46);
47
48#------------------------------------------------------------------------------
49# Extract information from a Rawzor file
50# Inputs: 0) ExifTool object reference, 1) dirInfo reference
51# Returns: 1 on success, 0 if this wasn't a valid Rawzor file
52sub ProcessRWZ($$)
53{
54    my ($et, $dirInfo) = @_;
55    my $raf = $$dirInfo{RAF};
56    my ($buff, $buf2);
57
58    # read the Rawzor file header:
59    #  0 string - "rawzor" signature
60    #  6 int16u - Required SDK version
61    #  8 int16u - Creator SDK version
62    # 10 int64u - RWZ file size
63    # 18 int64u - original raw file size
64    # 26 undef[12] - reserved
65    # 38 int64u - metadata offset
66    $raf->Read($buff, 46) == 46 and $buff =~ /^rawzor/ or return 0;
67
68    SetByteOrder('II');
69    my $reqVers = Get16u(\$buff, 6);
70    my $creatorVers = Get16u(\$buff, 8);
71    my $rwzSize = Get64u(\$buff, 10);
72    my $origSize = Get64u(\$buff, 18);
73    my $tagTablePtr = GetTagTable('Image::ExifTool::Rawzor::Main');
74    $et->HandleTag($tagTablePtr, RawzorRequiredVersion => $reqVers);
75    $et->HandleTag($tagTablePtr, RawzorCreatorVersion => $creatorVers);
76    $et->HandleTag($tagTablePtr, OriginalFileSize => $origSize);
77    $et->HandleTag($tagTablePtr, CompressionFactor => $origSize/$rwzSize) if $rwzSize;
78    # check version numbers
79    if ($reqVers > $implementedRawzorVersion) {
80        $et->Warn("Version $reqVers Rawzor images not yet supported");
81        return 1;
82    }
83    my $metaOffset = Get64u(\$buff, 38);
84    if ($metaOffset > 0x7fffffff) {
85        $et->Warn('Bad metadata offset');
86        return 1;
87    }
88    # check for the ability to uncompress the information
89    unless (eval { require IO::Uncompress::Bunzip2 }) {
90        $et->Warn('Install IO::Compress::Bzip2 to decode Rawzor bzip2 compression');
91        return 1;
92    }
93    # read the metadata header:
94    #  0 int64u - metadata section 0 end (offset in original file)
95    #  8 int64u - metadata section 1 start
96    # 16 int64u - metadata section 1 end
97    # 24 int64u - metadata section 2 start
98    # 32 undef[4] - reserved
99    # 36 int32u - original metadata size
100    # 40 int32u - compressed metadata size
101    unless ($raf->Seek($metaOffset, 0) and $raf->Read($buff, 44) == 44) {
102        $et->Warn('Error reading metadata header');
103        return 1;
104    }
105    my $metaSize = Get32u(\$buff, 36);
106    if ($metaSize) {
107        $$et{DontValidateImageData} = 1;
108        # validate the metadata header and read the compressed metadata
109        my $end0 = Get64u(\$buff, 0);
110        my $pos1 = Get64u(\$buff, 8);
111        my $end1 = Get64u(\$buff, 16);
112        my $pos2 = Get64u(\$buff, 24);
113        my $len = Get32u(\$buff, 40);
114        unless ($raf->Read($buff, $len) == $len and
115            $end0 + ($end1 - $pos1) + ($origSize - $pos2) == $metaSize and
116            $end0 <= $pos1 and $pos1 <= $end1 and $end1 <= $pos2)
117        {
118            $et->Warn('Error reading image metadata');
119            return 1;
120        }
121        # uncompress the metadata
122        unless (IO::Uncompress::Bunzip2::bunzip2(\$buff, \$buf2) and
123            length($buf2) eq $metaSize)
124        {
125            $et->Warn('Error uncompressing image metadata');
126            return 1;
127        }
128        # re-assemble the original file (sans image data)
129        undef $buff; # (can't hurt to free memory as soon as possible)
130        $buff = substr($buf2, 0, $end0) . ("\0" x ($pos1 - $end0)) .
131                substr($buf2, $end0, $end1 - $pos1) . ("\0" x ($pos2 - $end1)) .
132                substr($buf2, $end0 + $end1 - $pos1, $origSize - $pos2);
133        undef $buf2;
134
135        # extract original information by calling ExtractInfo recursively
136        $et->ExtractInfo(\$buff, { ReEntry => 1 });
137        undef $buff;
138    }
139    # set OriginalFileType from FileType of original file
140    # then change FileType and MIMEType to indicate a Rawzor image
141    my $origFileType = $$et{VALUE}{FileType};
142    if ($origFileType) {
143        $et->HandleTag($tagTablePtr, OriginalFileType => $origFileType);
144        $et->OverrideFileType('RWZ');
145    } else {
146        $et->HandleTag($tagTablePtr, OriginalFileType => 'Unknown');
147        $et->SetFileType();
148    }
149    return 1;
150}
151
1521;  # end
153
154__END__
155
156=head1 NAME
157
158Image::ExifTool::Rawzor - Read meta information from Rawzor compressed images
159
160=head1 SYNOPSIS
161
162This module is used by Image::ExifTool
163
164=head1 DESCRIPTION
165
166This module contains definitions required by Image::ExifTool to extract meta
167information from Rawzor compressed images.
168
169=head1 AUTHOR
170
171Copyright 2003-2021, Phil Harvey (philharvey66 at gmail.com)
172
173This library is free software; you can redistribute it and/or modify it
174under the same terms as Perl itself.
175
176=head1 REFERENCES
177
178=over 4
179
180=item L<http://www.rawzor.com/>
181
182=back
183
184=head1 SEE ALSO
185
186L<Image::ExifTool::TagNames/Rawzor Tags>,
187L<Image::ExifTool(3pm)|Image::ExifTool>
188
189=cut
190
191