Bug #1129
Different behaviour of exiv2 between remote and local file.
100%
Description
This issue has surfaced during discussion of #1080.
The file exiv2 -pa http://dev.exiv2.org/attachments/download/786/exiv2-divzero.jpg behaves differently when local.
690 rmills@rmillsmbp:~/gnu/exiv2/trunk $ exiv2 -pa http://dev.exiv2.org/attachments/download/786/exiv2-divzero.jpg
Exiv2 exception in print action for file http://dev.exiv2.org/attachments/download/786/exiv2-divzero.jpg:
Failed to read image data
691 rmills@rmillsmbp:~/gnu/exiv2/trunk $ curl http://dev.exiv2.org/attachments/download/786/exiv2-divzero.jpg | exiv2 -pa -
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 4404 0 4404 0 0 45235 0 --:--:-- --:--:-- --:--:-- 46851
Error: Directory Image: Next pointer is out of bounds; ignored.
Warning: Directory Image, entry 0x3030 has unknown Exif (TIFF) type 12336; setting type size 1.
Error: Directory Image, entry 0x3030 has invalid size 808464432*1; skipping entry.
... hundreds of similar lines deleted ...
Error: Directory Image, entry 0x3030 has invalid size 808464432*1; skipping entry.
Warning: JPEG format error, rc = 5
Exif.Image.ExifTag Long 1 217
Floating point exception: 8
692 rmills@rmillsmbp:~/gnu/exiv2/trunk $ Curiously, the file appears to corrupt and is diagnosed consistently with option -pS694 rmills@rmillsmbp:~/gnu/exiv2/trunk $ curl http://dev.exiv2.org/attachments/download/786/exiv2-divzero.jpg | exiv2 -pS -
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 4404 0 4404 0 0 60926 0 --:--:-- --:--:-- --:--:-- 63826
STRUCTURE OF JPEG FILE: 1444679207.exiv2_temp
address | marker | length | data
2 | 0xd8 SOI | 0
4 | 0xe1 APP1 | 4400 | Exif..MM.*.....00000000000000000
4404 | 0xffffffff ?HU?Exiv2 exception in print action for file -:
This does not look like a JPEG image
695 rmills@rmillsmbp:~/gnu/exiv2/trunk $ The floating point exception reported by the local file is the subject of #1080.
The scope of this issue is to investigate why FileIo and HttpIo result in different output with option -pa.
Related issues
Associated revisions
History
Updated by Robin Mills about 6 years ago
699 rmills@rmillsmbp:~/gnu/exiv2/trunk $ exiv2 -pS http://dev.exiv2.org/attachments/download/786/exiv2-divzero.jpg
STRUCTURE OF JPEG FILE: http://dev.exiv2.org/attachments/download/786/exiv2-divzero.jpg
address | marker | length | data
2 | 0xd8 SOI | 0
4 | 0xe1 APP1 | 4400 | Exif..MM.*.....00000000000000000
4404 | 0xffffffff q$V?Exiv2 exception in print action for file http://dev.exiv2.org/attachments/download/786/exiv2-divzero.jpg:
This does not look like a JPEG image
700 rmills@rmillsmbp:~/gnu/exiv2/trunk $ Updated by Robin Mills about 6 years ago
- Status changed from Assigned to Resolved
- % Done changed from 0 to 100
- Estimated time set to 2.00 h
Fix submitted: r3991
This is a very interesting bug. It's caused by different semantics of eof() in the classes RemoteIo and FileIo.
In jpgimage.cpp#365 in function jpegBase::ReadMetadata(), we have:
io_->read(rawExif.pData_, rawExif.size_);
if (io_->error() || io_->eof()) throw Error(14);RemoteIo::eof() returns true when every byte in the file has been read. class FileIo is a wrapper for the standard "C" FILE pointer and FileIo::eof() returns feof(f) != 0. However feof(f) only returns > 0 when there has been an attempt to read past the end-of-file. This is an artefact of the stdio.h implementation. The function feof(f) returns the status of the EOF bit which is only set when an attempt to read beyond the final byte is requested. That every byte in the file has been consumed is not understood/respected by feof(f).
My fix makes RemoteIo and FileIo consistent as follows:
bool FileIo::eof() const
{
assert(p_->fp_ != 0);
return feof(p_->fp_) != 0 || tell() >= size() ;
}The test suite fails on bugfixes-test.sh bug=480 in largeiptc-test.cpp in the following code: Exiv2::DataBuf buf(io.size());
std::cout << "Reading " << buf.size_ << " bytes from " << data << "\n";
io.read(buf.pData_, buf.size_);
if (io.error() || io.eof()) throw Exiv2::Error(14);This code reads the complete file into memory and throws if the file is at EOF. However, I've modified the semantics of eof() to report true when the whole file has been read. The fix for largeiptc-test.cpp is to require eof() to be true: Exiv2::DataBuf buf(io.size());
std::cout << "Reading " << buf.size_ << " bytes from " << data << "\n";
io.read(buf.pData_, buf.size_);
if (io.error() || !io.eof()) throw Exiv2::Error(14);And now we pass the test suite.
I am a little nervous of this change as we are changing the semantics of basicio::eof(). The documentation http://www.exiv2.org/doc/classExiv2_1_1BasicIo.html states:
Returns true if the IO position has reached the end, otherwise false.I believe my RemoteIo implementation is totally correct and FileIo should be modified to implement this definition.
The messages from local fileio such as:
Error: Directory Image, entry 0x3030 has invalid size 808464432*1; skipping entry. ... hundreds of similar lines deleted ... Error: Directory Image, entry 0x3030 has invalid size 808464432*1; skipping entry.are totally bogus and coming from TiffParser. We shouldn't be in TiffParser. The file is corrupt and jpegBase::ReadMetadata() now behaves correctly by throwing for both local and remote files.
There is a English typo in the documentation generated from basicio.hpp and has been fixed.
#1129. Fix submitted.