New Upstream Release - ddrescueview

Ready changes

Summary

Merged new upstream version: 0.4.5 (was: 0.4~alpha4).

Resulting package

Built on 2022-03-14T18:53 (took 3m23s)

The resulting binary packages can be installed (if you have the apt repository enabled) by running one of:

apt install -t fresh-releases ddrescueview

Lintian Result

Diff

diff --git a/changelog.txt b/changelog.txt
index 17ca37f..cc3e71f 100644
--- a/changelog.txt
+++ b/changelog.txt
@@ -1,5 +1,15 @@
+#### v0.4.5 ####
+Released 2022-02-25
+
+- Fixed an issue that emerged with the mapfile backup mechanism in ddrescue 1.24 and later.
+  When an update interval was set in ddrescueview, the program would be stuck on the backup version
+  of the mapfile, causing no progress to be shown over time.
+  With this patch, ddrescueview avoids the issue by re-opening the file every time it needs to be read.
+- Abandoned the nonsensical versioning scheme (alpha x - labled versions)
+
 #### v0.4 alpha 4 ####
 Released 2020-09-01
+
 - Updated to compile on FPC 3.2.0 without errors. Thanks to Peter Green for the patch.
 - It's now possible to select a range on the Zoom Bar using right click dragging, just like on the Block Grid.
 - Added an option in the Settings to zoom in on mouse position without centering the Block Grid on that position.
diff --git a/debian/changelog b/debian/changelog
index 3b96ffa..61048b2 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,9 +1,10 @@
-ddrescueview (0.4~alpha4-3) UNRELEASED; urgency=medium
+ddrescueview (0.4.5-1) UNRELEASED; urgency=medium
 
   * Fix field name typo in debian/copyright (Uptream-Contact =>
     Upstream-Contact).
+  * New upstream release.
 
- -- Debian Janitor <janitor@jelmer.uk>  Fri, 30 Oct 2020 08:58:14 -0000
+ -- Debian Janitor <janitor@jelmer.uk>  Mon, 14 Mar 2022 18:50:42 -0000
 
 ddrescueview (0.4~alpha4-2) unstable; urgency=medium
 
