File Coverage

blib/lib/Image/ExifTool/CanonRaw.pm
Criterion Covered Total %
statement 132 147 89.8
branch 69 98 70.4
condition 29 48 60.4
subroutine 8 8 100.0
pod 0 2 0.0
total 238 303 78.5


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   8823 use strict;
  20         46  
  20         1130  
19 20     20   133 use vars qw($VERSION $AUTOLOAD %crwTagFormat);
  20         43  
  20         1602  
20 20     20   153 use Image::ExifTool qw(:DataAccess :Utils);
  20         227  
  20         6095  
21 20     20   1745 use Image::ExifTool::Exif;
  20         52  
  20         1230  
22 20     20   19852 use Image::ExifTool::Canon;
  20         91  
  20         70931  
23              
24             $VERSION = '1.62';
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 => 1,
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             # (followed by the encrypted white sample values, ref 1)
599             # BlackLevels seem valid for D30 and D60, but not sure about PowerShot models
600             0x37 => { Name => 'BlackLevels', Format => 'int16u[4]' }, #github387
601             );
602              
603             #------------------------------------------------------------------------------
604             # AutoLoad our writer routines when necessary
605             #
606             sub AUTOLOAD
607             {
608 11     11   92 return Image::ExifTool::DoAutoLoad($AUTOLOAD, @_);
609             }
610              
611             #------------------------------------------------------------------------------
612             # Process Raw file directory
613             # Inputs: 0) ExifTool object reference
614             # 1) directory information reference, 2) tag table reference
615             # Returns: 1 on success
616             sub ProcessCanonRaw($$$)
617             {
618 182     182 0 437 my ($et, $dirInfo, $rawTagTable) = @_;
619 182         447 my $blockStart = $$dirInfo{DirStart};
620 182         451 my $blockSize = $$dirInfo{DirLen};
621 182 50       588 my $raf = $$dirInfo{RAF} or return 0;
622 182         338 my $buff;
623 182         695 my $verbose = $et->Options('Verbose');
624 182         506 my $buildMakerNotes = $et->Options('MakerNotes');
625              
626             # 4 bytes at end of block give directory position within block
627 182 50       866 $raf->Seek($blockStart+$blockSize-4, 0) or return 0;
628 182 50       667 $raf->Read($buff, 4) == 4 or return 0;
629 182         669 my $dirOffset = Get32u(\$buff,0) + $blockStart;
630             # avoid infinite recursion
631 182 100       787 $$et{ProcessedCanonRaw} or $$et{ProcessedCanonRaw} = { };
632 182 50       664 if ($$et{ProcessedCanonRaw}{$dirOffset}) {
633 0         0 $et->Warn("Not processing double-referenced $$dirInfo{DirName} directory");
634 0         0 return 0;
635             }
636 182         626 $$et{ProcessedCanonRaw}{$dirOffset} = 1;
637 182 50       579 $raf->Seek($dirOffset, 0) or return 0;
638 182 50       551 $raf->Read($buff, 2) == 2 or return 0;
639 182         647 my $entries = Get16u(\$buff,0); # get number of entries in directory
640             # read the directory (10 bytes per entry)
641 182 50       651 $raf->Read($buff, 10 * $entries) == 10 * $entries or return 0;
642              
643 182 100       481 $verbose and $et->VerboseDir('CIFF', $entries);
644 182         297 my $index;
645 182         565 for ($index=0; $index<$entries; ++$index) {
646 1008         1931 my $pt = 10 * $index;
647 1008         3059 my $tag = Get16u(\$buff, $pt);
648 1008         3012 my $size = Get32u(\$buff, $pt+2);
649 1008         2779 my $valuePtr = Get32u(\$buff, $pt+6);
650 1008         1950 my $ptr = $valuePtr + $blockStart; # all pointers relative to block start
651 1008 50       2741 if ($tag & 0x8000) {
652 0         0 $et->Warn('Bad CRW directory entry');
653 0         0 return 1;
654             }
655 1008         1807 my $tagID = $tag & 0x3fff; # get tag ID
656 1008         1840 my $tagType = ($tag >> 8) & 0x38; # get tag type
657 1008         1587 my $valueInDir = ($tag & 0x4000); # flag for value in directory
658 1008         3512 my $tagInfo = $et->GetTagInfo($rawTagTable, $tagID);
659 1008 100 100     5234 if (($tagType==0x28 or $tagType==0x30) and not $valueInDir) {
      66        
660             # this type of tag specifies a raw subdirectory
661 156         261 my $name;
662 156 50       566 $tagInfo and $name = $$tagInfo{Name};
663 156 50       407 $name or $name = sprintf("CanonRaw_0x%.4x", $tag);
664             my %subdirInfo = (
665             DirName => $name,
666             DataLen => 0,
667             DirStart => $ptr,
668             DirLen => $size,
669             Nesting => $$dirInfo{Nesting} + 1,
670             RAF => $raf,
671             Parent => $$dirInfo{DirName},
672 156         1268 );
673 156 100       393 if ($verbose) {
674 6         28 my $fakeInfo = { Name => $name, SubDirectory => { } };
675 6         35 $et->VerboseInfo($tagID, $fakeInfo,
676             'Index' => $index,
677             'Size' => $size,
678             'Start' => $ptr,
679             );
680             }
681 156         675 $et->ProcessDirectory(\%subdirInfo, $rawTagTable);
682 156         866 next;
683             }
684 852         1474 my ($valueDataPos, $count, $subdir);
685 852         2297 my $format = $crwTagFormat{$tagType};
686 852 100       2057 if ($tagInfo) {
687 684         1363 $subdir = $$tagInfo{SubDirectory};
688 684 100       1898 $format = $$tagInfo{Format} if $$tagInfo{Format};
689 684         1354 $count = $$tagInfo{Count};
690             }
691             # get value data
692 852         1467 my ($value, $delRawConv);
693 852 100       1793 if ($valueInDir) { # is the value data in the directory?
694             # this type of tag stores the value in the 'size' and 'ptr' fields
695 381         751 $valueDataPos = $dirOffset + $pt + 4; # (remember, +2 for the entry count)
696 381         664 $size = 8;
697 381         990 $value = substr($buff, $pt+2, $size);
698             # set count to 1 by default for normal values in directory
699 381 100 66     2765 $count = 1 if not defined $count and $format and
      100        
      100        
700             $format ne 'string' and not $subdir;
701             } else {
702 471         801 $valueDataPos = $ptr;
703             # do hash of image data if requested
704 471 50 33     1513 if ($$et{ImageDataHash} and $tagID == 0x2005) {
705 0 0       0 $raf->Seek($ptr, 0) and $et->ImageDataHash($raf, $size, 'raw');
706             }
707 471 100 33     1682 if ($size <= 512 or ($verbose > 2 and $size <= 65536)
      66        
      33        
      66        
      33        
708             or ($tagInfo and ($$tagInfo{SubDirectory}
709             or grep(/^$$tagInfo{Name}$/i, $et->GetRequestedTags()) )))
710             {
711             # read value if size is small or specifically requested
712             # or if this is a SubDirectory
713 457 50 33     1901 unless ($raf->Seek($ptr, 0) and $raf->Read($value, $size) == $size) {
714 0         0 $et->Warn(sprintf("Error reading %d bytes from 0x%x",$size,$ptr));
715 0         0 next;
716             }
717             } else {
718 14         53 $value = "Binary data $size bytes";
719 14 100       53 if ($tagInfo) {
720 2 50 33     13 if ($et->Options('Binary') or $verbose) {
721             # read the value anyway
722 2 50 33     16 unless ($raf->Seek($ptr, 0) and $raf->Read($value, $size) == $size) {
723 0         0 $et->Warn(sprintf("Error reading %d bytes from 0x%x",$size,$ptr));
724 0         0 next;
725             }
726             }
727             # force this to be a binary (scalar reference)
728 2         11 $$tagInfo{RawConv} = '\$val';
729 2         6 $delRawConv = 1;
730             }
731 14         32 $size = length $value;
732 14         32 undef $format;
733             }
734             }
735             # set count from tagInfo count if necessary
736 852 100 100     3280 if ($format and not $count) {
737             # set count according to format and size
738 540         1671 my $fnum = $Image::ExifTool::Exif::formatNumber{$format};
739 540         1120 my $fsiz = $Image::ExifTool::Exif::formatSize[$fnum];
740 540         1406 $count = int($size / $fsiz);
741             }
742 852 100       1924 if ($verbose) {
743 43         99 my $val = $value;
744 43 100       232 $format and $val = ReadValue(\$val, 0, $format, $count, $size);
745 43         373 $et->VerboseInfo($tagID, $tagInfo,
746             Table => $rawTagTable,
747             Index => $index,
748             Value => $val,
749             DataPt => \$value,
750             DataPos => $valueDataPos,
751             Size => $size,
752             Format => $format,
753             Count => $count,
754             );
755             }
756 852 100       1811 if ($buildMakerNotes) {
757             # build maker notes information if requested
758 188         699 BuildMakerNotes($et, $tagID, $tagInfo, \$value, $format, $count);
759             }
760 852 100       2498 next unless defined $tagInfo;
761              
762 684 100       1557 if ($subdir) {
763 224         649 my $name = $$tagInfo{Name};
764 224         359 my $newTagTable;
765 224 50       683 if ($$subdir{TagTable}) {
766 224         960 $newTagTable = GetTagTable($$subdir{TagTable});
767 224 50       593 unless ($newTagTable) {
768 0         0 warn "Unknown tag table $$subdir{TagTable}\n";
769 0         0 next;
770             }
771             } else {
772 0         0 warn "Must specify TagTable for SubDirectory $name\n";
773 0         0 next;
774             }
775 224         474 my $subdirStart = 0;
776             #### eval Start ()
777 224 50       686 $subdirStart = eval $$subdir{Start} if $$subdir{Start};
778 224         424 my $dirData = \$value;
779             my %subdirInfo = (
780             Name => $name,
781             DataPt => $dirData,
782             DataLen => $size,
783             DataPos => $valueDataPos,
784             DirStart => $subdirStart,
785             DirLen => $size - $subdirStart,
786             Nesting => $$dirInfo{Nesting} + 1,
787             RAF => $raf,
788             DirName => $name,
789             Parent => $$dirInfo{DirName},
790 224         2721 );
791             #### eval Validate ($dirData, $subdirStart, $size)
792 224 50 66     2241 if (defined $$subdir{Validate} and not eval $$subdir{Validate}) {
793 0         0 $et->Warn("Invalid $name data");
794             } else {
795 224         1559 $et->ProcessDirectory(\%subdirInfo, $newTagTable, $$subdir{ProcessProc});
796             }
797             } else {
798             # convert to specified format if necessary
799 460 100       1901 $format and $value = ReadValue(\$value, 0, $format, $count, $size);
800             # save the information
801 460         2296 $et->FoundTag($tagInfo, $value);
802 460 100       2241 delete $$tagInfo{RawConv} if $delRawConv;
803             }
804             }
805 182         733 return 1;
806             }
807              
808             #------------------------------------------------------------------------------
809             # get information from raw file
810             # Inputs: 0) ExifTool object reference, 1) dirInfo reference
811             # Returns: 1 if this was a valid Canon RAW file
812             sub ProcessCRW($$)
813             {
814 26     26 0 102 my ($et, $dirInfo) = @_;
815 26         60 my ($buff, $sig);
816 26         90 my $raf = $$dirInfo{RAF};
817 26         157 my $buildMakerNotes = $et->Options('MakerNotes');
818              
819 26 50       153 $raf->Read($buff,2) == 2 or return 0;
820 26 50       126 SetByteOrder($buff) or return 0;
821 26 50       143 $raf->Read($buff,4) == 4 or return 0;
822 26 50       87 $raf->Read($sig,8) == 8 or return 0; # get file signature
823 26 50       225 $sig =~ /^HEAP(CCDR|JPGM)/ or return 0; # validate signature
824 26         156 my $hlen = Get32u(\$buff, 0);
825              
826 26 50       185 $raf->Seek(0, 2) or return 0; # seek to end of file
827 26 50       97 my $filesize = $raf->Tell() or return 0;
828              
829             # initialize maker note data if building maker notes
830 26 100       126 $buildMakerNotes and InitMakerNotes($et);
831              
832             # set the FileType tag unless already done (eg. APP0 CIFF record in JPEG image)
833 26         206 $et->SetFileType();
834              
835             # build directory information for main raw directory
836 26         269 my %dirInfo = (
837             DataLen => 0,
838             DirStart => $hlen,
839             DirLen => $filesize - $hlen,
840             Nesting => 0,
841             RAF => $raf,
842             Parent => 'CRW',
843             );
844              
845             # process the raw directory
846 26         121 my $rawTagTable = GetTagTable('Image::ExifTool::CanonRaw::Main');
847 26         85 my $oldIndent = $$et{INDENT};
848 26         85 $$et{INDENT} .= '| ';
849 26 50       151 unless (ProcessCanonRaw($et, \%dirInfo, $rawTagTable)) {
850 0         0 $et->Warn('CRW file format error');
851             }
852 26         106 $$et{INDENT} = $oldIndent;
853              
854             # finish building maker notes if necessary
855 26 100       143 $buildMakerNotes and SaveMakerNotes($et);
856              
857             # process trailers if they exist in CRW file (not in CIFF information!)
858 26 100       155 if ($$et{FILE_TYPE} eq 'CRW') {
859 7         49 my $trailInfo = $et->IdentifyTrailer($raf);
860 7 50       58 $et->ProcessTrailers($trailInfo) if $trailInfo;
861             }
862              
863 26         196 return 1;
864             }
865              
866             1; # end
867              
868             __END__