diff --git a/include/exiv2/jpgimage.hpp b/include/exiv2/jpgimage.hpp
index 881b9a63..f317c685 100644
--- a/include/exiv2/jpgimage.hpp
+++ b/include/exiv2/jpgimage.hpp
@@ -28,6 +28,7 @@
// included header files
#include "image.hpp"
+#include "error.hpp"
// *****************************************************************************
// namespace extensions
@@ -277,12 +278,19 @@ namespace Exiv2 {
Jpeg marker and returns the marker. This method should be called
when the BasicIo instance is positioned one byte past the end of a
Jpeg segment.
+ @param err the error code to throw if no marker is found
@return the next Jpeg segment marker if successful;
- -1 if a maker was not found before EOF
+ throws an Error if not successful
*/
- int advanceToMarker() const;
+ byte advanceToMarker(ErrorCode err) const;
//@}
+ /*!
+ @brief Is the marker followed by a non-zero payload?
+ @param marker The marker at the start of a segment
+ @return true if the marker is followed by a non-zero payload
+ */
+ static bool markerHasLength(byte marker);
}; // class JpegBase
/*!
diff --git a/src/jpgimage.cpp b/src/jpgimage.cpp
index e8c80925..d4c203c7 100644
--- a/src/jpgimage.cpp
+++ b/src/jpgimage.cpp
@@ -313,6 +313,16 @@ namespace Exiv2 {
} // Photoshop::setIptcIrb
+ bool JpegBase::markerHasLength(byte marker) {
+ return (marker >= sof0_ && marker <= sof15_) ||
+ (marker >= app0_ && marker <= (app0_ | 0x0F)) ||
+ marker == dht_ ||
+ marker == dqt_ ||
+ marker == dri_ ||
+ marker == com_ ||
+ marker == sos_;
+ }
+
JpegBase::JpegBase(int type, BasicIo::UniquePtr io, bool create,
const byte initData[], long dataSize)
: Image(type, mdExif | mdIptc | mdXmp | mdComment, std::move(io))
@@ -334,19 +344,22 @@ namespace Exiv2 {
return 0;
}
- int JpegBase::advanceToMarker() const
+ byte JpegBase::advanceToMarker(ErrorCode err) const
{
int c = -1;
// Skips potential padding between markers
while ((c=io_->getb()) != 0xff) {
if (c == EOF)
- return -1;
+ throw Error(err);
}
// Markers can start with any number of 0xff
while ((c=io_->getb()) == 0xff) {
}
- return c;
+ if (c == EOF)
+ throw Error(err);
+
+ return static_cast(c);
}
void JpegBase::readMetadata()
@@ -368,22 +381,14 @@ namespace Exiv2 {
bool foundXmpData = false;
bool foundIccData = false;
- // which markers have a length field?
- // TODO: move this to a utility function
- bool mHasLength[256];
- for (int i = 0; i < 256; i++)
- mHasLength[i] = (i >= sof0_ && i <= sof15_) || (i >= app0_ && i <= (app0_ | 0x0F)) ||
- (i == dht_ || i == dqt_ || i == dri_ || i == com_ || i == sos_);
-
// Read section marker
- int marker = advanceToMarker();
- if (marker < 0) throw Error(kerNotAJpeg);
+ byte marker = advanceToMarker(kerNotAJpeg);
while (marker != sos_ && marker != eoi_ && search > 0) {
// 2-byte buffer for reading the size.
byte sizebuf[2];
uint16_t size = 0;
- if (mHasLength[marker]) {
+ if (markerHasLength(marker)) {
readOrThrow(*io_, sizebuf, 2, kerFailedToReadImageData);
size = getUShort(sizebuf, bigEndian);
// `size` is the size of the segment, including the 2-byte size field
@@ -505,8 +510,9 @@ namespace Exiv2 {
}
// Read the beginning of the next segment
- marker = advanceToMarker();
- if (marker < 0) {
+ try {
+ marker = advanceToMarker(kerFailedToReadImageData);
+ } catch (Error&) {
rc = 5;
break;
}
@@ -588,20 +594,11 @@ namespace Exiv2 {
}
}
- // which markers have a length field?
- // TODO: move this to a utility function
- bool mHasLength[256];
- for (int i = 0; i < 256; i++)
- mHasLength[i] = (i >= sof0_ && i <= sof15_) || (i >= app0_ && i <= (app0_ | 0x0F)) ||
- (i == dht_ || i == dqt_ || i == dri_ || i == com_ || i == sos_);
-
// Container for the signature
bool bExtXMP = false;
// Read section marker
- int marker = advanceToMarker();
- if (marker < 0)
- throw Error(kerNotAJpeg);
+ byte marker = advanceToMarker(kerNotAJpeg);
bool done = false;
bool first = true;
@@ -618,7 +615,7 @@ namespace Exiv2 {
// 2-byte buffer for reading the size.
byte sizebuf[2];
uint16_t size = 0;
- if (mHasLength[marker]) {
+ if (markerHasLength(marker)) {
readOrThrow(*io_, sizebuf, 2, kerFailedToReadImageData);
size = getUShort(sizebuf, bigEndian);
// `size` is the size of the segment, including the 2-byte size field
@@ -634,12 +631,12 @@ namespace Exiv2 {
memcpy(buf.pData_, sizebuf, 2);
}
- if (bPrint && mHasLength[marker])
+ if (bPrint && markerHasLength(marker))
out << Internal::stringFormat(" | %7d ", size);
// print signature for APPn
if (marker >= app0_ && marker <= (app0_ | 0x0F)) {
- assert(mHasLength[marker]);
+ assert(markerHasLength(marker));
assert(size >= 2); // Because this marker has a length field.
// http://www.adobe.com/content/dam/Adobe/en/devnet/xmp/pdfs/XMPSpecificationPart3.pdf p75
const std::string signature =
@@ -776,7 +773,7 @@ namespace Exiv2 {
// print COM marker
if (bPrint && marker == com_) {
- assert(mHasLength[marker]);
+ assert(markerHasLength(marker));
assert(size >= 2); // Because this marker has a length field.
// size includes 2 for the two bytes for size!
const size_t n = (size - 2) > 32 ? 32 : size - 2;
@@ -791,8 +788,7 @@ namespace Exiv2 {
if (marker != sos_) {
// Read the beginning of the next segment
- marker = advanceToMarker();
- enforce(marker>=0, kerNoImageInInputData);
+ marker = advanceToMarker(kerNoImageInInputData);
REPORT_MARKER;
}
done |= marker == eoi_ || marker == sos_;
@@ -914,17 +910,8 @@ namespace Exiv2 {
if (writeHeader(outIo))
throw Error(kerImageWriteFailed);
- // which markers have a length field?
- // TODO: move this to a utility function
- bool mHasLength[256];
- for (int i = 0; i < 256; i++)
- mHasLength[i] = (i >= sof0_ && i <= sof15_) || (i >= app0_ && i <= (app0_ | 0x0F)) ||
- (i == dht_ || i == dqt_ || i == dri_ || i == com_ || i == sos_);
-
// Read section marker
- int marker = advanceToMarker();
- if (marker < 0)
- throw Error(kerNoImageInInputData);
+ byte marker = advanceToMarker(kerNoImageInInputData);
// First find segments of interest. Normally app0 is first and we want
// to insert after it. But if app0 comes after com, app1 and app13 then
@@ -933,7 +920,7 @@ namespace Exiv2 {
// 2-byte buffer for reading the size.
byte sizebuf[2];
uint16_t size = 0;
- if (mHasLength[marker]) {
+ if (markerHasLength(marker)) {
readOrThrow(*io_, sizebuf, 2, kerFailedToReadImageData);
size = getUShort(sizebuf, bigEndian);
// `size` is the size of the segment, including the 2-byte size field
@@ -950,7 +937,7 @@ namespace Exiv2 {
}
if (marker == app0_) {
- assert(mHasLength[marker]);
+ assert(markerHasLength(marker));
assert(size >= 2); // Because this marker has a length field.
insertPos = count + 1;
} else if (skipApp1Exif == notfound && marker == app1_ && memcmp(buf.pData_ + 2, exifId_, 6) == 0) {
@@ -983,7 +970,7 @@ namespace Exiv2 {
foundCompletePsData = true;
}
} else if (marker == com_ && skipCom == notfound) {
- assert(mHasLength[marker]);
+ assert(markerHasLength(marker));
assert(size >= 2); // Because this marker has a length field.
// Jpegs can have multiple comments, but for now only handle
// the first one (most jpegs only have one anyway).
@@ -1000,9 +987,7 @@ namespace Exiv2 {
comPos = count;
++search;
}
- marker = advanceToMarker();
- if (marker < 0)
- throw Error(kerNoImageInInputData);
+ marker = advanceToMarker(kerNoImageInInputData);
++count;
}
@@ -1030,9 +1015,7 @@ namespace Exiv2 {
seekOrThrow(*io_, seek, BasicIo::beg, kerNoImageInInputData);
count = 0;
- marker = advanceToMarker();
- if (marker < 0)
- throw Error(kerNoImageInInputData);
+ marker = advanceToMarker(kerNoImageInInputData);
// To simplify this a bit, new segments are inserts at either the start
// or right after app0. This is standard in most jpegs, but has the
@@ -1042,7 +1025,7 @@ namespace Exiv2 {
// 2-byte buffer for reading the size.
byte sizebuf[2];
uint16_t size = 0;
- if (mHasLength[marker]) {
+ if (markerHasLength(marker)) {
readOrThrow(*io_, sizebuf, 2, kerFailedToReadImageData);
size = getUShort(sizebuf, bigEndian);
// `size` is the size of the segment, including the 2-byte size field
@@ -1255,9 +1238,7 @@ namespace Exiv2 {
}
// Next marker
- marker = advanceToMarker();
- if (marker < 0)
- throw Error(kerNoImageInInputData);
+ marker = advanceToMarker(kerNoImageInInputData);
++count;
}