1*c8dee2aaSAndroid Build Coastguard Worker /*
2*c8dee2aaSAndroid Build Coastguard Worker * Copyright 2023 Google Inc.
3*c8dee2aaSAndroid Build Coastguard Worker *
4*c8dee2aaSAndroid Build Coastguard Worker * Use of this source code is governed by a BSD-style license that can be
5*c8dee2aaSAndroid Build Coastguard Worker * found in the LICENSE file.
6*c8dee2aaSAndroid Build Coastguard Worker */
7*c8dee2aaSAndroid Build Coastguard Worker
8*c8dee2aaSAndroid Build Coastguard Worker #include "src/codec/SkTiffUtility.h"
9*c8dee2aaSAndroid Build Coastguard Worker
10*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkData.h"
11*c8dee2aaSAndroid Build Coastguard Worker #include "src/codec/SkCodecPriv.h"
12*c8dee2aaSAndroid Build Coastguard Worker
13*c8dee2aaSAndroid Build Coastguard Worker #include <cstddef>
14*c8dee2aaSAndroid Build Coastguard Worker #include <utility>
15*c8dee2aaSAndroid Build Coastguard Worker
16*c8dee2aaSAndroid Build Coastguard Worker namespace SkTiff {
17*c8dee2aaSAndroid Build Coastguard Worker
IsValidType(uint16_t type)18*c8dee2aaSAndroid Build Coastguard Worker bool ImageFileDirectory::IsValidType(uint16_t type) { return type >= 1 && type <= 12; }
19*c8dee2aaSAndroid Build Coastguard Worker
BytesForType(uint16_t type)20*c8dee2aaSAndroid Build Coastguard Worker size_t ImageFileDirectory::BytesForType(uint16_t type) {
21*c8dee2aaSAndroid Build Coastguard Worker switch (type) {
22*c8dee2aaSAndroid Build Coastguard Worker case kTypeUnsignedByte:
23*c8dee2aaSAndroid Build Coastguard Worker return 1;
24*c8dee2aaSAndroid Build Coastguard Worker case kTypeAsciiString:
25*c8dee2aaSAndroid Build Coastguard Worker return 1;
26*c8dee2aaSAndroid Build Coastguard Worker case kTypeUnsignedShort:
27*c8dee2aaSAndroid Build Coastguard Worker return kSizeShort;
28*c8dee2aaSAndroid Build Coastguard Worker case kTypeUnsignedLong:
29*c8dee2aaSAndroid Build Coastguard Worker return kSizeLong;
30*c8dee2aaSAndroid Build Coastguard Worker case kTypeUnsignedRational:
31*c8dee2aaSAndroid Build Coastguard Worker return 8;
32*c8dee2aaSAndroid Build Coastguard Worker case kTypeSignedByte:
33*c8dee2aaSAndroid Build Coastguard Worker return 1;
34*c8dee2aaSAndroid Build Coastguard Worker case kTypeUndefined:
35*c8dee2aaSAndroid Build Coastguard Worker return 1;
36*c8dee2aaSAndroid Build Coastguard Worker case kTypeSignedShort:
37*c8dee2aaSAndroid Build Coastguard Worker return kSizeShort;
38*c8dee2aaSAndroid Build Coastguard Worker case kTypeSignedLong:
39*c8dee2aaSAndroid Build Coastguard Worker return kSizeLong;
40*c8dee2aaSAndroid Build Coastguard Worker case kTypeSignedRational:
41*c8dee2aaSAndroid Build Coastguard Worker return 8;
42*c8dee2aaSAndroid Build Coastguard Worker case kTypeSingleFloat:
43*c8dee2aaSAndroid Build Coastguard Worker return 4;
44*c8dee2aaSAndroid Build Coastguard Worker case kTypeDoubleFloat:
45*c8dee2aaSAndroid Build Coastguard Worker return 8;
46*c8dee2aaSAndroid Build Coastguard Worker }
47*c8dee2aaSAndroid Build Coastguard Worker return 0;
48*c8dee2aaSAndroid Build Coastguard Worker }
49*c8dee2aaSAndroid Build Coastguard Worker
50*c8dee2aaSAndroid Build Coastguard Worker // Helper function for computing the address of an entry.
get_entry_address(const SkData * data,uint32_t ifdOffset,uint16_t entryIndex)51*c8dee2aaSAndroid Build Coastguard Worker static const uint8_t* get_entry_address(const SkData* data,
52*c8dee2aaSAndroid Build Coastguard Worker uint32_t ifdOffset,
53*c8dee2aaSAndroid Build Coastguard Worker uint16_t entryIndex) {
54*c8dee2aaSAndroid Build Coastguard Worker return data->bytes() + // Base address
55*c8dee2aaSAndroid Build Coastguard Worker ifdOffset + // IFD offset
56*c8dee2aaSAndroid Build Coastguard Worker kSizeShort + // IFD number of entries
57*c8dee2aaSAndroid Build Coastguard Worker kSizeEntry * entryIndex; // Entries
58*c8dee2aaSAndroid Build Coastguard Worker }
59*c8dee2aaSAndroid Build Coastguard Worker
60*c8dee2aaSAndroid Build Coastguard Worker // Return true if the IFD starting at |ifdOffset| contains valid number of entries (that doesn't
61*c8dee2aaSAndroid Build Coastguard Worker // overrun |data|).
validate_ifd(const SkData * data,bool littleEndian,uint32_t ifdOffset,bool allowTruncated,uint16_t * outNumEntries,uint32_t * outNextIfdOffset)62*c8dee2aaSAndroid Build Coastguard Worker static bool validate_ifd(const SkData* data,
63*c8dee2aaSAndroid Build Coastguard Worker bool littleEndian,
64*c8dee2aaSAndroid Build Coastguard Worker uint32_t ifdOffset,
65*c8dee2aaSAndroid Build Coastguard Worker bool allowTruncated,
66*c8dee2aaSAndroid Build Coastguard Worker uint16_t* outNumEntries,
67*c8dee2aaSAndroid Build Coastguard Worker uint32_t* outNextIfdOffset) {
68*c8dee2aaSAndroid Build Coastguard Worker const uint8_t* dataCurrent = data->bytes();
69*c8dee2aaSAndroid Build Coastguard Worker size_t dataSize = data->size();
70*c8dee2aaSAndroid Build Coastguard Worker
71*c8dee2aaSAndroid Build Coastguard Worker // Seek to the IFD offset.
72*c8dee2aaSAndroid Build Coastguard Worker if (dataSize < ifdOffset) {
73*c8dee2aaSAndroid Build Coastguard Worker SkCodecPrintf("IFD offset is too large.\n");
74*c8dee2aaSAndroid Build Coastguard Worker return false;
75*c8dee2aaSAndroid Build Coastguard Worker }
76*c8dee2aaSAndroid Build Coastguard Worker dataCurrent += ifdOffset;
77*c8dee2aaSAndroid Build Coastguard Worker dataSize -= ifdOffset;
78*c8dee2aaSAndroid Build Coastguard Worker
79*c8dee2aaSAndroid Build Coastguard Worker // Read the number of entries.
80*c8dee2aaSAndroid Build Coastguard Worker if (dataSize < kSizeShort) {
81*c8dee2aaSAndroid Build Coastguard Worker SkCodecPrintf("Insufficient space to store number of entries.\n");
82*c8dee2aaSAndroid Build Coastguard Worker return false;
83*c8dee2aaSAndroid Build Coastguard Worker }
84*c8dee2aaSAndroid Build Coastguard Worker uint16_t numEntries = get_endian_short(dataCurrent, littleEndian);
85*c8dee2aaSAndroid Build Coastguard Worker dataCurrent += kSizeShort;
86*c8dee2aaSAndroid Build Coastguard Worker dataSize -= kSizeShort;
87*c8dee2aaSAndroid Build Coastguard Worker
88*c8dee2aaSAndroid Build Coastguard Worker // Check that there is enough space for all entries.
89*c8dee2aaSAndroid Build Coastguard Worker if (dataSize < kSizeEntry * numEntries) {
90*c8dee2aaSAndroid Build Coastguard Worker SkCodecPrintf("Insufficient space (%u) to store all %u entries.\n",
91*c8dee2aaSAndroid Build Coastguard Worker static_cast<uint32_t>(data->size()),
92*c8dee2aaSAndroid Build Coastguard Worker numEntries);
93*c8dee2aaSAndroid Build Coastguard Worker if (allowTruncated) {
94*c8dee2aaSAndroid Build Coastguard Worker // Set the number of entries to the number of entries that can be fully read, and set
95*c8dee2aaSAndroid Build Coastguard Worker // the next IFD offset to 0 (indicating that there is no next IFD).
96*c8dee2aaSAndroid Build Coastguard Worker *outNumEntries = dataSize / kSizeEntry;
97*c8dee2aaSAndroid Build Coastguard Worker *outNextIfdOffset = 0;
98*c8dee2aaSAndroid Build Coastguard Worker return true;
99*c8dee2aaSAndroid Build Coastguard Worker }
100*c8dee2aaSAndroid Build Coastguard Worker return false;
101*c8dee2aaSAndroid Build Coastguard Worker }
102*c8dee2aaSAndroid Build Coastguard Worker
103*c8dee2aaSAndroid Build Coastguard Worker // Save the number of entries.
104*c8dee2aaSAndroid Build Coastguard Worker *outNumEntries = numEntries;
105*c8dee2aaSAndroid Build Coastguard Worker
106*c8dee2aaSAndroid Build Coastguard Worker // Seek past the entries.
107*c8dee2aaSAndroid Build Coastguard Worker dataCurrent += kSizeEntry * numEntries;
108*c8dee2aaSAndroid Build Coastguard Worker dataSize -= kSizeEntry * numEntries;
109*c8dee2aaSAndroid Build Coastguard Worker
110*c8dee2aaSAndroid Build Coastguard Worker // Read the next IFD offset.
111*c8dee2aaSAndroid Build Coastguard Worker if (dataSize < kSizeLong) {
112*c8dee2aaSAndroid Build Coastguard Worker SkCodecPrintf("Insufficient space to store next IFD offset.\n");
113*c8dee2aaSAndroid Build Coastguard Worker if (allowTruncated) {
114*c8dee2aaSAndroid Build Coastguard Worker // Set the next IFD offset to 0 (indicating that there is no next IFD).
115*c8dee2aaSAndroid Build Coastguard Worker *outNextIfdOffset = 0;
116*c8dee2aaSAndroid Build Coastguard Worker return true;
117*c8dee2aaSAndroid Build Coastguard Worker }
118*c8dee2aaSAndroid Build Coastguard Worker return false;
119*c8dee2aaSAndroid Build Coastguard Worker }
120*c8dee2aaSAndroid Build Coastguard Worker
121*c8dee2aaSAndroid Build Coastguard Worker // Save the next IFD offset.
122*c8dee2aaSAndroid Build Coastguard Worker *outNextIfdOffset = get_endian_int(dataCurrent, littleEndian);
123*c8dee2aaSAndroid Build Coastguard Worker return true;
124*c8dee2aaSAndroid Build Coastguard Worker }
125*c8dee2aaSAndroid Build Coastguard Worker
ParseHeader(const SkData * data,bool * outLittleEndian,uint32_t * outIfdOffset)126*c8dee2aaSAndroid Build Coastguard Worker bool ImageFileDirectory::ParseHeader(const SkData* data,
127*c8dee2aaSAndroid Build Coastguard Worker bool* outLittleEndian,
128*c8dee2aaSAndroid Build Coastguard Worker uint32_t* outIfdOffset) {
129*c8dee2aaSAndroid Build Coastguard Worker // Read the endianness (4 bytes) and IFD offset (4 bytes).
130*c8dee2aaSAndroid Build Coastguard Worker if (data->size() < 8) {
131*c8dee2aaSAndroid Build Coastguard Worker SkCodecPrintf("Tiff header must be at least 8 bytes.\n");
132*c8dee2aaSAndroid Build Coastguard Worker return false;
133*c8dee2aaSAndroid Build Coastguard Worker }
134*c8dee2aaSAndroid Build Coastguard Worker if (!is_valid_endian_marker(data->bytes(), outLittleEndian)) {
135*c8dee2aaSAndroid Build Coastguard Worker SkCodecPrintf("Tiff header had invalid endian marker 0x%x,0x%x,0x%x,0x%x.\n",
136*c8dee2aaSAndroid Build Coastguard Worker data->bytes()[0],
137*c8dee2aaSAndroid Build Coastguard Worker data->bytes()[1],
138*c8dee2aaSAndroid Build Coastguard Worker data->bytes()[2],
139*c8dee2aaSAndroid Build Coastguard Worker data->bytes()[3]);
140*c8dee2aaSAndroid Build Coastguard Worker return false;
141*c8dee2aaSAndroid Build Coastguard Worker }
142*c8dee2aaSAndroid Build Coastguard Worker *outIfdOffset = get_endian_int(data->bytes() + 4, *outLittleEndian);
143*c8dee2aaSAndroid Build Coastguard Worker return true;
144*c8dee2aaSAndroid Build Coastguard Worker }
145*c8dee2aaSAndroid Build Coastguard Worker
MakeFromOffset(sk_sp<SkData> data,bool littleEndian,uint32_t ifdOffset,bool allowTruncated)146*c8dee2aaSAndroid Build Coastguard Worker std::unique_ptr<ImageFileDirectory> ImageFileDirectory::MakeFromOffset(sk_sp<SkData> data,
147*c8dee2aaSAndroid Build Coastguard Worker bool littleEndian,
148*c8dee2aaSAndroid Build Coastguard Worker uint32_t ifdOffset,
149*c8dee2aaSAndroid Build Coastguard Worker bool allowTruncated) {
150*c8dee2aaSAndroid Build Coastguard Worker uint16_t numEntries = 0;
151*c8dee2aaSAndroid Build Coastguard Worker uint32_t nextOffset = 0;
152*c8dee2aaSAndroid Build Coastguard Worker if (!validate_ifd(
153*c8dee2aaSAndroid Build Coastguard Worker data.get(), littleEndian, ifdOffset, allowTruncated, &numEntries, &nextOffset)) {
154*c8dee2aaSAndroid Build Coastguard Worker SkCodecPrintf("Failed to validate IFD.\n");
155*c8dee2aaSAndroid Build Coastguard Worker return nullptr;
156*c8dee2aaSAndroid Build Coastguard Worker }
157*c8dee2aaSAndroid Build Coastguard Worker return std::unique_ptr<ImageFileDirectory>(new ImageFileDirectory(
158*c8dee2aaSAndroid Build Coastguard Worker std::move(data), littleEndian, ifdOffset, numEntries, nextOffset));
159*c8dee2aaSAndroid Build Coastguard Worker }
160*c8dee2aaSAndroid Build Coastguard Worker
ImageFileDirectory(sk_sp<SkData> data,bool littleEndian,uint32_t offset,uint16_t numEntries,uint32_t nextIfdOffset)161*c8dee2aaSAndroid Build Coastguard Worker ImageFileDirectory::ImageFileDirectory(sk_sp<SkData> data,
162*c8dee2aaSAndroid Build Coastguard Worker bool littleEndian,
163*c8dee2aaSAndroid Build Coastguard Worker uint32_t offset,
164*c8dee2aaSAndroid Build Coastguard Worker uint16_t numEntries,
165*c8dee2aaSAndroid Build Coastguard Worker uint32_t nextIfdOffset)
166*c8dee2aaSAndroid Build Coastguard Worker : fData(std::move(data))
167*c8dee2aaSAndroid Build Coastguard Worker , fLittleEndian(littleEndian)
168*c8dee2aaSAndroid Build Coastguard Worker , fOffset(offset)
169*c8dee2aaSAndroid Build Coastguard Worker , fNumEntries(numEntries)
170*c8dee2aaSAndroid Build Coastguard Worker , fNextIfdOffset(nextIfdOffset) {}
171*c8dee2aaSAndroid Build Coastguard Worker
getEntryTag(uint16_t entryIndex) const172*c8dee2aaSAndroid Build Coastguard Worker uint16_t ImageFileDirectory::getEntryTag(uint16_t entryIndex) const {
173*c8dee2aaSAndroid Build Coastguard Worker const uint8_t* entry = get_entry_address(fData.get(), fOffset, entryIndex);
174*c8dee2aaSAndroid Build Coastguard Worker return get_endian_short(entry, fLittleEndian);
175*c8dee2aaSAndroid Build Coastguard Worker }
176*c8dee2aaSAndroid Build Coastguard Worker
getEntryRawData(uint16_t entryIndex,uint16_t * outTag,uint16_t * outType,uint32_t * outCount,const uint8_t ** outData,size_t * outDataSize) const177*c8dee2aaSAndroid Build Coastguard Worker bool ImageFileDirectory::getEntryRawData(uint16_t entryIndex,
178*c8dee2aaSAndroid Build Coastguard Worker uint16_t* outTag,
179*c8dee2aaSAndroid Build Coastguard Worker uint16_t* outType,
180*c8dee2aaSAndroid Build Coastguard Worker uint32_t* outCount,
181*c8dee2aaSAndroid Build Coastguard Worker const uint8_t** outData,
182*c8dee2aaSAndroid Build Coastguard Worker size_t* outDataSize) const {
183*c8dee2aaSAndroid Build Coastguard Worker const uint8_t* entry = get_entry_address(fData.get(), fOffset, entryIndex);
184*c8dee2aaSAndroid Build Coastguard Worker
185*c8dee2aaSAndroid Build Coastguard Worker // Read the tag
186*c8dee2aaSAndroid Build Coastguard Worker const uint16_t tag = get_endian_short(entry, fLittleEndian);
187*c8dee2aaSAndroid Build Coastguard Worker entry += kSizeShort;
188*c8dee2aaSAndroid Build Coastguard Worker
189*c8dee2aaSAndroid Build Coastguard Worker // Read the type.
190*c8dee2aaSAndroid Build Coastguard Worker const uint16_t type = get_endian_short(entry, fLittleEndian);
191*c8dee2aaSAndroid Build Coastguard Worker entry += kSizeShort;
192*c8dee2aaSAndroid Build Coastguard Worker if (!IsValidType(type)) {
193*c8dee2aaSAndroid Build Coastguard Worker return false;
194*c8dee2aaSAndroid Build Coastguard Worker }
195*c8dee2aaSAndroid Build Coastguard Worker
196*c8dee2aaSAndroid Build Coastguard Worker // Read the count.
197*c8dee2aaSAndroid Build Coastguard Worker const uint32_t count = get_endian_int(entry, fLittleEndian);
198*c8dee2aaSAndroid Build Coastguard Worker entry += kSizeLong;
199*c8dee2aaSAndroid Build Coastguard Worker
200*c8dee2aaSAndroid Build Coastguard Worker // If the entry fits in the remaining 4 bytes, use that.
201*c8dee2aaSAndroid Build Coastguard Worker const size_t entryDataBytes = BytesForType(type) * count;
202*c8dee2aaSAndroid Build Coastguard Worker const uint8_t* entryData = nullptr;
203*c8dee2aaSAndroid Build Coastguard Worker if (entryDataBytes <= kSizeLong) {
204*c8dee2aaSAndroid Build Coastguard Worker entryData = entry;
205*c8dee2aaSAndroid Build Coastguard Worker } else {
206*c8dee2aaSAndroid Build Coastguard Worker // Otherwise, the next 4 bytes specify an offset where the data can be found.
207*c8dee2aaSAndroid Build Coastguard Worker const uint32_t entryDataOffset = get_endian_int(entry, fLittleEndian);
208*c8dee2aaSAndroid Build Coastguard Worker if (fData->size() < entryDataOffset || fData->size() - entryDataOffset < entryDataBytes) {
209*c8dee2aaSAndroid Build Coastguard Worker return false;
210*c8dee2aaSAndroid Build Coastguard Worker }
211*c8dee2aaSAndroid Build Coastguard Worker entryData = fData->bytes() + entryDataOffset;
212*c8dee2aaSAndroid Build Coastguard Worker }
213*c8dee2aaSAndroid Build Coastguard Worker
214*c8dee2aaSAndroid Build Coastguard Worker if (outTag) *outTag = tag;
215*c8dee2aaSAndroid Build Coastguard Worker if (outType) *outType = type;
216*c8dee2aaSAndroid Build Coastguard Worker if (outCount) *outCount = count;
217*c8dee2aaSAndroid Build Coastguard Worker if (outData) *outData = entryData;
218*c8dee2aaSAndroid Build Coastguard Worker if (outDataSize) *outDataSize = entryDataBytes;
219*c8dee2aaSAndroid Build Coastguard Worker return true;
220*c8dee2aaSAndroid Build Coastguard Worker }
221*c8dee2aaSAndroid Build Coastguard Worker
getEntryUndefinedData(uint16_t entryIndex) const222*c8dee2aaSAndroid Build Coastguard Worker sk_sp<SkData> ImageFileDirectory::getEntryUndefinedData(uint16_t entryIndex) const {
223*c8dee2aaSAndroid Build Coastguard Worker uint16_t type = 0;
224*c8dee2aaSAndroid Build Coastguard Worker uint32_t count = 0;
225*c8dee2aaSAndroid Build Coastguard Worker const uint8_t* data = nullptr;
226*c8dee2aaSAndroid Build Coastguard Worker size_t size = 0;
227*c8dee2aaSAndroid Build Coastguard Worker if (!getEntryRawData(entryIndex, nullptr, &type, &count, &data, &size)) {
228*c8dee2aaSAndroid Build Coastguard Worker return nullptr;
229*c8dee2aaSAndroid Build Coastguard Worker }
230*c8dee2aaSAndroid Build Coastguard Worker if (type != kTypeUndefined) {
231*c8dee2aaSAndroid Build Coastguard Worker return nullptr;
232*c8dee2aaSAndroid Build Coastguard Worker }
233*c8dee2aaSAndroid Build Coastguard Worker return SkData::MakeSubset(fData.get(), data - fData->bytes(), size);
234*c8dee2aaSAndroid Build Coastguard Worker }
235*c8dee2aaSAndroid Build Coastguard Worker
getEntryValuesGeneric(uint16_t entryIndex,uint16_t type,uint32_t count,void * values) const236*c8dee2aaSAndroid Build Coastguard Worker bool ImageFileDirectory::getEntryValuesGeneric(uint16_t entryIndex,
237*c8dee2aaSAndroid Build Coastguard Worker uint16_t type,
238*c8dee2aaSAndroid Build Coastguard Worker uint32_t count,
239*c8dee2aaSAndroid Build Coastguard Worker void* values) const {
240*c8dee2aaSAndroid Build Coastguard Worker uint16_t entryType = 0;
241*c8dee2aaSAndroid Build Coastguard Worker uint32_t entryCount = 0;
242*c8dee2aaSAndroid Build Coastguard Worker const uint8_t* entryData = nullptr;
243*c8dee2aaSAndroid Build Coastguard Worker if (!getEntryRawData(entryIndex, nullptr, &entryType, &entryCount, &entryData, nullptr)) {
244*c8dee2aaSAndroid Build Coastguard Worker return false;
245*c8dee2aaSAndroid Build Coastguard Worker }
246*c8dee2aaSAndroid Build Coastguard Worker if (type != entryType) {
247*c8dee2aaSAndroid Build Coastguard Worker return false;
248*c8dee2aaSAndroid Build Coastguard Worker }
249*c8dee2aaSAndroid Build Coastguard Worker if (count != entryCount) {
250*c8dee2aaSAndroid Build Coastguard Worker return false;
251*c8dee2aaSAndroid Build Coastguard Worker }
252*c8dee2aaSAndroid Build Coastguard Worker for (uint32_t i = 0; i < count; ++i) {
253*c8dee2aaSAndroid Build Coastguard Worker const uint8_t* data = entryData + i * BytesForType(kTypeUnsignedLong);
254*c8dee2aaSAndroid Build Coastguard Worker switch (type) {
255*c8dee2aaSAndroid Build Coastguard Worker case kTypeUnsignedShort:
256*c8dee2aaSAndroid Build Coastguard Worker reinterpret_cast<uint16_t*>(values)[i] = get_endian_short(data, fLittleEndian);
257*c8dee2aaSAndroid Build Coastguard Worker break;
258*c8dee2aaSAndroid Build Coastguard Worker case kTypeUnsignedLong:
259*c8dee2aaSAndroid Build Coastguard Worker reinterpret_cast<uint32_t*>(values)[i] = get_endian_int(data, fLittleEndian);
260*c8dee2aaSAndroid Build Coastguard Worker break;
261*c8dee2aaSAndroid Build Coastguard Worker case kTypeSignedRational: {
262*c8dee2aaSAndroid Build Coastguard Worker uint32_t numerator = get_endian_int(data, fLittleEndian);
263*c8dee2aaSAndroid Build Coastguard Worker uint32_t denominator = get_endian_int(data + kSizeLong, fLittleEndian);
264*c8dee2aaSAndroid Build Coastguard Worker if (denominator == 0) {
265*c8dee2aaSAndroid Build Coastguard Worker // The TIFF specification does not indicate a behavior when the denominator is
266*c8dee2aaSAndroid Build Coastguard Worker // zero. The behavior of returning zero for a denominator of zero is a
267*c8dee2aaSAndroid Build Coastguard Worker // preservation of the behavior introduced in https://crrev.com/767874.
268*c8dee2aaSAndroid Build Coastguard Worker reinterpret_cast<float*>(values)[i] = 0;
269*c8dee2aaSAndroid Build Coastguard Worker } else {
270*c8dee2aaSAndroid Build Coastguard Worker reinterpret_cast<float*>(values)[i] =
271*c8dee2aaSAndroid Build Coastguard Worker numerator / static_cast<float>(denominator);
272*c8dee2aaSAndroid Build Coastguard Worker }
273*c8dee2aaSAndroid Build Coastguard Worker break;
274*c8dee2aaSAndroid Build Coastguard Worker }
275*c8dee2aaSAndroid Build Coastguard Worker case kTypeUnsignedRational: {
276*c8dee2aaSAndroid Build Coastguard Worker uint32_t numerator = get_endian_int(data, fLittleEndian);
277*c8dee2aaSAndroid Build Coastguard Worker uint32_t denominator = get_endian_int(data + kSizeLong, fLittleEndian);
278*c8dee2aaSAndroid Build Coastguard Worker if (denominator == 0) {
279*c8dee2aaSAndroid Build Coastguard Worker // See comments in kTypeSignedRational.
280*c8dee2aaSAndroid Build Coastguard Worker reinterpret_cast<float*>(values)[i] = 0.f;
281*c8dee2aaSAndroid Build Coastguard Worker } else {
282*c8dee2aaSAndroid Build Coastguard Worker reinterpret_cast<float*>(values)[i] =
283*c8dee2aaSAndroid Build Coastguard Worker numerator / static_cast<float>(denominator);
284*c8dee2aaSAndroid Build Coastguard Worker }
285*c8dee2aaSAndroid Build Coastguard Worker break;
286*c8dee2aaSAndroid Build Coastguard Worker }
287*c8dee2aaSAndroid Build Coastguard Worker default:
288*c8dee2aaSAndroid Build Coastguard Worker SkCodecPrintf("Unsupported type %u\n", type);
289*c8dee2aaSAndroid Build Coastguard Worker return false;
290*c8dee2aaSAndroid Build Coastguard Worker break;
291*c8dee2aaSAndroid Build Coastguard Worker }
292*c8dee2aaSAndroid Build Coastguard Worker }
293*c8dee2aaSAndroid Build Coastguard Worker return true;
294*c8dee2aaSAndroid Build Coastguard Worker }
295*c8dee2aaSAndroid Build Coastguard Worker
296*c8dee2aaSAndroid Build Coastguard Worker } // namespace SkTiff
297