aboutsummaryrefslogtreecommitdiff
path: root/src/tiff_directory
diff options
context:
space:
mode:
Diffstat (limited to 'src/tiff_directory')
-rwxr-xr-xsrc/tiff_directory/tiff_directory.cc282
-rwxr-xr-xsrc/tiff_directory/tiff_directory.h161
2 files changed, 443 insertions, 0 deletions
diff --git a/src/tiff_directory/tiff_directory.cc b/src/tiff_directory/tiff_directory.cc
new file mode 100755
index 0000000..8db15a2
--- /dev/null
+++ b/src/tiff_directory/tiff_directory.cc
@@ -0,0 +1,282 @@
+// Copyright 2015 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+#include "src/tiff_directory/tiff_directory.h"
+
+#include <assert.h>
+#include <climits>
+
+#include "src/binary_parse/range_checked_byte_ptr.h"
+
+namespace piex {
+namespace tiff_directory {
+namespace {
+
+using binary_parse::Get16s;
+using binary_parse::Get16u;
+using binary_parse::Get32s;
+using binary_parse::Get32u;
+using binary_parse::MemoryStatus;
+using binary_parse::RANGE_CHECKED_BYTE_SUCCESS;
+using binary_parse::RangeCheckedBytePtr;
+
+} // namespace
+
+TiffDirectory::TiffDirectory(Endian endian) : endian_(endian) {}
+
+bool TiffDirectory::Has(const Tag tag) const {
+ return directory_entries_.count(tag) == 1;
+}
+
+bool TiffDirectory::Get(const Tag tag, std::vector<std::uint8_t>* value) const {
+ const DirectoryEntry* directory_entry = Find(tag);
+ if (directory_entry == NULL ||
+ (directory_entry->type != TIFF_TYPE_BYTE &&
+ directory_entry->type != TIFF_TYPE_UNDEFINED)) {
+ return false;
+ }
+
+ *value = directory_entry->value;
+ return true;
+}
+
+bool TiffDirectory::Get(const Tag tag, std::string* value) const {
+ const DirectoryEntry* directory_entry = Find(tag);
+ if (directory_entry == NULL || directory_entry->type != TIFF_TYPE_ASCII) {
+ return false;
+ }
+ *value =
+ std::string(directory_entry->value.begin(), directory_entry->value.end());
+ return true;
+}
+
+bool TiffDirectory::Get(const Tag tag, std::uint32_t* value) const {
+ std::vector<std::uint32_t> my_values;
+ if (!Get(tag, &my_values) || my_values.size() != 1) {
+ return false;
+ }
+ *value = my_values[0];
+ return true;
+}
+
+bool TiffDirectory::Get(const Tag tag,
+ std::vector<std::uint32_t>* value) const {
+ const DirectoryEntry* directory_entry = Find(tag);
+ if (directory_entry == NULL || (directory_entry->type != TIFF_TYPE_SHORT &&
+ directory_entry->type != TIFF_TYPE_LONG)) {
+ return false;
+ }
+
+ RangeCheckedBytePtr value_ptr(&directory_entry->value[0],
+ directory_entry->value.size());
+ std::vector<std::uint32_t> my_value(directory_entry->count);
+ const bool is_big_endian = (endian_ == kBigEndian);
+
+ MemoryStatus err = RANGE_CHECKED_BYTE_SUCCESS;
+ for (std::uint32_t c = 0; c < directory_entry->count; ++c) {
+ if (directory_entry->type == TIFF_TYPE_SHORT) {
+ my_value[c] = Get16u(value_ptr + c * 2, is_big_endian, &err);
+ } else {
+ my_value[c] = Get32u(value_ptr + c * 4, is_big_endian, &err);
+ }
+ }
+ if (err != RANGE_CHECKED_BYTE_SUCCESS) {
+ return false;
+ }
+
+ *value = my_value;
+ return true;
+}
+
+bool TiffDirectory::Get(const Tag tag, Rational* value) const {
+ std::vector<Rational> my_values;
+ if (!Get(tag, &my_values) || my_values.size() != 1) {
+ return false;
+ }
+ *value = my_values[0];
+ return true;
+}
+
+bool TiffDirectory::Get(const Tag tag, std::vector<Rational>* value) const {
+ const DirectoryEntry* directory_entry = Find(tag);
+ if (directory_entry == NULL ||
+ (directory_entry->type != TIFF_TYPE_SHORT &&
+ directory_entry->type != TIFF_TYPE_LONG &&
+ directory_entry->type != TIFF_TYPE_RATIONAL)) {
+ return false;
+ }
+
+ RangeCheckedBytePtr value_ptr(&directory_entry->value[0],
+ directory_entry->value.size());
+ std::vector<Rational> my_value(directory_entry->count);
+ const bool is_big_endian = (endian_ == kBigEndian);
+
+ MemoryStatus err = RANGE_CHECKED_BYTE_SUCCESS;
+ for (std::uint32_t c = 0; c < directory_entry->count; ++c) {
+ switch (directory_entry->type) {
+ case TIFF_TYPE_SHORT: {
+ my_value[c].numerator = Get16u(value_ptr + c * 2, is_big_endian, &err);
+ my_value[c].denominator = 1;
+ break;
+ }
+ case TIFF_TYPE_LONG: {
+ my_value[c].numerator = Get32u(value_ptr + c * 4, is_big_endian, &err);
+ my_value[c].denominator = 1;
+ break;
+ }
+ case TIFF_TYPE_RATIONAL: {
+ my_value[c].numerator = Get32u(value_ptr + c * 8, is_big_endian, &err);
+ my_value[c].denominator =
+ Get32u(value_ptr + c * 8 + 4, is_big_endian, &err);
+ if (my_value[c].denominator == 0) {
+ return false;
+ }
+ break;
+ }
+ }
+ }
+ if (err != RANGE_CHECKED_BYTE_SUCCESS) {
+ return false;
+ }
+
+ *value = my_value;
+ return true;
+}
+
+bool TiffDirectory::Get(const Tag tag, SRational* value) const {
+ std::vector<SRational> my_values;
+ if (!Get(tag, &my_values) || my_values.size() != 1) {
+ return false;
+ }
+ *value = my_values[0];
+ return true;
+}
+
+bool TiffDirectory::Get(const Tag tag, std::vector<SRational>* value) const {
+ const DirectoryEntry* directory_entry = Find(tag);
+ if (directory_entry == NULL ||
+ (directory_entry->type != TIFF_TYPE_SSHORT &&
+ directory_entry->type != TIFF_TYPE_SLONG &&
+ directory_entry->type != TIFF_TYPE_SRATIONAL)) {
+ return false;
+ }
+
+ RangeCheckedBytePtr value_ptr(&directory_entry->value[0],
+ directory_entry->value.size());
+ std::vector<SRational> my_value(directory_entry->count);
+ const bool is_big_endian = (endian_ == kBigEndian);
+
+ MemoryStatus err = RANGE_CHECKED_BYTE_SUCCESS;
+ for (std::uint32_t c = 0; c < directory_entry->count; ++c) {
+ switch (directory_entry->type) {
+ case TIFF_TYPE_SSHORT: {
+ my_value[c].numerator = Get16s(value_ptr + c * 2, is_big_endian, &err);
+ my_value[c].denominator = 1;
+ break;
+ }
+ case TIFF_TYPE_SLONG: {
+ my_value[c].numerator = Get32s(value_ptr + c * 4, is_big_endian, &err);
+ my_value[c].denominator = 1;
+ break;
+ }
+ case TIFF_TYPE_SRATIONAL: {
+ my_value[c].numerator = Get32s(value_ptr + c * 8, is_big_endian, &err);
+ my_value[c].denominator =
+ Get32s(value_ptr + c * 8 + 4, is_big_endian, &err);
+ if (my_value[c].denominator == 0) {
+ return false;
+ }
+ break;
+ }
+ }
+ }
+ if (err != RANGE_CHECKED_BYTE_SUCCESS) {
+ return false;
+ }
+
+ *value = my_value;
+ return true;
+}
+
+bool TiffDirectory::GetOffsetAndLength(const Tag tag, const Type type,
+ std::uint32_t* offset,
+ std::uint32_t* length) const {
+ const DirectoryEntry* directory_entry = Find(tag);
+ if (directory_entry == NULL || directory_entry->type != type) {
+ return false;
+ }
+ *offset = directory_entry->offset;
+ *length = static_cast<std::uint32_t>(directory_entry->value.size());
+ return true;
+}
+
+void TiffDirectory::AddEntry(const Tag tag, const Type type,
+ const std::uint32_t count,
+ const std::uint32_t offset,
+ const std::vector<std::uint8_t>& value) {
+ assert(SizeOfType(type, NULL /* success */) * count == value.size());
+
+ const DirectoryEntry directory_entry = {type, count, offset, value};
+ directory_entries_[tag] = directory_entry;
+ tag_order_.push_back(tag);
+}
+
+void TiffDirectory::AddSubDirectory(const TiffDirectory& sub_directory) {
+ sub_directories_.push_back(sub_directory);
+}
+
+const std::vector<TiffDirectory>& TiffDirectory::GetSubDirectories() const {
+ return sub_directories_;
+}
+
+const TiffDirectory::DirectoryEntry* TiffDirectory::Find(const Tag tag) const {
+ std::map<Tag, DirectoryEntry>::const_iterator iter =
+ directory_entries_.find(tag);
+ if (iter == directory_entries_.end()) {
+ return NULL;
+ }
+ return &iter->second;
+}
+
+size_t SizeOfType(const TiffDirectory::Type type, bool* success) {
+ switch (type) {
+ case TIFF_TYPE_BYTE:
+ case TIFF_TYPE_ASCII:
+ case TIFF_TYPE_SBYTE:
+ case TIFF_TYPE_UNDEFINED:
+ return 1;
+ case TIFF_TYPE_SHORT:
+ case TIFF_TYPE_SSHORT:
+ return 2;
+ case TIFF_TYPE_LONG:
+ case TIFF_TYPE_SLONG:
+ case TIFF_TYPE_FLOAT:
+ case TIFF_IFD:
+ return 4;
+ case TIFF_TYPE_RATIONAL:
+ case TIFF_TYPE_SRATIONAL:
+ case TIFF_TYPE_DOUBLE:
+ return 8;
+ }
+
+ if (success != NULL) {
+ *success = false;
+ }
+ return 0;
+}
+
+} // namespace tiff_directory
+} // namespace piex
diff --git a/src/tiff_directory/tiff_directory.h b/src/tiff_directory/tiff_directory.h
new file mode 100755
index 0000000..855adfc
--- /dev/null
+++ b/src/tiff_directory/tiff_directory.h
@@ -0,0 +1,161 @@
+// Copyright 2015 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+//
+// TiffDirectory contains an abstraction of an image file directory (IFD) as
+// proposed by the TIFF specification.
+
+#ifndef PIEX_TIFF_DIRECTORY_TIFF_DIRECTORY_H_
+#define PIEX_TIFF_DIRECTORY_TIFF_DIRECTORY_H_
+
+#include <cstdint>
+#include <map>
+#include <string>
+#include <vector>
+
+namespace piex {
+namespace tiff_directory {
+
+enum Endian {
+ kLittleEndian = 0,
+ kBigEndian = 1,
+};
+
+struct Rational {
+ std::uint32_t numerator;
+ std::uint32_t denominator;
+};
+
+struct SRational {
+ std::int32_t numerator;
+ std::int32_t denominator;
+};
+
+enum TiffTypes {
+ TIFF_TYPE_NONE = 0,
+ TIFF_TYPE_BYTE, /* 8bit unsigned */
+ TIFF_TYPE_ASCII, /* Ascii string (terminated by \0) */
+ TIFF_TYPE_SHORT, /* 16bit unsigned */
+ TIFF_TYPE_LONG, /* 32bit unsigned */
+ TIFF_TYPE_RATIONAL, /* 32bit/32bit unsigned */
+ TIFF_TYPE_SBYTE, /* 8bit signed */
+ TIFF_TYPE_UNDEFINED, /* undefined (depend of tag) */
+ TIFF_TYPE_SSHORT, /* 16bit signed*/
+ TIFF_TYPE_SLONG, /* 32bit signed */
+ TIFF_TYPE_SRATIONAL, /* 32bit/32bit signed */
+ TIFF_TYPE_FLOAT, /* 32-bit IEEE float */
+ TIFF_TYPE_DOUBLE, /* 64-bit IEEE float */
+ TIFF_IFD, /* IFD type */
+};
+
+// The TiffDirectory class stores all information necessary to interpret TIFF
+// tags and manages also potential sub directories.
+class TiffDirectory {
+ public:
+ typedef std::uint32_t Tag;
+ typedef std::uint32_t Type;
+
+ explicit TiffDirectory(Endian endianness);
+
+ // Returns true if the directory contains the specified tag.
+ bool Has(const Tag tag) const;
+
+ // Gets the value of a tag of byte vector type.
+ // Returns false if the tag is not part of the directory or if the
+ // type is not BYTE or UNDEFINED.
+ bool Get(const Tag tag, std::vector<std::uint8_t>* value) const;
+
+ // Gets the value of a tag of type "ASCII".
+ // Returns false if the tag is not part of the directory or if its
+ // type is not ASCII.
+ // If *err is not equal to ERR_OK initially, this method does nothing.
+ bool Get(const Tag tag, std::string* value) const;
+
+ // Gets the value of a tag of type "SHORT" or "LONG".
+ // Returns false
+ // - if the tag is not part of the directory or
+ // - if the type is not SHORT or LONG, or
+ // - if, for the non-vector version, the number of elements is unequal to 1.
+ bool Get(const Tag tag, std::uint32_t* value) const;
+ bool Get(const Tag tag, std::vector<std::uint32_t>* value) const;
+
+ // Gets the value of a tag of type "SHORT", "LONG" or "RATIONAL".
+ // Returns false
+ // - if the tag is not part of the directory or
+ // - if the type is not SHORT, LONG or RATIONAL, or
+ // - if, for the non-vector version, the number of elements is unequal to 1.
+ bool Get(const Tag tag, Rational* value) const;
+ bool Get(const Tag tag, std::vector<Rational>* value) const;
+
+ // Gets the value of a tag of type "SSHORT", "SLONG" or "SRATIONAL".
+ // Returns false
+ // - if the tag is not part of the directory or
+ // - if the type is not SSHORT, SLONG or SRATIONAL, or
+ // - if, for the non-vector version, the number of elements is unequal to 1.
+ bool Get(const Tag tag, SRational* value) const;
+ bool Get(const Tag tag, std::vector<SRational>* value) const;
+
+ // Gets the 'offset' to the value data in the file and its 'length' in bytes.
+ // Returns false if the 'tag' is not part of the directory or if its type does
+ // not match the desired 'type'.
+ bool GetOffsetAndLength(const Tag tag, const Type type, std::uint32_t* offset,
+ std::uint32_t* length) const;
+
+ // Adds a tag to the directory, setting its type, number of elements
+ // ('count'), the offset to the binary data in the file ('offset') and the
+ // associated binary data ('value'). The binary data is encoded according to
+ // the TIFF specification with the endianness that was specified when this
+ // object was constructed. The caller must ensure that the size of 'value' and
+ // the data it contains are consistent with 'type' and 'count'. It is not
+ // legal to call this method with a tag that is already contained in the
+ // directory.
+ void AddEntry(const Tag tag, const Type type, const std::uint32_t count,
+ const std::uint32_t offset,
+ const std::vector<std::uint8_t>& value);
+
+ // Add a subdirectory to the directory.
+ void AddSubDirectory(const TiffDirectory& sub_directory);
+
+ // Returns a vector of all subdirectories contained in this directory.
+ const std::vector<TiffDirectory>& GetSubDirectories() const;
+
+ private:
+ struct DirectoryEntry {
+ Type type;
+ std::uint32_t count; // The number of values of type, not a byte count.
+ std::uint32_t offset; // Offset of the entry's data in the file. '0' means
+ // the offset is not set.
+ std::vector<std::uint8_t> value;
+ };
+
+ const DirectoryEntry* Find(const Tag tag) const;
+
+ std::map<Tag, DirectoryEntry> directory_entries_;
+ std::vector<Tag> tag_order_;
+ std::vector<TiffDirectory> sub_directories_;
+ Endian endian_;
+};
+
+// Returns the number of bytes a single value of 'type' requires; this is
+// guaranteed to be in the range of 0 to 8.
+// Returns 0 if 'type' is TIFF_TYPE_NONE or invalid. Sets 'success' to false if
+// 'type' is invalid. If you are not interested in 'success' you can set it to
+// a nullptr.
+size_t SizeOfType(const TiffDirectory::Type type, bool* success);
+
+} // namespace tiff_directory
+} // namespace piex
+
+#endif // PIEX_TIFF_DIRECTORY_TIFF_DIRECTORY_H_