Skip to content

Commit fde8ed0

Browse files
Merge pull request #1967 from kevinbackhouse/ReadOrThrow
Add readOrThrow and seekOrThrow to BasicIo
2 parents 1ae9f42 + 68473d9 commit fde8ed0

File tree

5 files changed

+92
-85
lines changed

5 files changed

+92
-85
lines changed

include/exiv2/basicio.hpp

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
#include "exiv2lib_export.h"
2828

2929
// included header files
30+
#include "error.hpp"
3031
#include "types.hpp"
3132

3233
// + standard includes
@@ -142,6 +143,17 @@ namespace Exiv2 {
142143
0 if failure;
143144
*/
144145
virtual long read(byte* buf, long rcount) = 0;
146+
/*!
147+
@brief Safe version of `read()` that checks for errors and throws
148+
an exception if the read was unsuccessful.
149+
@param buf Pointer to a block of memory into which the read data
150+
is stored. The memory block must be at least \em rcount bytes
151+
long.
152+
@param rcount Maximum number of bytes to read. Fewer bytes may be
153+
read if \em rcount bytes are not available.
154+
@param err Error code to use if an exception is thrown.
155+
*/
156+
void readOrThrow(byte* buf, long rcount, ErrorCode err);
145157
/*!
146158
@brief Read one byte from the IO source. Current IO position is
147159
advanced by one byte.
@@ -176,6 +188,19 @@ namespace Exiv2 {
176188
#else
177189
virtual int seek(long offset, Position pos) = 0;
178190
#endif
191+
/*!
192+
@brief Safe version of `seek()` that checks for errors and throws
193+
an exception if the seek was unsuccessful.
194+
@param offset Number of bytes to move the position relative
195+
to the starting position specified by \em pos
196+
@param pos Position from which the seek should start
197+
@param err Error code to use if an exception is thrown.
198+
*/
199+
#if defined(_MSC_VER)
200+
void seekOrThrow(int64_t offset, Position pos, ErrorCode err);
201+
#else
202+
void seekOrThrow(long offset, Position pos, ErrorCode err);
203+
#endif
179204

180205
/*!
181206
@brief Direct access to the IO data. For files, this is done by

src/basicio.cpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
#include "futils.hpp"
2929
#include "types.hpp"
3030
#include "error.hpp"
31+
#include "enforce.hpp"
3132
#include "http.hpp"
3233
#include "properties.hpp"
3334
#include "image_int.hpp"
@@ -77,6 +78,21 @@ using nlink_t = short;
7778
// *****************************************************************************
7879
// class member definitions
7980
namespace Exiv2 {
81+
void BasicIo::readOrThrow(byte* buf, long rcount, ErrorCode err) {
82+
const long nread = read(buf, rcount);
83+
enforce(nread == rcount, err);
84+
enforce(!error(), err);
85+
}
86+
87+
#if defined(_MSC_VER)
88+
void BasicIo::seekOrThrow(int64_t offset, Position pos, ErrorCode err) {
89+
#else
90+
void BasicIo::seekOrThrow(long offset, Position pos, ErrorCode err) {
91+
#endif
92+
const int r = seek(offset, pos);
93+
enforce(r == 0, err);
94+
}
95+
8096
//! Internal Pimpl structure of class FileIo.
8197
class FileIo::Impl {
8298
public:

src/image.cpp

Lines changed: 17 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -138,19 +138,6 @@ namespace {
138138
// *****************************************************************************
139139
// class member definitions
140140
namespace Exiv2 {
141-
// BasicIo::read() with error checking
142-
static void readOrThrow(BasicIo& iIo, byte* buf, long rcount, ErrorCode err) {
143-
const long nread = iIo.read(buf, rcount);
144-
enforce(nread == rcount, err);
145-
enforce(!iIo.error(), err);
146-
}
147-
148-
// BasicIo::seek() with error checking
149-
static void seekOrThrow(BasicIo& iIo, long offset, BasicIo::Position pos, ErrorCode err) {
150-
const int r = iIo.seek(offset, pos);
151-
enforce(r == 0, err);
152-
}
153-
154141
Image::Image(int imageType, uint16_t supportedMetadata, BasicIo::UniquePtr io)
155142
: io_(std::move(io)),
156143
pixelWidth_(0),
@@ -342,8 +329,8 @@ namespace Exiv2 {
342329

343330
do {
344331
// Read top of directory
345-
seekOrThrow(io, start, BasicIo::beg, kerCorruptedMetadata);
346-
readOrThrow(io, dir.data(), 2, kerCorruptedMetadata);
332+
io.seekOrThrow(start, BasicIo::beg, kerCorruptedMetadata);
333+
io.readOrThrow(dir.data(), 2, kerCorruptedMetadata);
347334
uint16_t dirLength = byteSwap2(dir,0,bSwap);
348335
// Prevent infinite loops. (GHSA-m479-7frc-gqqg)
349336
enforce(dirLength > 0, kerCorruptedMetadata);
@@ -369,7 +356,7 @@ namespace Exiv2 {
369356
}
370357
bFirst = false;
371358

372-
readOrThrow(io, dir.data(), 12, kerCorruptedMetadata);
359+
io.readOrThrow(dir.data(), 12, kerCorruptedMetadata);
373360
uint16_t tag = byteSwap2(dir,0,bSwap);
374361
uint16_t type = byteSwap2(dir,2,bSwap);
375362
uint32_t count = byteSwap4(dir,4,bSwap);
@@ -420,9 +407,9 @@ namespace Exiv2 {
420407

421408
if ( bOffsetIsPointer ) { // read into buffer
422409
const long restore = io.tell(); // save
423-
seekOrThrow(io, offset, BasicIo::beg, kerCorruptedMetadata); // position
424-
readOrThrow(io, buf.data(), static_cast<long>(count_x_size), kerCorruptedMetadata); // read
425-
seekOrThrow(io, restore, BasicIo::beg, kerCorruptedMetadata); // restore
410+
io.seekOrThrow(offset, BasicIo::beg, kerCorruptedMetadata); // position
411+
io.readOrThrow(buf.data(), static_cast<long>(count_x_size), kerCorruptedMetadata); // read
412+
io.seekOrThrow(restore, BasicIo::beg, kerCorruptedMetadata); // restore
426413
}
427414

428415
if ( bPrint ) {
@@ -464,7 +451,7 @@ namespace Exiv2 {
464451
const long restore = io.tell();
465452
offset = byteSwap4(buf,k*size,bSwap);
466453
printIFDStructure(io,out,option,offset,bSwap,c,depth);
467-
seekOrThrow(io, restore, BasicIo::beg, kerCorruptedMetadata);
454+
io.seekOrThrow(restore, BasicIo::beg, kerCorruptedMetadata);
468455
}
469456
} else if ( option == kpsRecursive && tag == 0x83bb /* IPTCNAA */ ) {
470457
if (count > 0) {
@@ -473,11 +460,11 @@ namespace Exiv2 {
473460
}
474461

475462
const long restore = io.tell();
476-
seekOrThrow(io, offset, BasicIo::beg, kerCorruptedMetadata); // position
463+
io.seekOrThrow(offset, BasicIo::beg, kerCorruptedMetadata); // position
477464
std::vector<byte> bytes(count) ; // allocate memory
478465
// TODO: once we have C++11 use bytes.data()
479-
readOrThrow(io, &bytes[0], count, kerCorruptedMetadata);
480-
seekOrThrow(io, restore, BasicIo::beg, kerCorruptedMetadata);
466+
io.readOrThrow(&bytes[0], count, kerCorruptedMetadata);
467+
io.seekOrThrow(restore, BasicIo::beg, kerCorruptedMetadata);
481468
// TODO: once we have C++11 use bytes.data()
482469
IptcData::printStructure(out, makeSliceUntil(&bytes[0], count), depth);
483470
}
@@ -487,23 +474,23 @@ namespace Exiv2 {
487474
uint32_t jump= 10 ;
488475
byte bytes[20] ;
489476
const auto chars = reinterpret_cast<const char*>(&bytes[0]);
490-
seekOrThrow(io, offset, BasicIo::beg, kerCorruptedMetadata); // position
491-
readOrThrow(io, bytes, jump, kerCorruptedMetadata) ; // read
477+
io.seekOrThrow(offset, BasicIo::beg, kerCorruptedMetadata); // position
478+
io.readOrThrow(bytes, jump, kerCorruptedMetadata) ; // read
492479
bytes[jump]=0 ;
493480
if ( ::strcmp("Nikon",chars) == 0 ) {
494481
// tag is an embedded tiff
495482
const long byteslen = count-jump;
496483
DataBuf bytes(byteslen); // allocate a buffer
497-
readOrThrow(io, bytes.data(), byteslen, kerCorruptedMetadata); // read
484+
io.readOrThrow(bytes.data(), byteslen, kerCorruptedMetadata); // read
498485
MemIo memIo(bytes.c_data(), byteslen) ; // create a file
499486
printTiffStructure(memIo,out,option,depth);
500487
} else {
501488
// tag is an IFD
502-
seekOrThrow(io, 0, BasicIo::beg, kerCorruptedMetadata); // position
489+
io.seekOrThrow(0, BasicIo::beg, kerCorruptedMetadata); // position
503490
printIFDStructure(io,out,option,offset,bSwap,c,depth);
504491
}
505492

506-
seekOrThrow(io, restore, BasicIo::beg, kerCorruptedMetadata); // restore
493+
io.seekOrThrow(restore, BasicIo::beg, kerCorruptedMetadata); // restore
507494
}
508495
}
509496