diff --git a/resources/linux/applications/ddrescueview.desktop b/resources/linux/applications/ddrescueview.desktop
old mode 100644
new mode 100755
diff --git a/source/About.pas b/source/About.pas
index 85f8a38..97a3aab 100644
--- a/source/About.pas
+++ b/source/About.pas
@@ -1,7 +1,7 @@
 (*
    About.pas - About Box unit
 
-   Copyright (C) 2013 - 2020 Martin Bittermann (martinbittermann@gmx.de)
+   Copyright (C) 2013 - 2022 Martin Bittermann (martinbittermann@gmx.de)
 
    This file is part of ddrescueview.
 
@@ -50,7 +50,7 @@ var
   AboutBox: TAboutBox;
 
 implementation
-uses Shared;
+uses Shared, SysUtils;
 
 {$R *.lfm}
 
@@ -58,8 +58,8 @@ uses Shared;
 
 procedure TAboutBox.FormCreate(Sender: TObject);
 begin
-  Version.Caption := 'Version ' + VERSION_MAJOR + '.' + VERSION_MINOR +
-    ' ' + VERSION_SUFFIX;
+  Version.Caption := Format('Version %s.%s.%s %s',
+    [VERSION_MAJOR, VERSION_MINOR, VERSION_PATCH, VERSION_SUFFIX]);
 end;
 
 procedure TAboutBox.FormShow(Sender: TObject);
diff --git a/source/BlockInspector.pas b/source/BlockInspector.pas
index 0b55f80..4a815d6 100644
--- a/source/BlockInspector.pas
+++ b/source/BlockInspector.pas
@@ -1,7 +1,7 @@
 (*
    BlockInspector.pas - Grid Block Inspector unit
 
-   Copyright (C) 2013 - 2020 Martin Bittermann (martinbittermann@gmx.de)
+   Copyright (C) 2013 - 2022 Martin Bittermann (martinbittermann@gmx.de)
 
    This file is part of ddrescueview.
 
diff --git a/source/GUI.lfm b/source/GUI.lfm
index 0dc56ea..f1f8789 100644
--- a/source/GUI.lfm
+++ b/source/GUI.lfm
@@ -1,11 +1,11 @@
 object MainForm: TMainForm
-  Left = 1251
+  Left = 985
   Height = 439
-  Top = 468
+  Top = 396
   Width = 615
   AllowDropFiles = True
   Caption = 'ddrescueview'
-  ClientHeight = 419
+  ClientHeight = 415
   ClientWidth = 615
   Color = clForm
   Constraints.MinHeight = 200
@@ -21,21 +21,21 @@ object MainForm: TMainForm
   LCLVersion = '2.0.10.0'
   object TopPanel: TPanel
     Left = 0
-    Height = 96
+    Height = 113
     Top = 0
     Width = 615
     Align = alTop
     AutoSize = True
     BevelOuter = bvNone
-    ClientHeight = 96
+    ClientHeight = 113
     ClientWidth = 615
     ParentFont = False
     TabOrder = 0
     object RescueStatusBox: TGroupBox
       Left = 4
-      Height = 92
+      Height = 109
       Top = 2
-      Width = 528
+      Width = 548
       Align = alLeft
       AutoSize = True
       BorderSpacing.Left = 4
@@ -43,15 +43,15 @@ object MainForm: TMainForm
       BorderSpacing.Right = 4
       BorderSpacing.Bottom = 2
       Caption = 'Rescue status'
-      ClientHeight = 72
-      ClientWidth = 524
+      ClientHeight = 92
+      ClientWidth = 546
       ParentFont = False
       TabOrder = 0
       object RSCol1Panel: TPanel
         Left = 6
-        Height = 70
+        Height = 90
         Top = 0
-        Width = 153
+        Width = 161
         Align = alLeft
         AutoSize = True
         BorderSpacing.Left = 6
@@ -64,15 +64,15 @@ object MainForm: TMainForm
         ChildSizing.VerticalSpacing = 2
         ChildSizing.Layout = cclLeftToRightThenTopToBottom
         ChildSizing.ControlsPerLine = 2
-        ClientHeight = 70
-        ClientWidth = 153
+        ClientHeight = 90
+        ClientWidth = 161
         TabOrder = 0
         object lblInputSize: TLabel
           Left = 2
-          Height = 15
+          Height = 16
           Hint = 'Size of the rescue device'
-          Top = 2
-          Width = 67
+          Top = 4
+          Width = 75
           BorderSpacing.CellAlignVertical = ccaCenter
           Caption = 'Input size:'
           ParentColor = False
@@ -80,8 +80,8 @@ object MainForm: TMainForm
         end
         object EditInputSize: TEdit
           AnchorSideLeft.Side = asrBottom
-          Left = 71
-          Height = 15
+          Left = 79
+          Height = 20
           Top = 2
           Width = 80
           BorderSpacing.Left = 2
@@ -96,10 +96,10 @@ object MainForm: TMainForm
         end
         object lblDomainSize: TLabel
           Left = 2
-          Height = 15
+          Height = 16
           Hint = 'Size of the rescue domain'
-          Top = 19
-          Width = 67
+          Top = 26
+          Width = 75
           BorderSpacing.CellAlignVertical = ccaCenter
           Caption = 'Domain size:'
           ParentColor = False
@@ -108,9 +108,9 @@ object MainForm: TMainForm
         end
         object EditDomainSize: TEdit
           AnchorSideLeft.Side = asrBottom
-          Left = 71
-          Height = 15
-          Top = 19
+          Left = 79
+          Height = 20
+          Top = 24
           Width = 80
           BorderSpacing.Left = 2
           BorderStyle = bsNone
@@ -125,19 +125,19 @@ object MainForm: TMainForm
         end
         object lblErrorCount: TLabel
           Left = 2
-          Height = 15
+          Height = 16
           Hint = 'Number of distinct bad sector areas'
-          Top = 36
-          Width = 67
+          Top = 48
+          Width = 75
           BorderSpacing.CellAlignVertical = ccaCenter
           Caption = 'Error count:'
           ParentColor = False
         end
         object EditErrorCount: TEdit
           AnchorSideLeft.Side = asrBottom
-          Left = 71
-          Height = 15
-          Top = 36
+          Left = 79
+          Height = 20
+          Top = 46
           Width = 80
           BorderSpacing.Left = 2
           BorderStyle = bsNone
@@ -151,10 +151,10 @@ object MainForm: TMainForm
         end
         object lblPending: TLabel
           Left = 2
-          Height = 15
+          Height = 16
           Hint = 'Total size of pending areas (non-tried + non-trimmed + non-scraped)'
-          Top = 53
-          Width = 67
+          Top = 70
+          Width = 75
           BorderSpacing.CellAlignVertical = ccaCenter
           Caption = 'Pending:'
           ParentColor = False
@@ -162,9 +162,9 @@ object MainForm: TMainForm
         end
         object EditPending: TEdit
           AnchorSideLeft.Side = asrBottom
-          Left = 71
-          Height = 15
-          Top = 53
+          Left = 79
+          Height = 20
+          Top = 68
           Width = 80
           BorderSpacing.Left = 2
           BorderStyle = bsNone
@@ -178,10 +178,10 @@ object MainForm: TMainForm
         end
       end
       object RSCol2Panel: TPanel
-        Left = 165
-        Height = 70
+        Left = 173
+        Height = 90
         Top = 0
-        Width = 175
+        Width = 183
         Align = alLeft
         AutoSize = True
         BorderSpacing.Left = 6
@@ -194,13 +194,13 @@ object MainForm: TMainForm
         ChildSizing.VerticalSpacing = 2
         ChildSizing.Layout = cclLeftToRightThenTopToBottom
         ChildSizing.ControlsPerLine = 3
-        ClientHeight = 70
-        ClientWidth = 175
+        ClientHeight = 90
+        ClientWidth = 183
         TabOrder = 1
         object ShapeFinished: TShape
           Left = 2
           Height = 10
-          Top = 4
+          Top = 7
           Width = 10
           BorderSpacing.CellAlignHorizontal = ccaCenter
           BorderSpacing.CellAlignVertical = ccaCenter
@@ -210,10 +210,10 @@ object MainForm: TMainForm
         end
         object lblRescued: TLabel
           Left = 14
-          Height = 15
+          Height = 16
           Hint = 'Rescued data block'
-          Top = 2
-          Width = 77
+          Top = 4
+          Width = 85
           BorderSpacing.CellAlignVertical = ccaCenter
           Caption = 'Rescued:'
           ParentColor = False
@@ -221,8 +221,8 @@ object MainForm: TMainForm
         end
         object EditRescued: TEdit
           AnchorSideLeft.Side = asrBottom
-          Left = 93
-          Height = 15
+          Left = 101
+          Height = 20
           Top = 2
           Width = 80
           BorderSpacing.Left = 2
@@ -238,7 +238,7 @@ object MainForm: TMainForm
         object ShapeOutsideDomain: TShape
           Left = 2
           Height = 10
-          Top = 21
+          Top = 29
           Width = 10
           BorderSpacing.CellAlignHorizontal = ccaCenter
           BorderSpacing.CellAlignVertical = ccaCenter
@@ -249,10 +249,10 @@ object MainForm: TMainForm
         end
         object lblOutsideDomain: TLabel
           Left = 14
-          Height = 15
+          Height = 16
           Hint = 'Block outside the rescue domain specified in the domain log file'
-          Top = 19
-          Width = 77
+          Top = 26
+          Width = 85
           BorderSpacing.CellAlignVertical = ccaCenter
           Caption = 'Not in domain'
           ParentColor = False
@@ -261,9 +261,9 @@ object MainForm: TMainForm
         end
         object EditOutsideDomain: TEdit
           AnchorSideLeft.Side = asrBottom
-          Left = 93
-          Height = 15
-          Top = 19
+          Left = 101
+          Height = 20
+          Top = 24
           Width = 80
           BorderSpacing.Left = 2
           BorderStyle = bsNone
@@ -279,7 +279,7 @@ object MainForm: TMainForm
         object ShapeBad: TShape
           Left = 2
           Height = 10
-          Top = 38
+          Top = 51
           Width = 10
           BorderSpacing.CellAlignHorizontal = ccaCenter
           BorderSpacing.CellAlignVertical = ccaCenter
@@ -289,10 +289,10 @@ object MainForm: TMainForm
         end
         object lblBadSectors: TLabel
           Left = 14
-          Height = 15
+          Height = 16
           Hint = 'Block which failed to read on the previous attempt'
-          Top = 36
-          Width = 77
+          Top = 48
+          Width = 85
           BorderSpacing.CellAlignVertical = ccaCenter
           Caption = 'Bad sectors:'
           ParentColor = False
@@ -300,9 +300,9 @@ object MainForm: TMainForm
         end
         object EditBadSectors: TEdit
           AnchorSideLeft.Side = asrBottom
-          Left = 93
-          Height = 15
-          Top = 36
+          Left = 101
+          Height = 20
+          Top = 46
           Width = 80
           BorderSpacing.Left = 2
           BorderStyle = bsNone
@@ -317,7 +317,7 @@ object MainForm: TMainForm
         object ShapeActive: TShape
           Left = 2
           Height = 10
-          Top = 55
+          Top = 73
           Width = 10
           BorderSpacing.CellAlignHorizontal = ccaCenter
           BorderSpacing.CellAlignVertical = ccaCenter
@@ -328,10 +328,10 @@ object MainForm: TMainForm
         end
         object lblCurrentPos: TLabel
           Left = 14
-          Height = 15
+          Height = 16
           Hint = 'Current read position on the rescue device'
-          Top = 53
-          Width = 77
+          Top = 70
+          Width = 85
           BorderSpacing.CellAlignVertical = ccaCenter
           Caption = 'Current pos:'
           ParentColor = False
@@ -339,9 +339,9 @@ object MainForm: TMainForm
         end
         object EditCurrentPos: TEdit
           AnchorSideLeft.Side = asrBottom
-          Left = 93
-          Height = 15
-          Top = 53
+          Left = 101
+          Height = 20
+          Top = 68
           Width = 80
           BorderSpacing.Left = 2
           BorderStyle = bsNone
@@ -355,10 +355,10 @@ object MainForm: TMainForm
         end
       end
       object RSCol3Panel: TPanel
-        Left = 346
-        Height = 70
+        Left = 362
+        Height = 90
         Top = 0
-        Width = 172
+        Width = 178
         Align = alLeft
         AutoSize = True
         BorderSpacing.Left = 6
@@ -371,13 +371,13 @@ object MainForm: TMainForm
         ChildSizing.VerticalSpacing = 2
         ChildSizing.Layout = cclLeftToRightThenTopToBottom
         ChildSizing.ControlsPerLine = 3
-        ClientHeight = 70
-        ClientWidth = 172
+        ClientHeight = 90
+        ClientWidth = 178
         TabOrder = 2
         object ShapeNonTried: TShape
           Left = 2
           Height = 10
-          Top = 4
+          Top = 7
           Width = 10
           BorderSpacing.CellAlignHorizontal = ccaCenter
           BorderSpacing.CellAlignVertical = ccaCenter
@@ -387,10 +387,10 @@ object MainForm: TMainForm
         end
         object lblNonTried: TLabel
           Left = 14
-          Height = 15
+          Height = 16
           Hint = 'Block that has not yet been attempted to read'
-          Top = 2
-          Width = 74
+          Top = 4
+          Width = 80
           BorderSpacing.CellAlignVertical = ccaCenter
           Caption = 'Non-tried'
           ParentColor = False
@@ -398,8 +398,8 @@ object MainForm: TMainForm
         end
         object EditNontried: TEdit
           AnchorSideLeft.Side = asrBottom
-          Left = 90
-          Height = 15
+          Left = 96
+          Height = 20
           Top = 2
           Width = 80
           BorderSpacing.Left = 2
@@ -415,7 +415,7 @@ object MainForm: TMainForm
         object ShapeNonTrimmed: TShape
           Left = 2
           Height = 10
-          Top = 21
+          Top = 29
           Width = 10
           BorderSpacing.CellAlignHorizontal = ccaCenter
           BorderSpacing.CellAlignVertical = ccaCenter
@@ -425,10 +425,10 @@ object MainForm: TMainForm
         end
         object lblNonTrimmed: TLabel
           Left = 14
-          Height = 15
+          Height = 16
           Hint = 'Block that was skipped by ddrescue on a read error (or slow read), to maximize performance. May contain readable data.'
-          Top = 19
-          Width = 74
+          Top = 26
+          Width = 80
           BorderSpacing.CellAlignVertical = ccaCenter
           Caption = 'Non-trimmed'
           ParentColor = False
@@ -436,9 +436,9 @@ object MainForm: TMainForm
         end
         object EditNontrimmed: TEdit
           AnchorSideLeft.Side = asrBottom
-          Left = 90
-          Height = 15
-          Top = 19
+          Left = 96
+          Height = 20
+          Top = 24
           Width = 80
           BorderSpacing.Left = 2
           BorderStyle = bsNone
@@ -453,7 +453,7 @@ object MainForm: TMainForm
         object ShapeNonScraped: TShape
           Left = 2
           Height = 10
-          Top = 38
+          Top = 51
           Width = 10
           BorderSpacing.CellAlignHorizontal = ccaCenter
           BorderSpacing.CellAlignVertical = ccaCenter
@@ -463,10 +463,10 @@ object MainForm: TMainForm
         end
         object lblNonScraped: TLabel
           Left = 14
-          Height = 15
+          Height = 16
           Hint = 'Trimmed block that has yet to be scraped (pre-1.19 ddrescue: Trimmed block that has yet to be split). May contain readable data.'
-          Top = 36
-          Width = 74
+          Top = 48
+          Width = 80
           BorderSpacing.CellAlignVertical = ccaCenter
           Caption = 'Non-scraped'
           ParentColor = False
@@ -474,9 +474,9 @@ object MainForm: TMainForm
         end
         object EditNonscraped: TEdit
           AnchorSideLeft.Side = asrBottom
-          Left = 90
-          Height = 15
-          Top = 36
+          Left = 96
+          Height = 20
+          Top = 46
           Width = 80
           BorderSpacing.Left = 2
           BorderStyle = bsNone
@@ -492,7 +492,7 @@ object MainForm: TMainForm
     end
     object TopPiePanel: TPanel
       Left = 549
-      Height = 92
+      Height = 109
       Top = 2
       Width = 64
       Align = alRight
@@ -502,13 +502,13 @@ object MainForm: TMainForm
       ChildSizing.EnlargeVertical = crsHomogenousSpaceResize
       ChildSizing.Layout = cclLeftToRightThenTopToBottom
       ChildSizing.ControlsPerLine = 1
-      ClientHeight = 92
+      ClientHeight = 109
       ClientWidth = 64
       TabOrder = 1
       object PieImage: TImage
         Left = 0
         Height = 64
-        Top = 14
+        Top = 23
         Width = 64
         BorderSpacing.CellAlignVertical = ccaCenter
         Constraints.MaxHeight = 64
@@ -520,24 +520,24 @@ object MainForm: TMainForm
   end
   object MainPanel: TPanel
     Left = 0
-    Height = 300
-    Top = 96
+    Height = 284
+    Top = 113
     Width = 615
     Align = alClient
     BevelOuter = bvNone
-    ClientHeight = 300
+    ClientHeight = 284
     ClientWidth = 615
     TabOrder = 1
     object ZoomPanel: TPanel
       Left = 0
-      Height = 245
+      Height = 229
       Top = 0
       Width = 50
       Align = alLeft
       BevelOuter = bvNone
       BorderStyle = bsSingle
-      ClientHeight = 241
-      ClientWidth = 46
+      ClientHeight = 227
+      ClientWidth = 48
       Color = clGray
       Constraints.MinHeight = 30
       Constraints.MinWidth = 30
@@ -545,9 +545,9 @@ object MainForm: TMainForm
       TabOrder = 0
       object ZoomImage: TImage
         Left = 0
-        Height = 241
+        Height = 227
         Top = 0
-        Width = 46
+        Width = 48
         Align = alClient
         Constraints.MinHeight = 25
         Constraints.MinWidth = 25
@@ -556,7 +556,7 @@ object MainForm: TMainForm
         OnMouseUp = ZoomImageMouseUp
       end
       object BtnCloseZoomBar: TSpeedButton
-        Left = 30
+        Left = 32
         Height = 13
         Hint = 'Close zoom bar'
         Top = 2
@@ -584,14 +584,14 @@ object MainForm: TMainForm
     end
     object GridPanel: TPanel
       Left = 50
-      Height = 245
+      Height = 229
       Top = 0
       Width = 565
       Align = alClient
       BevelOuter = bvNone
       BorderStyle = bsSingle
-      ClientHeight = 241
-      ClientWidth = 561
+      ClientHeight = 227
+      ClientWidth = 563
       Color = clGray
       Constraints.MinHeight = 30
       Constraints.MinWidth = 30
@@ -600,9 +600,9 @@ object MainForm: TMainForm
       OnResize = GridPanelResize
       object BlockImage: TImage
         Left = 0
-        Height = 241
+        Height = 227
         Top = 0
-        Width = 561
+        Width = 563
         Align = alClient
         Constraints.MinHeight = 25
         Constraints.MinWidth = 25
@@ -615,7 +615,7 @@ object MainForm: TMainForm
     object BottomPanel: TPanel
       Left = 0
       Height = 50
-      Top = 250
+      Top = 234
       Width = 615
       Align = alBottom
       BevelOuter = bvNone
@@ -665,7 +665,7 @@ object MainForm: TMainForm
       Cursor = crVSplit
       Left = 0
       Height = 5
-      Top = 245
+      Top = 229
       Width = 615
       Align = alBottom
       AutoSnap = False
@@ -678,8 +678,8 @@ object MainForm: TMainForm
   end
   object StatusBar: TStatusBar
     Left = 0
-    Height = 23
-    Top = 396
+    Height = 18
+    Top = 397
     Width = 615
     Panels = <    
       item
diff --git a/source/GUI.pas b/source/GUI.pas
index 237ab1c..272ad50 100644
--- a/source/GUI.pas
+++ b/source/GUI.pas
@@ -1,7 +1,7 @@
 (*
    GUI.pas - Main GUI unit
 
-   Copyright (C) 2013 - 2020 Martin Bittermann (martinbittermann@gmx.de)
+   Copyright (C) 2013 - 2022 Martin Bittermann (martinbittermann@gmx.de)
 
    This file is part of ddrescueview.
 
diff --git a/source/Parser.pas b/source/Parser.pas
index 533d078..e5c8c43 100644
--- a/source/Parser.pas
+++ b/source/Parser.pas
@@ -1,7 +1,7 @@
 (*
    Parser.pas - Mapfile parser unit
 
-   Copyright (C) 2013 - 2020 Martin Bittermann (martinbittermann@gmx.de)
+   Copyright (C) 2013 - 2022 Martin Bittermann (martinbittermann@gmx.de)
 
    This file is part of ddrescueview.
 
@@ -36,7 +36,6 @@ type
     FRescueStatus : TRescueStatus;
     FComments : TStringList; // comment lines of mapfile
     FVersion : String; // ddrescue version in first comment line / for future use?
-    FMapStream : TStream;
     FFileName : String;
     procedure logMsg(msg : String);
     function isEmptyLine(strLine : String) : boolean;
@@ -45,14 +44,14 @@ type
     constructor Create;
     destructor Destroy; override;
     procedure OpenFile(filename : String);
-    procedure CloseFile;
+    procedure CloseFile();
     function parse(forceSameDevSize : Boolean) : Boolean;
     function hasFile() : boolean;
     property rescueStatus : TRescueStatus read FRescueStatus;
     property map : TMap read FMap;
     property CommentLines : TStringList read FComments;
     property Version : String read FVersion;
-    property MapFileName :String read FFileName;
+    property MapFileName : String read FFileName;
   end;
 
 
@@ -79,7 +78,7 @@ type
     destructor Destroy; override;
     procedure OpenFile(filename : String);
     procedure OpenDomainFile(filename : String);
-    procedure CloseFile;
+    procedure CloseFile();
     function parse(forceSameDevSize : Boolean) : Boolean;
     function hasFile() : boolean;
     function hasDomFile() : Boolean;
@@ -130,7 +129,7 @@ begin
   postParse;
 end;
 
-procedure TMapParser.CloseFile;
+procedure TMapParser.CloseFile();
 begin
   FDomParser.CloseFile;
   FMapParser.CloseFile;
@@ -140,7 +139,7 @@ begin
   FPONotifyObservers(self, ooDeleteItem, nil);
 end;
 
-procedure TMapParser.postParse;
+procedure TMapParser.postParse();
 var
   ResMap, DomMap: TMap;
   i, iRes, iDom : Longint;
@@ -241,22 +240,41 @@ begin
   postParse;
 end;
 
-function TMapParser.hasFile: boolean;
+function TMapParser.hasFile(): boolean;
 begin
   result:=FHasFile;
 end;
 
-function TMapParser.hasDomFile: Boolean;
+function TMapParser.hasDomFile(): Boolean;
 begin
   result:=FHasFile and FDomParser.hasFile;
 end;
 
-function TMapParser.getMap: TMap;
+function TMapParser.getMap(): TMap;
 begin
   if not FDomParser.hasFile then result:=FMapParser.map
   else result:=FMap;
 end;
 
+function TMapParser.getCommentLines(): TStringList;
+begin
+  getCommentLines:=FMapParser.FComments;
+end;
+
+function TMapParser.getVersion(): String;
+begin
+  getVersion:=FMapParser.FVersion;
+end;
+
+function TMapParser.getMapFileName(): String;
+begin
+  getMapFileName:=FMapParser.FFileName;
+end;
+
+function TMapParser.getDomFileName(): String;
+begin
+  getDomFileName:=FDomParser.FFileName;
+end;
 
 { TSimpleParser }
 
@@ -273,11 +291,14 @@ begin
 end;
 
 procedure TSimpleParser.OpenFile(filename : String);
+var mapStream : TFileStream;
 begin
   try
-    CloseFile(); // close already open file
-    // open the mapfile using shared read access, so ddrescue can still write to it.
-    FMapStream := TFileStream.Create(filename, fmOpenRead or fmShareDenyNone);
+    if hasFile() then CloseFile(); // close already open file
+    // check mapfile access once, and close the file again.
+    mapStream := TFileStream.Create(filename, fmOpenRead or fmShareDenyNone);
+    FreeAndNil(mapStream);
+    // file checked, it can be considered 'open' now.
     FComments := TStringList.Create;
     FFileName := filename;
     parse(false);  // start parsing after opening
@@ -293,7 +314,6 @@ procedure TSimpleParser.CloseFile;
 begin
   FFileName := '';
   FreeAndNil(FComments);
-  FreeAndNil(FMapStream);
   FRescueStatus := emptyRescueStatus;
   SetLength(FMap, 0);
   FPONotifyObservers(self, ooDeleteItem, nil);
@@ -325,6 +345,7 @@ var
   line : string;
   token : array[0..2] of string;
   i, mapEntry, lineIdx, idx : Integer;
+  mapStream : TFileStream = nil;
   mapStrings : TStringList = nil;
   prevHadFile, statuslineFound : boolean;
   newMap : TMap;
@@ -336,8 +357,8 @@ var
   {$ENDIF}
 begin
   result:=False;
-  // make sure the file is open
-  if not hasFile then begin
+  // make sure the parser has a file
+  if not hasFile() then begin
     logMsg('Parser: No mapfile opened.');
     FPONotifyObservers(self, ooChange, nil);
     exit;
@@ -345,27 +366,27 @@ begin
   {$IFDEF VerboseProfiler}
   lTimeStart := Now();
   {$ENDIF}
-  // read file contents into string list
+  // open the file and read its contents into string list
   try
-    mapStrings := TStringList.Create;
-    if FMapStream.Seek(0, soFromBeginning) <> 0 then
-      raise Exception.Create('Seek error!');
-    mapStrings.LoadFromStream(FMapStream);
-    if (FMapStream.Size = 0) or (mapStrings.Count = 0) then begin
-      logMsg('Parser: mapfile seems empty, trying to reopen.');
-      FreeAndNil(FMapStream);
-      FMapStream := TFileStream.Create(FFilename, fmOpenRead or fmShareDenyNone);
-      FMapStream.Seek(0, soFromBeginning);
-      mapStrings.LoadFromStream(FMapStream);
-    end;
-    logMsg('Reading mapfile: ' +IntToStr(mapStrings.Count) + ' lines.');
-  except
-    on E : Exception do begin
-      logMsg('Error: Cannot read mapfile: '+E.Message+'('+E.ClassName+')');
-      FreeAndNil(mapStrings);
-      FPONotifyObservers(self, ooChange, nil);
-      exit;
+    try
+      mapStream := TFileStream.Create(FFilename, fmOpenRead or fmShareDenyNone);
+      if mapStream.Seek(0, soFromBeginning) <> 0 then
+        raise Exception.Create('Seek error!');
+      mapStrings := TStringList.Create;
+      mapStrings.LoadFromStream(mapStream);
+      if mapStrings.Count = 0 then
+        raise Exception.Create('File is empty!');
+      logMsg('Reading mapfile: ' +IntToStr(mapStrings.Count) + ' lines.');
+    except
+      on E : Exception do begin
+        logMsg('Error: Cannot read mapfile: '+E.Message+'('+E.ClassName+')');
+        FreeAndNil(mapStrings);
+        FPONotifyObservers(self, ooChange, nil);
+        exit;
+      end;
     end;
+  finally
+    FreeAndNil(mapStream); // close the map file immediately after reading
   end;
 
   {$IFDEF VerboseProfiler}
@@ -503,27 +524,9 @@ begin
      else FPONotifyObservers(self, ooAddItem, nil); // notify of new file
 end;
 
-function TSimpleParser.hasFile: boolean;
-begin
-  hasFile:=Assigned(FMapStream);
-end;
-
-function TMapParser.getCommentLines(): TStringList;
+function TSimpleParser.hasFile(): boolean;
 begin
-  getCommentLines:=FMapParser.FComments;end;
-
-function TMapParser.getVersion(): String;
-begin
-  getVersion:=FMapParser.FVersion;
+  hasFile:=Length(FFileName) > 0;
 end;
 
-function TMapParser.getMapFileName(): String;
-begin
-  getMapFileName:=FMapParser.FFileName;
-end;
-
-function TMapParser.getDomFileName(): String;
-begin
-  getDomFileName:=FDomParser.FFileName;
-end;
 end.
diff --git a/source/Shared.pas b/source/Shared.pas
index 9cedf44..2d17500 100644
--- a/source/Shared.pas
+++ b/source/Shared.pas
@@ -1,7 +1,7 @@
 (*
    Shared.pas - Shared functionality
 
-   Copyright (C) 2013 - 2020 Martin Bittermann (martinbittermann@gmx.de)
+   Copyright (C) 2013 - 2022 Martin Bittermann (martinbittermann@gmx.de)
 
    This file is part of ddrescueview.
 
@@ -130,7 +130,8 @@ const
   PROGRAM_TITLE = 'ddrescueview';
   VERSION_MAJOR = '0';
   VERSION_MINOR = '4';
-  VERSION_SUFFIX = 'alpha 4';
+  VERSION_PATCH = '5';
+  VERSION_SUFFIX = '';
   emptyRescueStatus : TRescueStatus =
   (devicesize : 0; suggestedBlockSize : DEF_BSIZE; pos : 0; rescued : 0;
    nontried : 0; bad : 0; nonscraped : 0; nontrimmed : 0; outsidedomain : 0;
diff --git a/source/ddrescueview.lpi b/source/ddrescueview.lpi
index 7db6b06..baa8e34 100644
--- a/source/ddrescueview.lpi
+++ b/source/ddrescueview.lpi
@@ -24,12 +24,13 @@
     <VersionInfo>
       <UseVersionInfo Value="True"/>
       <MinorVersionNr Value="4"/>
+      <RevisionNr Value="5"/>
       <BuildNr Value="94"/>
       <Attributes pvaPreRelease="True"/>
-      <StringTable Comments="Graphical viewer for GNU ddrescue mapfiles" InternalName="ddrescueview" LegalCopyright="GPL v3" ProductName="ddrescueview" ProductVersion="0.4 alpha 4"/>
+      <StringTable Comments="Graphical viewer for GNU ddrescue mapfiles" InternalName="ddrescueview" LegalCopyright="GPL v3" ProductName="ddrescueview" ProductVersion="0.4.5"/>
     </VersionInfo>
-    <BuildModes Count="3">
-      <Item1 Name="GNU/Linux Release" Default="True"/>
+    <BuildModes Count="4">
+      <Item1 Name="Native Release (Default)" Default="True"/>
       <Item2 Name="Win32 Release">
         <MacroValues Count="1">
           <Macro1 Name="LCLWidgetType" Value="win32"/>
@@ -76,7 +77,47 @@
           </Other>
         </CompilerOptions>
       </Item2>
-      <Item3 Name="Common Debug (huge executable)">
+      <Item3 Name="GNU/Linux Release">
+        <CompilerOptions>
+          <Version Value="11"/>
+          <PathDelim Value="\"/>
+          <SearchPaths>
+            <IncludeFiles Value="$(ProjOutDir)"/>
+          </SearchPaths>
+          <Parsing>
+            <SyntaxOptions>
+              <AllowLabel Value="False"/>
+            </SyntaxOptions>
+          </Parsing>
+          <CodeGeneration>
+            <SmartLinkUnit Value="True"/>
+            <TargetOS Value="linux"/>
+            <Optimizations>
+              <OptimizationLevel Value="3"/>
+            </Optimizations>
+          </CodeGeneration>
+          <Linking>
+            <Debugging>
+              <GenerateDebugInfo Value="False"/>
+              <StripSymbols Value="True"/>
+            </Debugging>
+            <LinkSmart Value="True"/>
+            <Options>
+              <PassLinkerOptions Value="True"/>
+              <LinkerOptions Value=" -z relro --as-needed"/>
+              <Win32>
+                <GraphicApplication Value="True"/>
+              </Win32>
+            </Options>
+          </Linking>
+          <Other>
+            <CompilerMessages>
+              <IgnoredMessages idx5091="True" idx5024="True" idx4080="True" idx4079="True"/>
+            </CompilerMessages>
+          </Other>
+        </CompilerOptions>
+      </Item3>
+      <Item4 Name="Common Debug (huge executable)">
         <CompilerOptions>
           <Version Value="11"/>
           <PathDelim Value="\"/>
@@ -114,7 +155,7 @@
             </CompilerMessages>
           </Other>
         </CompilerOptions>
-      </Item3>
+      </Item4>
       <SharedMatrixOptions Count="1">
         <Item1 ID="298808952253" Modes="Win32 Release" Type="IDEMacro" MacroName="LCLWidgetType" Value="win32"/>
       </SharedMatrixOptions>
@@ -197,7 +238,6 @@
     </Parsing>
     <CodeGeneration>
       <SmartLinkUnit Value="True"/>
-      <TargetOS Value="linux"/>
       <Optimizations>
         <OptimizationLevel Value="3"/>
       </Optimizations>
@@ -222,17 +262,4 @@
       </CompilerMessages>
     </Other>
   </CompilerOptions>
-  <Debugging>
-    <Exceptions Count="3">
-      <Item1>
-        <Name Value="EAbort"/>
-      </Item1>
-      <Item2>
-        <Name Value="ECodetoolError"/>
-      </Item2>
-      <Item3>
-        <Name Value="EFOpenError"/>
-      </Item3>
-    </Exceptions>
-  </Debugging>
 </CONFIG>
diff --git a/source/ddrescueview.lpr b/source/ddrescueview.lpr
index 66f4367..cf81288 100644
--- a/source/ddrescueview.lpr
+++ b/source/ddrescueview.lpr
@@ -1,7 +1,7 @@
 (*
    ddrescueview.lpr - main program of ddrescueview
 
-   Copyright (C) 2013 - 2020 Martin Bittermann (martinbittermann@gmx.de)
+   Copyright (C) 2013 - 2022 Martin Bittermann (martinbittermann@gmx.de)
 
    This file is part of ddrescueview.
 
diff --git a/source/imgblockstore.pas b/source/imgblockstore.pas
index 93c2735..45698b3 100644
--- a/source/imgblockstore.pas
+++ b/source/imgblockstore.pas
@@ -1,7 +1,7 @@
 (*
    ImgBlockStore.pas - Image Block Storage unit
 
-   Copyright (C) 2013 - 2020 Martin Bittermann (martinbittermann@gmx.de)
+   Copyright (C) 2013 - 2022 Martin Bittermann (martinbittermann@gmx.de)
 
    This file is part of ddrescueview.
 
diff --git a/source/settings.pas b/source/settings.pas
index 26445ac..d6ed991 100644
--- a/source/settings.pas
+++ b/source/settings.pas
@@ -1,7 +1,7 @@
 (*
    Settings.pas - Settings GUI unit
 
-   Copyright (C) 2013 - 2020 Martin Bittermann (martinbittermann@gmx.de)
+   Copyright (C) 2013 - 2022 Martin Bittermann (martinbittermann@gmx.de)
 
    This file is part of ddrescueview.
 

More details

Full run details