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
24namespace piex {
25namespace tiff_directory {
26namespace {
27
28using binary_parse::Get16s;
29using binary_parse::Get16u;
30using binary_parse::Get32s;
31using binary_parse::Get32u;
32using binary_parse::MemoryStatus;
33using binary_parse::RANGE_CHECKED_BYTE_SUCCESS;
34using binary_parse::RangeCheckedBytePtr;
35
36} // namespace
37
38TiffDirectory::TiffDirectory(Endian endian) : endian_(endian) {}
39
40bool TiffDirectory::Has(const Tag tag) const {
41 return directory_entries_.count(tag) == 1;
42}
43
44bool 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
56bool 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
66bool 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
75bool 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
104bool 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
113bool 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
159bool 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
168bool 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
214bool 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
226void 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
237void TiffDirectory::AddSubDirectory(const TiffDirectory& sub_directory) {
238 sub_directories_.push_back(sub_directory);
239}
240
241const std::vector<TiffDirectory>& TiffDirectory::GetSubDirectories() const {
242 return sub_directories_;
243}
244
245const 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
254size_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