@@ -516,7 +503,7 @@ namespace Exiv2 {
516503
}
517504
}
518505
if ( start ) {
519-
readOrThrow(io, dir.data(), 4, kerCorruptedMetadata);
506+
io.readOrThrow(dir.data(), 4, kerCorruptedMetadata);
520507
start = byteSwap4(dir,0,bSwap);
521508
}
522509
} while (start) ;
@@ -536,7 +523,7 @@ namespace Exiv2 {
536523
DataBuf dir(dirSize);
537524

538525
// read header (we already know for certain that we have a Tiff file)
539-
readOrThrow(io, dir.data(), 8, kerCorruptedMetadata);
526+
io.readOrThrow(dir.data(), 8, kerCorruptedMetadata);
540527
char c = static_cast<char>(dir.read_uint8(0));
541528
bool bSwap = ( c == 'M' && isLittleEndianPlatform() )
542529
|| ( c == 'I' && isBigEndianPlatform() )

src/jpgimage.cpp

Lines changed: 13 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -94,19 +94,6 @@ namespace Exiv2 {
9494
constexpr uint16_t Photoshop::iptc_ = 0x0404;
9595
constexpr uint16_t Photoshop::preview_ = 0x040c;
9696

97-
// BasicIo::read() with error checking
98-
static void readOrThrow(BasicIo& iIo, byte* buf, long rcount, ErrorCode err) {
99-
const long nread = iIo.read(buf, rcount);
100-
enforce(nread == rcount, err);
101-
enforce(!iIo.error(), err);
102-
}
103-
104-
// BasicIo::seek() with error checking
105-
static void seekOrThrow(BasicIo& iIo, long offset, BasicIo::Position pos, ErrorCode err) {
106-
const int r = iIo.seek(offset, pos);
107-
enforce(r == 0, err);
108-
}
109-
11097
static inline bool inRange(int lo,int value, int hi)
11198
{
11299
return lo<=value && value <= hi;
@@ -389,7 +376,7 @@ namespace Exiv2 {
389376
byte sizebuf[2];
390377
uint16_t size = 0;
391378
if (markerHasLength(marker)) {
392-
readOrThrow(*io_, sizebuf, 2, kerFailedToReadImageData);
379+
io_->readOrThrow(sizebuf, 2, kerFailedToReadImageData);
393380
size = getUShort(sizebuf, bigEndian);
394381
// `size` is the size of the segment, including the 2-byte size field
395382
// that we just read.
@@ -399,7 +386,7 @@ namespace Exiv2 {
399386
// Read the rest of the segment.
400387
DataBuf buf(size);
401388
if (size > 0) {
402-
readOrThrow(*io_, buf.data(2), size - 2, kerFailedToReadImageData);
389+
io_->readOrThrow(buf.data(2), size - 2, kerFailedToReadImageData);
403390
buf.copyBytes(0, sizebuf, 2);
404391
}
405392

@@ -616,7 +603,7 @@ namespace Exiv2 {
616603
byte sizebuf[2];
617604
uint16_t size = 0;
618605
if (markerHasLength(marker)) {
619-
readOrThrow(*io_, sizebuf, 2, kerFailedToReadImageData);
606+
io_->readOrThrow(sizebuf, 2, kerFailedToReadImageData);
620607
size = getUShort(sizebuf, bigEndian);
621608
// `size` is the size of the segment, including the 2-byte size field
622609
// that we just read.
@@ -627,7 +614,7 @@ namespace Exiv2 {
627614
DataBuf buf(size);
628615
if (size > 0) {
629616
assert(size >= 2); // enforced above
630-
readOrThrow(*io_, buf.data(2), size - 2, kerFailedToReadImageData);
617+
io_->readOrThrow(buf.data(2), size - 2, kerFailedToReadImageData);
631618
buf.copyBytes(0, sizebuf, 2);
632619
}
633620

@@ -847,16 +834,16 @@ namespace Exiv2 {
847834
#ifdef EXIV2_DEBUG_MESSAGES
848835
std::cout << start << ":" << length << std::endl;
849836
#endif
850-
seekOrThrow(*io_, start, BasicIo::beg, kerFailedToReadImageData);
837+
io_->seekOrThrow(start, BasicIo::beg, kerFailedToReadImageData);
851838
DataBuf buf(length);
852-
readOrThrow(*io_, buf.data(), buf.size(), kerFailedToReadImageData);
839+
io_->readOrThrow(buf.data(), buf.size(), kerFailedToReadImageData);
853840
tempIo->write(buf.c_data(), buf.size());
854841
}
855842
}
856843

857-
seekOrThrow(*io_, 0, BasicIo::beg, kerFailedToReadImageData);
844+
io_->seekOrThrow(0, BasicIo::beg, kerFailedToReadImageData);
858845
io_->transfer(*tempIo); // may throw
859-
seekOrThrow(*io_, 0, BasicIo::beg, kerFailedToReadImageData);
846+
io_->seekOrThrow(0, BasicIo::beg, kerFailedToReadImageData);
860847
readMetadata();
861848
}
862849
} // JpegBase::printStructure
@@ -923,7 +910,7 @@ namespace Exiv2 {
923910
byte sizebuf[2];
924911
uint16_t size = 0;
925912
if (markerHasLength(marker)) {
926-
readOrThrow(*io_, sizebuf, 2, kerFailedToReadImageData);
913+
io_->readOrThrow(sizebuf, 2, kerFailedToReadImageData);
927914
size = getUShort(sizebuf, bigEndian);
928915
// `size` is the size of the segment, including the 2-byte size field
929916
// that we just read.
@@ -934,7 +921,7 @@ namespace Exiv2 {
934921
DataBuf buf(size);
935922
if (size > 0) {
936923
assert(size >= 2); // enforced above
937-
readOrThrow(*io_, buf.data(2), size - 2, kerFailedToReadImageData);
924+
io_->readOrThrow(buf.data(2), size - 2, kerFailedToReadImageData);
938925
buf.copyBytes(0, sizebuf, 2);
939926
}
940927

@@ -1024,7 +1011,7 @@ namespace Exiv2 {
10241011
if (!comment_.empty())
10251012
++search;
10261013

1027-
seekOrThrow(*io_, seek, BasicIo::beg, kerNoImageInInputData);
1014+
io_->seekOrThrow(seek, BasicIo::beg, kerNoImageInInputData);
10281015
count = 0;
10291016
marker = advanceToMarker(kerNoImageInInputData);
10301017

@@ -1037,7 +1024,7 @@ namespace Exiv2 {
10371024
byte sizebuf[2];
10381025
uint16_t size = 0;
10391026
if (markerHasLength(marker)) {
1040-
readOrThrow(*io_, sizebuf, 2, kerFailedToReadImageData);
1027+
io_->readOrThrow(sizebuf, 2, kerFailedToReadImageData);
10411028
size = getUShort(sizebuf, bigEndian);
10421029
// `size` is the size of the segment, including the 2-byte size field
10431030
// that we just read.
@@ -1048,7 +1035,7 @@ namespace Exiv2 {
10481035
DataBuf buf(size);
10491036
if (size > 0) {
10501037
assert(size >= 2); // enforced above
1051-
readOrThrow(*io_, buf.data(2), size - 2, kerFailedToReadImageData);
1038+
io_->readOrThrow(buf.data(2), size - 2, kerFailedToReadImageData);
10521039
buf.copyBytes(0, sizebuf, 2);
10531040
}
10541041

0 commit comments

Comments
 (0)