From 55c784eb32cfc800884c619d1cbbfdb27ccb1c7f Mon Sep 17 00:00:00 2001 From: Nitin Nair Date: Fri, 30 Jan 2026 12:11:03 -0500 Subject: [PATCH 1/3] added a patch to backup settings files --- EmotiBitInstaller/EmotiBitInstaller.iss | 167 +++++++++++++++++++++++- src/ofxEmotiBitVersion.h | 2 +- 2 files changed, 163 insertions(+), 6 deletions(-) diff --git a/EmotiBitInstaller/EmotiBitInstaller.iss b/EmotiBitInstaller/EmotiBitInstaller.iss index c9707ab..d949fb4 100644 --- a/EmotiBitInstaller/EmotiBitInstaller.iss +++ b/EmotiBitInstaller/EmotiBitInstaller.iss @@ -30,15 +30,21 @@ ArchitecturesInstallIn64BitMode=x64 ; EmotiBit Oscilloscope Source: "..\EmotiBitOscilloscope\bin\EmotiBitOscilloscope.exe"; DestDir: "{app}\EmotiBit Oscilloscope" Source: "..\EmotiBitOscilloscope\bin\*.dll"; DestDir: "{app}\EmotiBit Oscilloscope" -Source: "..\EmotiBitOscilloscope\bin\data\*.json"; DestDir: "{app}\EmotiBit Oscilloscope\data" -Source: "..\EmotiBitOscilloscope\bin\data\*.xml"; DestDir: "{app}\EmotiBit Oscilloscope\data" Source: "..\EmotiBitOscilloscope\bin\data\*.ttf"; DestDir: "{app}\EmotiBit Oscilloscope\data" +; Settings files - existing files backed up in [Code] PrepareToInstall before Inno copies new ones +Source: "..\EmotiBitOscilloscope\bin\data\emotibitCommSettings.json"; DestDir: "{app}\EmotiBit Oscilloscope\data" +Source: "..\EmotiBitOscilloscope\bin\data\lslOutputSettings.json"; DestDir: "{app}\EmotiBit Oscilloscope\data" +Source: "..\EmotiBitOscilloscope\bin\data\inputSettings.xml"; DestDir: "{app}\EmotiBit Oscilloscope\data" +Source: "..\EmotiBitOscilloscope\bin\data\ofxOscilloscopeSettings.xml"; DestDir: "{app}\EmotiBit Oscilloscope\data" +Source: "..\EmotiBitOscilloscope\bin\data\oscOutputSettings.xml"; DestDir: "{app}\EmotiBit Oscilloscope\data" +Source: "..\EmotiBitOscilloscope\bin\data\udpOutputSettings.xml"; DestDir: "{app}\EmotiBit Oscilloscope\data" ; EmotiBit DataParser Source: "..\EmotiBitDataParser\bin\EmotiBitDataParser.exe"; DestDir: "{app}\EmotiBit DataParser" Source: "..\EmotiBitDataParser\bin\*.dll"; DestDir: "{app}\EmotiBit DataParser" -Source: "..\EmotiBitDataParser\bin\data\*.json"; DestDir: "{app}\EmotiBit DataParser\data" Source: "..\EmotiBitDataParser\bin\data\*.ttf"; DestDir: "{app}\EmotiBit DataParser\data" +; Settings files - existing files backed up in [Code] PrepareToInstall before Inno copies new ones +Source: "..\EmotiBitDataParser\bin\data\parsedDataFormat.json"; DestDir: "{app}\EmotiBit DataParser\data" ; EmotiBit FirmwareInstaller Source: "..\EmotiBitFirmwareInstaller\bin\EmotiBitFirmwareInstaller.exe"; DestDir: "{app}\EmotiBit FirmwareInstaller" @@ -77,11 +83,17 @@ const MSI_PRODUCT_CODE = '{B2F470EF-3C46-46C9-9948-9446D059330D}'; MSI_UNINSTALL_KEY = 'SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\{B2F470EF-3C46-46C9-9948-9446D059330D}'; + // Number of settings files to backup (update when adding new files) + SETTINGS_FILE_COUNT = 7; + var DriverAckPage: TWizardPage; DriverInfoLabel: TNewStaticText; DriverLinkLabel: TNewStaticText; DriverAckCheckbox: TNewCheckBox; + // Settings backup tracking + BackedUpFilesCount: Integer; + BackupTimestamp: String; //============================================================================= // MSI Detection Functions @@ -163,7 +175,146 @@ begin end; //============================================================================= -// Pre-Installation Check (MSI Migration) +// Settings File Backup Functions +//============================================================================= + +// Centralized settings file list - update here when adding new files +// Also update SETTINGS_FILE_COUNT constant +procedure GetSettingsFileInfo(Index: Integer; var FileName, DestDir: String); +begin + case Index of + 0: begin FileName := 'emotibitCommSettings.json'; DestDir := '{app}\EmotiBit Oscilloscope\data'; end; + 1: begin FileName := 'lslOutputSettings.json'; DestDir := '{app}\EmotiBit Oscilloscope\data'; end; + 2: begin FileName := 'inputSettings.xml'; DestDir := '{app}\EmotiBit Oscilloscope\data'; end; + 3: begin FileName := 'ofxOscilloscopeSettings.xml'; DestDir := '{app}\EmotiBit Oscilloscope\data'; end; + 4: begin FileName := 'oscOutputSettings.xml'; DestDir := '{app}\EmotiBit Oscilloscope\data'; end; + 5: begin FileName := 'udpOutputSettings.xml'; DestDir := '{app}\EmotiBit Oscilloscope\data'; end; + 6: begin FileName := 'parsedDataFormat.json'; DestDir := '{app}\EmotiBit DataParser\data'; end; + end; +end; + +function GetBackupTimestamp: String; +begin + // Get current date/time formatted as YYYY-MM-DD_HHMMSS + // Format specifiers: yyyy=year, mm=month, dd=day, hh=hour, nn=minute, ss=second + Result := GetDateTimeString('yyyy-mm-dd_hhnnss', '-', ':'); +end; + +function GetBackupFilePath(OriginalPath: String): String; +var + Dir, Name, Ext: String; +begin + // Convert "C:\path\settings.json" to "C:\path\settings_backup_2026-01-29_143052.json" + Dir := ExtractFilePath(OriginalPath); + Name := ExtractFileName(OriginalPath); + Ext := ExtractFileExt(Name); + Name := Copy(Name, 1, Length(Name) - Length(Ext)); + Result := Dir + Name + '_backup_' + BackupTimestamp + Ext; +end; + +procedure BackupSettingsFile(FileName, DestSubDir: String); +var + DestPath, BackupPath: String; +begin + DestPath := ExpandConstant(DestSubDir + '\') + FileName; + + if FileExists(DestPath) then + begin + BackupPath := GetBackupFilePath(DestPath); + if RenameFile(DestPath, BackupPath) then + begin + Log('Backed up: ' + DestPath + ' -> ' + BackupPath); + BackedUpFilesCount := BackedUpFilesCount + 1; + end + else + Log('Warning: Failed to backup ' + DestPath); + end + else + Log('No existing file to backup: ' + FileName); +end; + +procedure BackupAllSettingsFiles; +var + I: Integer; + FileName, DestDir: String; +begin + BackupTimestamp := GetBackupTimestamp(); + BackedUpFilesCount := 0; + + for I := 0 to SETTINGS_FILE_COUNT - 1 do + begin + GetSettingsFileInfo(I, FileName, DestDir); + BackupSettingsFile(FileName, DestDir); + end; +end; + +procedure CleanupBackupIfIdentical(FileName, DestSubDir: String); +var + NewFilePath, BackupPath: String; + NewContent, BackupContent: AnsiString; +begin + NewFilePath := ExpandConstant(DestSubDir + '\') + FileName; + BackupPath := GetBackupFilePath(NewFilePath); + + if not FileExists(BackupPath) then + Exit; + + if not FileExists(NewFilePath) then + begin + Log('Warning: New file not found, keeping backup: ' + BackupPath); + Exit; + end; + + if LoadStringFromFile(NewFilePath, NewContent) and + LoadStringFromFile(BackupPath, BackupContent) then + begin + if NewContent = BackupContent then + begin + if DeleteFile(BackupPath) then + begin + Log('Deleted identical backup: ' + BackupPath); + BackedUpFilesCount := BackedUpFilesCount - 1; + end + else + Log('Warning: Failed to delete backup: ' + BackupPath); + end + else + Log('Keeping backup (file was modified): ' + BackupPath); + end + else + Log('Warning: Could not compare files, keeping backup: ' + BackupPath); +end; + +procedure CleanupIdenticalBackups; +var + I: Integer; + FileName, DestDir: String; +begin + for I := 0 to SETTINGS_FILE_COUNT - 1 do + begin + GetSettingsFileInfo(I, FileName, DestDir); + CleanupBackupIfIdentical(FileName, DestDir); + end; +end; + +procedure CurStepChanged(CurStep: TSetupStep); +begin + if CurStep = ssPostInstall then + begin + // Clean up backups that are identical to new files + CleanupIdenticalBackups(); + + // Show message if any backups remain (user had customizations) + if (BackedUpFilesCount > 0) and (not WizardSilent()) then + begin + MsgBox('Your customized settings files were backed up with a _backup_' + BackupTimestamp + ' suffix.', + mbInformation, MB_OK); + end; + end; +end; + +//============================================================================= +// Pre-Installation: Settings Backup and MSI Migration //============================================================================= function PrepareToInstall(var NeedsRestart: Boolean): String; @@ -174,7 +325,13 @@ begin Result := ''; NeedsRestart := False; - // Check for old MSI installation + // STEP 1: Backup existing settings files FIRST (before any uninstall) + // This preserves user settings whether upgrading from MSI or Inno + // New files are copied later by [Files] section + // Identical backups are cleaned up in CurStepChanged(ssPostInstall) + BackupAllSettingsFiles(); + + // STEP 2: Check for old MSI installation and remove it if IsMsiInstalled() then begin MsiVersion := GetMsiVersion(); diff --git a/src/ofxEmotiBitVersion.h b/src/ofxEmotiBitVersion.h index fbf76bf..1a475cc 100644 --- a/src/ofxEmotiBitVersion.h +++ b/src/ofxEmotiBitVersion.h @@ -3,7 +3,7 @@ #include "ofMain.h" -const std::string ofxEmotiBitVersion = "1.14.2"; +const std::string ofxEmotiBitVersion = "1.14.3"; static const char SOFTWARE_VERSION_PREFIX = 'v'; From 9ff9483408b8e3a1644436b94d597b3042ca89ef Mon Sep 17 00:00:00 2001 From: Nitin Nair Date: Fri, 30 Jan 2026 17:13:59 -0500 Subject: [PATCH 2/3] updated the installer to move backup files to a backup directory. also adds a patch to remove all emotibit directories on uninstall (was an issue if upgrading from MSI to INNO installer) --- EmotiBitInstaller/EmotiBitInstaller.iss | 62 +++++++++++++++++++++++-- src/ofxEmotiBitVersion.h | 2 +- 2 files changed, 58 insertions(+), 6 deletions(-) diff --git a/EmotiBitInstaller/EmotiBitInstaller.iss b/EmotiBitInstaller/EmotiBitInstaller.iss index d949fb4..7d64125 100644 --- a/EmotiBitInstaller/EmotiBitInstaller.iss +++ b/EmotiBitInstaller/EmotiBitInstaller.iss @@ -77,6 +77,15 @@ Name: "{group}\EmotiBit FirmwareInstaller"; Filename: "{app}\EmotiBit FirmwareIn ; Install VC++ 2017 Redistributable if not already installed Filename: "{tmp}\vc_redist.x64.exe"; Parameters: "/passive /norestart"; StatusMsg: "Installing Visual C++ 2017 Redistributable..."; Check: VCRedistNeedsInstall +[UninstallDelete] +; Delete entire application folders to ensure clean uninstall +; This removes all files including runtime-created logs, cache, backups, and user data +Type: filesandordirs; Name: "{app}\EmotiBit Oscilloscope" +Type: filesandordirs; Name: "{app}\EmotiBit DataParser" +Type: filesandordirs; Name: "{app}\EmotiBit FirmwareInstaller" +; Delete the parent EmotiBit folder if empty after above deletions +Type: dirifempty; Name: "{app}" + [Code] const // MSI ProductCode from the old Visual Studio Installer Project (v1.12.2) @@ -204,23 +213,56 @@ function GetBackupFilePath(OriginalPath: String): String; var Dir, Name, Ext: String; begin - // Convert "C:\path\settings.json" to "C:\path\settings_backup_2026-01-29_143052.json" + // Convert "C:\path\settings.json" to "C:\path\backups\settings_2026-01-29_143052.json" Dir := ExtractFilePath(OriginalPath); Name := ExtractFileName(OriginalPath); Ext := ExtractFileExt(Name); Name := Copy(Name, 1, Length(Name) - Length(Ext)); - Result := Dir + Name + '_backup_' + BackupTimestamp + Ext; + Result := Dir + 'backups\' + Name + '_' + BackupTimestamp + Ext; +end; + +function GetBackupsFolder(OriginalPath: String): String; +begin + // Get the backups folder path for a given file path + Result := ExtractFilePath(OriginalPath) + 'backups'; +end; + +function IsDirEmpty(DirPath: String): Boolean; +var + FindRec: TFindRec; +begin + Result := True; + if FindFirst(DirPath + '\*', FindRec) then + begin + try + repeat + if (FindRec.Name <> '.') and (FindRec.Name <> '..') then + begin + Result := False; + Break; + end; + until not FindNext(FindRec); + finally + FindClose(FindRec); + end; + end; end; procedure BackupSettingsFile(FileName, DestSubDir: String); var - DestPath, BackupPath: String; + DestPath, BackupPath, BackupsFolder: String; begin DestPath := ExpandConstant(DestSubDir + '\') + FileName; if FileExists(DestPath) then begin BackupPath := GetBackupFilePath(DestPath); + BackupsFolder := GetBackupsFolder(DestPath); + + // Create the backups folder if it doesn't exist + if not DirExists(BackupsFolder) then + ForceDirectories(BackupsFolder); + if RenameFile(DestPath, BackupPath) then begin Log('Backed up: ' + DestPath + ' -> ' + BackupPath); @@ -250,11 +292,12 @@ end; procedure CleanupBackupIfIdentical(FileName, DestSubDir: String); var - NewFilePath, BackupPath: String; + NewFilePath, BackupPath, BackupsFolder: String; NewContent, BackupContent: AnsiString; begin NewFilePath := ExpandConstant(DestSubDir + '\') + FileName; BackupPath := GetBackupFilePath(NewFilePath); + BackupsFolder := GetBackupsFolder(NewFilePath); if not FileExists(BackupPath) then Exit; @@ -274,6 +317,15 @@ begin begin Log('Deleted identical backup: ' + BackupPath); BackedUpFilesCount := BackedUpFilesCount - 1; + + // Delete the backups folder if it's now empty + if DirExists(BackupsFolder) and IsDirEmpty(BackupsFolder) then + begin + if RemoveDir(BackupsFolder) then + Log('Deleted empty backups folder: ' + BackupsFolder) + else + Log('Warning: Failed to delete empty backups folder: ' + BackupsFolder); + end; end else Log('Warning: Failed to delete backup: ' + BackupPath); @@ -307,7 +359,7 @@ begin // Show message if any backups remain (user had customizations) if (BackedUpFilesCount > 0) and (not WizardSilent()) then begin - MsgBox('Your customized settings files were backed up with a _backup_' + BackupTimestamp + ' suffix.', + MsgBox('Your customized settings files were backed up to the "backups" folder with timestamp ' + BackupTimestamp + '.', mbInformation, MB_OK); end; end; diff --git a/src/ofxEmotiBitVersion.h b/src/ofxEmotiBitVersion.h index 1a475cc..8d727e9 100644 --- a/src/ofxEmotiBitVersion.h +++ b/src/ofxEmotiBitVersion.h @@ -3,7 +3,7 @@ #include "ofMain.h" -const std::string ofxEmotiBitVersion = "1.14.3"; +const std::string ofxEmotiBitVersion = "1.14.4"; static const char SOFTWARE_VERSION_PREFIX = 'v'; From 736f0903a4f3fea918cadbe4258efa5e6e7193c6 Mon Sep 17 00:00:00 2001 From: Nitin Nair Date: Fri, 30 Jan 2026 17:37:10 -0500 Subject: [PATCH 3/3] updated the backup logic to not depend on hardcoded file paths. increases extensibility. tested working. --- EmotiBitInstaller/EmotiBitInstaller.iss | 197 +++++++++++++----------- src/ofxEmotiBitVersion.h | 2 +- 2 files changed, 109 insertions(+), 90 deletions(-) diff --git a/EmotiBitInstaller/EmotiBitInstaller.iss b/EmotiBitInstaller/EmotiBitInstaller.iss index 7d64125..cabd7c5 100644 --- a/EmotiBitInstaller/EmotiBitInstaller.iss +++ b/EmotiBitInstaller/EmotiBitInstaller.iss @@ -31,20 +31,16 @@ ArchitecturesInstallIn64BitMode=x64 Source: "..\EmotiBitOscilloscope\bin\EmotiBitOscilloscope.exe"; DestDir: "{app}\EmotiBit Oscilloscope" Source: "..\EmotiBitOscilloscope\bin\*.dll"; DestDir: "{app}\EmotiBit Oscilloscope" Source: "..\EmotiBitOscilloscope\bin\data\*.ttf"; DestDir: "{app}\EmotiBit Oscilloscope\data" -; Settings files - existing files backed up in [Code] PrepareToInstall before Inno copies new ones -Source: "..\EmotiBitOscilloscope\bin\data\emotibitCommSettings.json"; DestDir: "{app}\EmotiBit Oscilloscope\data" -Source: "..\EmotiBitOscilloscope\bin\data\lslOutputSettings.json"; DestDir: "{app}\EmotiBit Oscilloscope\data" -Source: "..\EmotiBitOscilloscope\bin\data\inputSettings.xml"; DestDir: "{app}\EmotiBit Oscilloscope\data" -Source: "..\EmotiBitOscilloscope\bin\data\ofxOscilloscopeSettings.xml"; DestDir: "{app}\EmotiBit Oscilloscope\data" -Source: "..\EmotiBitOscilloscope\bin\data\oscOutputSettings.xml"; DestDir: "{app}\EmotiBit Oscilloscope\data" -Source: "..\EmotiBitOscilloscope\bin\data\udpOutputSettings.xml"; DestDir: "{app}\EmotiBit Oscilloscope\data" +; Settings files (*.json, *.xml) - backed up automatically in [Code] before overwriting +Source: "..\EmotiBitOscilloscope\bin\data\*.json"; DestDir: "{app}\EmotiBit Oscilloscope\data" +Source: "..\EmotiBitOscilloscope\bin\data\*.xml"; DestDir: "{app}\EmotiBit Oscilloscope\data" ; EmotiBit DataParser Source: "..\EmotiBitDataParser\bin\EmotiBitDataParser.exe"; DestDir: "{app}\EmotiBit DataParser" Source: "..\EmotiBitDataParser\bin\*.dll"; DestDir: "{app}\EmotiBit DataParser" Source: "..\EmotiBitDataParser\bin\data\*.ttf"; DestDir: "{app}\EmotiBit DataParser\data" -; Settings files - existing files backed up in [Code] PrepareToInstall before Inno copies new ones -Source: "..\EmotiBitDataParser\bin\data\parsedDataFormat.json"; DestDir: "{app}\EmotiBit DataParser\data" +; Settings files (*.json, *.xml) - backed up automatically in [Code] before overwriting +Source: "..\EmotiBitDataParser\bin\data\*.json"; DestDir: "{app}\EmotiBit DataParser\data" ; EmotiBit FirmwareInstaller Source: "..\EmotiBitFirmwareInstaller\bin\EmotiBitFirmwareInstaller.exe"; DestDir: "{app}\EmotiBit FirmwareInstaller" @@ -92,9 +88,6 @@ const MSI_PRODUCT_CODE = '{B2F470EF-3C46-46C9-9948-9446D059330D}'; MSI_UNINSTALL_KEY = 'SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\{B2F470EF-3C46-46C9-9948-9446D059330D}'; - // Number of settings files to backup (update when adding new files) - SETTINGS_FILE_COUNT = 7; - var DriverAckPage: TWizardPage; DriverInfoLabel: TNewStaticText; @@ -187,21 +180,6 @@ end; // Settings File Backup Functions //============================================================================= -// Centralized settings file list - update here when adding new files -// Also update SETTINGS_FILE_COUNT constant -procedure GetSettingsFileInfo(Index: Integer; var FileName, DestDir: String); -begin - case Index of - 0: begin FileName := 'emotibitCommSettings.json'; DestDir := '{app}\EmotiBit Oscilloscope\data'; end; - 1: begin FileName := 'lslOutputSettings.json'; DestDir := '{app}\EmotiBit Oscilloscope\data'; end; - 2: begin FileName := 'inputSettings.xml'; DestDir := '{app}\EmotiBit Oscilloscope\data'; end; - 3: begin FileName := 'ofxOscilloscopeSettings.xml'; DestDir := '{app}\EmotiBit Oscilloscope\data'; end; - 4: begin FileName := 'oscOutputSettings.xml'; DestDir := '{app}\EmotiBit Oscilloscope\data'; end; - 5: begin FileName := 'udpOutputSettings.xml'; DestDir := '{app}\EmotiBit Oscilloscope\data'; end; - 6: begin FileName := 'parsedDataFormat.json'; DestDir := '{app}\EmotiBit DataParser\data'; end; - end; -end; - function GetBackupTimestamp: String; begin // Get current date/time formatted as YYYY-MM-DD_HHMMSS @@ -211,20 +189,18 @@ end; function GetBackupFilePath(OriginalPath: String): String; var - Dir, Name, Ext: String; + Dir, FileName: String; begin - // Convert "C:\path\settings.json" to "C:\path\backups\settings_2026-01-29_143052.json" + // Convert "C:\path\data\settings.json" to "C:\path\data\backups\2026-01-29_143052\settings.json" Dir := ExtractFilePath(OriginalPath); - Name := ExtractFileName(OriginalPath); - Ext := ExtractFileExt(Name); - Name := Copy(Name, 1, Length(Name) - Length(Ext)); - Result := Dir + 'backups\' + Name + '_' + BackupTimestamp + Ext; + FileName := ExtractFileName(OriginalPath); + Result := Dir + 'backups\' + BackupTimestamp + '\' + FileName; end; -function GetBackupsFolder(OriginalPath: String): String; +function GetBackupSessionFolder(DataDir: String): String; begin - // Get the backups folder path for a given file path - Result := ExtractFilePath(OriginalPath) + 'backups'; + // Get the backup session folder: "C:\path\data\backups\2026-01-29_143052" + Result := DataDir + '\backups\' + BackupTimestamp; end; function IsDirEmpty(DirPath: String): Boolean; @@ -248,67 +224,83 @@ begin end; end; -procedure BackupSettingsFile(FileName, DestSubDir: String); +procedure BackupFile(FilePath: String); var - DestPath, BackupPath, BackupsFolder: String; + BackupPath, BackupDir: String; begin - DestPath := ExpandConstant(DestSubDir + '\') + FileName; - - if FileExists(DestPath) then + if not FileExists(FilePath) then begin - BackupPath := GetBackupFilePath(DestPath); - BackupsFolder := GetBackupsFolder(DestPath); + Log('No file to backup: ' + FilePath); + Exit; + end; - // Create the backups folder if it doesn't exist - if not DirExists(BackupsFolder) then - ForceDirectories(BackupsFolder); + BackupPath := GetBackupFilePath(FilePath); + BackupDir := ExtractFilePath(BackupPath); - if RenameFile(DestPath, BackupPath) then - begin - Log('Backed up: ' + DestPath + ' -> ' + BackupPath); - BackedUpFilesCount := BackedUpFilesCount + 1; - end - else - Log('Warning: Failed to backup ' + DestPath); + if not DirExists(BackupDir) then + ForceDirectories(BackupDir); + + if RenameFile(FilePath, BackupPath) then + begin + Log('Backed up: ' + FilePath + ' -> ' + BackupPath); + BackedUpFilesCount := BackedUpFilesCount + 1; end else - Log('No existing file to backup: ' + FileName); + Log('Warning: Failed to backup ' + FilePath); end; -procedure BackupAllSettingsFiles; +procedure BackupSettingsInDir(DataDir: String); var - I: Integer; - FileName, DestDir: String; + FindRec: TFindRec; begin - BackupTimestamp := GetBackupTimestamp(); - BackedUpFilesCount := 0; + if not DirExists(DataDir) then + Exit; - for I := 0 to SETTINGS_FILE_COUNT - 1 do + // Backup *.json files + if FindFirst(DataDir + '\*.json', FindRec) then begin - GetSettingsFileInfo(I, FileName, DestDir); - BackupSettingsFile(FileName, DestDir); + try + repeat + BackupFile(DataDir + '\' + FindRec.Name); + until not FindNext(FindRec); + finally + FindClose(FindRec); + end; + end; + + // Backup *.xml files + if FindFirst(DataDir + '\*.xml', FindRec) then + begin + try + repeat + BackupFile(DataDir + '\' + FindRec.Name); + until not FindNext(FindRec); + finally + FindClose(FindRec); + end; end; end; -procedure CleanupBackupIfIdentical(FileName, DestSubDir: String); -var - NewFilePath, BackupPath, BackupsFolder: String; - NewContent, BackupContent: AnsiString; +procedure BackupAllSettingsFiles; begin - NewFilePath := ExpandConstant(DestSubDir + '\') + FileName; - BackupPath := GetBackupFilePath(NewFilePath); - BackupsFolder := GetBackupsFolder(NewFilePath); + BackupTimestamp := GetBackupTimestamp(); + BackedUpFilesCount := 0; - if not FileExists(BackupPath) then - Exit; + BackupSettingsInDir(ExpandConstant('{app}\EmotiBit Oscilloscope\data')); + BackupSettingsInDir(ExpandConstant('{app}\EmotiBit DataParser\data')); +end; - if not FileExists(NewFilePath) then +procedure CleanupBackupFile(BackupPath, OriginalPath: String); +var + NewContent, BackupContent: AnsiString; +begin + if not FileExists(OriginalPath) then begin Log('Warning: New file not found, keeping backup: ' + BackupPath); Exit; end; - if LoadStringFromFile(NewFilePath, NewContent) and + if LoadStringFromFile(OriginalPath, NewContent) and LoadStringFromFile(BackupPath, BackupContent) then begin if NewContent = BackupContent then @@ -317,15 +309,6 @@ begin begin Log('Deleted identical backup: ' + BackupPath); BackedUpFilesCount := BackedUpFilesCount - 1; - - // Delete the backups folder if it's now empty - if DirExists(BackupsFolder) and IsDirEmpty(BackupsFolder) then - begin - if RemoveDir(BackupsFolder) then - Log('Deleted empty backups folder: ' + BackupsFolder) - else - Log('Warning: Failed to delete empty backups folder: ' + BackupsFolder); - end; end else Log('Warning: Failed to delete backup: ' + BackupPath); @@ -337,16 +320,52 @@ begin Log('Warning: Could not compare files, keeping backup: ' + BackupPath); end; -procedure CleanupIdenticalBackups; +procedure CleanupBackupsInDir(DataDir: String); var - I: Integer; - FileName, DestDir: String; + FindRec: TFindRec; + BackupSessionDir, BackupPath, OriginalPath: String; begin - for I := 0 to SETTINGS_FILE_COUNT - 1 do + BackupSessionDir := GetBackupSessionFolder(DataDir); + + if not DirExists(BackupSessionDir) then + Exit; + + // Scan all files in the backup session folder + if FindFirst(BackupSessionDir + '\*.*', FindRec) then begin - GetSettingsFileInfo(I, FileName, DestDir); - CleanupBackupIfIdentical(FileName, DestDir); + try + repeat + if (FindRec.Name <> '.') and (FindRec.Name <> '..') then + begin + BackupPath := BackupSessionDir + '\' + FindRec.Name; + OriginalPath := DataDir + '\' + FindRec.Name; + CleanupBackupFile(BackupPath, OriginalPath); + end; + until not FindNext(FindRec); + finally + FindClose(FindRec); + end; end; + + // Delete backup session folder if empty + if DirExists(BackupSessionDir) and IsDirEmpty(BackupSessionDir) then + begin + if RemoveDir(BackupSessionDir) then + Log('Deleted empty backup session folder: ' + BackupSessionDir); + end; + + // Delete backups folder if empty + if DirExists(DataDir + '\backups') and IsDirEmpty(DataDir + '\backups') then + begin + if RemoveDir(DataDir + '\backups') then + Log('Deleted empty backups folder: ' + DataDir + '\backups'); + end; +end; + +procedure CleanupIdenticalBackups; +begin + CleanupBackupsInDir(ExpandConstant('{app}\EmotiBit Oscilloscope\data')); + CleanupBackupsInDir(ExpandConstant('{app}\EmotiBit DataParser\data')); end; procedure CurStepChanged(CurStep: TSetupStep); @@ -359,7 +378,7 @@ begin // Show message if any backups remain (user had customizations) if (BackedUpFilesCount > 0) and (not WizardSilent()) then begin - MsgBox('Your customized settings files were backed up to the "backups" folder with timestamp ' + BackupTimestamp + '.', + MsgBox('Your customized settings files were backed up to "backups\' + BackupTimestamp + '" folder.', mbInformation, MB_OK); end; end; diff --git a/src/ofxEmotiBitVersion.h b/src/ofxEmotiBitVersion.h index 8d727e9..b0253bd 100644 --- a/src/ofxEmotiBitVersion.h +++ b/src/ofxEmotiBitVersion.h @@ -3,7 +3,7 @@ #include "ofMain.h" -const std::string ofxEmotiBitVersion = "1.14.4"; +const std::string ofxEmotiBitVersion = "1.14.5"; static const char SOFTWARE_VERSION_PREFIX = 'v';