You've already forked lazarus-ccr
fpexif: Fix crash when file with incorrectly specified segment length is written. Fix XMP metadata being lost when they coexist together with EXIF.
git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@7965 8e941d3f-bd1b-0410-a28a-d453659cc2b4
This commit is contained in:
@ -397,11 +397,14 @@ type
|
||||
end;
|
||||
const
|
||||
SOI_MARKER: array[0..1] of byte = ($FF, $D8);
|
||||
XMP_SIGNATURE = 'http://ns.adobe.com/xap/1.0/';
|
||||
var
|
||||
header: TSegmentHeader;
|
||||
headerSize, newHeaderSize: Word;
|
||||
n, count: Int64;
|
||||
savedPos: Int64;
|
||||
jfif: TJpegJFIFSegment;
|
||||
s: String;
|
||||
begin
|
||||
// Write the header segment and all metadata segments stored in TImgInfo
|
||||
// to the beginning of the stream
|
||||
@ -415,19 +418,61 @@ begin
|
||||
while AInputStream.Position < AInputStream.Size do begin
|
||||
savedPos := AInputStream.Position; // just for debugging
|
||||
n := AInputStream.Read(header{%H-}, SizeOf(header));
|
||||
if n <> Sizeof(header) then
|
||||
if n <> SizeOf(header) then
|
||||
// End of file reached, cannot read complete header
|
||||
Error(rsIncompleteJpegSegmentHeader);
|
||||
|
||||
// Some images do not specify the segment length correctly and fill the
|
||||
// space to the next segment with zero bytes.
|
||||
if LongInt(header) = 0 then begin
|
||||
n := 0;
|
||||
while AInputStream.ReadByte = 0 do
|
||||
inc(n);
|
||||
AInputStream.Position := AInputStream.Position - 1;
|
||||
n := AInputStream.Read(header, SizeOf(Header));
|
||||
if n <> SizeOf(Header) then
|
||||
Error(rsIncompleteJpegSegmentHeader);
|
||||
end;
|
||||
|
||||
if header.Key <> $FF then
|
||||
Error(rsJpegSegmentMarkerExpected);
|
||||
header.Size := BEToN(header.Size);
|
||||
headerSize := BEToN(header.Size);
|
||||
|
||||
// Save stream position before segment size value.
|
||||
savedPos := AInputStream.Position - 2;
|
||||
case header.Marker of
|
||||
M_SOI:
|
||||
header.Size := 0;
|
||||
M_JFIF, M_EXIF, M_IPTC, M_COM: // these segments were already written by WriteJpeg
|
||||
headerSize := 0;
|
||||
M_JFIF, M_IPTC, M_COM: // These segments were already written by WriteJpeg
|
||||
;
|
||||
M_EXIF:
|
||||
// there may be also the XMP segment which has the same key $E1.
|
||||
begin
|
||||
SetLength(s, Length(XMP_SIGNATURE));
|
||||
AInputStream.Read(s[1], Length(XMP_SIGNATURE));
|
||||
if s = XMP_SIGNATURE then
|
||||
begin
|
||||
// XMP segment found --> write it back as it is (needs to be fixed to write current meta data)
|
||||
newHeaderSize := (Trunc(headerSize / 256) + 1) * 256 - SizeOf(header);
|
||||
SetLength(s, newHeaderSize - Length(XMP_SIGNATURE));
|
||||
FillChar(s[1], Length(s), 0);
|
||||
AInputStream.Read(s[1], headerSize);
|
||||
header.Size := NToBE(newHeaderSize);
|
||||
AOutputStream.Write(header, SizeOf(Header));
|
||||
AOutputStream.Write(XMP_SIGNATURE, Length(XMP_SIGNATURE));
|
||||
AOutputStream.Write(s[1], Length(s));
|
||||
{
|
||||
AInputStream.Position := savedPos - 4;
|
||||
n := AOutputStream.CopyFrom(AInputStream, Int64(header.Size) + 2);
|
||||
if n <> Int64(header.Size) + 2 then
|
||||
Error(rsJpegReadWriteErrorInSegment);
|
||||
}
|
||||
end
|
||||
else
|
||||
begin
|
||||
// EXIF segment found. But this already has been written by WriteJpeg -> nothing to do
|
||||
end;
|
||||
end;
|
||||
M_SOS:
|
||||
begin
|
||||
// this is the last segment before compressed data which don't have a marker
|
||||
@ -442,11 +487,11 @@ begin
|
||||
end;
|
||||
else
|
||||
AInputStream.Position := AInputStream.Position - 4; // go back to where the segment begins
|
||||
n := AOutputStream.CopyFrom(AInputStream, Int64(header.Size) + 2);
|
||||
if n <> Int64(header.Size) + 2 then
|
||||
n := AOutputStream.CopyFrom(AInputStream, headerSize + 2);
|
||||
if n <> Int64(headerSize) + 2 then
|
||||
Error(rsJpegReadWriteErrorInSegment);
|
||||
end;
|
||||
AInputStream.Position := savedPos + header.Size;
|
||||
AInputStream.Position := savedPos + headerSize;
|
||||
end;
|
||||
end;
|
||||
|
||||
|
Reference in New Issue
Block a user