File Coverage

blib/lib/Image/ExifTool/CanonRaw.pm
Criterion Covered Total %
statement 131 145 90.3
branch 68 94 72.3
condition 28 45 62.2
subroutine 8 8 100.0
pod 0 2 0.0
total 235 294 79.9


line stmt bran cond sub pod time code
1             #------------------------------------------------------------------------------
2             # File: CanonRaw.pm
3             #
4             # Description: Read Canon RAW (CRW) meta information
5             #
6             # Revisions: 11/25/2003 - P. Harvey Created
7             # 12/02/2003 - P. Harvey Completely reworked and figured out many
8             # more tags
9             #
10             # References: 1) http://www.cybercom.net/~dcoffin/dcraw/
11             # 2) http://www.wonderland.org/crw/
12             # 3) http://xyrion.org/ciff/CIFFspecV1R04.pdf
13             # 4) Dave Nicholson private communication (PowerShot S30)
14             #------------------------------------------------------------------------------
15              
16             package Image::ExifTool::CanonRaw;
17              
18 20     20   4752 use strict;
  20         56  
  20         880  
19 20     20   124 use vars qw($VERSION $AUTOLOAD %crwTagFormat);
  20         46  
  20         1387  
20 20     20   134 use Image::ExifTool qw(:DataAccess :Utils);
  20         70  
  20         5139  
21 20     20   1467 use Image::ExifTool::Exif;
  20         54  
  20         633  
22 20     20   15649 use Image::ExifTool::Canon;
  20         723  
  20         54096  
