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