fpexif: Fix crash when the image file contains xmp data with invalid xml structure (missing first '<')

git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@8994 8e941d3f-bd1b-0410-a28a-d453659cc2b4
This commit is contained in:
wp_xxyyzz 2023-10-28 23:14:27 +00:00
parent 180d051924
commit 116abaad54
4 changed files with 38 additions and 20 deletions

View File

@ -6,10 +6,10 @@ object MainForm: TMainForm
Caption = 'Metadata viewer' Caption = 'Metadata viewer'
ClientHeight = 714 ClientHeight = 714
ClientWidth = 926 ClientWidth = 926
ShowHint = True
LCLVersion = '3.99.0.0'
OnCreate = FormCreate OnCreate = FormCreate
OnDestroy = FormDestroy OnDestroy = FormDestroy
ShowHint = True
LCLVersion = '2.3.0.0'
object ShellPanel: TPanel object ShellPanel: TPanel
Left = 0 Left = 0
Height = 691 Height = 691
@ -31,11 +31,11 @@ object MainForm: TMainForm
HideSelection = False HideSelection = False
ReadOnly = True ReadOnly = True
TabOrder = 0 TabOrder = 0
OnGetImageIndex = ShellTreeViewGetImageIndex
OnSelectionChanged = ShellTreeViewSelectionChanged
Options = [tvoAutoItemHeight, tvoKeepCollapsedNodes, tvoReadOnly, tvoShowButtons, tvoShowLines, tvoShowRoot, tvoToolTips, tvoThemedDraw] Options = [tvoAutoItemHeight, tvoKeepCollapsedNodes, tvoReadOnly, tvoShowButtons, tvoShowLines, tvoShowRoot, tvoToolTips, tvoThemedDraw]
ObjectTypes = [otFolders] ObjectTypes = [otFolders]
ShellListView = ShellListView ShellListView = ShellListView
OnGetImageIndex = ShellTreeViewGetImageIndex
OnSelectionChanged = ShellTreeViewSelectionChanged
end end
object Splitter1: TSplitter object Splitter1: TSplitter
Cursor = crVSplit Cursor = crVSplit
@ -59,9 +59,9 @@ object MainForm: TMainForm
ReadOnly = True ReadOnly = True
SortColumn = 0 SortColumn = 0
TabOrder = 2 TabOrder = 2
OnSelectItem = ShellListViewSelectItem
ObjectTypes = [otNonFolders] ObjectTypes = [otNonFolders]
ShellTreeView = ShellTreeView ShellTreeView = ShellTreeView
OnSelectItem = ShellListViewSelectItem
end end
object PreviewImage: TImage object PreviewImage: TImage
Left = 0 Left = 0
@ -136,16 +136,16 @@ object MainForm: TMainForm
Caption = 'File: ' Caption = 'File: '
end end
end end
object PageControl1: TPageControl object PageControl: TPageControl
Left = 0 Left = 0
Height = 539 Height = 539
Top = 23 Top = 23
Width = 647 Width = 647
ActivePage = PgXMP ActivePage = PgMetadata
Align = alClient Align = alClient
TabIndex = 1 TabIndex = 0
TabOrder = 1 TabOrder = 1
OnChange = PageControl1Change OnChange = PageControlChange
object PgMetadata: TTabSheet object PgMetadata: TTabSheet
Caption = 'EXIF, IPTC' Caption = 'EXIF, IPTC'
ClientHeight = 511 ClientHeight = 511
@ -223,9 +223,9 @@ object MainForm: TMainForm
BorderSpacing.Left = 8 BorderSpacing.Left = 8
Caption = 'Show tag IDs' Caption = 'Show tag IDs'
Checked = True Checked = True
OnChange = CbShowTagIDsChange
State = cbChecked State = cbChecked
TabOrder = 1 TabOrder = 1
OnChange = CbShowTagIDsChange
end end
object CbShowParentTagID: TCheckBox object CbShowParentTagID: TCheckBox
AnchorSideLeft.Control = CbShowTagIDs AnchorSideLeft.Control = CbShowTagIDs
@ -798,8 +798,8 @@ object MainForm: TMainForm
AutoSize = True AutoSize = True
BorderSpacing.Left = 16 BorderSpacing.Left = 16
Caption = 'Apply changes' Caption = 'Apply changes'
OnClick = btnApplyChangesXMPClick
TabOrder = 0 TabOrder = 0
OnClick = btnApplyChangesXMPClick
end end
object btnSaveXMP: TButton object btnSaveXMP: TButton
AnchorSideLeft.Control = btnApplyChangesXMP AnchorSideLeft.Control = btnApplyChangesXMP
@ -812,8 +812,8 @@ object MainForm: TMainForm
AutoSize = True AutoSize = True
BorderSpacing.Left = 4 BorderSpacing.Left = 4
Caption = 'Save' Caption = 'Save'
OnClick = btnSaveXMPClick
TabOrder = 1 TabOrder = 1
OnClick = btnSaveXMPClick
end end
object cbProcessXMP: TCheckBox object cbProcessXMP: TCheckBox
AnchorSideLeft.Control = Panel5 AnchorSideLeft.Control = Panel5
@ -917,8 +917,8 @@ object MainForm: TMainForm
BorderSpacing.Left = 8 BorderSpacing.Left = 8
BorderSpacing.Bottom = 4 BorderSpacing.Bottom = 4
Caption = 'Execute' Caption = 'Execute'
OnClick = BtnChangeDateClick
TabOrder = 1 TabOrder = 1
OnClick = BtnChangeDateClick
end end
end end
end end

