Home | History | Annotate | Download | only in tiff_directory
      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