Skip to content

Commit e2b0115

Browse files
committed
Update ExifTool to 12.65...
...and add a new, more robust mechanism for in-place ExifTool upgrades. PhotoDemon uses the wonderful ExifTool library to retrieve and embed metadata in a number of different image formats. ExifTool is written in Perl and when it is run (on Windows), it extracts a portable Perl runtime and a local copy of Exiftool itself (as a collection of Perl files.) The total extraction list is well over 1,000 files extracted, and PhotoDemon has ExifTool place these files in the /Data/PluginData folder. Normally, I have been able to just drop-in a new copy of ExifTool without trouble, but when trying to upgrade from v12.44, ExifTool would throw random errors related to individual Perl (.pl) files in various subfolders of /Data/PluginData. This appears to be tied to internal library changes over the past year. To prevent this from causing issues for PD users, I now check for in-place ExifTool upgrades and when these occur, PD manually deletes relevant files from the ExifTool subfolder, which prompts ExifTool to re-extract its files from scratch when we invoke it next. This was not straightforward as the portable Perl version ExifTool uses assigns inconsistent file permissions to random files, even within the same subfolder! I have manually blacklisted files and folders where I encountered permissions issues, and the new solution allows for in-place upgrades, without errors, and without throwing a bunch of permission errors when PD tries to clean-up ExifTool's portable Perl copy between upgrades. Long story short, ExifTool has now been updated and future updates should (fingers crossed) not cause problems for anyone. (I tackled this problem now because recent ExifTool versions add some support for JPEG XL metadata.)
1 parent 881edee commit e2b0115

File tree

4 files changed

+146
-6
lines changed

4 files changed

+146
-6
lines changed
495 KB
Binary file not shown.

Modules/Plugin_ExifTool.bas

Lines changed: 144 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@ Attribute VB_Name = "ExifTool"
33
'ExifTool Plugin Interface
44
'Copyright 2013-2023 by Tanner Helland
55
'Created: 24/May/13
6-
'Last updated: 13/September/23
7-
'Last update: switch to pdPipeSync for one-off shell instances (like retrieving library version)
6+
'Last updated: 18/September/23
7+
'Last update: expansive new upgrade-in-place system to solve errors when upgrading from ExifTool 12.44 to 12.65.
88
'
99
'Module for handling all ExifTool interfacing. This module is pointless without the accompanying ExifTool plugin,
1010
' which can be found in the App/PhotoDemon/Plugins subdirectory as "exiftool.exe". The ExifTool plugin is
@@ -1305,11 +1305,151 @@ End Function
13051305
' loading via FreeImage or GDI+.
13061306
Public Function StartExifTool() As Boolean
13071307

