#------------------------------------------------------------------------------ # File: ISO.pm # # Description: Read information from ISO 9660 disk images # # Revisions: 2016-04-07 - P. Harvey created # # References: 1) http://wiki.osdev.org/ISO_9660 #------------------------------------------------------------------------------ package Image::ExifTool::ISO; use strict; use vars qw($VERSION); use Image::ExifTool qw(:DataAccess :Utils); $VERSION = '1.01'; # trim trailing spaces and ignore tag if empty my %rawStr = ( RawConv => sub { my $val = shift; $val =~ s/ +$//; return length($val) ? $val : undef; }, ); # tag info for date/time tags my %dateInfo = ( Format => 'undef[17]', Groups => { 2 => 'Time' }, ValueConv => q{ return undef if $val !~ /[^0\0 ]/; # ignore if empty if ($val =~ s/(\d{4})(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})(.)/$1:$2:$3 $4:$5:$6.$7/s) { $val .= TimeZoneString(unpack('c', $8) * 15); } return $val; }, PrintConv => '$self->ConvertDateTime($val)', ); # lookup for volume descriptor types my %volumeDescriptorType = ( 0 => 'Boot Record', 1 => 'Primary Volume', 2 => 'Supplementary Volume', 3 => 'Volume Partition', 255 => 'Terminator', ); # ISO tags %Image::ExifTool::ISO::Main = ( GROUPS => { 2 => 'Other' }, NOTES => 'Tags extracted from ISO 9660 disk images.', 0 => { Name => 'BootRecord', SubDirectory => { TagTable => 'Image::ExifTool::ISO::BootRecord' }, }, 1 => { Name => 'PrimaryVolume', SubDirectory => { TagTable => 'Image::ExifTool::ISO::PrimaryVolume' }, }, ); %Image::ExifTool::ISO::BootRecord = ( GROUPS => { 2 => 'Other' }, PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData, # 0 => { Name => 'VolumeType', PrintConv => \%volumeDescriptorType }, # (0 for boot record) # 1 => { Name => 'Identifier', Format => 'undef[5]' }, # (always "CD001") # 6 => 'VolumeDesriptorVersion', # (always 1) # always extract BootSystem, even if empty, as an indication that this is bootable 7 => { Name => 'BootSystem', Format => 'string[32]', ValueConv => '$val=~s/ +$//; $val' }, 39 => { Name => 'BootIdentifier', Format => 'string[32]', %rawStr }, ); %Image::ExifTool::ISO::PrimaryVolume = ( GROUPS => { 2 => 'Other' }, PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData, # 0 => { Name => 'VolumeType', PrintConv => \%volumeDescriptorType }, # (1 for primary volume) # 1 => { Name => 'Identifier', Format => 'undef[5]' }, # (always "CD001") # 6 => 'VolumeDesriptorVersion', # (always 1) 8 => { Name => 'System', Format => 'string[32]', %rawStr }, 40 => { Name => 'VolumeName', Format => 'string[32]', %rawStr }, 80 => { Name => 'VolumeBlockCount', Format => 'int32u' }, 120 => { Name => 'VolumeSetDiskCount', Format => 'int16u', Unknown => 1 }, 124 => { Name => 'VolumeSetDiskNumber', Format => 'int16u', Unknown => 1 }, 128 => { Name => 'VolumeBlockSize', Format => 'int16u' }, 132 => { Name => 'PathTableSize', Format => 'int32u', Unknown => 1 }, 140 => { Name => 'PathTableLocation', Format => 'int32u', Unknown => 1 }, 174 => { Name => 'RootDirectoryCreateDate', Format => 'undef[7]', Groups => { 2 => 'Time' }, ValueConv => q{ my @a = unpack('C6c', $val); $a[0] += 1900; $a[6] = TimeZoneString($a[6] * 15); return sprintf('%.4d:%.2d:%.2d %.2d:%.2d:%.2d%s', @a); }, PrintConv => '$self->ConvertDateTime($val)', }, 190 => { Name => 'VolumeSetName', Format => 'string[128]', %rawStr }, 318 => { Name => 'Publisher', Format => 'string[128]', %rawStr }, 446 => { Name => 'DataPreparer', Format => 'string[128]', %rawStr }, 574 => { Name => 'Software', Format => 'string[128]', %rawStr }, 702 => { Name => 'CopyrightFileName', Format => 'string[38]', %rawStr }, 740 => { Name => 'AbstractFileName', Format => 'string[36]', %rawStr }, 776 => { Name => 'BibligraphicFileName',Format => 'string[37]', %rawStr }, 813 => { Name => 'VolumeCreateDate', %dateInfo }, 830 => { Name => 'VolumeModifyDate', %dateInfo }, 847 => { Name => 'VolumeExpirationDate',%dateInfo }, 864 => { Name => 'VolumeEffectiveDate', %dateInfo }, #881 => 'FileStructureVersion', # (always 1) ); # ISO Composite tags %Image::ExifTool::ISO::Composite = ( GROUPS => { 2 => 'Other' }, VolumeSize => { Require => { 0 => 'ISO:VolumeBlockCount', 1 => 'ISO:VolumeBlockSize', }, ValueConv => '$val[0] * $val[1]', PrintConv => \&Image::ExifTool::ConvertFileSize, }, ); # add our composite tags Image::ExifTool::AddCompositeTags('Image::ExifTool::ISO'); #------------------------------------------------------------------------------ # Extract information from an ISO 9660 disk image # Inputs: 0) ExifTool object reference, 1) dirInfo reference # Returns: 1 on success, 0 if this wasn't a valid ISO 9660 image sub ProcessISO($$) { my ($et, $dirInfo) = @_; my $raf = $$dirInfo{RAF}; my ($buff, $tagTablePtr); # verify this is a valid ISO file return 0 unless $raf->Seek(32768, 0); while ($raf->Read($buff, 2048) == 2048) { last unless $buff =~ /^[\0-\x03\xff]CD001/; unless ($tagTablePtr) { $et->SetFileType(); # set the FileType tag SetByteOrder('II'); # read little-endian values only $tagTablePtr = GetTagTable('Image::ExifTool::ISO::Main'); } my $type = unpack('C', $buff); $et->VPrint(0, "Volume descriptor type $type ($volumeDescriptorType{$type})\n"); last if $type == 255; # stop at terminator next unless $$tagTablePtr{$type}; my $subTablePtr = GetTagTable($$tagTablePtr{$type}{SubDirectory}{TagTable}); my %dirInfo = ( DataPt => \$buff, DataPos => $raf->Tell() - 2048, DirStart => 0, DirLen => length($buff), ); $et->ProcessDirectory(\%dirInfo, $subTablePtr); } return $tagTablePtr ? 1 : 0; } 1; # end __END__ =head1 NAME Image::ExifTool::ISO - Read information from ISO 9660 disk images =head1 SYNOPSIS This module is used by Image::ExifTool =head1 DESCRIPTION This module contains definitions required by Image::ExifTool to read information from ISO 9660 disk images. =head1 AUTHOR Copyright 2003-2018, Phil Harvey (phil at owl.phy.queensu.ca) This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself. =head1 REFERENCES =over 4 =item L =back =head1 SEE ALSO L, L =cut