Ignore:
Timestamp:
2021-02-26T19:39:51+13:00 (3 years ago)
Author:
anupama
Message:

Committing the improvements to EmbeddedMetaPlugin's processing of Keywords vs other metadata fields. Keywords were literally stored as arrays of words rather than phrases in PDFs (at least in Diego's sample PDF), whereas other meta fields like Subjects and Creators stored them as arrays of phrases. To get both to work, Kathy updated EXIF to a newer version, to retrieve the actual EXIF values stored in the PDF. And Kathy and Dr Bainbridge came up with a new option that I added called apply_join_before_split_to_metafields that's a regex which can list the metadata fields to apply the join_before_split to and whcih previously always got applied to all metadata fields. Now it's applied to any *Keywords metafields by default, as that's the metafield we have experience of that behaves differently to the others, as it stores by word instead of phrases. Tested on Diego's sample PDF. Diego has double-checked it to works on his sample PDF too, setting the split char to ; and turning on the join_before_split and leaving apply_join_before_split_to_metafields at its default of .*Keywords. File changes are strings.properties for the tooltip, the plugin introducing the option and working with it and Kathy's EXIF updates affecting cpan/File and cpan/Image.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • main/trunk/greenstone2/perllib/cpan/Image/ExifTool/FlashPix.pm

    r24107 r34921  
    1010#               3) http://search.cpan.org/~jdb/libwin32/
    1111#               4) http://msdn.microsoft.com/en-us/library/aa380374.aspx
     12#               5) http://www.cpan.org/modules/by-authors/id/H/HC/HCARVEY/File-MSWord-0.1.zip
     13#               6) https://msdn.microsoft.com/en-us/library/cc313153(v=office.12).aspx
    1214#------------------------------------------------------------------------------
    1315
     
    2022use Image::ExifTool::ASF;   # for GetGUID()
    2123
    22 $VERSION = '1.19';
     24$VERSION = '1.38';
    2325
    2426sub ProcessFPX($$);
     
    2830sub ProcessHyperlinks($$);
    2931sub ProcessContents($$$);
     32sub ProcessWordDocument($$$);
     33sub ProcessDocumentTable($);
     34sub ProcessCommentBy($$$);
     35sub ProcessLastSavedBy($$$);
    3036sub SetDocNum($$;$$$);
     37sub ConvertDTTM($);
    3138
    3239# sector type constants
     
    8087    30 => 'VT_LPSTR',   # VT_LPSTR (int32u count, followed by string)
    8188    31 => 'VT_LPWSTR',  # VT_LPWSTR (int32u word count, followed by Unicode string)
    82     64 => 'VT_FILETIME',# VT_FILETIME (int64u, number of nanoseconds since Jan 1, 1601)
     89    64 => 'VT_FILETIME',# VT_FILETIME (int64u, 100 ns increments since Jan 1, 1601)
    8390    65 => 'VT_BLOB',    # VT_BLOB
    8491#   66 => 'VT_STREAM',
     
    119126# (ref http://msdn.microsoft.com/en-us/library/dd317756(VS.85).aspx)
    120127my %codePage = (
    121     037 => 'IBM EBCDIC US-Canada',
     128     37 => 'IBM EBCDIC US-Canada',
    122129    437 => 'DOS United States',
    123130    500 => 'IBM EBCDIC International',
     
    299306        popular.  However, some of the structures used in FlashPix streams are part
    300307        of the EXIF specification, and are still being used in the APP2 FPXR segment
    301         of JPEG images by some Kodak and Hewlett-Packard digital cameras.
     308        of JPEG images by some digital cameras from manufacturers such as FujiFilm,
     309        Hewlett-Packard, Kodak and Sanyo.
    302310
    303311        ExifTool extracts FlashPix information from both FPX images and the APP2
     
    306314        (Microsoft Visio) drawings, and FLA (Macromedia/Adobe Flash project) files
    307315        since these are based on the same file format as FlashPix (the Windows
    308         Compound Binary File format).  See
     316        Compound Binary File format).  Note that ExifTool identifies any
     317        unrecognized Windows Compound Binary file as a FlashPix (FPX) file.  See
    309318        L<http://graphcomp.com/info/specs/livepicture/fpx.pdf> for the FlashPix
    310319        specification.
     
    371380    },
    372381#   'Subimage 0000 Data'
    373     "\x05Data Object" => {  # plus instance number (ie. " 000000")
     382    "\x05Data Object" => {  # plus instance number (eg. " 000000")
    374383        Name => 'DataObject',
    375384        SubDirectory => {
     
    377386        },
    378387    },
    379 #   "\x05Data Object Store" => { # plus instance number (ie. " 000000")
    380     "\x05Transform" => {    # plus instance number (ie. " 000000")
     388#   "\x05Data Object Store" => { # plus instance number (eg. " 000000")
     389    "\x05Transform" => {    # plus instance number (eg. " 000000")
    381390        Name => 'Transform',
    382391        SubDirectory => {
     
    384393        },
    385394    },
    386     "\x05Operation" => {    # plus instance number (ie. " 000000")
     395    "\x05Operation" => {    # plus instance number (eg. " 000000")
    387396        Name => 'Operation',
    388397        SubDirectory => {
     
    396405        },
    397406    },
    398     "\x05Screen Nail" => { # plus class ID (ie. "_bd0100609719a180")
     407    "\x05Screen Nail" => { # plus class ID (eg. "_bd0100609719a180")
    399408        Name => 'ScreenNail',
    400409        Groups => { 2 => 'Other' },
     
    408417        },
    409418    },
    410     'Audio Stream' => { # plus instance number (ie. " 000000")
     419    'Audio Stream' => { # plus instance number (eg. " 000000")
    411420        Name => 'AudioStream',
    412421        Groups => { 2 => 'Audio' },
     
    423432            return undef if $len < 0 or length $val < $size + 8;
    424433            return substr($val, 8 + $pos, $len);
     434        },
     435    },
     436    'WordDocument' => {
     437        Name => 'WordDocument',
     438        SubDirectory => { TagTable => 'Image::ExifTool::FlashPix::WordDocument' },
     439    },
     440    # save these tables until after the WordDocument was processed
     441    '0Table' => {
     442        Name => 'Table0',
     443        Hidden => 1, # (used only as temporary storage until table is processed)
     444        Binary => 1,
     445    },
     446    '1Table' => {
     447        Name => 'Table1',
     448        Hidden => 1, # (used only as temporary storage until table is processed)
     449        Binary => 1,
     450    },
     451    Preview => {
     452        Name => 'PreviewImage',
     453        Groups => { 2 => 'Preview' },
     454        Binary => 1,
     455        Notes => 'written by some FujiFilm models',
     456        # skip 47-byte Fuji header
     457        RawConv => q{
     458            return undef unless length $val > 47;
     459            $val = substr($val, 47);
     460            return $val =~ /^\xff\xd8\xff/ ? $val : undef;
     461        },
     462    },
     463    Property => {
     464        Name => 'PreviewInfo',
     465        SubDirectory => {
     466            TagTable => 'Image::ExifTool::FlashPix::PreviewInfo',
     467            ByteOrder => 'BigEndian',
    425468        },
    426469    },
     
    464507    0x0f => 'Words',
    465508    0x10 => 'Characters',
    466     0x11 => { Name => 'ThumbnailClip',  Binary => 1 },
     509    0x11 => {
     510        Name => 'ThumbnailClip',
     511        # (not a displayable format, so not in the "Preview" group)
     512        Binary => 1,
     513    },
    467514    0x12 => {
    468515        Name => 'Software',
     
    474521        PrintConv => {
    475522            0 => 'None',
    476             1 => 'Password protected',
    477             2 => 'Read-only recommended',
    478             4 => 'Read-only enforced',
    479             8 => 'Locked for annotations',
    480         },
    481     },
     523            BITMASK => {
     524                0 => 'Password protected',
     525                1 => 'Read-only recommended',
     526                2 => 'Read-only enforced',
     527                3 => 'Locked for annotations',
     528            },
     529        },
     530    },
     531    0x22 => { Name => 'CreatedBy', Groups => { 2 => 'Author' } }, #PH (guess) (MAX files)
     532    0x23 => 'DocumentID', # PH (guess) (MAX files)
     533  # 0x25 ? seen values 1.0-1.97 (MAX files)
    482534    0x80000000 => { Name => 'LocaleIndicator', Groups => { 2 => 'Other' } },
    483535);
     
    507559    },
    508560    0x0c => 'HeadingPairs',
    509     0x0d => 'TitleOfParts',
     561    0x0d => {
     562        Name => 'TitleOfParts',
     563        # look for "3ds Max" software name at beginning of TitleOfParts
     564        RawConv => q{
     565            (ref $val eq 'ARRAY' ? $$val[0] : $val) =~ /^(3ds Max)/ and $$self{Software} = $1;
     566            return $val;
     567        }
     568    },
    510569    0x0e => 'Manager',
    511570    0x0f => 'Company',
     
    515574    },
    516575    0x11 => 'CharCountWithSpaces',
    517   # 0x12 ?
     576  # 0x12 ? seen -32.1850395202637,-386.220672607422,-9.8100004196167,-9810,...
    518577    0x13 => { #PH (unconfirmed)
    519578        Name => 'SharedDoc',
    520579        PrintConv => { 0 => 'No', 1 => 'Yes' },
    521580    },
    522   # 0x14 ?
    523   # 0x15 ?
     581  # 0x14 ? seen -1
     582  # 0x15 ? seen 1
    524583    0x16 => {
    525584        Name => 'HyperlinksChanged',
    526585        PrintConv => { 0 => 'No', 1 => 'Yes' },
    527586    },
    528     0x17 => { #PH (unconfirmed handling of lower 16 bits)
     587    0x17 => { #PH (unconfirmed handling of lower 16 bits, not valid for MAX files)
    529588        Name => 'AppVersion',
    530589        ValueConv => 'sprintf("%d.%.4d",$val >> 16, $val & 0xffff)',
    531590    },
     591  # 0x18 ? seen -1
     592  # 0x19 ? seen 0
     593  # 0x1a ? seen 0
     594  # 0x1b ? seen 0
     595  # 0x1c ? seen 0,1
     596  # 0x1d ? seen 1
     597  # 0x1e ? seen 1
     598  # 0x1f ? seen 1,5
     599  # 0x20 ? seen 0,5
     600  # 0x21 ? seen -1
     601  # 0x22 ? seen 0
    532602   '_PID_LINKBASE' => {
    533603        Name => 'HyperlinkBase',
     
    9851055);
    9861056
     1057# decode Word document FIB header (ref [MS-DOC].pdf)
     1058%Image::ExifTool::FlashPix::WordDocument = (
     1059    PROCESS_PROC => \&ProcessWordDocument,
     1060    GROUPS => { 2 => 'Other' },
     1061    FORMAT => 'int16u',
     1062    NOTES => 'Tags extracted from the Microsoft Word document stream.',
     1063    0 => {
     1064        Name => 'Identification',
     1065        PrintHex => 1,
     1066        PrintConv => {
     1067            0x6a62 => 'MS Word 97',
     1068            0x626a => 'Word 98 Mac',
     1069            0xa5dc => 'Word 6.0/7.0',
     1070            0xa5ec => 'Word 8.0',
     1071        },
     1072    },
     1073    3 => {
     1074        Name => 'LanguageCode',
     1075        PrintHex => 1,
     1076        PrintConv => {
     1077            0x0400 => 'None',
     1078            0x0401 => 'Arabic',
     1079            0x0402 => 'Bulgarian',
     1080            0x0403 => 'Catalan',
     1081            0x0404 => 'Traditional Chinese',
     1082            0x0804 => 'Simplified Chinese',
     1083            0x0405 => 'Czech',
     1084            0x0406 => 'Danish',
     1085            0x0407 => 'German',
     1086            0x0807 => 'German (Swiss)',
     1087            0x0408 => 'Greek',
     1088            0x0409 => 'English (US)',
     1089            0x0809 => 'English (British)',
     1090            0x0c09 => 'English (Australian)',
     1091            0x040a => 'Spanish (Castilian)',
     1092            0x080a => 'Spanish (Mexican)',
     1093            0x040b => 'Finnish',
     1094            0x040c => 'French',
     1095            0x080c => 'French (Belgian)',
     1096            0x0c0c => 'French (Canadian)',
     1097            0x100c => 'French (Swiss)',
     1098            0x040d => 'Hebrew',
     1099            0x040e => 'Hungarian',
     1100            0x040f => 'Icelandic',
     1101            0x0410 => 'Italian',
     1102            0x0810 => 'Italian (Swiss)',
     1103            0x0411 => 'Japanese',
     1104            0x0412 => 'Korean',
     1105            0x0413 => 'Dutch',
     1106            0x0813 => 'Dutch (Belgian)',
     1107            0x0414 => 'Norwegian (Bokmal)',
     1108            0x0814 => 'Norwegian (Nynorsk)',
     1109            0x0415 => 'Polish',
     1110            0x0416 => 'Portuguese (Brazilian)',
     1111            0x0816 => 'Portuguese',
     1112            0x0417 => 'Rhaeto-Romanic',
     1113            0x0418 => 'Romanian',
     1114            0x0419 => 'Russian',
     1115            0x041a => 'Croato-Serbian (Latin)',
     1116            0x081a => 'Serbo-Croatian (Cyrillic)',
     1117            0x041b => 'Slovak',
     1118            0x041c => 'Albanian',
     1119            0x041d => 'Swedish',
     1120            0x041e => 'Thai',
     1121            0x041f => 'Turkish',
     1122            0x0420 => 'Urdu',
     1123            0x0421 => 'Bahasa',
     1124            0x0422 => 'Ukrainian',
     1125            0x0423 => 'Byelorussian',
     1126            0x0424 => 'Slovenian',
     1127            0x0425 => 'Estonian',
     1128            0x0426 => 'Latvian',
     1129            0x0427 => 'Lithuanian',
     1130            0x0429 => 'Farsi',
     1131            0x042d => 'Basque',
     1132            0x042f => 'Macedonian',
     1133            0x0436 => 'Afrikaans',
     1134            0x043e => 'Malaysian',
     1135        },
     1136    },
     1137    5 => {
     1138        Name => 'DocFlags',
     1139        Mask => 0xff0f, # ignore save count
     1140        RawConv => '$$self{DocFlags} = $val',
     1141        PrintConv => { BITMASK => {
     1142            0 => 'Template',
     1143            1 => 'AutoText only',
     1144            2 => 'Complex',
     1145            3 => 'Has picture',
     1146            # 4-7 = number of incremental saves
     1147            8 => 'Encrypted',
     1148            9 => '1Table',
     1149            10 => 'Read only',
     1150            11 => 'Passworded',
     1151            12 => 'ExtChar',
     1152            13 => 'Load override',
     1153            14 => 'Far east',
     1154            15 => 'Obfuscated',
     1155        }},
     1156    },
     1157    9.1 => {
     1158        Name => 'System',
     1159        Mask => 0x0001,
     1160        PrintConv => {
     1161            0x0000 => 'Windows',
     1162            0x0001 => 'Macintosh',
     1163        },
     1164    },
     1165    9.2 => {
     1166        Name => 'Word97',
     1167        Mask => 0x0010,
     1168        PrintConv => { 0 => 'No', 1 => 'Yes' },
     1169    },
     1170);
     1171
     1172# tags decoded from Word document table
     1173%Image::ExifTool::FlashPix::DocTable = (
     1174    GROUPS => { 1 => 'MS-DOC', 2 => 'Document' },
     1175    NOTES => 'Tags extracted from the Microsoft Word document table.',
     1176    VARS => { NO_ID => 1 },
     1177    CommentBy => {
     1178        Groups => { 2 => 'Author' },
     1179        Notes => 'enable L<Duplicates|../ExifTool.html#Duplicates> option to extract all entries',
     1180    },
     1181    LastSavedBy => {
     1182        Groups => { 2 => 'Author' },
     1183        Notes => 'enable L<Duplicates|../ExifTool.html#Duplicates> option to extract history of up to 10 entries',
     1184    },
     1185    DOP => { SubDirectory => { TagTable => 'Image::ExifTool::FlashPix::DOP' } },
     1186    ModifyDate => {
     1187        Groups => { 2 => 'Time' },
     1188        Format => 'int64u',
     1189        Priority => 0,
     1190        RawConv => q{
     1191            $val = $val * 1e-7 - 11644473600;   # convert to seconds since 1970
     1192            return $val > 0 ? $val : undef;
     1193        },
     1194        ValueConv => 'ConvertUnixTime($val)',
     1195        PrintConv => '$self->ConvertDateTime($val)',
     1196    },
     1197#
     1198# tags below are used internally in intermediate steps to extract the tags above
     1199#
     1200    TableOffsets => { Hidden => 1 }, # stores offsets to extract data from document table
     1201    CommentByBlock => {   # entire block of CommentBy entries
     1202        SubDirectory => {
     1203            TagTable => 'Image::ExifTool::FlashPix::DocTable',
     1204            ProcessProc => \&ProcessCommentBy,
     1205        },
     1206        Hidden => 1,
     1207    },
     1208    LastSavedByBlock => {   # entire block of LastSavedBy entries
     1209        SubDirectory => {
     1210            TagTable => 'Image::ExifTool::FlashPix::DocTable',
     1211            ProcessProc => \&ProcessLastSavedBy,
     1212        },
     1213        Hidden => 1,
     1214    },
     1215);
     1216
     1217# Microsoft Office Document Properties (ref [MS-DOC].pdf)
     1218%Image::ExifTool::FlashPix::DOP = (
     1219    PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
     1220    GROUPS => { 1 => 'MS-DOC', 2 => 'Document' },
     1221    NOTES => 'Microsoft office document properties.',
     1222    20 => {
     1223        Name => 'CreateDate',
     1224        Format => 'int32u',
     1225        Groups => { 2 => 'Time' },
     1226        Priority => 0,
     1227        RawConv => \&ConvertDTTM,
     1228        PrintConv => '$self->ConvertDateTime($val)',
     1229    },
     1230    24 => {
     1231        Name => 'ModifyDate',
     1232        Format => 'int32u',
     1233        Groups => { 2 => 'Time' },
     1234        Priority => 0,
     1235        RawConv => \&ConvertDTTM,
     1236        PrintConv => '$self->ConvertDateTime($val)',
     1237    },
     1238    28 => {
     1239        Name => 'LastPrinted',
     1240        Format => 'int32u',
     1241        Groups => { 2 => 'Time' },
     1242        RawConv => \&ConvertDTTM,
     1243        PrintConv => '$self->ConvertDateTime($val)',
     1244    },
     1245    32 => { Name => 'RevisionNumber', Format => 'int16u' },
     1246    34 => {
     1247        Name => 'TotalEditTime',
     1248        Format => 'int32u',
     1249        PrintConv => 'ConvertTimeSpan($val,60)',
     1250    },
     1251    # (according to the MS-DOC specification, the following are accurate only if
     1252    # flag 'X' is set, and flag 'u' specifies whether the main or subdoc tags are
     1253    # used, but in my tests it seems that both are filled in with reasonable values,
     1254    # so just extract the main counts and ignore the subdoc counts for now - PH)
     1255    38 => { Name => 'Words',      Format => 'int32u' },
     1256    42 => { Name => 'Characters', Format => 'int32u' },
     1257    46 => { Name => 'Pages',      Format => 'int16u' },
     1258    48 => { Name => 'Paragraphs', Format => 'int32u' },
     1259    56 => { Name => 'Lines',      Format => 'int32u' },
     1260    #60 => { Name => 'WordsWithSubdocs',      Format => 'int32u' },
     1261    #64 => { Name => 'CharactersWithSubdocs', Format => 'int32u' },
     1262    #68 => { Name => 'PagesWithSubdocs',      Format => 'int16u' },
     1263    #70 => { Name => 'ParagraphsWithSubdocs', Format => 'int32u' },
     1264    #74 => { Name => 'LinesWithSubdocs',      Format => 'int32u' },
     1265);
     1266
     1267# FujiFilm "Property" information (ref PH)
     1268%Image::ExifTool::FlashPix::PreviewInfo = (
     1269    PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
     1270    GROUPS => { 2 => 'Image' },
     1271    NOTES => 'Preview information written by some FujiFilm models.',
     1272    FIRST_ENTRY => 0,
     1273    # values are all constant for for my samples except the two decoded tags
     1274    # 0x0000: 01 01 00 00 02 01 00 00 00 00 00 00 00 xx xx 01
     1275    # 0x0010: 01 00 00 00 00 00 00 xx xx 00 00 00 00 00 00 00
     1276    # 0x0020: 00 00 00 00 00
     1277    0x0d => {
     1278        Name => 'PreviewImageWidth',
     1279        Format => 'int16u',
     1280    },
     1281    0x17 => {
     1282        Name => 'PreviewImageHeight',
     1283        Format => 'int16u',
     1284    },
     1285);
     1286
    9871287# composite FlashPix tags
    9881288%Image::ExifTool::FlashPix::Composite = (
    9891289    GROUPS => { 2 => 'Image' },
    9901290    PreviewImage => {
     1291        Groups => { 2 => 'Preview' },
    9911292        # extract JPEG preview from ScreenNail if possible
    9921293        Require => {
     
    9961297        RawConv => q{
    9971298            return undef unless $val[0] =~ /\xff\xd8\xff/g;
     1299            @grps = $self->GetGroup($$val{0});  # set groups from ScreenNail
    9981300            return substr($val[0], pos($val[0])-3);
    9991301        },
     
    10031305# add our composite tags
    10041306Image::ExifTool::AddCompositeTags('Image::ExifTool::FlashPix');
     1307
     1308#------------------------------------------------------------------------------
     1309# Convert Microsoft DTTM structure to date/time
     1310# Inputs: 0) DTTM value
     1311# Returns: EXIF-format date/time string ("0000:00:00 00:00:00" for zero date/time)
     1312sub ConvertDTTM($)
     1313{
     1314    my $val = shift;
     1315    my $yr  = ($val >> 20) & 0x1ff;
     1316    my $mon = ($val >> 16) & 0x0f;
     1317    my $day = ($val >> 11) & 0x1f;
     1318    my $hr  = ($val >> 6)  & 0x1f;
     1319    my $min = ($val & 0x3f);
     1320    $yr += 1900 if $val;
     1321    return sprintf("%.4d:%.2d:%.2d %.2d:%.2d:00%s",$yr,$mon,$day,$hr,$min,$val ? 'Z' : '');
     1322}
    10051323
    10061324#------------------------------------------------------------------------------
     
    10111329sub ProcessHyperlinks($$)
    10121330{
    1013     my ($val, $exifTool) = @_;
     1331    my ($val, $et) = @_;
    10141332
    10151333    # process as an array of VT_VARIANT's
     
    10211339    for ($i=0; $i<$num; ++$i) {
    10221340        # read VT_BLOB entries as an array of VT_VARIANT's
    1023         my $value = ReadFPXValue($exifTool, \$val, $valPos, VT_VARIANT, $dirEnd);
     1341        my $value = ReadFPXValue($et, \$val, $valPos, VT_VARIANT, $dirEnd);
    10241342        last unless defined $value;
    10251343        push @vals, $value;
     
    10421360sub ReadFPXValue($$$$$;$$)
    10431361{
    1044     my ($exifTool, $dataPt, $valPos, $type, $dirEnd, $noPad, $codePage) = @_;
     1362    my ($et, $dataPt, $valPos, $type, $dirEnd, $noPad, $codePage) = @_;
    10451363    my @vals;
    10461364
     
    10781396                my $subType = Get32u($dataPt, $valPos);
    10791397                $valPos += $size;
    1080                 $val = ReadFPXValue($exifTool, $dataPt, $valPos, $subType, $dirEnd, $noPad, $codePage);
     1398                $val = ReadFPXValue($et, $dataPt, $valPos, $subType, $dirEnd, $noPad, $codePage);
    10811399                last unless defined $val;
    10821400                push @vals, $val;
    10831401                next;   # avoid adding $size to $valPos again
    10841402            } elsif ($format eq 'VT_FILETIME') {
    1085                 # get time in seconds
     1403                # convert from time in 100 ns increments to time in seconds
    10861404                $val = 1e-7 * Image::ExifTool::Get64u($dataPt, $valPos);
    10871405                # print as date/time if value is greater than one year (PH hack)
    1088                 if ($val > 365 * 24 * 3600) {
     1406                my $secDay = 24 * 3600;
     1407                if ($val > 365 * $secDay) {
    10891408                    # shift from Jan 1, 1601 to Jan 1, 1970
    1090                     $val -= 134774 * 24 * 3600 if $val != 0;
     1409                    my $unixTimeZero = 134774 * $secDay;
     1410                    $val -= $unixTimeZero;
     1411                    # there are a lot of bad programmers out there...
     1412                    my $sec100yr = 100 * 365 * $secDay;
     1413                    if ($val < 0 || $val > $sec100yr) {
     1414                        # some software writes the wrong byte order (but the proper word order)
     1415                        my @w = unpack("x${valPos}NN", $$dataPt);
     1416                        my $v2 = ($w[0] + $w[1] * 4294967296) * 1e-7 - $unixTimeZero;
     1417                        if ($v2 > 0 && $v2 < $sec100yr) {
     1418                            $val = $v2;
     1419                        # also check for wrong time base
     1420                        } elsif ($val < 0 && $val + $unixTimeZero > 0) {
     1421                            $val += $unixTimeZero;
     1422                        }
     1423                    }
    10911424                    $val = Image::ExifTool::ConvertUnixTime($val);
    10921425                }
     
    11031436                if ($format eq 'VT_LPWSTR') {
    11041437                    # convert wide string from Unicode
    1105                     $val = $exifTool->Decode($val, 'UCS2');
     1438                    $val = $et->Decode($val, 'UCS2');
    11061439                } elsif ($codePage) {
    11071440                    my $charset = $Image::ExifTool::charsetName{"cp$codePage"};
    11081441                    if ($charset) {
    1109                         $val = $exifTool->Decode($val, $charset);
    1110                     } elsif ($codePage eq 1200) {   # UTF-16, little endian
    1111                         $val = $exifTool->Decode(undef, 'UCS2', 'II');
     1442                        $val = $et->Decode($val, $charset);
     1443                    } elsif ($codePage == 1200) {   # UTF-16, little endian
     1444                        $val = $et->Decode($val, 'UCS2', 'II');
    11121445                    }
    11131446                }
     
    11311464        }
    11321465        # join VT_ values with commas unless we want an array
    1133         @vals = ( join $exifTool->Options('ListSep'), @vals ) if @vals > 1 and not wantarray;
     1466        @vals = ( join $et->Options('ListSep'), @vals ) if @vals > 1 and not wantarray;
    11341467        last;   # didn't really want to loop
    11351468    }
     
    11531486sub ProcessContents($$$)
    11541487{
    1155     my ($exifTool, $dirInfo, $tagTablePtr) = @_;
     1488    my ($et, $dirInfo, $tagTablePtr) = @_;
    11561489    my $dataPt = $$dirInfo{DataPt};
    11571490    my $isFLA;
    11581491
    1159     # all of my FLA samples contain "Contents" data, an no other FPX-like samples have
     1492    # all of my FLA samples contain "Contents" data, and no other FPX-like samples have
    11601493    # this, but check the data for a familiar pattern to be sure this is FLA: the
    11611494    # Contents of all of my FLA samples start with two bytes (0x29,0x38,0x3f,0x43 or 0x47,
    11621495    # then 0x01) followed by a number of zero bytes (from 0x18 to 0x26 of them, related
    11631496    # somehow to the value of the first byte), followed by the string "DocumentPage"
    1164     $isFLA = 1 if $$dataPt =~ /^..\0+\xff\xff\x01\0\x0d\0CDocumentPage/;
    1165    
     1497    $isFLA = 1 if $$dataPt =~ /^..\0+\xff\xff\x01\0\x0d\0CDocumentPage/s;
     1498
    11661499    # do a brute-force scan of the "Contents" for UTF-16 XMP
    11671500    # (this may always be little-endian, but allow for either endianness)
     
    11701503        if ($$dataPt =~ /<\0\?\0x\0p\0a\0c\0k\0e\0t\0 \0e\0n\0d\0=\0['"]\0[wr]\0['"]\0\?\0>\0?/g) {
    11711504            $$dirInfo{DirLen} = pos($$dataPt) - $$dirInfo{DirStart};
    1172             Image::ExifTool::XMP::ProcessXMP($exifTool, $dirInfo, $tagTablePtr);
     1505            Image::ExifTool::XMP::ProcessXMP($et, $dirInfo, $tagTablePtr);
    11731506            # override format if not already FLA but XMP-dc:Format indicates it is
    1174             $isFLA = 1 if $$exifTool{FILE_TYPE} ne 'FLA' and $$exifTool{VALUE}{Format} and
    1175                           $$exifTool{VALUE}{Format} eq 'application/vnd.adobe.fla';
    1176         }
    1177     }
    1178     $exifTool->OverrideFileType('FLA') if $isFLA;
     1507            $isFLA = 1 if $$et{FILE_TYPE} ne 'FLA' and $$et{VALUE}{Format} and
     1508                          $$et{VALUE}{Format} eq 'application/vnd.adobe.fla';
     1509        }
     1510    }
     1511    $et->OverrideFileType('FLA') if $isFLA;
     1512    return 1;
     1513}
     1514
     1515#------------------------------------------------------------------------------
     1516# Process WordDocument stream of MSWord doc file (ref 6)
     1517# Inputs: 0) ExifTool object ref, 1) dirInfo ref, 2) tag table ref
     1518# Returns: 1 on success
     1519sub ProcessWordDocument($$$)
     1520{
     1521    my ($et, $dirInfo, $tagTablePtr) = @_;
     1522    my $dataPt = $$dirInfo{DataPt} or return 0;
     1523    my $dirLen = length $$dataPt;
     1524    # validate the FIB signature
     1525    unless ($dirLen > 2 and Get16u($dataPt,0) == 0xa5ec) {
     1526        $et->WarnOnce('Invalid FIB signature', 1);
     1527        return 0;
     1528    }
     1529    $et->ProcessBinaryData($dirInfo, $tagTablePtr); # process FIB
     1530    # continue parsing the WordDocument stream until we find the FibRgFcLcb
     1531    my $pos = 32;
     1532    return 0 if $pos + 2 > $dirLen;
     1533    my $n = Get16u($dataPt, $pos);  # read csw
     1534    $pos += 2 + $n * 2;             # skip fibRgW
     1535    return 0 if $pos + 2 > $dirLen;
     1536    $n = Get16u($dataPt, $pos);     # read cslw
     1537    $pos += 2 + $n * 4;             # skip fibRgLw
     1538    return 0 if $pos + 2 > $dirLen;
     1539    $n = Get16u($dataPt, $pos);     # read cbRgFcLcb
     1540    $pos += 2;  # point to start of fibRgFcLcbBlob
     1541    return 0 if $pos + $n * 8 > $dirLen;
     1542    my ($off, @tableOffsets);
     1543    # save necessary entries for later processing of document table
     1544    # (DOP, CommentBy, LastSavedBy)
     1545    foreach $off (0xf8, 0x120, 0x238) {
     1546        last if $off + 8 > $n * 8;
     1547        push @tableOffsets, Get32u($dataPt, $pos + $off);
     1548        push @tableOffsets, Get32u($dataPt, $pos + $off + 4);
     1549    }
     1550    my $tbl = GetTagTable('Image::ExifTool::FlashPix::DocTable');
     1551    # extract ModifyDate if it exists
     1552    $et->HandleTag($tbl, 'ModifyDate', undef,
     1553        DataPt => $dataPt,
     1554        Start  => $pos + 0x2b8,
     1555        Size   => 8,
     1556    );
     1557    $et->HandleTag($tbl, TableOffsets => \@tableOffsets);   # save for later
     1558    # $pos += $n * 8;                 # skip fibRgFcLcbBlob
     1559    # return 0 if $pos + 2 > $dirLen;
     1560    # $n = Get16u($dataPt, $pos);     # read cswNew
     1561    # return 0 if $pos + 2 + $n * 2 > $dirLen;
     1562    # my $nFib = Get16u($dataPt, 2 + ($n ? $pos : 0));
     1563    # $pos += 2 + $n * 2;             # skip fibRgCswNew
     1564    return 1;
     1565}
     1566
     1567#------------------------------------------------------------------------------
     1568# Process Microsoft Word Document Table
     1569# Inputs: 0) ExifTool object ref
     1570sub ProcessDocumentTable($)
     1571{
     1572    my $et = shift;
     1573    my $value = $$et{VALUE};
     1574    my $extra = $$et{TAG_EXTRA};
     1575    my ($i, $j, $tag);
     1576    # loop through TableOffsets for each sub-document
     1577    for ($i=0; ; ++$i) {
     1578        my $key = 'TableOffsets' . ($i ? " ($i)" : '');
     1579        my $offsets = $$value{$key};
     1580        last unless defined $offsets;
     1581        my $doc;
     1582        $doc = $$extra{$key}{G3} if $$extra{$key};
     1583        $doc = '' unless $doc;
     1584        # get DocFlags for this sub-document
     1585        my ($docFlags, $docTable);
     1586        for ($j=0; ; ++$j) {
     1587            my $key = 'DocFlags' . ($j ? " ($j)" : '');
     1588            last unless defined $$value{$key};
     1589            my $tmp;
     1590            $tmp = $$extra{$key}{G3} if $$extra{$key};
     1591            $tmp = '' unless $tmp;
     1592            if ($tmp eq $doc) {
     1593                $docFlags = $$value{$key};
     1594                last;
     1595            }
     1596        }
     1597        next unless defined $docFlags;
     1598        $tag = $docFlags & 0x200 ? 'Table1' : 'Table0';
     1599        # get table for this sub-document
     1600        for ($j=0; ; ++$j) {
     1601            my $key = $tag . ($j ? " ($j)" : '');
     1602            last unless defined $$value{$key};
     1603            my $tmp;
     1604            $tmp = $$extra{$key}{G3} if $$extra{$key};
     1605            $tmp = '' unless $tmp;
     1606            if ($tmp eq $doc) {
     1607                $docTable = \$$value{$key};
     1608                last;
     1609            }
     1610        }
     1611        next unless defined $docTable;
     1612        # extract DOP and LastSavedBy information from document table
     1613        $$et{DOC_NUM} = $doc;   # use same document number
     1614        my $tagTablePtr = GetTagTable('Image::ExifTool::FlashPix::DocTable');
     1615        foreach $tag (qw(DOP CommentByBlock LastSavedByBlock)) {
     1616            last unless @$offsets;
     1617            my $off = shift @$offsets;
     1618            my $len = shift @$offsets;
     1619            next unless $len and $off + $len <= length $$docTable;
     1620            $et->HandleTag($tagTablePtr, $tag, undef,
     1621                DataPt => $docTable,
     1622                Start  => $off,
     1623                Size   => $len,
     1624            );
     1625        }
     1626        delete $$et{DOC_NUM};
     1627    }
     1628    # delete intermediate tags
     1629    foreach $tag (qw(TableOffsets Table0 Table1)) {
     1630        for ($i=0; ; ++$i) {
     1631            my $key = $tag . ($i ? " ($i)" : '');
     1632            last unless defined $$value{$key};
     1633            $et->DeleteTag($key);
     1634        }
     1635    }
     1636}
     1637
     1638#------------------------------------------------------------------------------
     1639# Extract names of comment authors (ref 6)
     1640# Inputs: 0) ExifTool object ref, 1) dirInfo ref, 2) tag table ref
     1641# Returns: 1 on success
     1642sub ProcessCommentBy($$$)
     1643{
     1644    my ($et, $dirInfo, $tagTablePtr) = @_;
     1645    my $dataPt = $$dirInfo{DataPt};
     1646    my $pos = $$dirInfo{DirStart};
     1647    my $end = $$dirInfo{DirLen} + $pos;
     1648    $et->VerboseDir($$dirInfo{DirName});
     1649    while ($pos + 2 < $end) {
     1650        my $len = Get16u($dataPt, $pos);
     1651        $pos += 2;
     1652        last if $pos + $len * 2 > $end;
     1653        my $author = $et->Decode(substr($$dataPt, $pos, $len*2), 'UCS2');
     1654        $pos += $len * 2;
     1655        $et->HandleTag($tagTablePtr, CommentBy => $author);
     1656    }
     1657    return 1;
     1658}
     1659
     1660#------------------------------------------------------------------------------
     1661# Extract last-saved-by names (ref 5)
     1662# Inputs: 0) ExifTool object ref, 1) dirInfo ref, 2) tag table ref
     1663# Returns: 1 on success
     1664sub ProcessLastSavedBy($$$)
     1665{
     1666    my ($et, $dirInfo, $tagTablePtr) = @_;
     1667    my $dataPt = $$dirInfo{DataPt};
     1668    my $pos = $$dirInfo{DirStart};
     1669    my $end = $$dirInfo{DirLen} + $pos;
     1670    return 0 if $pos + 6 > $end;
     1671    $et->VerboseDir($$dirInfo{DirName});
     1672    my $num = Get16u($dataPt, $pos+2);
     1673    $pos += 6;
     1674    while ($num >= 2) {
     1675        last if $pos + 2 > $end;
     1676        my $len = Get16u($dataPt, $pos);
     1677        $pos += 2;
     1678        last if $pos + $len * 2 > $end;
     1679        my $author = $et->Decode(substr($$dataPt, $pos, $len*2), 'UCS2');
     1680        $pos += $len * 2;
     1681        last if $pos + 2 > $end;
     1682        $len = Get16u($dataPt, $pos);
     1683        $pos += 2;
     1684        last if $pos + $len * 2 > $end;
     1685        my $path = $et->Decode(substr($$dataPt, $pos, $len*2), 'UCS2');
     1686        $pos += $len * 2;
     1687        $et->HandleTag($tagTablePtr, LastSavedBy => "$author ($path)");
     1688        $num -= 2;
     1689    }
    11791690    return 1;
    11801691}
     
    12001711sub ProcessProperties($$$)
    12011712{
    1202     my ($exifTool, $dirInfo, $tagTablePtr) = @_;
     1713    my ($et, $dirInfo, $tagTablePtr) = @_;
    12031714    my $dataPt = $$dirInfo{DataPt};
    12041715    my $pos = $$dirInfo{DirStart} || 0;
    12051716    my $dirLen = $$dirInfo{DirLen} || length($$dataPt) - $pos;
    12061717    my $dirEnd = $pos + $dirLen;
    1207     my $verbose = $exifTool->Options('Verbose');
     1718    my $verbose = $et->Options('Verbose');
    12081719    my $n;
    12091720
    12101721    if ($dirLen < 48) {
    1211         $exifTool->Warn('Truncated FPX properties');
     1722        $et->Warn('Truncated FPX properties');
    12121723        return 0;
    12131724    }
    12141725    # check and set our byte order if necessary
    12151726    unless (CheckBOM($dataPt, $pos)) {
    1216         $exifTool->Warn('Bad FPX property byte order mark');
     1727        $et->Warn('Bad FPX property byte order mark');
    12171728        return 0;
    12181729    }
     
    12201731    $pos = Get32u($dataPt, $pos + 44);
    12211732    if ($pos < 48) {
    1222         $exifTool->Warn('Bad FPX property section offset');
     1733        $et->Warn('Bad FPX property section offset');
    12231734        return 0;
    12241735    }
     
    12311742        last unless $size;
    12321743        my $numEntries = Get32u($dataPt, $pos + 4);
    1233         $verbose and $exifTool->VerboseDir('Property Info', $numEntries, $size);
     1744        $verbose and $et->VerboseDir('Property Info', $numEntries, $size);
    12341745        if ($pos + 8 + 8 * $numEntries > $dirEnd) {
    1235             $exifTool->Warn('Truncated property list');
     1746            $et->Warn('Truncated property list');
    12361747            last;
    12371748        }
     
    12631774                    $name =~ tr/-_a-zA-Z0-9//dc;    # remove illegal characters
    12641775                    next unless length $name;
    1265                     $exifTool->VPrint(0, "$$exifTool{INDENT}\[adding $name]\n") if $verbose;
    1266                     Image::ExifTool::AddTagToTable($tagTablePtr, $tag, { Name => $name });
     1776                    $et->VPrint(0, "$$et{INDENT}\[adding $name]\n") if $verbose;
     1777                    AddTagToTable($tagTablePtr, $tag, { Name => $name });
    12671778                }
    12681779                next;
     
    12741785                $custom = 1;
    12751786            }
    1276             my @vals = ReadFPXValue($exifTool, $dataPt, $valPos, $type, $dirEnd, undef, $codePage);
    1277             @vals or $exifTool->Warn('Error reading property value');
     1787            my @vals = ReadFPXValue($et, $dataPt, $valPos, $type, $dirEnd, undef, $codePage);
     1788            @vals or $et->Warn('Error reading property value');
    12781789            $val = @vals > 1 ? \@vals : $vals[0];
    12791790            my $format = $type & 0x0fff;
     
    12871798                # get tagInfo from SummaryInfo table
    12881799                my $summaryTable = GetTagTable('Image::ExifTool::FlashPix::SummaryInfo');
    1289                 $tagInfo = $exifTool->GetTagInfo($summaryTable, $tag);
     1800                $tagInfo = $et->GetTagInfo($summaryTable, $tag);
    12901801                if ($tag == 1) {
    12911802                    $val += 0x10000 if $val < 0; # (may be incorrectly stored as int16s)
     
    12931804                }
    12941805            } elsif ($$tagTablePtr{$tag}) {
    1295                 $tagInfo = $exifTool->GetTagInfo($tagTablePtr, $tag);
     1806                $tagInfo = $et->GetTagInfo($tagTablePtr, $tag);
    12961807            } elsif ($$tagTablePtr{VARS} and not $custom) {
    12971808                # mask off insignificant bits of tag ID if necessary
     
    13001811                foreach $mask (keys %$masked) {
    13011812                    if ($masked->{$mask}->{$tag & $mask}) {
    1302                         $tagInfo = $exifTool->GetTagInfo($tagTablePtr, $tag & $mask);
     1813                        $tagInfo = $et->GetTagInfo($tagTablePtr, $tag & $mask);
    13031814                        last;
    13041815                    }
    13051816                }
    13061817            }
    1307             $exifTool->HandleTag($tagTablePtr, $tag, $val,
     1818            $et->HandleTag($tagTablePtr, $tag, $val,
    13081819                DataPt  => $dataPt,
    13091820                Start   => $valStart,
     
    13161827        }
    13171828        # issue warning if we hit end of property section prematurely
    1318         $exifTool->Warn('Truncated property data') if $index < $numEntries;
     1829        $et->Warn('Truncated property data') if $index < $numEntries;
    13191830        last unless $$dirInfo{Multi};
    13201831        $pos += $size;
     
    13551866sub ProcessFPXR($$$)
    13561867{
    1357     my ($exifTool, $dirInfo, $tagTablePtr) = @_;
     1868    my ($et, $dirInfo, $tagTablePtr) = @_;
    13581869    my $dataPt = $$dirInfo{DataPt};
    13591870    my $dirStart = $$dirInfo{DirStart};
    13601871    my $dirLen = $$dirInfo{DirLen};
    1361     my $verbose = $exifTool->Options('Verbose');
     1872    my $verbose = $et->Options('Verbose');
    13621873
    13631874    if ($dirLen < 13) {
    1364         $exifTool->Warn('FPXR segment to small');
     1875        $et->Warn('FPXR segment too small');
    13651876        return 0;
    13661877    }
     
    13711882    if ($type == 1) {   # a "Contents List" segment
    13721883
    1373         $vers != 0 and $exifTool->Warn("Untested FPXR version $vers");
    1374         if ($$exifTool{FPXR}) {
    1375             $exifTool->Warn('Multiple FPXR contents lists');
    1376             delete $$exifTool{FPXR};
     1884        $vers != 0 and $et->Warn("Untested FPXR version $vers");
     1885        if ($$et{FPXR}) {
     1886            $et->Warn('Multiple FPXR contents lists');
     1887            delete $$et{FPXR};
    13771888        }
    13781889        my $numEntries = unpack('x7n', $$dataPt);
    13791890        my @contents;
    1380         $verbose and $exifTool->VerboseDir('Contents List', $numEntries);
     1891        $verbose and $et->VerboseDir('Contents List', $numEntries);
    13811892        my $pos = 9;
    13821893        my $entry;
    13831894        for ($entry = 0; $entry < $numEntries; ++$entry) {
    13841895            if ($pos + 4 > $dirLen) {
    1385                 $exifTool->Warn('Truncated FPXR contents');
     1896                $et->Warn('Truncated FPXR contents');
    13861897                return 0;
    13871898            }
     
    13921903            # and the first char must be '/'
    13931904            unless ($$dataPt =~ m{\G(/\0(..)*?)\0\0}sg) {
    1394                 $exifTool->Warn('Invalid FPXR stream name');
     1905                $et->Warn('Invalid FPXR stream name');
    13951906                return 0;
    13961907            }
     
    13991910            if ($verbose) {
    14001911                my $psize = ($size == 0xffffffff) ? 'storage' : "$size bytes";
    1401                 $exifTool->VPrint(0,"  |  $entry) Name: '$name' [$psize]\n");
     1912                $et->VPrint(0,"  |  $entry) Name: '${name}' [$psize]\n");
    14021913            }
    14031914            # remove directory specification
     
    14071918            if ($size == 0xffffffff) {
    14081919                unless ($$dataPt =~ m{(.{16})}sg) {
    1409                     $exifTool->Warn('Truncated FPXR storage class ID');
     1920                    $et->Warn('Truncated FPXR storage class ID');
    14101921                    return 0;
    14111922                }
    14121923                # unpack class ID in case we want to use it sometime
    14131924                $classID = Image::ExifTool::ASF::GetGUID($1);
     1925            }
     1926            # find the tagInfo if available
     1927            my $tagInfo;
     1928            unless ($$tagTablePtr{$name}) {
     1929                # remove instance number or class ID from tag if necessary
     1930                $tagInfo = $et->GetTagInfo($tagTablePtr, $1) if
     1931                    ($name =~ /(.*) \d{6}$/s and $$tagTablePtr{$1}) or
     1932                    ($name =~ /(.*)_[0-9a-f]{16}$/s and $$tagTablePtr{$1});
    14141933            }
    14151934            # update position in list
     
    14211940                Default => $default,
    14221941                ClassID => $classID,
     1942                TagInfo => $tagInfo,
    14231943            };
    14241944        }
    1425         # save contents list as $exifTool member variable
     1945        # save contents list as $et member variable
    14261946        # (must do this last so we don't save list on error)
    1427         $$exifTool{FPXR} = \@contents;
     1947        $$et{FPXR} = \@contents;
    14281948
    14291949    } elsif ($type == 2) {  # a "Stream Data" segment
     
    14311951        # get the contents list index and stream data offset
    14321952        my ($index, $offset) = unpack('x7nN', $$dataPt);
    1433         my $fpxr = $$exifTool{FPXR};
     1953        my $fpxr = $$et{FPXR};
    14341954        if ($fpxr and $$fpxr[$index]) {
    14351955            my $obj = $$fpxr[$index];
     
    14401960                $$obj{Stream} = substr($$dataPt, $dirStart+13);
    14411961            } else {
    1442                 # add data to the stream at the proper offset
    1443                 my $pad = $offset - length($$obj{Stream});
    1444                 if ($pad >= 0) {
    1445                     if ($pad) {
    1446                         if ($pad > 0x10000) {
    1447                             $exifTool->Warn("Bad FPXR stream offset ($offset)");
    1448                         } else {
    1449                             # pad with default value to specified offset
    1450                             $exifTool->Warn("Padding FPXR stream with $pad default bytes",1);
    1451                             $$obj{Stream} .= ($$obj{Default} x $pad);
    1452                         }
    1453                     }
    1454                     # concatenate data with this stream
    1455                     $$obj{Stream} .= substr($$dataPt, $dirStart+13);
     1962                # add data at the proper offset to the stream
     1963                my $overlap = length($$obj{Stream}) - $offset;
     1964                my $start = $dirStart + 13;
     1965                if ($overlap < 0 or $dirLen - $overlap < 13) {
     1966                    $et->WarnOnce("Bad FPXR stream $index offset",1);
    14561967                } else {
    1457                     $exifTool->Warn("Duplicate FPXR stream data at offset $offset");
    1458                     substr($$obj{Stream}, $offset, -$pad) = substr($$dataPt, $dirStart+13);
     1968                    # ignore any overlapping data in this segment
     1969                    # (this seems to be the convention)
     1970                    $start += $overlap;
    14591971                }
     1972                # concatenate data with this stream
     1973                $$obj{Stream} .= substr($$dataPt, $start);
    14601974            }
    14611975            # save value for this tag if stream is complete
    14621976            my $len = length $$obj{Stream};
    14631977            if ($len >= $$obj{Size}) {
    1464                 if ($verbose) {
    1465                     $exifTool->VPrint(0, "  + [FPXR stream, Contents index $index, $len bytes]\n");
    1466                 }
     1978                $et->VPrint(0, "  + [FPXR stream $index, $len bytes]\n") if $verbose;
    14671979                if ($len > $$obj{Size}) {
    1468                     $exifTool->Warn('Extra data in FPXR segment (truncated)');
     1980                    $et->Warn('Extra data in FPXR segment (truncated)');
    14691981                    $$obj{Stream} = substr($$obj{Stream}, 0, $$obj{Size});
    14701982                }
    1471                 my $tag = $$obj{Name};
    1472                 my $tagInfo;
    1473                 unless ($$tagTablePtr{$tag}) {
    1474                     # remove instance number or class ID from tag if necessary
    1475                     $tagInfo = $exifTool->GetTagInfo($tagTablePtr, $1) if
    1476                         ($tag =~ /(.*) \d{6}$/s and $$tagTablePtr{$1}) or
    1477                         ($tag =~ /(.*)_[0-9a-f]{16}$/s and $$tagTablePtr{$1});
    1478                 }
    1479                 # save the data for this tag
    1480                 $exifTool->HandleTag($tagTablePtr, $tag, $$obj{Stream},
     1983                # handle this tag
     1984                $et->HandleTag($tagTablePtr, $$obj{Name}, $$obj{Stream},
    14811985                    DataPt => \$$obj{Stream},
    1482                     TagInfo => $tagInfo,
     1986                    TagInfo => $$obj{TagInfo},
    14831987                );
    14841988                delete $$obj{Stream}; # done with this stream
    14851989            }
    14861990        # hack for improperly stored FujiFilm PreviewImage (stored with no contents list)
    1487         } elsif ($index == 512 and $dirLen > 60 and ($$exifTool{FujiPreview} or
     1991        } elsif ($index == 512 and $dirLen > 60 and ($$et{FujiPreview} or
    14881992            ($dirLen > 64 and substr($$dataPt, $dirStart+60, 4) eq "\xff\xd8\xff\xdb")))
    14891993        {
    1490             # recombine PreviewImage, skipping unknown 60 byte header
    1491             if ($$exifTool{FujiPreview}) {
    1492                 $$exifTool{FujiPreview} .= substr($$dataPt, $dirStart+60);
    1493             } else {
    1494                 $$exifTool{FujiPreview} = substr($$dataPt, $dirStart+60);
    1495             }
     1994            $$et{FujiPreview} = '' unless defined $$et{FujiPreview};
     1995            # recombine PreviewImage, skipping 13-byte FPXR header + 47-byte Fuji header
     1996            $$et{FujiPreview} .= substr($$dataPt, $dirStart+60);
    14961997        } else {
    14971998            # (Kodak uses index 255 for a free segment in images from some cameras)
    1498             $exifTool->Warn("Unlisted FPXR segment (index $index)") if $index != 255;
    1499         }
    1500 
    1501     } elsif ($type ne 3) {  # not a "Reserved" segment
    1502 
    1503         $exifTool->Warn("Unknown FPXR segment (type $type)");
     1999            $et->Warn("Unlisted FPXR segment (index $index)") if $index != 255;
     2000        }
     2001
     2002    } elsif ($type != 3) {  # not a "Reserved" segment
     2003
     2004        $et->Warn("Unknown FPXR segment (type $type)");
    15042005
    15052006    }
     
    15072008    # clean up if this was the last FPXR segment
    15082009    if ($$dirInfo{LastFPXR}) {
    1509         if ($$exifTool{FPXR}) {
     2010        if ($$et{FPXR}) {
    15102011            my $obj;
    1511             my $i = 0;
    1512             foreach $obj (@{$$exifTool{FPXR}}) {
    1513                 $exifTool->Warn("Missing stream for FPXR object $i") if defined $$obj{Stream};
    1514                 ++$i;
     2012            foreach $obj (@{$$et{FPXR}}) {
     2013                next unless defined $$obj{Stream} and length $$obj{Stream};
     2014                # parse it even though it isn't the proper length
     2015                $et->HandleTag($tagTablePtr, $$obj{Name}, $$obj{Stream},
     2016                    DataPt => \$$obj{Stream},
     2017                    TagInfo => $$obj{TagInfo},
     2018                );
    15152019            }
    1516             delete $$exifTool{FPXR};    # delete our temporary variables
    1517         }
    1518         if ($$exifTool{FujiPreview}) {
    1519             $exifTool->FoundTag('PreviewImage', $$exifTool{FujiPreview});
    1520             delete $$exifTool{FujiPreview};
     2020            delete $$et{FPXR};    # delete our temporary variables
     2021        }
     2022        if ($$et{FujiPreview}) {
     2023            $et->FoundTag('PreviewImage', $$et{FujiPreview});
     2024            delete $$et{FujiPreview};
    15212025        }
    15222026    }
     
    15492053            $subDoc[-1] = ++$$used[$#subDoc];
    15502054        }
    1551         SetDocNum($hier, $$obj{Child}, \@subDoc, $used, not $meta) 
     2055        SetDocNum($hier, $$obj{Child}, \@subDoc, $used, not $meta);
    15522056    }
    15532057}
     
    15592063sub ProcessFPX($$)
    15602064{
    1561     my ($exifTool, $dirInfo) = @_;
     2065    my ($et, $dirInfo) = @_;
    15622066    my $raf = $$dirInfo{RAF};
    1563     my ($buff, $out, %dumpParms, $oldIndent, $miniStreamBuff);
    1564     my ($tag, %hier, %objIndex);
     2067    my ($buff, $out, $oldIndent, $miniStreamBuff);
     2068    my ($tag, %hier, %objIndex, %loadedDifSect);
    15652069
    15662070    # read header
     
    15702074
    15712075    # set FileType initially based on file extension (we may override this later)
    1572     my $fileType = $exifTool->{FILE_EXT};
     2076    my $fileType = $$et{FILE_EXT};
    15732077    $fileType = 'FPX' unless $fileType and $fpxFileType{$fileType};
    1574     $exifTool->SetFileType($fileType);
     2078    $et->SetFileType($fileType);
    15752079    SetByteOrder(substr($buff, 0x1c, 2) eq "\xff\xfe" ? 'MM' : 'II');
    15762080    my $tagTablePtr = GetTagTable('Image::ExifTool::FlashPix::Main');
    1577     my $verbose = $exifTool->Options('Verbose');
     2081    my $verbose = $et->Options('Verbose');
    15782082    # copy LargeFileSupport option to RAF for use in LoadChain
    1579     $$raf{LargeFileSupport} = $exifTool->Options('LargeFileSupport');
     2083    $$raf{LargeFileSupport} = $et->Options('LargeFileSupport');
    15802084
    15812085    my $sectSize = 1 << Get16u(\$buff, 0x1e);
     
    15902094
    15912095    if ($verbose) {
    1592         $out = $exifTool->Options('TextOut');
    1593         $dumpParms{Out} = $out;
    1594         $dumpParms{MaxLen} = 96 if $verbose == 3;
     2096        $out = $et->Options('TextOut');
    15952097        print $out "  Sector size=$sectSize\n  FAT: Count=$fatCount\n";
    15962098        print $out "  DIR: Start=$dirStart\n";
     
    16052107    my $fat = '';
    16062108    my $fatCountCheck = 0;
     2109    my $difCountCheck = 0;
     2110    my $hdrSize = $sectSize > HDR_SIZE ? $sectSize : HDR_SIZE;
     2111
    16072112    for (;;) {
    16082113        while ($pos <= $endPos - 4) {
     
    16102115            $pos += 4;
    16112116            next if $sect == FREE_SECT;
    1612             my $offset = $sect * $sectSize + HDR_SIZE;
     2117            my $offset = $sect * $sectSize + $hdrSize;
    16132118            my $fatSect;
    16142119            unless ($raf->Seek($offset, 0) and
    16152120                    $raf->Read($fatSect, $sectSize) == $sectSize)
    16162121            {
    1617                 $exifTool->Error("Error reading FAT from sector $sect");
     2122                $et->Error("Error reading FAT from sector $sect");
    16182123                return 1;
    16192124            }
     
    16232128        last if $difStart >= END_OF_CHAIN;
    16242129        # read next DIF (Dual Indirect FAT) sector
    1625         my $offset = $difStart * $sectSize + HDR_SIZE;
     2130        if (++$difCountCheck > $difCount) {
     2131            $et->Warn('Unterminated DIF FAT');
     2132            last;
     2133        }
     2134        if ($loadedDifSect{$difStart}) {
     2135            $et->Warn('Cyclical reference in DIF FAT');
     2136            last;
     2137        }
     2138        my $offset = $difStart * $sectSize + $hdrSize;
    16262139        unless ($raf->Seek($offset, 0) and $raf->Read($buff, $sectSize) == $sectSize) {
    1627             $exifTool->Error("Error reading DIF sector $difStart");
     2140            $et->Error("Error reading DIF sector $difStart");
    16282141            return 1;
    16292142        }
     2143        $loadedDifSect{$difStart} = 1;
    16302144        # set end of sector information in this DIF
    16312145        $pos = 0;
     
    16352149    }
    16362150    if ($fatCountCheck != $fatCount) {
    1637         $exifTool->Warn("Bad number of FAT sectors (expected $fatCount but found $fatCountCheck)");
     2151        $et->Warn("Bad number of FAT sectors (expected $fatCount but found $fatCountCheck)");
    16382152    }
    16392153#
    16402154# load the mini-FAT and the directory
    16412155#
    1642     my $miniFat = LoadChain($raf, $miniStart, \$fat, $sectSize, HDR_SIZE);
    1643     my $dir = LoadChain($raf, $dirStart, \$fat, $sectSize, HDR_SIZE);
     2156    my $miniFat = LoadChain($raf, $miniStart, \$fat, $sectSize, $hdrSize);
     2157    my $dir = LoadChain($raf, $dirStart, \$fat, $sectSize, $hdrSize);
    16442158    unless (defined $miniFat and defined $dir) {
    1645         $exifTool->Error('Error reading mini-FAT or directory stream');
     2159        $et->Error('Error reading mini-FAT or directory stream');
    16462160        return 1;
    16472161    }
    16482162    if ($verbose) {
    16492163        print $out "  FAT [",length($fat)," bytes]:\n";
    1650         Image::ExifTool::HexDump(\$fat, undef, %dumpParms) if $verbose > 2;
     2164        $et->VerboseDump(\$fat);
    16512165        print $out "  Mini-FAT [",length($miniFat)," bytes]:\n";
    1652         Image::ExifTool::HexDump(\$miniFat, undef, %dumpParms) if $verbose > 2;
     2166        $et->VerboseDump(\$miniFat);
    16532167        print $out "  Directory [",length($dir)," bytes]:\n";
    1654         Image::ExifTool::HexDump(\$dir, undef, %dumpParms) if $verbose > 2;
     2168        $et->VerboseDump(\$dir);
    16552169    }
    16562170#
     
    16582172#
    16592173    if ($verbose) {
    1660         $oldIndent = $exifTool->{INDENT};
    1661         $exifTool->{INDENT} .= '| ';
    1662         $exifTool->VerboseDir('FPX', undef, length $dir);
     2174        $oldIndent = $$et{INDENT};
     2175        $$et{INDENT} .= '| ';
     2176        $et->VerboseDir('FPX', undef, length $dir);
    16632177    }
    16642178    my $miniStream;
     
    16732187        next if $type == 0; # skip invalid entries
    16742188        if ($type > 5) {
    1675             $exifTool->Warn("Invalid directory entry type $type");
     2189            $et->Warn("Invalid directory entry type $type");
    16762190            last;   # rest of directory is probably garbage
    16772191        }
     
    16892203        # load Ministream (referenced from first directory entry)
    16902204        unless ($miniStream) {
    1691             $miniStreamBuff = LoadChain($raf, $sect, \$fat, $sectSize, HDR_SIZE);
     2205            $miniStreamBuff = LoadChain($raf, $sect, \$fat, $sectSize, $hdrSize);
    16922206            unless (defined $miniStreamBuff) {
    1693                 $exifTool->Warn('Error loading Mini-FAT stream');
     2207                $et->Warn('Error loading Mini-FAT stream');
    16942208                last;
    16952209            }
     
    16992213        my $tagInfo;
    17002214        if ($$tagTablePtr{$tag}) {
    1701             $tagInfo = $exifTool->GetTagInfo($tagTablePtr, $tag);
     2215            $tagInfo = $et->GetTagInfo($tagTablePtr, $tag);
    17022216        } else {
    17032217            # remove instance number or class ID from tag if necessary
    1704             $tagInfo = $exifTool->GetTagInfo($tagTablePtr, $1) if
     2218            $tagInfo = $et->GetTagInfo($tagTablePtr, $1) if
    17052219                ($tag =~ /(.*) \d{6}$/s and $$tagTablePtr{$1}) or
    17062220                ($tag =~ /(.*)_[0-9a-f]{16}$/s and $$tagTablePtr{$1});
     
    17112225        my $chld = Get32u(\$dir, $pos + 0x4c);  # child directory
    17122226
    1713         # save information about object hierachy
     2227        # save information about object hierarchy
    17142228        my ($obj, $sub);
    17152229        $obj = $hier{$index} or $obj = $hier{$index} = { };
     
    17302244            if ($size >= $miniCutoff) {
    17312245                # stream is in the main FAT
    1732                 $buff = LoadChain($raf, $sect, \$fat, $sectSize, HDR_SIZE);
     2246                $buff = LoadChain($raf, $sect, \$fat, $sectSize, $hdrSize);
    17332247            } elsif ($size) {
    17342248                # stream is in the mini-FAT
     
    17392253            unless (defined $buff) {
    17402254                my $name = $tagInfo ? $$tagInfo{Name} : 'unknown';
    1741                 $exifTool->Warn("Error reading $name stream");
     2255                $et->Warn("Error reading $name stream");
    17422256                $buff = '';
    17432257            }
     
    17562270            $extra .= " Right=$rSib" unless $rSib == FREE_SECT;
    17572271            $extra .= " Child=$chld" unless $chld == FREE_SECT;
    1758             $exifTool->VerboseInfo($tag, $tagInfo,
     2272            $et->VerboseInfo($tag, $tagInfo,
    17592273                Index  => $index,
    17602274                Value  => $buff,
     
    17652279        }
    17662280        if ($tagInfo and $buff) {
    1767             my $num = $$exifTool{NUM_FOUND};
     2281            my $num = $$et{NUM_FOUND};
    17682282            my $subdir = $$tagInfo{SubDirectory};
    17692283            if ($subdir) {
     
    17752289                );
    17762290                my $subTablePtr = GetTagTable($$subdir{TagTable});
    1777                 $exifTool->ProcessDirectory(\%dirInfo, $subTablePtr,  $$subdir{ProcessProc});
     2291                $et->ProcessDirectory(\%dirInfo, $subTablePtr,  $$subdir{ProcessProc});
    17782292            } else {
    1779                 $exifTool->FoundTag($tagInfo, $buff);
     2293                $et->FoundTag($tagInfo, $buff);
    17802294            }
    17812295            # save object index number for all found tags
    1782             my $num2 = $$exifTool{NUM_FOUND};
     2296            my $num2 = $$et{NUM_FOUND};
    17832297            $objIndex{++$num} = $index while $num < $num2;
    17842298        }
    17852299    }
    17862300    # set document numbers for tags extracted from embedded documents
    1787     unless ($$exifTool{DOC_NUM}) {
     2301    unless ($$et{DOC_NUM}) {
    17882302        # initialize document number for all objects, beginning at root (index 0)
    17892303        SetDocNum(\%hier, 0);
    17902304        # set family 3 group name for all tags in embedded documents
    1791         my $order = $$exifTool{FILE_ORDER};
     2305        my $order = $$et{FILE_ORDER};
    17922306        my (@pri, $copy, $member);
    17932307        foreach $tag (keys %$order) {
     
    17972311            my $docNums = $$obj{DocNum};
    17982312            next unless $docNums and @$docNums;
    1799             $$exifTool{TAG_EXTRA}{$tag}{G3} = join '-', @$docNums;
     2313            $$et{TAG_EXTRA}{$tag}{G3} = join '-', @$docNums;
    18002314            push @pri, $tag unless $tag =~ / /; # save keys for priority sub-doc tags
    18012315        }
     
    18042318            for ($copy=1; ;++$copy) {
    18052319                my $key = "$tag ($copy)";
    1806                 last unless defined $$exifTool{VALUE}{$key};
    1807                 my $extra = $$exifTool{TAG_EXTRA}{$key};
     2320                last unless defined $$et{VALUE}{$key};
     2321                my $extra = $$et{TAG_EXTRA}{$key};
    18082322                next if $extra and $$extra{G3}; # not Main if family 3 group is set
    18092323                foreach $member ('PRIORITY','VALUE','FILE_ORDER','TAG_INFO','TAG_EXTRA') {
    1810                     my $pHash = $$exifTool{$member};
     2324                    my $pHash = $$et{$member};
    18112325                    my $t = $$pHash{$tag};
    18122326                    $$pHash{$tag} = $$pHash{$key};
     
    18172331        }
    18182332    }
    1819     $exifTool->{INDENT} = $oldIndent if $verbose;
     2333    $$et{INDENT} = $oldIndent if $verbose;
    18202334    # try to better identify the file type
    1821     if ($$exifTool{VALUE}{FileType} eq 'FPX') {
    1822         my $val = $$exifTool{CompObjUserType} || $$exifTool{Software};
     2335    if ($$et{VALUE}{FileType} eq 'FPX') {
     2336        my $val = $$et{CompObjUserType} || $$et{Software};
    18232337        if ($val) {
    1824             my %type = ( Word => 'DOC', PowerPoint => 'PPT', Excel => 'XLS' );
     2338            my %type = ( '^3ds Max' => 'MAX', Word => 'DOC', PowerPoint => 'PPT', Excel => 'XLS' );
    18252339            my $pat;
    18262340            foreach $pat (sort keys %type) {
    18272341                next unless $val =~ /$pat/;
    1828                 $exifTool->OverrideFileType($type{$pat});
     2342                $et->OverrideFileType($type{$pat});
    18292343                last;
    18302344            }
    18312345        }
    18322346    }
     2347    # process Word document table
     2348    ProcessDocumentTable($et);
     2349
    18332350    return 1;
    18342351}
     
    18542371=head1 AUTHOR
    18552372
    1856 Copyright 2003-2011, Phil Harvey (phil at owl.phy.queensu.ca)
     2373Copyright 2003-2021, Phil Harvey (philharvey66 at gmail.com)
    18572374
    18582375This library is free software; you can redistribute it and/or modify it
Note: See TracChangeset for help on using the changeset viewer.