• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
TiffDirectory(Endian endian)38 TiffDirectory::TiffDirectory(Endian endian) : endian_(endian) {}
39 
Has(const Tag tag) const40 bool TiffDirectory::Has(const Tag tag) const {
41   return directory_entries_.count(tag) == 1;
42 }
43 
Get(const Tag tag,std::vector<std::uint8_t> * value) const44 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 
Get(const Tag tag,std::string * value) const56 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 
Get(const Tag tag,std::uint32_t * value) const66 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 
Get(const Tag tag,std::vector<std::uint32_t> * value) const75 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 
Get(const Tag tag,Rational * value) const104 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 
Get(const Tag tag,std::vector<Rational> * value) const113 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 
Get(const Tag tag,SRational * value) const159 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 
Get(const Tag tag,std::vector<SRational> * value) const168 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 
GetOffsetAndLength(const Tag tag,const Type type,std::uint32_t * offset,std::uint32_t * length) const214 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 
AddEntry(const Tag tag,const Type type,const std::uint32_t count,const std::uint32_t offset,const std::vector<std::uint8_t> & value)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 
AddSubDirectory(const TiffDirectory & sub_directory)237 void TiffDirectory::AddSubDirectory(const TiffDirectory& sub_directory) {
238   sub_directories_.push_back(sub_directory);
239 }
240 
GetSubDirectories() const241 const std::vector<TiffDirectory>& TiffDirectory::GetSubDirectories() const {
242   return sub_directories_;
243 }
244 
Find(const Tag tag) const245 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 
SizeOfType(const TiffDirectory::Type type,bool * success)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