1308-
'Start by creating a temp folder for ExifTool-specific data, as necessary
1308+
'Start by creating a dedicated temp folder for ExifTool's required run-time extraction of Perl
13091309
m_ExifToolDataFolder = UserPrefs.GetDataPath() & "PluginData\"
13101310
Dim cFSO As pdFSO
13111311
Set cFSO = New pdFSO
1312-
Files.PathCreate m_ExifToolDataFolder
1312+
1313+
If Files.PathExists(m_ExifToolDataFolder) Then
1314+
1315+
'Ensure that the version of ExifTool hasn't changed since the last extraction.
1316+
' (If it has, errors can occur - this happened to PD after updating from the ExifTool 12.44 release
1317+
' to a later build.)
1318+
'
1319+
'To do this, we can quickly grab the main ExifTool Perl file and compare it against our current expected
1320+
' ExifTool version. If the two do not match, kill the existing ExifTool folder and allow the .exe to
1321+
' re-create it anew.
1322+
Const VERSION_REF_FILE As String = "inc\script\exiftool"
1323+
1324+
Dim fullPathToRefFile As String
1325+
fullPathToRefFile = m_ExifToolDataFolder & VERSION_REF_FILE
1326+
1327+
If Files.FileExists(fullPathToRefFile) Then
1328+
1329+
Const SAFE_BUFFER_SIZE As Long = 1024
1330+
1331+
Dim cStream As pdStream
1332+
Set cStream = New pdStream
1333+
If cStream.StartStream(PD_SM_FileMemoryMapped, PD_SA_ReadOnly, fullPathToRefFile, SAFE_BUFFER_SIZE, optimizeAccess:=OptimizeSequentialAccess) Then
1334+
1335+
'Grab just the first 1024 bytes. Version should appear around char ~450, so this is a
1336+
' sufficiently safe sample size.
1337+
Dim fileContents As String
1338+
fileContents = cStream.ReadString_UTF8(SAFE_BUFFER_SIZE, False)
1339+
1340+
'We no longer need access to the file
1341+
cStream.StopStream True
1342+
Set cStream = Nothing
1343+
1344+
Const VERSION_STRING_PREFIX As String = "my $version = '"
1345+
1346+
Dim posVersion As Long
1347+
posVersion = InStr(1, fileContents, VERSION_STRING_PREFIX, vbBinaryCompare)
1348+
If (posVersion > 0) Then
1349+
1350+
'Increment past the initial single-quote
1351+
posVersion = posVersion + Len(VERSION_STRING_PREFIX)
1352+
1353+
'Find the version string trailer single-quote
1354+
Dim posVersionEnd As Long
1355+
posVersionEnd = InStr(posVersion, fileContents, "'", vbBinaryCompare)
1356+
If (posVersionEnd > posVersion + 1) Then
1357+
1358+
Dim efVersion As String
1359+
efVersion = Mid$(fileContents, posVersion, posVersionEnd - posVersion)
1360+
1361+
'Compare the embedded version to the expected version for this PhotoDemon build.
1362+
Dim versionMatch As Boolean
1363+
versionMatch = Strings.StringsEqual(efVersion, PluginManager.ExpectedPluginVersion(CCP_ExifTool), True)
1364+
1365+
If (Not versionMatch) Then
1366+
1367+
PDDebug.LogAction "Warning: ExifTool data folder is out of date. Preparing to rebuild..."
1368+
1369+
'We now need to remove all files and subfolders from the /PluginData folder so that
1370+
' ExifTool can rebuild it according to its current version.
1371+
Dim filesToDelete As pdStringStack
1372+
Set filesToDelete = New pdStringStack
1373+
If Files.RetrieveAllFiles(m_ExifToolDataFolder, filesToDelete, True, False) Then
1374+
1375+
Dim numFilesDeleted As Long
1376+
numFilesDeleted = 0
1377+
1378+
'In a perfect world, we could just remove files one-by-one and that would be that!
1379+
' Unfortunately, the Perl packer ExifTool uses generates a lot of files with weird
1380+
' permissions, so if we try to just blind-delete everything we will generate a ton
1381+
' of permission errors.
1382+
'
1383+
'I have instead tried to blacklist file locations where I've encountered permission
1384+
' errors while testing this feature, which should allows us to delete files that have
1385+
' caused upgrade errors in past versions *without* engaging with any portable Perl
1386+
' files that we don't have delete permissions on. (Theoretically we could also check
1387+
' permissions on each file before attempting to delete, but mass-checking arbitrary
1388+
' file permissions risks upsetting some virus scanners, so I simply avoid interacting
1389+
' with unnecessary files at all.)
1390+
Dim i As Long
1391+
For i = 0 To filesToDelete.GetNumOfStrings - 1
1392+
1393+
Dim targetFile As String
1394+
targetFile = filesToDelete.GetString(i)
1395+
1396+
Dim okToDelete As Boolean
1397+
okToDelete = Files.FileExists(targetFile) 'Failsafe only
1398+
1399+
'This blacklist is hard-coded per manual file permission checks in the past.
1400+
If okToDelete Then
1401+
okToDelete = okToDelete And (InStr(1, targetFile, "\inc\lib\auto\", vbTextCompare) <= 0)
1402+
If okToDelete Then okToDelete = okToDelete And (InStr(1, targetFile, "\inc\lib\unicore\", vbTextCompare) <= 0)
1403+
If okToDelete Then okToDelete = okToDelete And (InStr(1, targetFile, "\inc\lib\Win32API\File\", vbTextCompare) <= 0)
1404+
If okToDelete Then okToDelete = okToDelete And (InStr(1, targetFile, "\inc\lib\bytes_heavy.pl", vbTextCompare) <= 0)
1405+
If okToDelete Then okToDelete = okToDelete And (InStr(1, targetFile, "\inc\lib\Config_git.pl", vbTextCompare) <= 0)
1406+
If okToDelete Then okToDelete = okToDelete And (InStr(1, targetFile, "\inc\lib\Config_heavy.pl", vbTextCompare) <= 0)
1407+
End If
1408+
1409+
'Remove valid files (ExifTool will auto-regenerate them as necessary)
1410+
If okToDelete Then
1411+
If Files.FileDeleteIfExists(targetFile) Then
1412+
numFilesDeleted = numFilesDeleted + 1
1413+
Else
1414+
PDDebug.LogAction "Failed to delete: " & filesToDelete.GetString(i)
1415+
End If
1416+
End If
1417+
1418+
Next i
1419+
1420+
PDDebug.LogAction "ExifTool upgrade prep resulted in " & numFilesDeleted & " of " & filesToDelete.GetNumOfStrings & " files removed."
1421+
1422+
'With all files gone, ExifTool can now rebuild itself accordingly
1423+
PDDebug.LogAction "ExifTool will now automatically rebuild its file cache..."
1424+
1425+
End If
1426+
1427+
'/if versions match, do nothing! We are good to go.
1428+
Else
1429+
PDDebug.LogAction "(ExifTool version OK!)"
1430+
End If
1431+
1432+
'/some kind of formatting problem; file structure has possibly changed since I last investigated?
1433+
Else
1434+
PDDebug.LogAction "WARNING: EXIFTOOL VERSION FORMAT UNEXPECTED"
1435+
End If
1436+
1437+
'/Version not found - file format has possibly changed?
1438+
Else
1439+
PDDebug.LogAction "WARNING: NO EXIFTOOL VERSION IN PLUGINDATA"
1440+
End If
1441+
1442+
'/If we can't open the file, do not attempt to analyze (ExifTool may have it open already,
1443+
' in which case it's too late to do anything about it)
1444+
End If
1445+
1446+
'/no else required; if the target file doesn't exist, ExifTool will create it automatically
1447+
End If
1448+
1449+
'Create the folder anew
1450+
Else
1451+
Files.PathCreate m_ExifToolDataFolder
1452+
End If
13131453

13141454
'Set any other, related ExifTool paths now
13151455
m_DatabasePath = m_ExifToolDataFolder & "exifToolDatabase.xml"

Modules/Plugin_Management.bas

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ End Enum
5757
'Expected version numbers of plugins. These are updated at each new PhotoDemon release (if a new version of
5858
' the plugin is available, obviously).
5959
Private Const EXPECTED_CHARLS_VERSION As String = "2.2"
60-
Private Const EXPECTED_EXIFTOOL_VERSION As String = "12.44"
60+
Private Const EXPECTED_EXIFTOOL_VERSION As String = "12.65"
6161
Private Const EXPECTED_EZTWAIN_VERSION As String = "1.18.0"
6262
Private Const EXPECTED_FREEIMAGE_VERSION As String = "3.19.0"
6363
Private Const EXPECTED_LIBAVIF_VERSION As String = "1.0.1"

PhotoDemon.vbp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -519,7 +519,7 @@ Description="PhotoDemon Photo Editor"
519519
CompatibleMode="0"
520520
MajorVer=9
521521
MinorVer=1
522-
RevisionVer=180
522+
RevisionVer=181
523523
AutoIncrementVer=1
524524
ServerSupportFiles=0
525525
VersionComments="Copyright 2000-2023 Tanner Helland - photodemon.org"

0 commit comments

Comments
 (0)