1 // Copyright 2015 Google Inc. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 // 15 //////////////////////////////////////////////////////////////////////////////// 16 17 #include "src/tiff_directory/tiff_directory.h" 18 19 #include <assert.h> 20 #include <climits> 21 22 #include "src/binary_parse/range_checked_byte_ptr.h" 23 24 namespace piex { 25 namespace tiff_directory { 26 namespace { 27 28 using binary_parse::Get16s; 29 using binary_parse::Get16u; 30 using binary_parse::Get32s; 31 using binary_parse::Get32u; 32 using binary_parse::MemoryStatus; 33 using binary_parse::RANGE_CHECKED_BYTE_SUCCESS; 34 using binary_parse::RangeCheckedBytePtr; 35 36 } // namespace 37 38 TiffDirectory::TiffDirectory(Endian endian) : endian_(endian) {} 39 40 bool TiffDirectory::Has(const Tag tag) const { 41 return directory_entries_.count(tag) == 1; 42 } 43 44 bool TiffDirectory::Get(const Tag tag, std::vector<std::uint8_t>* value) const { 45 const DirectoryEntry* directory_entry = Find(tag); 46 if (directory_entry == NULL || 47 (directory_entry->type != TIFF_TYPE_BYTE && 48 directory_entry->type != TIFF_TYPE_UNDEFINED)) { 49 return false; 50 } 51 52 *value = directory_entry->value; 53 return true; 54 } 55 56 bool TiffDirectory::Get(const Tag tag, std::string* value) const { 57 const DirectoryEntry* directory_entry = Find(tag); 58 if (directory_entry == NULL || directory_entry->type != TIFF_TYPE_ASCII) { 59 return false; 60 } 61 *value = 62 std::string(directory_entry->value.begin(), directory_entry->value.end()); 63 return true; 64 } 65 66 bool TiffDirectory::Get(const Tag tag, std::uint32_t* value) const { 67 std::vector<std::uint32_t> my_values; 68 if (!Get(tag, &my_values) || my_values.size() != 1) { 69 return false; 70 } 71 *value = my_values[0]; 72 return true; 73 } 74 75 bool TiffDirectory::Get(const Tag tag, 76 std::vector<std::uint32_t>* value) const { 77 const DirectoryEntry* directory_entry = Find(tag); 78 if (directory_entry == NULL || (directory_entry->type != TIFF_TYPE_SHORT && 79 directory_entry->type != TIFF_TYPE_LONG)) { 80 return false; 81 } 82 83 RangeCheckedBytePtr value_ptr(&directory_entry->value[0], 84 directory_entry->value.size()); 85 std::vector<std::uint32_t> my_value(directory_entry->count); 86 const bool is_big_endian = (endian_ == kBigEndian); 87 88 MemoryStatus err = RANGE_CHECKED_BYTE_SUCCESS; 89 for (std::uint32_t c = 0; c < directory_entry->count; ++c) { 90 if (directory_entry->type == TIFF_TYPE_SHORT) { 91 my_value[c] = Get16u(value_ptr + c * 2, is_big_endian, &err); 92 } else { 93 my_value[c] = Get32u(value_ptr + c * 4, is_big_endian, &err); 94 } 95 } 96 if (err != RANGE_CHECKED_BYTE_SUCCESS) { 97 return false; 98 } 99 100 *value = my_value; 101 return true; 102 } 103 104 bool TiffDirectory::Get(const Tag tag, Rational* value) const { 105 std::vector<Rational> my_values; 106 if (!Get(tag, &my_values) || my_values.size() != 1) { 107 return false; 108 } 109 *value = my_values[0]; 110 return true; 111 } 112 113 bool TiffDirectory::Get(const Tag tag, std::vector<Rational>* value) const { 114 const DirectoryEntry* directory_entry = Find(tag); 115 if (directory_entry == NULL || 116 (directory_entry->type != TIFF_TYPE_SHORT && 117 directory_entry->type != TIFF_TYPE_LONG && 118 directory_entry->type != TIFF_TYPE_RATIONAL)) { 119 return false; 120 } 121 122 RangeCheckedBytePtr value_ptr(&directory_entry->value[0], 123 directory_entry->value.size()); 124 std::vector<Rational> my_value(directory_entry->count); 125 const bool is_big_endian = (endian_ == kBigEndian); 126 127 MemoryStatus err = RANGE_CHECKED_BYTE_SUCCESS; 128 for (std::uint32_t c = 0; c < directory_entry->count; ++c) { 129 switch (directory_entry->type) { 130 case TIFF_TYPE_SHORT: { 131 my_value[c].numerator = Get16u(value_ptr + c * 2, is_big_endian, &err); 132 my_value[c].denominator = 1; 133 break; 134 } 135 case TIFF_TYPE_LONG: { 136 my_value[c].numerator = Get32u(value_ptr + c * 4, is_big_endian, &err); 137 my_value[c].denominator = 1; 138 break; 139 } 140 case TIFF_TYPE_RATIONAL: { 141 my_value[c].numerator = Get32u(value_ptr + c * 8, is_big_endian, &err); 142 my_value[c].denominator = 143 Get32u(value_ptr + c * 8 + 4, is_big_endian, &err); 144 if (my_value[c].denominator == 0) { 145 return false; 146 } 147 break; 148 } 149 } 150 } 151 if (err != RANGE_CHECKED_BYTE_SUCCESS) { 152 return false; 153 } 154 155 *value = my_value; 156 return true; 157 } 158 159 bool TiffDirectory::Get(const Tag tag, SRational* value) const { 160 std::vector<SRational> my_values; 161 if (!Get(tag, &my_values) || my_values.size() != 1) { 162 return false; 163 } 164 *value = my_values[0]; 165 return true; 166 } 167 168 bool TiffDirectory::Get(const Tag tag, std::vector<SRational>* value) const { 169 const DirectoryEntry* directory_entry = Find(tag); 170 if (directory_entry == NULL || 171 (directory_entry->type != TIFF_TYPE_SSHORT && 172 directory_entry->type != TIFF_TYPE_SLONG && 173 directory_entry->type != TIFF_TYPE_SRATIONAL)) { 174 return false; 175 } 176 177 RangeCheckedBytePtr value_ptr(&directory_entry->value[0], 178 directory_entry->value.size()); 179 std::vector<SRational> my_value(directory_entry->count); 180 const bool is_big_endian = (endian_ == kBigEndian); 181 182 MemoryStatus err = RANGE_CHECKED_BYTE_SUCCESS; 183 for (std::uint32_t c = 0; c < directory_entry->count; ++c) { 184 switch (directory_entry->type) { 185 case TIFF_TYPE_SSHORT: { 186 my_value[c].numerator = Get16s(value_ptr + c * 2, is_big_endian, &err); 187 my_value[c].denominator = 1; 188 break; 189 } 190 case TIFF_TYPE_SLONG: { 191 my_value[c].numerator = Get32s(value_ptr + c * 4, is_big_endian, &err); 192 my_value[c].denominator = 1; 193 break; 194 } 195 case TIFF_TYPE_SRATIONAL: { 196 my_value[c].numerator = Get32s(value_ptr + c * 8, is_big_endian, &err); 197 my_value[c].denominator = 198 Get32s(value_ptr + c * 8 + 4, is_big_endian, &err); 199 if (my_value[c].denominator == 0) { 200 return false; 201 } 202 break; 203 } 204 } 205 } 206 if (err != RANGE_CHECKED_BYTE_SUCCESS) { 207 return false; 208 } 209 210 *value = my_value; 211 return true; 212 } 213 214 bool TiffDirectory::GetOffsetAndLength(const Tag tag, const Type type, 215 std::uint32_t* offset, 216 std::uint32_t* length) const { 217 const DirectoryEntry* directory_entry = Find(tag); 218 if (directory_entry == NULL || directory_entry->type != type) { 219 return false; 220 } 221 *offset = directory_entry->offset; 222 *length = static_cast<std::uint32_t>(directory_entry->value.size()); 223 return true; 224 } 225 226 void TiffDirectory::AddEntry(const Tag tag, const Type type, 227 const std::uint32_t count, 228 const std::uint32_t offset, 229 const std::vector<std::uint8_t>& value) { 230 assert(SizeOfType(type, NULL /* success */) * count == value.size()); 231 232 const DirectoryEntry directory_entry = {type, count, offset, value}; 233 directory_entries_[tag] = directory_entry; 234 tag_order_.push_back(tag); 235 } 236 237 void TiffDirectory::AddSubDirectory(const TiffDirectory& sub_directory) { 238 sub_directories_.push_back(sub_directory); 239 } 240 241 const std::vector<TiffDirectory>& TiffDirectory::GetSubDirectories() const { 242 return sub_directories_; 243 } 244 245 const TiffDirectory::DirectoryEntry* TiffDirectory::Find(const Tag tag) const { 246 std::map<Tag, DirectoryEntry>::const_iterator iter = 247 directory_entries_.find(tag); 248 if (iter == directory_entries_.end()) { 249 return NULL; 250 } 251 return &iter->second; 252 } 253 254 size_t SizeOfType(const TiffDirectory::Type type, bool* success) { 255 switch (type) { 256 case TIFF_TYPE_BYTE: 257 case TIFF_TYPE_ASCII: 258 case TIFF_TYPE_SBYTE: 259 case TIFF_TYPE_UNDEFINED: 260 return 1; 261 case TIFF_TYPE_SHORT: 262 case TIFF_TYPE_SSHORT: 263 return 2; 264 case TIFF_TYPE_LONG: 265 case TIFF_TYPE_SLONG: 266 case TIFF_TYPE_FLOAT: 267 case TIFF_IFD: 268 return 4; 269 case TIFF_TYPE_RATIONAL: 270 case TIFF_TYPE_SRATIONAL: 271 case TIFF_TYPE_DOUBLE: 272 return 8; 273 } 274 275 if (success != NULL) { 276 *success = false; 277 } 278 return 0; 279 } 280 281 } // namespace tiff_directory 282 } // namespace piex 283