xref: /aosp_15_r20/external/skia/src/codec/SkTiffUtility.h (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
1 /*
2  * Copyright 2023 Google Inc.
3  *
4  * Use of this source code is governed by a BSD-style license that can be
5  * found in the LICENSE file.
6  */
7 
8 #ifndef SkTiffUtility_codec_DEFINED
9 #define SkTiffUtility_codec_DEFINED
10 
11 #include "include/core/SkData.h"
12 #include "include/core/SkRefCnt.h"
13 
14 #include <cstddef>
15 #include <cstdint>
16 #include <memory>
17 
18 namespace SkTiff {
19 
20 // Constants for endian signature.
21 inline constexpr size_t kEndianSize = 4;
22 inline constexpr uint8_t kEndianBig[kEndianSize] = {'M', 'M', 0, 42};
23 inline constexpr uint8_t kEndianLittle[kEndianSize] = {'I', 'I', 42, 0};
24 
25 // Constants for types.
26 inline constexpr uint16_t kTypeUnsignedByte = 1;
27 inline constexpr uint16_t kTypeAsciiString = 2;
28 inline constexpr uint16_t kTypeUnsignedShort = 3;
29 inline constexpr uint16_t kTypeUnsignedLong = 4;
30 inline constexpr uint16_t kTypeUnsignedRational = 5;
31 inline constexpr uint16_t kTypeSignedByte = 6;
32 inline constexpr uint16_t kTypeUndefined = 7;
33 inline constexpr uint16_t kTypeSignedShort = 8;
34 inline constexpr uint16_t kTypeSignedLong = 9;
35 inline constexpr uint16_t kTypeSignedRational = 10;
36 inline constexpr uint16_t kTypeSingleFloat = 11;
37 inline constexpr uint16_t kTypeDoubleFloat = 12;
38 
39 inline constexpr size_t kSizeEntry = 12;
40 inline constexpr size_t kSizeShort = 2;
41 inline constexpr size_t kSizeLong = 4;
42 
43 /*
44  * Helper function for parsing a Tiff Image File Directory (IFD) structure. This structure is used
45  * by EXIF tags, multi-picture, and maker note metadata.
46  */
47 class ImageFileDirectory {
48 public:
49     /*
50      * Parse |data| to read the endian-ness into |outLittleEndian| and the IFD offset into
51      * |outIfdOffset|. Return true if the endian-ness was successfully parsed and there was
52      * the IFD offset was read.
53      */
54     static bool ParseHeader(const SkData* data, bool* outLittleEndian, uint32_t* outIfdOffset);
55 
56     /*
57      * Create an object for parsing an IFD at offset |ifdOffset| inside |data| which has endianness
58      * indicated by |littleEndian|. If |allowTruncated| is true, then parse as much of |data| as is
59      * possible, otherwise reject any incomplete IFDs.
60      */
61     static std::unique_ptr<ImageFileDirectory> MakeFromOffset(sk_sp<SkData> data,
62                                                               bool littleEndian,
63                                                               uint32_t ifdOffset,
64                                                               bool allowTruncated = false);
65 
66     /*
67      * Return the number of entries.
68      */
getNumEntries()69     uint16_t getNumEntries() const { return fNumEntries; }
70 
71     /*
72      * Return the offset (within the specified SkData) of the next IFD in the list of IFDs.
73      */
nextIfdOffset()74     uint32_t nextIfdOffset() const { return fNextIfdOffset; }
75 
76     /*
77      * Return the tag, of a specific entry.
78      */
79     uint16_t getEntryTag(uint16_t entryIndex) const;
80 
81     /*
82      * If |entryIndex| has type unsigned short (3), unsigned long (4), or signed rational (10), and
83      * count |count|, then populate |values| with the data for the tag and return true. Otherwise
84      * return false.
85      */
getEntryUnsignedShort(uint16_t entryIndex,uint32_t count,uint16_t * values)86     bool getEntryUnsignedShort(uint16_t entryIndex, uint32_t count, uint16_t* values) const {
87         return getEntryValuesGeneric(entryIndex, kTypeUnsignedShort, count, values);
88     }
getEntryUnsignedLong(uint16_t entryIndex,uint32_t count,uint32_t * values)89     bool getEntryUnsignedLong(uint16_t entryIndex, uint32_t count, uint32_t* values) const {
90         return getEntryValuesGeneric(entryIndex, kTypeUnsignedLong, count, values);
91     }
getEntrySignedRational(uint16_t entryIndex,uint32_t count,float * values)92     bool getEntrySignedRational(uint16_t entryIndex, uint32_t count, float* values) const {
93         return getEntryValuesGeneric(entryIndex, kTypeSignedRational, count, values);
94     }
getEntryUnsignedRational(uint16_t entryIndex,uint32_t count,float * values)95     bool getEntryUnsignedRational(uint16_t entryIndex, uint32_t count, float* values) const {
96         return getEntryValuesGeneric(entryIndex, kTypeUnsignedRational, count, values);
97     }
98 
99     /*
100      * If |entryIndex| has type undefined (7), then return the bytes specified by the count field
101      * and the offset (read from the value field as an unsigned long).
102      */
103     sk_sp<SkData> getEntryUndefinedData(uint16_t entryIndex) const;
104 
105 private:
106     static bool IsValidType(uint16_t type);
107     static size_t BytesForType(uint16_t type);
108 
109     ImageFileDirectory(sk_sp<SkData> data,
110                        bool littleEndian,
111                        uint32_t offset,
112                        uint16_t ifdNumEntries,
113                        uint32_t ifdNextOffset);
114 
115     /*
116      * Return the tag, type, count, and data for the specified entry. Return false if the type
117      * is invalid, or if the data in the IFD is out of bounds.
118      */
119     bool getEntryRawData(uint16_t entryIndex,
120                          uint16_t* outTag,
121                          uint16_t* outType,
122                          uint32_t* outCount,
123                          const uint8_t** outData,
124                          size_t* outDataSize) const;
125 
126     /*
127      * Helper function for assorted getTag functions.
128      */
129     bool getEntryValuesGeneric(uint16_t entryIndex,
130                                uint16_t type,
131                                uint32_t count,
132                                void* values) const;
133 
134     // The data that the IFD indexes into.
135     const sk_sp<SkData> fData;
136 
137     // True if the data is little endian.
138     const bool fLittleEndian;
139 
140     // The offset where the IFD starts.
141     const uint32_t fOffset;
142 
143     // The number of entries of the IFD (read from the first 2 bytes at the IFD offset).
144     const uint16_t fNumEntries;
145 
146     // The offset of the next IFD (read from the next 4 bytes after the IFD entries).
147     const uint32_t fNextIfdOffset;
148 };
149 
150 }  // namespace SkTiff
151 
152 #endif
153