/src/piex/src/tiff_directory/tiff_directory.cc
Line | Count | Source |
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 | 6.62k | TiffDirectory::TiffDirectory(Endian endian) : endian_(endian) {} |
39 | | |
40 | 100k | bool TiffDirectory::Has(const Tag tag) const { |
41 | 100k | return directory_entries_.count(tag) == 1; |
42 | 100k | } |
43 | | |
44 | 44 | bool TiffDirectory::Get(const Tag tag, std::vector<std::uint8_t>* value) const { |
45 | 44 | const DirectoryEntry* directory_entry = Find(tag); |
46 | 44 | if (directory_entry == NULL || |
47 | 44 | (directory_entry->type != TIFF_TYPE_BYTE && |
48 | 23 | directory_entry->type != TIFF_TYPE_UNDEFINED)) { |
49 | 13 | return false; |
50 | 13 | } |
51 | | |
52 | 31 | *value = directory_entry->value; |
53 | 31 | return true; |
54 | 44 | } |
55 | | |
56 | 3.02k | bool TiffDirectory::Get(const Tag tag, std::string* value) const { |
57 | 3.02k | const DirectoryEntry* directory_entry = Find(tag); |
58 | 3.02k | if (directory_entry == NULL || directory_entry->type != TIFF_TYPE_ASCII) { |
59 | 1.28k | return false; |
60 | 1.28k | } |
61 | 1.74k | *value = |
62 | 1.74k | std::string(directory_entry->value.begin(), directory_entry->value.end()); |
63 | 1.74k | return true; |
64 | 3.02k | } |
65 | | |
66 | 11.3k | bool TiffDirectory::Get(const Tag tag, std::uint32_t* value) const { |
67 | 11.3k | std::vector<std::uint32_t> my_values; |
68 | 11.3k | if (!Get(tag, &my_values) || my_values.size() != 1) { |
69 | 4.03k | return false; |
70 | 4.03k | } |
71 | 7.35k | *value = my_values[0]; |
72 | 7.35k | return true; |
73 | 11.3k | } |
74 | | |
75 | | bool TiffDirectory::Get(const Tag tag, |
76 | 19.6k | std::vector<std::uint32_t>* value) const { |
77 | 19.6k | const DirectoryEntry* directory_entry = Find(tag); |
78 | 19.6k | if (directory_entry == NULL || (directory_entry->type != TIFF_TYPE_SHORT && |
79 | 7.82k | directory_entry->type != TIFF_TYPE_LONG)) { |
80 | 5.28k | return false; |
81 | 5.28k | } |
82 | | |
83 | 14.3k | RangeCheckedBytePtr value_ptr(&directory_entry->value[0], |
84 | 14.3k | directory_entry->value.size()); |
85 | 14.3k | std::vector<std::uint32_t> my_value(directory_entry->count); |
86 | 14.3k | const bool is_big_endian = (endian_ == kBigEndian); |
87 | | |
88 | 14.3k | MemoryStatus err = RANGE_CHECKED_BYTE_SUCCESS; |
89 | 6.54M | for (std::uint32_t c = 0; c < directory_entry->count; ++c) { |
90 | 6.53M | if (directory_entry->type == TIFF_TYPE_SHORT) { |
91 | 4.74M | my_value[c] = Get16u(value_ptr + c * 2, is_big_endian, &err); |
92 | 4.74M | } else { |
93 | 1.79M | my_value[c] = Get32u(value_ptr + c * 4, is_big_endian, &err); |
94 | 1.79M | } |
95 | 6.53M | } |
96 | 14.3k | if (err != RANGE_CHECKED_BYTE_SUCCESS) { |
97 | 0 | return false; |
98 | 0 | } |
99 | | |
100 | 14.3k | *value = my_value; |
101 | 14.3k | return true; |
102 | 14.3k | } |
103 | | |
104 | 0 | bool TiffDirectory::Get(const Tag tag, Rational* value) const { |
105 | 0 | std::vector<Rational> my_values; |
106 | 0 | if (!Get(tag, &my_values) || my_values.size() != 1) { |
107 | 0 | return false; |
108 | 0 | } |
109 | 0 | *value = my_values[0]; |
110 | 0 | return true; |
111 | 0 | } |
112 | | |
113 | 5.09k | bool TiffDirectory::Get(const Tag tag, std::vector<Rational>* value) const { |
114 | 5.09k | const DirectoryEntry* directory_entry = Find(tag); |
115 | 5.09k | if (directory_entry == NULL || |
116 | 3.49k | (directory_entry->type != TIFF_TYPE_SHORT && |
117 | 2.26k | directory_entry->type != TIFF_TYPE_LONG && |
118 | 1.91k | directory_entry->type != TIFF_TYPE_RATIONAL)) { |
119 | 1.73k | return false; |
120 | 1.73k | } |
121 | | |
122 | 3.36k | RangeCheckedBytePtr value_ptr(&directory_entry->value[0], |
123 | 3.36k | directory_entry->value.size()); |
124 | 3.36k | std::vector<Rational> my_value(directory_entry->count); |
125 | 3.36k | const bool is_big_endian = (endian_ == kBigEndian); |
126 | | |
127 | 3.36k | MemoryStatus err = RANGE_CHECKED_BYTE_SUCCESS; |
128 | 5.52M | for (std::uint32_t c = 0; c < directory_entry->count; ++c) { |
129 | 5.51M | switch (directory_entry->type) { |
130 | 3.01M | case TIFF_TYPE_SHORT: { |
131 | 3.01M | my_value[c].numerator = Get16u(value_ptr + c * 2, is_big_endian, &err); |
132 | 3.01M | my_value[c].denominator = 1; |
133 | 3.01M | break; |
134 | 0 | } |
135 | 2.45M | case TIFF_TYPE_LONG: { |
136 | 2.45M | my_value[c].numerator = Get32u(value_ptr + c * 4, is_big_endian, &err); |
137 | 2.45M | my_value[c].denominator = 1; |
138 | 2.45M | break; |
139 | 0 | } |
140 | 47.9k | case TIFF_TYPE_RATIONAL: { |
141 | 47.9k | my_value[c].numerator = Get32u(value_ptr + c * 8, is_big_endian, &err); |
142 | 47.9k | my_value[c].denominator = |
143 | 47.9k | Get32u(value_ptr + c * 8 + 4, is_big_endian, &err); |
144 | 47.9k | if (my_value[c].denominator == 0) { |
145 | 193 | return false; |
146 | 193 | } |
147 | 47.7k | break; |
148 | 47.9k | } |
149 | 5.51M | } |
150 | 5.51M | } |
151 | 3.17k | if (err != RANGE_CHECKED_BYTE_SUCCESS) { |
152 | 0 | return false; |
153 | 0 | } |
154 | | |
155 | 3.17k | *value = my_value; |
156 | 3.17k | return true; |
157 | 3.17k | } |
158 | | |
159 | 0 | bool TiffDirectory::Get(const Tag tag, SRational* value) const { |
160 | 0 | std::vector<SRational> my_values; |
161 | 0 | if (!Get(tag, &my_values) || my_values.size() != 1) { |
162 | 0 | return false; |
163 | 0 | } |
164 | 0 | *value = my_values[0]; |
165 | 0 | return true; |
166 | 0 | } |
167 | | |
168 | 0 | bool TiffDirectory::Get(const Tag tag, std::vector<SRational>* value) const { |
169 | 0 | const DirectoryEntry* directory_entry = Find(tag); |
170 | 0 | if (directory_entry == NULL || |
171 | 0 | (directory_entry->type != TIFF_TYPE_SSHORT && |
172 | 0 | directory_entry->type != TIFF_TYPE_SLONG && |
173 | 0 | directory_entry->type != TIFF_TYPE_SRATIONAL)) { |
174 | 0 | return false; |
175 | 0 | } |
176 | | |
177 | 0 | RangeCheckedBytePtr value_ptr(&directory_entry->value[0], |
178 | 0 | directory_entry->value.size()); |
179 | 0 | std::vector<SRational> my_value(directory_entry->count); |
180 | 0 | const bool is_big_endian = (endian_ == kBigEndian); |
181 | |
|
182 | 0 | MemoryStatus err = RANGE_CHECKED_BYTE_SUCCESS; |
183 | 0 | for (std::uint32_t c = 0; c < directory_entry->count; ++c) { |
184 | 0 | switch (directory_entry->type) { |
185 | 0 | case TIFF_TYPE_SSHORT: { |
186 | 0 | my_value[c].numerator = Get16s(value_ptr + c * 2, is_big_endian, &err); |
187 | 0 | my_value[c].denominator = 1; |
188 | 0 | break; |
189 | 0 | } |
190 | 0 | case TIFF_TYPE_SLONG: { |
191 | 0 | my_value[c].numerator = Get32s(value_ptr + c * 4, is_big_endian, &err); |
192 | 0 | my_value[c].denominator = 1; |
193 | 0 | break; |
194 | 0 | } |
195 | 0 | case TIFF_TYPE_SRATIONAL: { |
196 | 0 | my_value[c].numerator = Get32s(value_ptr + c * 8, is_big_endian, &err); |
197 | 0 | my_value[c].denominator = |
198 | 0 | Get32s(value_ptr + c * 8 + 4, is_big_endian, &err); |
199 | 0 | if (my_value[c].denominator == 0) { |
200 | 0 | return false; |
201 | 0 | } |
202 | 0 | break; |
203 | 0 | } |
204 | 0 | } |
205 | 0 | } |
206 | 0 | if (err != RANGE_CHECKED_BYTE_SUCCESS) { |
207 | 0 | return false; |
208 | 0 | } |
209 | | |
210 | 0 | *value = my_value; |
211 | 0 | return true; |
212 | 0 | } |
213 | | |
214 | | bool TiffDirectory::GetOffsetAndLength(const Tag tag, const Type type, |
215 | | std::uint32_t* offset, |
216 | 889 | std::uint32_t* length) const { |
217 | 889 | const DirectoryEntry* directory_entry = Find(tag); |
218 | 889 | if (directory_entry == NULL || directory_entry->type != type) { |
219 | 54 | return false; |
220 | 54 | } |
221 | 835 | *offset = directory_entry->offset; |
222 | 835 | *length = static_cast<std::uint32_t>(directory_entry->value.size()); |
223 | 835 | return true; |
224 | 889 | } |
225 | | |
226 | | void TiffDirectory::AddEntry(const Tag tag, const Type type, |
227 | | const std::uint32_t count, |
228 | | const std::uint32_t offset, |
229 | 185k | const std::vector<std::uint8_t>& value) { |
230 | 185k | assert(SizeOfType(type, NULL /* success */) * count == value.size()); |
231 | | |
232 | 185k | const DirectoryEntry directory_entry = {type, count, offset, value}; |
233 | 185k | directory_entries_[tag] = directory_entry; |
234 | 185k | tag_order_.push_back(tag); |
235 | 185k | } |
236 | | |
237 | 1.62k | void TiffDirectory::AddSubDirectory(const TiffDirectory& sub_directory) { |
238 | 1.62k | sub_directories_.push_back(sub_directory); |
239 | 1.62k | } |
240 | | |
241 | 10.1k | const std::vector<TiffDirectory>& TiffDirectory::GetSubDirectories() const { |
242 | 10.1k | return sub_directories_; |
243 | 10.1k | } |
244 | | |
245 | 28.6k | const TiffDirectory::DirectoryEntry* TiffDirectory::Find(const Tag tag) const { |
246 | 28.6k | std::map<Tag, DirectoryEntry>::const_iterator iter = |
247 | 28.6k | directory_entries_.find(tag); |
248 | 28.6k | if (iter == directory_entries_.end()) { |
249 | 5.13k | return NULL; |
250 | 5.13k | } |
251 | 23.5k | return &iter->second; |
252 | 28.6k | } |
253 | | |
254 | 485k | size_t SizeOfType(const TiffDirectory::Type type, bool* success) { |
255 | 485k | switch (type) { |
256 | 110k | case TIFF_TYPE_BYTE: |
257 | 163k | case TIFF_TYPE_ASCII: |
258 | 164k | case TIFF_TYPE_SBYTE: |
259 | 165k | case TIFF_TYPE_UNDEFINED: |
260 | 165k | return 1; |
261 | 173k | case TIFF_TYPE_SHORT: |
262 | 173k | case TIFF_TYPE_SSHORT: |
263 | 173k | return 2; |
264 | 26.6k | case TIFF_TYPE_LONG: |
265 | 26.9k | case TIFF_TYPE_SLONG: |
266 | 28.5k | case TIFF_TYPE_FLOAT: |
267 | 28.9k | case TIFF_IFD: |
268 | 28.9k | return 4; |
269 | 3.23k | case TIFF_TYPE_RATIONAL: |
270 | 4.39k | case TIFF_TYPE_SRATIONAL: |
271 | 4.89k | case TIFF_TYPE_DOUBLE: |
272 | 4.89k | return 8; |
273 | 485k | } |
274 | | |
275 | 112k | if (success != NULL) { |
276 | 0 | *success = false; |
277 | 0 | } |
278 | 112k | return 0; |
279 | 485k | } |
280 | | |
281 | | } // namespace tiff_directory |
282 | | } // namespace piex |