More consistent / better defined handling of Entry::size_
This commit is contained in:
+38
-35
@@ -20,14 +20,14 @@
|
||||
*/
|
||||
/*
|
||||
File: ifd.cpp
|
||||
Version: $Name: $ $Revision: 1.10 $
|
||||
Version: $Name: $ $Revision: 1.11 $
|
||||
Author(s): Andreas Huggel (ahu) <ahuggel@gmx.net>
|
||||
History: 26-Jan-04, ahu: created
|
||||
11-Feb-04, ahu: isolated as a component
|
||||
*/
|
||||
// *****************************************************************************
|
||||
#include "rcsid.hpp"
|
||||
EXIV2_RCSID("@(#) $Name: $ $Revision: 1.10 $ $RCSfile: ifd.cpp,v $")
|
||||
EXIV2_RCSID("@(#) $Name: $ $Revision: 1.11 $ $RCSfile: ifd.cpp,v $")
|
||||
|
||||
// *****************************************************************************
|
||||
// included header files
|
||||
@@ -104,51 +104,56 @@ namespace Exif {
|
||||
|
||||
void Entry::setValue(uint32 data, ByteOrder byteOrder)
|
||||
{
|
||||
if (data_ == 0) {
|
||||
if (data_ == 0 || size_ < 4) {
|
||||
if (!alloc_) {
|
||||
throw Error("Invariant alloc violated in Entry::setValue");
|
||||
throw Error("cannot allocate memory");
|
||||
}
|
||||
data_ = new char[4];
|
||||
size_ = 4;
|
||||
delete[] data_;
|
||||
data_ = new char[size_];
|
||||
}
|
||||
// No need to resize previously allocated memory
|
||||
ul2Data(data_, data, byteOrder);
|
||||
size_ = 4;
|
||||
// do not change size_
|
||||
type_ = unsignedLong;
|
||||
count_ = 1;
|
||||
}
|
||||
|
||||
void Entry::setValue(uint16 type, uint32 count, const char* data, long size)
|
||||
{
|
||||
// Make sure size is always at least four bytes
|
||||
long newSize = std::max(long(4), size);
|
||||
long dataSize = count * TypeInfo::typeSize(TypeId(type_));
|
||||
// No minimum size requirement, but make sure the buffer can hold the data
|
||||
if (size < dataSize) {
|
||||
throw Error("Size too small");
|
||||
}
|
||||
if (alloc_) {
|
||||
delete[] data_;
|
||||
data_ = new char[newSize];
|
||||
memset(data_, 0x0, 4);
|
||||
memcpy(data_, data, size);
|
||||
data_ = new char[size];
|
||||
memset(data_, 0x0, size);
|
||||
memcpy(data_, data, dataSize);
|
||||
size_ = size;
|
||||
}
|
||||
else {
|
||||
if (size_ == 0) {
|
||||
// Set the data pointer of a virgin entry
|
||||
if (size < 4) throw Error("Size too small");
|
||||
data_ = const_cast<char*>(data);
|
||||
size_ = size;
|
||||
}
|
||||
else {
|
||||
// Overwrite existing data if it fits into the buffer
|
||||
if (newSize > size_) throw Error("Size too large");
|
||||
memset(data_, 0x0, std::max(long(4), size_));
|
||||
memcpy(data_, data, size);
|
||||
if (dataSize > size_) throw Error("Value too large");
|
||||
memset(data_, 0x0, size_);
|
||||
memcpy(data_, data, dataSize);
|
||||
// do not change size_
|
||||
}
|
||||
}
|
||||
type_ = type;
|
||||
count_ = count;
|
||||
size_ = newSize;
|
||||
} // Entry::setValue
|
||||
|
||||
const char* Entry::component(uint32 n) const
|
||||
{
|
||||
if (n >= count()) return 0;
|
||||
return data_ + n * typeSize();
|
||||
return data() + n * typeSize();
|
||||
} // Entry::component
|
||||
|
||||
Ifd::Ifd(IfdId ifdId)
|
||||
@@ -173,7 +178,7 @@ namespace Exif {
|
||||
Ifd::PreEntries preEntries;
|
||||
|
||||
int n = getUShort(buf, byteOrder);
|
||||
long o = 2;
|
||||
long o = 2;
|
||||
|
||||
for (int i = 0; i < n; ++i) {
|
||||
Ifd::PreEntry pe;
|
||||
@@ -217,6 +222,7 @@ namespace Exif {
|
||||
e.setTag(i->tag_);
|
||||
// Set the offset to the data, relative to start of IFD
|
||||
e.setOffset(i->size_ > 4 ? i->offset_ - offset_ : i->offsetLoc_);
|
||||
// Set the size to at least for bytes to accomodate offset-data
|
||||
e.setValue(i->type_, i->count_, buf + e.offset(),
|
||||
std::max(long(4), i->size_));
|
||||
this->add(e);
|
||||
@@ -281,24 +287,25 @@ namespace Exif {
|
||||
const iterator e = entries_.end();
|
||||
iterator i = b;
|
||||
for (; i != e; ++i) {
|
||||
us2Data(buf+o, i->tag(), byteOrder);
|
||||
us2Data(buf+o+2, i->type(), byteOrder);
|
||||
ul2Data(buf+o+4, i->count(), byteOrder);
|
||||
us2Data(buf + o, i->tag(), byteOrder);
|
||||
us2Data(buf + o + 2, i->type(), byteOrder);
|
||||
ul2Data(buf + o + 4, i->count(), byteOrder);
|
||||
if (i->size() > 4) {
|
||||
// Set the offset of the entry, data immediately follows the IFD
|
||||
i->setOffset(size() + dataSize);
|
||||
ul2Data(buf+o+8, offset_ + i->offset(), byteOrder);
|
||||
ul2Data(buf + o + 8, offset_ + i->offset(), byteOrder);
|
||||
dataSize += i->size();
|
||||
}
|
||||
else {
|
||||
// Copy data into the offset field
|
||||
memcpy(buf+o+8, i->data(), 4);
|
||||
memset(buf + o + 8, 0x0, 4);
|
||||
memcpy(buf + o + 8, i->data(), i->size());
|
||||
}
|
||||
o += 12;
|
||||
}
|
||||
|
||||
// Add the offset to the next IFD to the data buffer
|
||||
o += ul2Data(buf+o, next_, byteOrder);
|
||||
o += ul2Data(buf + o, next_, byteOrder);
|
||||
|
||||
// Add the data of all IFD entries to the data buffer
|
||||
for (i = b; i != e; ++i) {
|
||||
@@ -322,10 +329,10 @@ namespace Exif {
|
||||
{
|
||||
// Todo: Implement Assert (Stroustup 24.3.7.2)
|
||||
if (alloc_ != entry.alloc()) {
|
||||
throw Error("Invariant alloc violated in Ifd::add");
|
||||
throw Error("Ifd::add : alloc mismatch");
|
||||
}
|
||||
if (ifdId_ != entry.ifdId()) {
|
||||
throw Error("Invariant ifdId violated in Ifd::add");
|
||||
throw Error("Ifd::add : ifdId mismatch");
|
||||
}
|
||||
// allow duplicates
|
||||
entries_.push_back(entry);
|
||||
@@ -387,14 +394,10 @@ namespace Exif {
|
||||
}
|
||||
else {
|
||||
unsigned char* data = (unsigned char*)i->data();
|
||||
offset << std::setw(2) << std::setfill('0') << std::hex
|
||||
<< (int)data[0] << " "
|
||||
<< std::setw(2) << std::setfill('0') << std::hex
|
||||
<< (int)data[1] << " "
|
||||
<< std::setw(2) << std::setfill('0') << std::hex
|
||||
<< (int)data[2] << " "
|
||||
<< std::setw(2) << std::setfill('0') << std::hex
|
||||
<< (int)data[3] << " ";
|
||||
for (int k = 0; k < i->size(); ++k) {
|
||||
offset << std::setw(2) << std::setfill('0') << std::hex
|
||||
<< (int)data[k] << " ";
|
||||
}
|
||||
}
|
||||
os << prefix << std::setw(5) << std::setfill(' ') << std::dec
|
||||
<< std::right << i - b
|
||||
|
||||
+58
-40
@@ -21,7 +21,7 @@
|
||||
/*!
|
||||
@file ifd.hpp
|
||||
@brief Encoding and decoding of IFD (Image File Directory) data
|
||||
@version $Name: $ $Revision: 1.10 $
|
||||
@version $Name: $ $Revision: 1.11 $
|
||||
@author Andreas Huggel (ahu)
|
||||
<a href="mailto:ahuggel@gmx.net">ahuggel@gmx.net</a>
|
||||
@date 09-Jan-04, ahu: created
|
||||
@@ -89,37 +89,42 @@ namespace Exif {
|
||||
/*!
|
||||
@brief Set the value of the entry to a single unsigned long component,
|
||||
i.e., set the type of the entry to unsigned long, number of
|
||||
components to one, size to four bytes and the value according
|
||||
to the data provided. This method can be used to set the value
|
||||
of a tag which contains a pointer (offset) to a location in the
|
||||
%Exif data (like e.g., ExifTag, 0x8769 in IFD0, which contains a
|
||||
pointer to the Exif IFD). This method cannot be used to set the
|
||||
value of a newly created %Entry in non-alloc mode.
|
||||
components to one and the value according to the data provided.
|
||||
|
||||
The size of the data buffer is set to at least four bytes, but is left
|
||||
unchanged if it can accomodate the pointer. This method can be used
|
||||
to set the value of a tag which contains a pointer (offset) to a
|
||||
location in the %Exif data (like e.g., ExifTag, 0x8769 in IFD0, which
|
||||
contains a pointer to the %Exif IFD).
|
||||
<BR>This method cannot be used to set the value of a newly created
|
||||
%Entry in non-alloc mode.
|
||||
*/
|
||||
void setValue(uint32 data, ByteOrder byteOrder);
|
||||
/*!
|
||||
@brief Set type, count, size and the data of the entry.
|
||||
|
||||
Copies the provided buffer when called in memory allocation mode. In
|
||||
non-alloc mode, use this method to set the data of a newly created
|
||||
%Entry. The data buffer provided must be at least four bytes to
|
||||
initialise an %Entry in non-alloc mode. In this case, only the pointer
|
||||
to the buffer is copied, i.e., the buffer must remain valid throughout
|
||||
the life of the %Entry. Subsequent calls in non-alloc mode overwrite
|
||||
the data pointed to by this pointer with the data provided, i.e., the
|
||||
buffer provided in subsequent calls can be deleted after the call.
|
||||
<BR>Todo: This sounds too complicated: should I isolate the init
|
||||
functionality into a separate method?
|
||||
@brief Set type, count, the data buffer and its size.
|
||||
|
||||
Copies the provided buffer when called in memory allocation mode.
|
||||
<BR>In non-alloc mode, use this method to initialise the data of a
|
||||
newly created %Entry. In this case, only the pointer to the buffer is
|
||||
copied, i.e., the buffer must remain valid throughout the life of the
|
||||
%Entry. Subsequent calls in non-alloc mode will overwrite the data
|
||||
pointed to by this pointer with the data provided, i.e., the buffer
|
||||
provided in subsequent calls can be deleted after the call.
|
||||
<BR>In either memory allocation mode, the data buffer provided must be
|
||||
large enough to hold count components of type. The size of the buffer
|
||||
will be as indicated in the size argument. I.e., it is possible to
|
||||
allocate (set) a data buffer larger than required to hold count
|
||||
components of the given type.
|
||||
|
||||
@param type The type of the data.
|
||||
@param count Number of components in the buffer.
|
||||
@param data Pointer to the data buffer.
|
||||
@param size Size of the data buffer in bytes.
|
||||
@throw Error ("Size too large") if no memory allocation is allowed and
|
||||
the size of the data in buf is greater than the existing size
|
||||
of the data of the entry.<BR>
|
||||
@throw Error ("Size too small") if an attempt is made to initialise an
|
||||
%Entry in non-alloc mode with a buffer with size less than four.
|
||||
@param data Pointer to the data buffer.
|
||||
@param size Size of the desired data buffer in bytes.
|
||||
@throw Error ("Value too large") if no memory allocation is allowed
|
||||
and the size of the data buffer is larger than the existing
|
||||
data buffer of the entry.<BR>
|
||||
@throw Error ("Size too small") if size is not large enough to hold
|
||||
count components of the given type.
|
||||
*/
|
||||
void setValue(uint16 type, uint32 count, const char* data, long size);
|
||||
//@}
|
||||
@@ -145,8 +150,9 @@ namespace Exif {
|
||||
//! Return the number of components in the value
|
||||
uint32 count() const { return count_; }
|
||||
/*!
|
||||
@brief Return the size of the value in bytes, it is at least four
|
||||
bytes unless it is 0.
|
||||
@brief Return the size of the data buffer in bytes.
|
||||
@note There is no minimum size for the data buffer, except that it
|
||||
must be large enough to hold the data.
|
||||
*/
|
||||
long size() const { return size_; }
|
||||
//! Return the offset from the start of the IFD to the data of the entry
|
||||
@@ -167,20 +173,32 @@ namespace Exif {
|
||||
|
||||
private:
|
||||
/*!
|
||||
@brief True: Requires memory allocation and deallocation,<BR>
|
||||
False: No memory management needed.
|
||||
True: Requires memory allocation and deallocation,<BR>
|
||||
False: No memory management needed.
|
||||
*/
|
||||
bool alloc_;
|
||||
IfdId ifdId_; // Redundant IFD id (it is also at the IFD)
|
||||
int idx_; // Unique id of an entry within an IFD (0 if not set)
|
||||
MakerNote* makerNote_; // Pointer to the associated MakerNote
|
||||
uint16 tag_; // Tag
|
||||
uint16 type_; // Type
|
||||
uint32 count_; // Number of components
|
||||
uint32 offset_; // Offset from the start of the IFD to the data
|
||||
long size_; // Size of the data in bytes, at least four bytes
|
||||
char* data_; // Pointer to the data buffer, which is always at
|
||||
// least four bytes big (or 0, if not allocated)
|
||||
//! Redundant IFD id (it is also at the IFD)
|
||||
IfdId ifdId_;
|
||||
//! Unique id of an entry within an IFD (0 if not set)
|
||||
int idx_;
|
||||
//! Pointer to the associated MakerNote
|
||||
MakerNote* makerNote_;
|
||||
//! Tag
|
||||
uint16 tag_;
|
||||
//! Type
|
||||
uint16 type_;
|
||||
//! Number of components
|
||||
uint32 count_;
|
||||
//! Offset from the start of the IFD to the data
|
||||
uint32 offset_;
|
||||
/*!
|
||||
Size of the data buffer holding the value in bytes, there is
|
||||
no minimum size.
|
||||
*/
|
||||
long size_;
|
||||
//! Pointer to the data buffer
|
||||
char* data_;
|
||||
|
||||
}; // class Entry
|
||||
|
||||
//! Container type to hold all IFD directory entries
|
||||
|
||||
Reference in New Issue
Block a user