View File

@ -29,7 +29,7 @@ type
Panel5: TPanel; Panel5: TPanel;
XMPListView: TListView; XMPListView: TListView;
Messages: TMemo; Messages: TMemo;
PageControl1: TPageControl; PageControl: TPageControl;
Panel1: TPanel; Panel1: TPanel;
Panel2: TPanel; Panel2: TPanel;
Panel3: TPanel; Panel3: TPanel;
@ -57,7 +57,7 @@ type
procedure CbShowTagIDsChange(Sender: TObject); procedure CbShowTagIDsChange(Sender: TObject);
procedure FormCreate(Sender: TObject); procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject); procedure FormDestroy(Sender: TObject);
procedure PageControl1Change(Sender: TObject); procedure PageControlChange(Sender: TObject);
procedure ShellListViewSelectItem(Sender: TObject; Item: TListItem; procedure ShellListViewSelectItem(Sender: TObject; Item: TListItem;
Selected: Boolean); Selected: Boolean);
procedure ShellTreeViewGetImageIndex(Sender: TObject; Node: TTreeNode); procedure ShellTreeViewGetImageIndex(Sender: TObject; Node: TTreeNode);
@ -408,7 +408,7 @@ begin
Messages.Show; Messages.Show;
end; end;
if PageControl1.ActivePage = PgImage then begin if PageControl.ActivePage = PgImage then begin
crs := Screen.Cursor; crs := Screen.Cursor;
try try
Screen.Cursor := crHourglass; Screen.Cursor := crHourglass;
@ -466,6 +466,8 @@ begin
h := ini.ReadInteger('MainForm', 'TreeHeight', 0); h := ini.ReadInteger('MainForm', 'TreeHeight', 0);
if h <> 0 then ShellTreeView.Height := h; if h <> 0 then ShellTreeView.Height := h;
PageControl.ActivePageIndex := ini.ReadInteger('MainForm', 'PageControl', 0);
for i:=0 to TagListView.Columns.Count-1 do begin for i:=0 to TagListView.Columns.Count-1 do begin
w := ini.ReadInteger('TagList', 'ColWidth'+IntToStr(i), 0); w := ini.ReadInteger('TagList', 'ColWidth'+IntToStr(i), 0);
if w <> 0 then if w <> 0 then
@ -504,7 +506,7 @@ begin
end; end;
end; end;
procedure TMainForm.PageControl1Change(Sender: TObject); procedure TMainForm.PageControlChange(Sender: TObject);
var var
crs: TCursor; crs: TCursor;
begin begin
@ -541,6 +543,7 @@ begin
ini.WriteString('MainForm', 'Path', ShellTreeView.Path); ini.WriteString('MainForm', 'Path', ShellTreeView.Path);
ini.WriteInteger('MainForm', 'LeftPanelWidth', ShellPanel.Width); ini.WriteInteger('MainForm', 'LeftPanelWidth', ShellPanel.Width);
ini.WriteInteger('MainForm', 'TreeHeight', ShellTreeView.Height); ini.WriteInteger('MainForm', 'TreeHeight', ShellTreeView.Height);
ini.WriteInteger('MainForm', 'PageControl', PageControl.ActivePageIndex);
ini.WriteBool('TagList', 'ShowTagIDs', CbShowTagIDs.Checked); ini.WriteBool('TagList', 'ShowTagIDs', CbShowTagIDs.Checked);
ini.WriteBool('TagList', 'ShowParentTagID', CbShowParentTagID.Checked); ini.WriteBool('TagList', 'ShowParentTagID', CbShowParentTagID.Checked);

View File

@ -577,8 +577,11 @@ begin
try try
FXmpData.LoadFromStream(AStream, size - Length(XMP_KEY)); FXmpData.LoadFromStream(AStream, size - Length(XMP_KEY));
except except
FreeAndNil(FXmpData); on E:Exception do
raise; begin
FreeAndNil(FXmpData);
raise EFpExifReader.Create('Error reading XMP data: ' + E.Message);
end;
end; end;
end; end;
end; end;

View File

@ -159,13 +159,25 @@ end;
procedure TXMPData.LoadFromStream(AStream: TStream; ASize: Integer = -1); procedure TXMPData.LoadFromStream(AStream: TStream; ASize: Integer = -1);
var var
p: Int64; p: Int64;
i: SizeInt;
begin begin
if ASize = -1 then if ASize = -1 then
ASize := AStream.Size; ASize := AStream.Size;
SetLength(FData, ASize); SetLength(FData, ASize);
p := AStream.Position; p := AStream.Position;
AStream.Read(FData[1], ASize); AStream.Read(FData[1], ASize);
// Sometimes there are incomplete xml files, missing the initial '<'.
// https://superuser.com/questions/1389971/error-0x80070057-the-parameter-is-incorrect-when-editing-jpeg-metadata
// Fixing this is better than rejecting the file...
if pos('?xpacket', FData) = 1 then
begin
SetLength(FData, ASize+1);
for i := ASize downto 1 do
FData[i+1] := FData[i];
FData[1] := '<';
end;
AStream.Position := p; AStream.Position := p;
{$IFDEF FPC} {$IFDEF FPC}
CreateTags; CreateTags;