More consistent / better defined handling of Entry::size_

This commit is contained in:
Andreas Huggel
2004-03-19 09:13:33 +00:00
parent 1d655bb915
commit f297a651f9
2 changed files with 96 additions and 75 deletions
+38 -35
View File
@@ -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
View File
@@ -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