1
// ***************************************************************** -*- C++ -*-
3
* Copyright (C) 2004, 2005 Andreas Huggel <ahuggel@gmx.net>
5
* This program is part of the Exiv2 distribution.
7
* This program is free software; you can redistribute it and/or
8
* modify it under the terms of the GNU General Public License
9
* as published by the Free Software Foundation; either version 2
10
* of the License, or (at your option) any later version.
12
* This program is distributed in the hope that it will be useful,
13
* but WITHOUT ANY WARRANTY; without even the implied warranty of
14
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
* GNU General Public License for more details.
17
* You should have received a copy of the GNU General Public License
18
* along with this program; if not, write to the Free Software
19
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
23
@brief Encoding and decoding of IFD (%Image File Directory) data
25
@author Andreas Huggel (ahu)
26
<a href="mailto:ahuggel@gmx.net">ahuggel@gmx.net</a>
27
@date 09-Jan-04, ahu: created<BR>
28
11-Feb-04, ahu: isolated as a component
33
// *****************************************************************************
34
// included header files
37
// + standard includes
42
// *****************************************************************************
43
// namespace extensions
46
// *****************************************************************************
50
// *****************************************************************************
54
@brief Data structure for one IFD directory entry. See the description of
55
class Ifd for an explanation of the supported modes for memory
63
@brief Default constructor. The entry allocates memory for its
64
data if alloc is true (the default), otherwise it remembers
65
just the pointers into a read and writeable data buffer which
66
it doesn't allocate or delete.
68
explicit Entry(bool alloc =true);
72
Entry(const Entry& rhs);
75
//! @name Manipulators
77
//! Assignment operator
78
Entry& operator=(const Entry& rhs);
80
void setTag(uint16_t tag) { tag_ = tag; }
82
void setIfdId(IfdId ifdId) { ifdId_ = ifdId; }
83
//! Set the index (unique id of an entry within one IFD)
84
void setIdx(int idx) { idx_ = idx; }
85
//! Set the offset. The offset is relative to the start of the IFD.
86
void setOffset(long offset) { offset_ = offset; }
88
@brief Set the value of the entry to a single unsigned long component,
89
i.e., set the type of the entry to unsigned long, number of
90
components to one and the value according to the data provided.
92
The size of the data buffer is set to at least four bytes, but is left
93
unchanged if it can accomodate the pointer. This method can be used
94
to set the value of a tag which contains a pointer (offset) to a
95
location in the Exif data (like e.g., ExifTag, 0x8769 in IFD0, which
96
contains a pointer to the Exif IFD).
97
<BR>This method cannot be used to set the value of a newly created
98
%Entry in non-alloc mode.
100
@note This method is now deprecated, use data area related methods
103
void setValue(uint32_t data, ByteOrder byteOrder);
105
@brief Set type, count, the data buffer and its size.
107
Copies the provided buffer when called in memory allocation mode.
108
<BR>In non-alloc mode, use this method to initialise the data of a
109
newly created %Entry. In this case, only the pointer to the buffer is
110
copied, i.e., the buffer must remain valid throughout the life of the
111
%Entry. Subsequent calls in non-alloc mode will overwrite the data
112
pointed to by this pointer with the data provided, i.e., the buffer
113
provided in subsequent calls can be deleted after the call.
114
<BR>In either memory allocation mode, the data buffer provided must be
115
large enough to hold count components of type. The size of the buffer
116
will be as indicated in the size argument. I.e., it is possible to
117
allocate (set) a data buffer larger than required to hold count
118
components of the given type.
120
@param type The type of the data.
121
@param count Number of components in the buffer.
122
@param data Pointer to the data buffer.
123
@param size Size of the desired data buffer in bytes.
124
@throw Error if no memory allocation is allowed
125
and the size of the data buffer is larger than the existing
126
data buffer of the entry or if size is not large enough to hold
127
count components of the given type.
129
void setValue(uint16_t type, uint32_t count, const byte* data, long size);
131
@brief Set the data area. Memory management as for
132
setValue(uint16_t, uint32_t, const byte*, long)
134
For certain tags the regular value of an IFD entry is an offset to a
135
data area outside of the IFD. Examples are Exif tag 0x8769 in IFD0
136
(Exif.Image.ExifTag) or tag 0x0201 in IFD1
137
(Exif.Thumbnail.JPEGInterchangeFormat). The offset of ExifTag points
138
to a data area containing the Exif IFD. That of JPEGInterchangeFormat
139
contains the JPEG thumbnail image.
140
This method sets the data area of a tag in accordance with the memory
143
@param buf Pointer to the data area.
144
@param len Size of the data area.
146
@throw Error in non-alloc mode, if there already is a dataarea but the
147
size of the existing dataarea is not large enough for the
150
void setDataArea(const byte* buf, long len);
152
@brief Set the offset(s) to the data area of an entry.
154
Add @em offset to each data component of the entry. This is used by
155
Ifd::copy to convert the data components of an entry containing
156
offsets relative to the data area to become offsets from the start of
157
the TIFF header. Usually, entries with a data area have exactly one
158
unsigned long data component, which is 0.
161
@param byteOrder Byte order
163
@throw Error if the offset is out of range for the data type of the
164
tag or the data type is not supported.
166
void setDataAreaOffsets(uint32_t offset, ByteOrder byteOrder);
168
@brief Update the base pointer of the Entry from \em pOldBase
171
Allows to re-locate the underlying data buffer to a new location
172
\em pNewBase. This method only has an effect in non-alloc mode.
174
@param pOldBase Base pointer of the old data buffer
175
@param pNewBase Base pointer of the new data buffer
177
void updateBase(byte* pOldBase, byte* pNewBase);
183
uint16_t tag() const { return tag_; }
184
//! Return the type id.
185
uint16_t type() const { return type_; }
186
//! Return the name of the type
187
const char* typeName() const
188
{ return TypeInfo::typeName(TypeId(type_)); }
189
//! Return the size in bytes of one element of this type
190
long typeSize() const
191
{ return TypeInfo::typeSize(TypeId(type_)); }
192
//! Return the IFD id
193
IfdId ifdId() const { return ifdId_; }
194
//! Return the index (unique id >0 of an entry within an IFD, 0 if not set)
195
int idx() const { return idx_; }
196
//! Return the number of components in the value
197
uint32_t count() const { return count_; }
199
@brief Return the size of the data buffer in bytes.
200
@note There is no minimum size for the data buffer, except that it
201
must be large enough to hold the data.
203
long size() const { return size_; }
204
//! Return the offset from the start of the IFD to the data of the entry
205
long offset() const { return offset_; }
207
@brief Return a pointer to the data buffer. Do not attempt to write
210
const byte* data() const { return pData_; }
212
@brief Return a pointer to the n-th component, 0 if there is no
213
n-th component. Do not attempt to write to this pointer.
215
const byte* component(uint32_t n) const;
216
//! Get the memory allocation mode
217
bool alloc() const { return alloc_; }
218
//! Return the size of the data area.
219
long sizeDataArea() const { return sizeDataArea_; }
221
@brief Return a pointer to the data area. Do not attempt to write to
224
For certain tags the regular value of an IFD entry is an offset to a
225
data area outside of the IFD. Examples are Exif tag 0x8769 in IFD0
226
(Exif.Image.ExifTag) or tag 0x0201 in IFD1
227
(Exif.Thumbnail.JPEGInterchangeFormat). The offset of ExifTag points
228
to a data area containing the Exif IFD. That of JPEGInterchangeFormat
229
contains the JPEG thumbnail image.
230
Use this method to access (read-only) the data area of a tag. Use
231
setDataArea() to write to the data area.
233
@return Return a pointer to the data area.
235
const byte* dataArea() const { return pDataArea_; }
241
True: Requires memory allocation and deallocation,<BR>
242
False: No memory management needed.
245
//! Redundant IFD id (it is also at the IFD)
247
//! Unique id of an entry within an IFD (0 if not set)
253
//! Number of components
255
//! Offset from the start of the IFD to the data
258
Size of the data buffer holding the value in bytes, there is
262
//! Pointer to the data buffer
264
//! Size of the data area
266
//! Pointer to the data area
271
//! Container type to hold all IFD directory entries
272
typedef std::vector<Entry> Entries;
274
//! Unary predicate that matches an Entry with a given index
275
class FindEntryByIdx {
277
//! Constructor, initializes the object with the index to look for
278
FindEntryByIdx(int idx) : idx_(idx) {}
280
@brief Returns true if the idx of the argument entry is equal
281
to that of the object.
283
bool operator()(const Entry& entry) const
284
{ return idx_ == entry.idx(); }
289
}; // class FindEntryByIdx
291
//! Unary predicate that matches an Entry with a given tag
292
class FindEntryByTag {
294
//! Constructor, initializes the object with the tag to look for
295
FindEntryByTag(uint16_t tag) : tag_(tag) {}
297
@brief Returns true if the tag of the argument entry is equal
298
to that of the object.
300
bool operator()(const Entry& entry) const
301
{ return tag_ == entry.tag(); }
306
}; // class FindEntryByTag
309
@brief Models an IFD (%Image File Directory)
311
This class models an IFD as described in the TIFF 6.0 specification.
313
An instance of class %Ifd can operate in two modes, one that allocates and
314
deallocates the memory required to store data, and one that doesn't
315
perform such memory management.
316
<BR>An external data buffer (not managed by %Ifd) is needed for an instance
317
of %Ifd which operates in no memory management mode. The %Ifd will
318
maintain only pointers into this buffer.
319
<BR> The mode without memory management is used to make "non-intrusive
320
write support" possible. This allows writing to Exif data of an image
321
without changing the data layout of the Exif data, to maximize chances
322
that tag data, which the Exif reader may not understand (e.g., the
323
Makernote) remains valid. A "non-intrusive write operation" is the
324
modification of tag data without increasing the data size.
326
@note Use the mode with memory management (the default) if you are unsure
327
or if these memory management considerations are of no concern to you.
329
@note The two different modes imply completely different copy and
330
assignment behaviours, with the first resulting in entirely separate
331
classes and the second mode resulting in multiple classes using one
332
and the same data buffer.
335
//! @name Not implemented
337
//! Assignment not allowed (memory management mode alloc_ is const)
338
Ifd& operator=(const Ifd& rhs);
342
//! %Entries const iterator type
343
typedef Entries::const_iterator const_iterator;
344
//! %Entries iterator type
345
typedef Entries::iterator iterator;
350
@brief Constructor. Allows to set the IFD identifier. Memory management
351
is enabled, offset is set to 0. Serves as default constructor.
353
explicit Ifd(IfdId ifdId =ifdIdNotSet);
355
@brief Constructor. Allows to set the IFD identifier and the offset of
356
the IFD from the start of TIFF header. Memory management is
359
Ifd(IfdId ifdId, long offset);
361
@brief Constructor. Allows to set the IFD identifier, offset of the
362
IFD from the start of TIFF header, choose whether or not
363
memory management is required for the Entries, and decide
364
whether this IFD has a next pointer.
366
Ifd(IfdId ifdId, long offset, bool alloc, bool hasNext =true);
373
//! @name Manipulators
376
@brief Read a complete IFD and its data from a data buffer
378
@param buf Pointer to the data to decode. The buffer must start with the
379
IFD data (unlike the readSubIfd() method).
380
@param len Number of bytes in the data buffer
381
@param byteOrder Applicable byte order (little or big endian).
382
@param offset (Optional) offset of the IFD from the start of the TIFF
383
header, if known. If not given, the offset will be guessed
384
using the assumption that the smallest offset of all IFD
385
directory entries points to a data buffer immediately follwing
388
@return 0 if successful;<BR>
389
6 if the data buffer is too small, e.g., if an offset points
390
beyond the provided buffer. The IFD is cleared in this
393
int read(const byte* buf, long len, ByteOrder byteOrder, long offset =0);
395
@brief Copy the IFD to a data array, update the offsets of the IFD and
396
all its entries, return the number of bytes written.
398
First the number of IFD entries is written (2 bytes), followed
399
by all directory entries: tag (2), type (2), number of data
400
components (4) and offset to the data or the data, if it
401
occupies not more than four bytes (4). The directory entries
402
are followed by the offset of the next IFD (4). All these
403
fields are encoded according to the byte order argument. Data
404
that doesn't fit into the offset fields follows immediately
405
after the IFD entries. The offsets in the IFD are set to
406
correctly point to the data fields, using the offset parameter
407
or the offset of the IFD.
409
@param buf Pointer to the data buffer. The user must ensure that the
410
buffer has enough memory. Otherwise the call results in
412
@param byteOrder Applicable byte order (little or big endian).
413
@param offset Target offset from the start of the TIFF header of the
414
data array. The IFD offsets will be adjusted as necessary. If
415
not given, then it is assumed that the IFD will remain at its
416
original position, i.e., the offset of the IFD will be used.
417
@return Returns the number of characters written.
419
long copy(byte* buf, ByteOrder byteOrder, long offset =0);
421
@brief Reset the IFD. Delete all IFD entries from the class and put
422
the object in a state where it can accept completely new
427
@brief Set the offset of the next IFD. Byte order is needed to update
428
the underlying data buffer in non-alloc mode. This method only
429
has an effect if the IFD was instantiated with hasNext = true.
431
void setNext(uint32_t next, ByteOrder byteOrder);
433
@brief Add the entry to the IFD. No duplicate-check is performed,
434
i.e., it is possible to add multiple entries with the same tag.
435
The memory allocation mode of the entry to be added must match
436
that of the IFD and the IFD ids of the IFD and entry must
439
void add(const Entry& entry);
441
@brief Delete the directory entry with the given tag. Return the index
442
of the deleted entry or 0 if no entry with tag was found.
444
int erase(uint16_t tag);
446
@brief Delete the directory entry at iterator position pos, return the
447
position of the next entry. Note that iterators into the
448
directory, including pos, are potentially invalidated by this
451
iterator erase(iterator pos);
452
//! Sort the IFD entries by tag
455
iterator begin() { return entries_.begin(); }
456
//! End of the entries
457
iterator end() { return entries_.end(); }
458
//! Find an IFD entry by idx, return an iterator into the entries list
459
iterator findIdx(int idx);
460
//! Find an IFD entry by tag, return an iterator into the entries list
461
iterator findTag(uint16_t tag);
463
@brief Update the base pointer of the Ifd and all entries to \em pNewBase.
465
Allows to re-locate the underlying data buffer to a new location
466
\em pNewBase. This method only has an effect in non-alloc mode.
468
@param pNewBase Pointer to the new data buffer
470
@return Old base pointer or 0 if called in alloc mode
472
byte* updateBase(byte* pNewBase);
478
@brief Read a sub-IFD from the location pointed to by the directory entry
481
@param dest References the destination IFD.
482
@param buf The data buffer to read from. The buffer must contain all Exif
483
data starting from the TIFF header (unlike the read() method).
484
@param len Number of bytes in the data buffer
485
@param byteOrder Applicable byte order (little or big endian).
486
@param tag Tag to look for.
488
@return 0 if successful;<BR>
489
6 if reading the sub-IFD failed (see read() above) or
490
the location pointed to by the directory entry with the
491
given tag is outside of the data buffer.
493
@note It is not considered an error if the tag cannot be found in the
494
IFD. 0 is returned and no action is taken in this case.
497
Ifd& dest, const byte* buf, long len, ByteOrder byteOrder, uint16_t tag
499
//! Get the memory allocation mode, see the Ifd class description for details
500
bool alloc() const { return alloc_; }
502
const_iterator begin() const { return entries_.begin(); }
503
//! End of the entries
504
const_iterator end() const { return entries_.end(); }
505
//! Find an IFD entry by idx, return a const iterator into the entries list
506
const_iterator findIdx(int idx) const;
507
//! Find an IFD entry by tag, return a const iterator into the entries list
508
const_iterator findTag(uint16_t tag) const;
509
//! Get the IfdId of the IFD
510
IfdId ifdId() const { return ifdId_; }
511
//! Get the offset of the IFD from the start of the TIFF header
512
long offset() const { return offset_; }
514
@brief Get the offset of the first data entry outside of the IFD from
515
the start of the TIFF header, return 0 if there is none. The
516
data offset is determined when the IFD is read.
518
long dataOffset() const { return dataOffset_; }
519
//! Get the offset to the next IFD from the start of the TIFF header
520
uint32_t next() const { return next_; }
521
//! Get the number of directory entries in the IFD
522
long count() const { return static_cast<long>(entries_.size()); }
523
//! Get the size of this IFD in bytes (IFD only, without data)
526
@brief Return the total size of the data of this IFD in bytes; sums
527
the size of all directory entries where size is greater than
528
four plus the size of all data areas, i.e., all data that
529
requires memory outside the IFD directory entries is counted.
531
long dataSize() const;
533
@brief Print the IFD in human readable format to the given stream;
534
begin each line with prefix.
536
void print(std::ostream& os, const std::string& prefix ="") const;
540
//! Helper structure to build IFD entries
550
//! cmpPreEntriesByOffset needs to know about PreEntry, that's all.
551
friend bool cmpPreEntriesByOffset(const PreEntry&, const PreEntry&);
553
//! Container for 'pre-entries'
554
typedef std::vector<PreEntry> PreEntries;
558
True: requires memory allocation and deallocation,
559
False: no memory management needed.
566
//! Pointer to IFD from the start of the TIFF header
568
//! Offset of the IFD from the start of the TIFF header
570
//! Offset of the first data entry outside of the IFD directory
572
//! Indicates whether the IFD has a next pointer
574
//! Pointer to the offset of next IFD from the start of the TIFF header
576
//! The offset of the next IFD as data value (always in sync with *pNext_)
581
// *****************************************************************************
585
@brief Compare two IFD entries by tag. Return true if the tag of entry
586
lhs is less than that of rhs.
588
bool cmpEntriesByTag(const Entry& lhs, const Entry& rhs);
591
@brief Compare two 'pre-IFD entries' by offset, taking care of special
592
cases where one or both of the entries don't have an offset.
593
Return true if the offset of entry lhs is less than that of rhs,
594
else false. By definition, entries without an offset are greater
595
than those with an offset.
597
bool cmpPreEntriesByOffset(const Ifd::PreEntry& lhs, const Ifd::PreEntry& rhs);
601
#endif // #ifndef IFD_HPP_