// 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 #include #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* 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 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* 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 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 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* 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 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 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* 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 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(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& 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::GetSubDirectories() const { return sub_directories_; } const TiffDirectory::DirectoryEntry* TiffDirectory::Find(const Tag tag) const { std::map::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