23              
24             $VERSION = '1.59';
25              
26             sub WriteCRW($$);
27             sub ProcessCanonRaw($$$);
28             sub WriteCanonRaw($$$);
29             sub CheckCanonRaw($$$);
30             sub InitMakerNotes($);
31             sub SaveMakerNotes($);
32             sub BuildMakerNotes($$$$$$);
33              
34             # formats for CRW tag types (($tag >> 8) & 0x38)
35             # Note: don't define format for undefined types
36             %crwTagFormat = (
37             0x00 => 'int8u',
38             0x08 => 'string',
39             0x10 => 'int16u',
40             0x18 => 'int32u',
41             # 0x20 => 'undef',
42             # 0x28 => 'undef',
43             # 0x30 => 'undef',
44             );
45              
46             # Canon raw file tag table
47             # Note: Tag ID's have upper 2 bits set to zero, since these 2 bits
48             # just specify the location of the information
49             %Image::ExifTool::CanonRaw::Main = (
50             GROUPS => { 0 => 'MakerNotes', 2 => 'Camera' },
51             PROCESS_PROC => \&ProcessCanonRaw,
52             WRITE_PROC => \&WriteCanonRaw,
53             CHECK_PROC => \&CheckCanonRaw,
54             WRITABLE => 1,
55             0x0000 => { Name => 'NullRecord', Writable => 'undef' }, #3
56             0x0001 => { #3
57             Name => 'FreeBytes',
58             Format => 'undef',
59             Binary => 1,
60             },
61             0x0032 => { Name => 'CanonColorInfo1', Writable => 0 },
62             0x0805 => [
63             # this tag is found in more than one directory...
64             {
65             Condition => '$self->{DIR_NAME} eq "ImageDescription"',
66             Name => 'CanonFileDescription',
67             Writable => 'string[32]',
68             },
69             {
70             Name => 'UserComment',
71             Writable => 'string[256]',
72             },
73             ],
74             0x080a => {
75             Name => 'CanonRawMakeModel',
76             Writable => 0,
77             SubDirectory => { TagTable => 'Image::ExifTool::CanonRaw::MakeModel' },
78             },
79             0x080b => { Name => 'CanonFirmwareVersion', Writable => 'string[32]' },
80             0x080c => { Name => 'ComponentVersion', Writable => 'string' }, #3
81             0x080d => { Name => 'ROMOperationMode', Writable => 'string[8]' }, #3
82             0x0810 => { Name => 'OwnerName', Writable => 'string[32]' },
83             0x0815 => { Name => 'CanonImageType', Writable => 'string[32]' },
84             0x0816 => { Name => 'OriginalFileName', Writable => 'string[32]' },
85             0x0817 => { Name => 'ThumbnailFileName', Writable => 'string[32]' },
86             0x100a => { #3
87             Name => 'TargetImageType',
88             Writable => 'int16u',
89             PrintConv => {
90             0 => 'Real-world Subject',
91             1 => 'Written Document',
92             },
93             },
94             0x1010 => { #3
95             Name => 'ShutterReleaseMethod',
96             Writable => 'int16u',
97             PrintConv => {
98             0 => 'Single Shot',
99             2 => 'Continuous Shooting',
100             },
101             },
102             0x1011 => { #3
103             Name => 'ShutterReleaseTiming',
104             Writable => 'int16u',
105             PrintConv => {
106             0 => 'Priority on shutter',
107             1 => 'Priority on focus',
108             },
109             },
110             0x1016 => { Name => 'ReleaseSetting', Writable => 'int16u' }, #3
111             0x101c => { Name => 'BaseISO', Writable => 'int16u' }, #3
112             0x1028=> { #PH
113             Name => 'CanonFlashInfo',
114             Writable => 'int16u',
115             Count => 4,
116             Unknown => 1,
117             },
118             0x1029 => {
119             Name => 'CanonFocalLength',
120             Writable => 0,
121             SubDirectory => { TagTable => 'Image::ExifTool::Canon::FocalLength' },
122             },
123             0x102a => {
124             Name => 'CanonShotInfo',
125             Writable => 0,
126             SubDirectory => { TagTable => 'Image::ExifTool::Canon::ShotInfo' },
127             },
128             0x102c => {
129             Name => 'CanonColorInfo2',
130             Writable => 0,
131             # for the S30, the following information has been decoded: (ref 4)
132             # offset 66: int32u - shutter half press time in ms
133             # offset 70: int32u - image capture time in ms
134             # offset 74: int16u - custom white balance flag (0=Off, 512=On)
135             },
136             0x102d => {
137             Name => 'CanonCameraSettings',
138             Writable => 0,
139             SubDirectory => { TagTable => 'Image::ExifTool::Canon::CameraSettings' },
140             },
141             0x1030 => { #4
142             Name => 'WhiteSample',
143             Writable => 0,
144             SubDirectory => {
145             Validate => 'Image::ExifTool::Canon::Validate($dirData,$subdirStart,$size)',
146             TagTable => 'Image::ExifTool::CanonRaw::WhiteSample',
147             },
148             },
149             0x1031 => {
150             Name => 'SensorInfo',
151             Writable => 0,
152             SubDirectory => { TagTable => 'Image::ExifTool::Canon::SensorInfo' },
153             },
154             # this tag has only be verified for the 10D in CRW files, but the D30 and D60
155             # also produce CRW images and have CustomFunction information in their JPEG's
156             0x1033 => [
157             {
158             Name => 'CustomFunctions10D',
159             Condition => '$self->{Model} =~ /EOS 10D/',
160             SubDirectory => {
161             Validate => 'Image::ExifTool::Canon::Validate($dirData,$subdirStart,$size)',
162             TagTable => 'Image::ExifTool::CanonCustom::Functions10D',
163             },
164             },
165             {
166             Name => 'CustomFunctionsD30',
167             Condition => '$self->{Model} =~ /EOS D30\b/',
168             SubDirectory => {
169             Validate => 'Image::ExifTool::Canon::Validate($dirData,$subdirStart,$size)',
170             TagTable => 'Image::ExifTool::CanonCustom::FunctionsD30',
171             },
172             },
173             {
174             Name => 'CustomFunctionsD60',
175             Condition => '$self->{Model} =~ /EOS D60\b/',
176             SubDirectory => {
177             # the stored size in the D60 apparently doesn't include the size word:
178             Validate => 'Image::ExifTool::Canon::Validate($dirData,$subdirStart,$size-2,$size)',
179             # (D60 custom functions are basically the same as D30)
180             TagTable => 'Image::ExifTool::CanonCustom::FunctionsD30',
181             },
182             },
183             {
184             Name => 'CustomFunctionsUnknown',
185             SubDirectory => {
186             Validate => 'Image::ExifTool::Canon::Validate($dirData,$subdirStart,$size)',
187             TagTable => 'Image::ExifTool::CanonCustom::FuncsUnknown',
188             },
189             },
190             ],
191             0x1038 => {
192             Name => 'CanonAFInfo',
193             Writable => 0,
194             SubDirectory => { TagTable => 'Image::ExifTool::Canon::AFInfo' },
195             },
196             0x1093 => {
197             Name => 'CanonFileInfo',
198             SubDirectory => {
199             Validate => 'Image::ExifTool::Canon::Validate($dirData,$subdirStart,$size)',
200             TagTable => 'Image::ExifTool::Canon::FileInfo',
201             },
202             },
203             0x10a9 => {
204             Name => 'ColorBalance',
205             Writable => 0,
206             SubDirectory => { TagTable => 'Image::ExifTool::Canon::ColorBalance' },
207             },
208             0x10b5 => { #PH
209             Name => 'RawJpgInfo',
210             SubDirectory => {
211             Validate => 'Image::ExifTool::Canon::Validate($dirData,$subdirStart,$size)',
212             TagTable => 'Image::ExifTool::CanonRaw::RawJpgInfo',
213             },
214             },
215             0x10ae => {
216             Name => 'ColorTemperature',
217             Writable => 'int16u',
218             },
219             0x10b4 => {
220             Name => 'ColorSpace',
221             Writable => 'int16u',
222             PrintConv => {
223             1 => 'sRGB',
224             2 => 'Adobe RGB',
225             0xffff => 'Uncalibrated',
226             },
227             },
228             0x1803 => { #3
229             Name => 'ImageFormat',
230             Writable => 0,
231             SubDirectory => { TagTable => 'Image::ExifTool::CanonRaw::ImageFormat' },
232             },
233             0x1804 => { Name => 'RecordID', Writable => 'int32u' }, #3
234             0x1806 => { #3
235             Name => 'SelfTimerTime',
236             Writable => 'int32u',
237             ValueConv => '$val / 1000',
238             ValueConvInv => '$val * 1000',
239             PrintConv => '"$val s"',
240             PrintConvInv => '$val=~s/\s*s.*//;$val',
241             },
242             0x1807 => {
243             Name => 'TargetDistanceSetting',
244             Format => 'float',
245             PrintConv => '"$val mm"',
246             PrintConvInv => '$val=~s/\s*mm$//;$val',
247             },
248             0x180b => [
249             {
250             # D30
251             Name => 'SerialNumber',
252             Condition => '$$self{Model} =~ /EOS D30\b/',
253             Writable => 'int32u',
254             PrintConv => 'sprintf("%x-%.5d",$val>>16,$val&0xffff)',
255             PrintConvInv => '$val=~/(.*)-(\d+)/ ? (hex($1)<<16)+$2 : undef',
256             },
257             {
258             # all EOS models (D30, 10D, 300D)
259             Name => 'SerialNumber',
260             Condition => '$$self{Model} =~ /EOS/',
261             Writable => 'int32u',
262             PrintConv => 'sprintf("%.10d",$val)',
263             PrintConvInv => '$val',
264             },
265             {
266             # this is not SerialNumber for PowerShot models (but what is it?) - PH
267             Name => 'UnknownNumber',
268             Unknown => 1,
269             },
270             ],
271             0x180e => {
272             Name => 'TimeStamp',
273             Writable => 0,
274             SubDirectory => {
275             TagTable => 'Image::ExifTool::CanonRaw::TimeStamp',
276             },
277             },
278             0x1810 => {
279             Name => 'ImageInfo',
280             Writable => 0,
281             SubDirectory => {
282             TagTable => 'Image::ExifTool::CanonRaw::ImageInfo',
283             },
284             },
285             0x1813 => { #3
286             Name => 'FlashInfo',
287             Writable => 0,
288             SubDirectory => {
289             TagTable => 'Image::ExifTool::CanonRaw::FlashInfo',
290             },
291             },
292             0x1814 => { #3
293             Name => 'MeasuredEV',
294             Notes => q{
295             this is the Canon name for what could better be called MeasuredLV, and
296             should be close to the calculated LightValue for a proper exposure with most
297             models
298             },
299             Format => 'float',
300             ValueConv => '$val + 5',
301             ValueConvInv => '$val - 5',
302             },
303             0x1817 => {
304             Name => 'FileNumber',
305             Writable => 'int32u',
306             Groups => { 2 => 'Image' },
307             PrintConv => '$_=$val;s/(\d+)(\d{4})/$1-$2/;$_',
308             PrintConvInv => '$_=$val;s/-//;$_',
309             },
310             0x1818 => { #3
311             Name => 'ExposureInfo',
312             Groups => { 1 => 'CIFF' }, # (only so CIFF shows up in group lists)
313             Writable => 0,
314             SubDirectory => { TagTable => 'Image::ExifTool::CanonRaw::ExposureInfo' },
315             },
316             0x1834 => { #PH
317             Name => 'CanonModelID',
318             Writable => 'int32u',
319             PrintHex => 1,
320             Notes => q{
321             this is the complete list of model ID numbers, but note that many of these
322             models do not produce CRW images
323             },
324             SeparateTable => 'Canon CanonModelID',
325             PrintConv => \%Image::ExifTool::Canon::canonModelID,
326             },
327             0x1835 => {
328             Name => 'DecoderTable',
329             Writable => 0,
330             SubDirectory => { TagTable => 'Image::ExifTool::CanonRaw::DecoderTable' },
331             },
332             0x183b => { #PH
333             # display format for serial number
334             Name => 'SerialNumberFormat',
335             Writable => 'int32u',
336             PrintHex => 1,
337             PrintConv => {
338             0x90000000 => 'Format 1',
339             0xa0000000 => 'Format 2',
340             },
341             },
342             0x2005 => {
343             Name => 'RawData',
344             Writable => 0,
345             Binary => 1,
346             },
347             0x2007 => {
348             Name => 'JpgFromRaw',
349             Groups => { 2 => 'Preview' },
350             Writable => 'resize', # 'resize' allows this value to change size
351             Permanent => 0,
352             RawConv => '$self->ValidateImage(\$val,$tag)',
353             },
354             0x2008 => {
355             Name => 'ThumbnailImage',
356             Groups => { 2 => 'Preview' },
357             Writable => 'resize', # 'resize' allows this value to change size
358             WriteCheck => '$self->CheckImage(\$val)',
359             Permanent => 0,
360             RawConv => '$self->ValidateImage(\$val,$tag)',
361             },
362             # the following entries are subdirectories
363             # (any 0x28 and 0x30 tag types are handled automatically by the decoding logic)
364             0x2804 => {
365             Name => 'ImageDescription',
366             SubDirectory => { },
367             Writable => 0,
368             },
369             0x2807 => { #3
370             Name => 'CameraObject',
371             SubDirectory => { },
372             Writable => 0,
373             },
374             0x3002 => { #3
375             Name => 'ShootingRecord',
376             SubDirectory => { },
377             Writable => 0,
378             },
379             0x3003 => { #3
380             Name => 'MeasuredInfo',
381             SubDirectory => { },
382             Writable => 0,
383             },
384             0x3004 => { #3
385             Name => 'CameraSpecification',
386             SubDirectory => { },
387             Writable => 0,
388             },
389             0x300a => { #3
390             Name => 'ImageProps',
391             SubDirectory => { },
392             Writable => 0,
393             },
394             0x300b => {
395             Name => 'ExifInformation',
396             SubDirectory => { },
397             Writable => 0,
398             },
399             );
400              
401             # Canon binary data blocks
402             %Image::ExifTool::CanonRaw::MakeModel = (
403             PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
404             WRITE_PROC => \&Image::ExifTool::WriteBinaryData,
405             CHECK_PROC => \&Image::ExifTool::CheckBinaryData,
406             DATAMEMBER => [ 0, 6 ], # indices of data members to extract when writing
407             WRITABLE => 1,
408             FORMAT => 'string',
409             GROUPS => { 0 => 'MakerNotes', 2 => 'Camera' },
410             # (can't specify a first entry because this isn't
411             # a simple binary table with fixed offsets)
412             0 => {
413             Name => 'Make',
414             Format => 'string[6]', # "Canon\0"
415             DataMember => 'Make',
416             RawConv => '$self->{Make} = $val',
417             },
418             6 => {
419             Name => 'Model',
420             Format => 'string', # no size = to the end of the data
421             Description => 'Camera Model Name',
422             DataMember => 'Model',
423             RawConv => '$self->{Model} = $val',
424             },
425             );
426              
427             %Image::ExifTool::CanonRaw::TimeStamp = (
428             PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
429             WRITE_PROC => \&Image::ExifTool::WriteBinaryData,
430             CHECK_PROC => \&Image::ExifTool::CheckBinaryData,
431             WRITABLE => 1,
432             FORMAT => 'int32u',
433             FIRST_ENTRY => 0,
434             GROUPS => { 0 => 'MakerNotes', 2 => 'Time' },
435             0 => {
436             Name => 'DateTimeOriginal',
437             Description => 'Date/Time Original',
438             Shift => 'Time',
439             ValueConv => 'ConvertUnixTime($val)',
440             ValueConvInv => 'GetUnixTime($val)',
441             PrintConv => '$self->ConvertDateTime($val)',
442             PrintConvInv => '$self->InverseDateTime($val)',
443             },
444             1 => { #3
445             Name => 'TimeZoneCode',
446             Format => 'int32s',
447             ValueConv => '$val / 3600',
448             ValueConvInv => '$val * 3600',
449             },
450             2 => { #3
451             Name => 'TimeZoneInfo',
452             Notes => 'set to 0x80000000 if TimeZoneCode is valid',
453             },
454             );
455              
456             %Image::ExifTool::CanonRaw::ImageFormat = (
457             PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
458             WRITE_PROC => \&Image::ExifTool::WriteBinaryData,
459             CHECK_PROC => \&Image::ExifTool::CheckBinaryData,
460             WRITABLE => 1,
461             FORMAT => 'int32u',
462             FIRST_ENTRY => 0,
463             GROUPS => { 0 => 'MakerNotes', 2 => 'Image' },
464             0 => {
465             Name => 'FileFormat',
466             Flags => 'PrintHex',
467             PrintConv => {
468             0x00010000 => 'JPEG (lossy)',
469             0x00010002 => 'JPEG (non-quantization)',
470             0x00010003 => 'JPEG (lossy/non-quantization toggled)',
471             0x00020001 => 'CRW',
472             },
473             },
474             1 => {
475             Name => 'TargetCompressionRatio',
476             Format => 'float',
477             },
478             );
479              
480             %Image::ExifTool::CanonRaw::RawJpgInfo = (
481             PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
482             WRITE_PROC => \&Image::ExifTool::WriteBinaryData,
483             CHECK_PROC => \&Image::ExifTool::CheckBinaryData,
484             WRITABLE => 1,
485             FORMAT => 'int16u',
486             FIRST_ENTRY => 1,
487             GROUPS => { 0 => 'MakerNotes', 2 => 'Image' },
488             # 0 => 'RawJpgInfoSize',
489             1 => { #PH
490             Name => 'RawJpgQuality',
491             PrintConv => {
492             1 => 'Economy',
493             2 => 'Normal',
494             3 => 'Fine',
495             5 => 'Superfine',
496             },
497             },
498             2 => { #PH
499             Name => 'RawJpgSize',
500             PrintConv => {
501             0 => 'Large',
502             1 => 'Medium',
503             2 => 'Small',
504             },
505             },
506             3 => 'RawJpgWidth', #PH
507             4 => 'RawJpgHeight', #PH
508             );
509              
510             %Image::ExifTool::CanonRaw::FlashInfo = (
511             PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
512             WRITE_PROC => \&Image::ExifTool::WriteBinaryData,
513             CHECK_PROC => \&Image::ExifTool::CheckBinaryData,
514             WRITABLE => 1,
515             FORMAT => 'float',
516             FIRST_ENTRY => 0,
517             GROUPS => { 0 => 'MakerNotes', 2 => 'Image' },
518             0 => 'FlashGuideNumber',
519             1 => 'FlashThreshold',
520             );
521              
522             %Image::ExifTool::CanonRaw::ExposureInfo = (
523             PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
524             WRITE_PROC => \&Image::ExifTool::WriteBinaryData,
525             CHECK_PROC => \&Image::ExifTool::CheckBinaryData,
526             WRITABLE => 1,
527             FORMAT => 'float',
528             FIRST_ENTRY => 0,
529             GROUPS => { 0 => 'MakerNotes', 2 => 'Image' },
530             0 => 'ExposureCompensation',
531             1 => {
532             Name => 'ShutterSpeedValue',
533             ValueConv => 'abs($val)<100 ? 1/(2**$val) : 0',
534             ValueConvInv => '$val>0 ? -log($val)/log(2) : -100',
535             PrintConv => 'Image::ExifTool::Exif::PrintExposureTime($val)',
536             PrintConvInv => 'Image::ExifTool::Exif::ConvertFraction($val)',
537             },
538             2 => {
539             Name => 'ApertureValue',
540             ValueConv => '2 ** ($val / 2)',
541             ValueConvInv => '$val>0 ? 2*log($val)/log(2) : 0',
542             PrintConv => 'sprintf("%.1f",$val)',
543             PrintConvInv => '$val',
544             },
545             );
546              
547             %Image::ExifTool::CanonRaw::ImageInfo = (
548             PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
549             WRITE_PROC => \&Image::ExifTool::WriteBinaryData,
550             CHECK_PROC => \&Image::ExifTool::CheckBinaryData,
551             FORMAT => 'int32u',
552             FIRST_ENTRY => 0,
553             GROUPS => { 0 => 'MakerNotes', 2 => 'Image' },
554             # Note: Don't make these writable (except rotation) because it confuses
555             # Canon decoding software if the are changed
556             0 => 'ImageWidth', #3
557             1 => 'ImageHeight', #3
558             2 => { #3
559             Name => 'PixelAspectRatio',
560             Format => 'float',
561             },
562             3 => {
563             Name => 'Rotation',
564             Format => 'int32s',
565             Writable => 'int32s',
566             },
567             4 => 'ComponentBitDepth', #3
568             5 => 'ColorBitDepth', #3
569             6 => 'ColorBW', #3
570             );
571              
572             # ref 4
573             %Image::ExifTool::CanonRaw::DecoderTable = (
574             PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
575             WRITE_PROC => \&Image::ExifTool::WriteBinaryData,
576             CHECK_PROC => \&Image::ExifTool::CheckBinaryData,
577             GROUPS => { 0 => 'MakerNotes', 2 => 'Camera' },
578             FORMAT => 'int32u',
579             FIRST_ENTRY => 0,
580             0 => 'DecoderTableNumber',
581             2 => 'CompressedDataOffset',
582             3 => 'CompressedDataLength',
583             );
584              
585             # ref 1/4
586             %Image::ExifTool::CanonRaw::WhiteSample = (
587             PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
588             WRITE_PROC => \&Image::ExifTool::WriteBinaryData,
589             CHECK_PROC => \&Image::ExifTool::CheckBinaryData,
590             GROUPS => { 0 => 'MakerNotes', 2 => 'Camera' },
591             FORMAT => 'int16u',
592             FIRST_ENTRY => 1,
593             1 => 'WhiteSampleWidth',
594             2 => 'WhiteSampleHeight',
595             3 => 'WhiteSampleLeftBorder',
596             4 => 'WhiteSampleTopBorder',
597             5 => 'WhiteSampleBits',
598             # this is followed by the encrypted white sample values (ref 1)
599             );
600              
601             #------------------------------------------------------------------------------
602             # AutoLoad our writer routines when necessary
603             #
604             sub AUTOLOAD
605             {
606 11     11   81 return Image::ExifTool::DoAutoLoad($AUTOLOAD, @_);
607             }
608              
609             #------------------------------------------------------------------------------
610             # Process Raw file directory
611             # Inputs: 0) ExifTool object reference
612             # 1) directory information reference, 2) tag table reference
613             # Returns: 1 on success
614             sub ProcessCanonRaw($$$)
615             {
616 182     182 0 423 my ($et, $dirInfo, $rawTagTable) = @_;
617 182         358 my $blockStart = $$dirInfo{DirStart};
618 182         405 my $blockSize = $$dirInfo{DirLen};
619 182 50       522 my $raf = $$dirInfo{RAF} or return 0;
620 182         289 my $buff;
621 182         536 my $verbose = $et->Options('Verbose');
622 182         515 my $buildMakerNotes = $et->Options('MakerNotes');
623              
624             # 4 bytes at end of block give directory position within block
625 182 50       677 $raf->Seek($blockStart+$blockSize-4, 0) or return 0;
626 182 50       600 $raf->Read($buff, 4) == 4 or return 0;
627 182         581 my $dirOffset = Get32u(\$buff,0) + $blockStart;
628             # avoid infinite recursion
629 182 100       642 $$et{ProcessedCanonRaw} or $$et{ProcessedCanonRaw} = { };
630 182 50       558 if ($$et{ProcessedCanonRaw}{$dirOffset}) {
631 0         0 $et->Warn("Not processing double-referenced $$dirInfo{DirName} directory");
632 0         0 return 0;
633             }
634 182         555 $$et{ProcessedCanonRaw}{$dirOffset} = 1;
635 182 50       478 $raf->Seek($dirOffset, 0) or return 0;
636 182 50       538 $raf->Read($buff, 2) == 2 or return 0;
637 182         612 my $entries = Get16u(\$buff,0); # get number of entries in directory
638             # read the directory (10 bytes per entry)
639 182 50       600 $raf->Read($buff, 10 * $entries) == 10 * $entries or return 0;
640              
641 182 100       488 $verbose and $et->VerboseDir('CIFF', $entries);
642 182         301 my $index;
643 182         528 for ($index=0; $index<$entries; ++$index) {
644 1008         1749 my $pt = 10 * $index;
645 1008         2505 my $tag = Get16u(\$buff, $pt);
646 1008         2731 my $size = Get32u(\$buff, $pt+2);
647 1008         2582 my $valuePtr = Get32u(\$buff, $pt+6);
648 1008         1997 my $ptr = $valuePtr + $blockStart; # all pointers relative to block start
649 1008 50       2285 if ($tag & 0x8000) {
650 0         0 $et->Warn('Bad CRW directory entry');
651 0         0 return 1;
652             }
653 1008         1545 my $tagID = $tag & 0x3fff; # get tag ID
654 1008         1693 my $tagType = ($tag >> 8) & 0x38; # get tag type
655 1008         1495 my $valueInDir = ($tag & 0x4000); # flag for value in directory
656 1008         2797 my $tagInfo = $et->GetTagInfo($rawTagTable, $tagID);
657 1008 100 100     4387 if (($tagType==0x28 or $tagType==0x30) and not $valueInDir) {
      66        
658             # this type of tag specifies a raw subdirectory
659 156         250 my $name;
660 156 50       548 $tagInfo and $name = $$tagInfo{Name};
661 156 50       357 $name or $name = sprintf("CanonRaw_0x%.4x", $tag);
662             my %subdirInfo = (
663             DirName => $name,
664             DataLen => 0,
665             DirStart => $ptr,
666             DirLen => $size,
667             Nesting => $$dirInfo{Nesting} + 1,
668             RAF => $raf,
669             Parent => $$dirInfo{DirName},
670 156         948 );
671 156 100       427 if ($verbose) {
672 6         22 my $fakeInfo = { Name => $name, SubDirectory => { } };
673 6         24 $et->VerboseInfo($tagID, $fakeInfo,
674             'Index' => $index,
675             'Size' => $size,
676             'Start' => $ptr,
677             );
678             }
679 156         577 $et->ProcessDirectory(\%subdirInfo, $rawTagTable);
680 156         654 next;
681             }
682 852         1435 my ($valueDataPos, $count, $subdir);
683 852         1835 my $format = $crwTagFormat{$tagType};
684 852 100       1770 if ($tagInfo) {
685 684         1384 $subdir = $$tagInfo{SubDirectory};
686 684 100       1680 $format = $$tagInfo{Format} if $$tagInfo{Format};
687 684         1250 $count = $$tagInfo{Count};
688             }
689             # get value data
690 852         1320 my ($value, $delRawConv);
691 852 100       1687 if ($valueInDir) { # is the value data in the directory?
692             # this type of tag stores the value in the 'size' and 'ptr' fields
693 381         683 $valueDataPos = $dirOffset + $pt + 4; # (remember, +2 for the entry count)
694 381         613 $size = 8;
695 381         875 $value = substr($buff, $pt+2, $size);
696             # set count to 1 by default for normal values in directory
697 381 100 66     2413 $count = 1 if not defined $count and $format and
      100        
      100        
698             $format ne 'string' and not $subdir;
699             } else {
700 471         800 $valueDataPos = $ptr;
701 471 100 33     1386 if ($size <= 512 or ($verbose > 2 and $size <= 65536)
      66        
      33        
      66        
      33        
702             or ($tagInfo and ($$tagInfo{SubDirectory}
703             or grep(/^$$tagInfo{Name}$/i, $et->GetRequestedTags()) )))
704             {
705             # read value if size is small or specifically requested
706             # or if this is a SubDirectory
707 457 50 33     1374 unless ($raf->Seek($ptr, 0) and $raf->Read($value, $size) == $size) {
708 0         0 $et->Warn(sprintf("Error reading %d bytes from 0x%x",$size,$ptr));
709 0         0 next;
710             }
711             } else {
712 14         46 $value = "Binary data $size bytes";
713 14 100       42 if ($tagInfo) {
714 2 50 33     8 if ($et->Options('Binary') or $verbose) {
715             # read the value anyway
716 2 50 33     8 unless ($raf->Seek($ptr, 0) and $raf->Read($value, $size) == $size) {
717 0         0 $et->Warn(sprintf("Error reading %d bytes from 0x%x",$size,$ptr));
718 0         0 next;
719             }
720             }
721             # force this to be a binary (scalar reference)
722 2         10 $$tagInfo{RawConv} = '\$val';
723 2         5 $delRawConv = 1;
724             }
725 14         30 $size = length $value;
726 14         28 undef $format;
727             }
728             }
729             # set count from tagInfo count if necessary
730 852 100 100     3263 if ($format and not $count) {
731             # set count according to format and size
732 540         1241 my $fnum = $Image::ExifTool::Exif::formatNumber{$format};
733 540         1059 my $fsiz = $Image::ExifTool::Exif::formatSize[$fnum];
734 540         1305 $count = int($size / $fsiz);
735             }
736 852 100       1800 if ($verbose) {
737 43         88 my $val = $value;
738 43 100       165 $format and $val = ReadValue(\$val, 0, $format, $count, $size);
739 43         188 $et->VerboseInfo($tagID, $tagInfo,
740             Table => $rawTagTable,
741             Index => $index,
742             Value => $val,
743             DataPt => \$value,
744             DataPos => $valueDataPos,
745             Size => $size,
746             Format => $format,
747             Count => $count,
748             );
749             }
750 852 100       1761 if ($buildMakerNotes) {
751             # build maker notes information if requested
752 188         611 BuildMakerNotes($et, $tagID, $tagInfo, \$value, $format, $count);
753             }
754 852 100       2060 next unless defined $tagInfo;
755              
756 684 100       1392 if ($subdir) {
757 224         567 my $name = $$tagInfo{Name};
758 224         351 my $newTagTable;
759 224 50       695 if ($$subdir{TagTable}) {
760 224         714 $newTagTable = GetTagTable($$subdir{TagTable});
761 224 50       604 unless ($newTagTable) {
762 0         0 warn "Unknown tag table $$subdir{TagTable}\n";
763 0         0 next;
764             }
765             } else {
766 0         0 warn "Must specify TagTable for SubDirectory $name\n";
767 0         0 next;
768             }
769 224         416 my $subdirStart = 0;
770             #### eval Start ()
771 224 50       574 $subdirStart = eval $$subdir{Start} if $$subdir{Start};
772 224         383 my $dirData = \$value;
773             my %subdirInfo = (
774             Name => $name,
775             DataPt => $dirData,
776             DataLen => $size,
777             DataPos => $valueDataPos,
778             DirStart => $subdirStart,
779             DirLen => $size - $subdirStart,
780             Nesting => $$dirInfo{Nesting} + 1,
781             RAF => $raf,
782             DirName => $name,
783             Parent => $$dirInfo{DirName},
784 224         2064 );
785             #### eval Validate ($dirData, $subdirStart, $size)
786 224 50 66     1920 if (defined $$subdir{Validate} and not eval $$subdir{Validate}) {
787 0         0 $et->Warn("Invalid $name data");
788             } else {
789 224         1151 $et->ProcessDirectory(\%subdirInfo, $newTagTable, $$subdir{ProcessProc});
790             }
791             } else {
792             # convert to specified format if necessary
793 460 100       1730 $format and $value = ReadValue(\$value, 0, $format, $count, $size);
794             # save the information
795 460         1736 $et->FoundTag($tagInfo, $value);
796 460 100       1757 delete $$tagInfo{RawConv} if $delRawConv;
797             }
798             }
799 182         645 return 1;
800             }
801              
802             #------------------------------------------------------------------------------
803             # get information from raw file
804             # Inputs: 0) ExifTool object reference, 1) dirInfo reference
805             # Returns: 1 if this was a valid Canon RAW file
806             sub ProcessCRW($$)
807             {
808 26     26 0 101 my ($et, $dirInfo) = @_;
809 26         67 my ($buff, $sig);
810 26         81 my $raf = $$dirInfo{RAF};
811 26         127 my $buildMakerNotes = $et->Options('MakerNotes');
812              
813 26 50       149 $raf->Read($buff,2) == 2 or return 0;
814 26 50       125 SetByteOrder($buff) or return 0;
815 26 50       160 $raf->Read($buff,4) == 4 or return 0;
816 26 50       114 $raf->Read($sig,8) == 8 or return 0; # get file signature
817 26 50       285 $sig =~ /^HEAP(CCDR|JPGM)/ or return 0; # validate signature
818 26         143 my $hlen = Get32u(\$buff, 0);
819              
820 26 50       145 $raf->Seek(0, 2) or return 0; # seek to end of file
821 26 50       135 my $filesize = $raf->Tell() or return 0;
822              
823             # initialize maker note data if building maker notes
824 26 100       147 $buildMakerNotes and InitMakerNotes($et);
825              
826             # set the FileType tag unless already done (eg. APP0 CIFF record in JPEG image)
827 26         161 $et->SetFileType();
828              
829             # build directory information for main raw directory
830 26         262 my %dirInfo = (
831             DataLen => 0,
832             DirStart => $hlen,
833             DirLen => $filesize - $hlen,
834             Nesting => 0,
835             RAF => $raf,
836             Parent => 'CRW',
837             );
838              
839             # process the raw directory
840 26         112 my $rawTagTable = GetTagTable('Image::ExifTool::CanonRaw::Main');
841 26         127 my $oldIndent = $$et{INDENT};
842 26         113 $$et{INDENT} .= '| ';
843 26 50       143 unless (ProcessCanonRaw($et, \%dirInfo, $rawTagTable)) {
844 0         0 $et->Warn('CRW file format error');
845             }
846 26         114 $$et{INDENT} = $oldIndent;
847              
848             # finish building maker notes if necessary
849 26 100       124 $buildMakerNotes and SaveMakerNotes($et);
850              
851             # process trailers if they exist in CRW file (not in CIFF information!)
852 26 100       145 if ($$et{FILE_TYPE} eq 'CRW') {
853 7         40 my $trailInfo = Image::ExifTool::IdentifyTrailer($raf);
854 7 50       74 $et->ProcessTrailers($trailInfo) if $trailInfo;
855             }
856              
857 26         152 return 1;
858             }
859              
860             1; # end
861              
862             __END__