Coverage Report

Created: 2026-01-16 06:49

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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