• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 /*
40  * Helper function for parsing a Tiff Image File Directory (IFD) structure. This structure is used
41  * by EXIF tags, multi-picture, and maker note metadata.
42  */
43 class ImageFileDirectory {
44 public:
45     /*
46      * Parse |data| to read the endian-ness into |outLittleEndian| and the IFD offset into
47      * |outIfdOffset|. Return true if the endian-ness was successfully parsed and there was
48      * the IFD offset was read.
49      */
50     static bool ParseHeader(const SkData* data, bool* outLittleEndian, uint32_t* outIfdOffset);
51 
52     /*
53      * Create an object for parsing an IFD at offset |ifdOffset| inside |data| which has endianness
54      * indicated by |littleEndian|. If |allowTruncated| is true, then parse as much of |data| as is
55      * possible, otherwise reject any incomplete IFDs.
56      */
57     static std::unique_ptr<ImageFileDirectory> MakeFromOffset(sk_sp<SkData> data,
58                                                               bool littleEndian,
59                                                               uint32_t ifdOffset,
60                                                               bool allowTruncated = false);
61 
62     /*
63      * Return the number of entries.
64      */
getNumEntries()65     uint16_t getNumEntries() const { return fNumEntries; }
66 
67     /*
68      * Return the offset (within the specified SkData) of the next IFD in the list of IFDs.
69      */
nextIfdOffset()70     uint32_t nextIfdOffset() const { return fNextIfdOffset; }
71 
72     /*
73      * Return the tag, of a specific entry.
74      */
75     uint16_t getEntryTag(uint16_t entryIndex) const;
76 
77     /*
78      * If |entryIndex| has type unsigned short (3), unsigned long (4), or signed rational (10), and
79      * count |count|, then populate |values| with the data for the tag and return true. Otherwise
80      * return false.
81      */
getEntryUnsignedShort(uint16_t entryIndex,uint32_t count,uint16_t * values)82     bool getEntryUnsignedShort(uint16_t entryIndex, uint32_t count, uint16_t* values) const {
83         return getEntryValuesGeneric(entryIndex, kTypeUnsignedShort, count, values);
84     }
getEntryUnsignedLong(uint16_t entryIndex,uint32_t count,uint32_t * values)85     bool getEntryUnsignedLong(uint16_t entryIndex, uint32_t count, uint32_t* values) const {
86         return getEntryValuesGeneric(entryIndex, kTypeUnsignedLong, count, values);
87     }
getEntrySignedRational(uint16_t entryIndex,uint32_t count,float * values)88     bool getEntrySignedRational(uint16_t entryIndex, uint32_t count, float* values) const {
89         return getEntryValuesGeneric(entryIndex, kTypeSignedRational, count, values);
90     }
getEntryUnsignedRational(uint16_t entryIndex,uint32_t count,float * values)91     bool getEntryUnsignedRational(uint16_t entryIndex, uint32_t count, float* values) const {
92         return getEntryValuesGeneric(entryIndex, kTypeUnsignedRational, count, values);
93     }
94 
95     /*
96      * If |entryIndex| has type undefined (7), then return the bytes specified by the count field
97      * and the offset (read from the value field as an unsigned long).
98      */
99     sk_sp<SkData> getEntryUndefinedData(uint16_t entryIndex) const;
100 
101 private:
102     static bool IsValidType(uint16_t type);
103     static size_t BytesForType(uint16_t type);
104 
105     ImageFileDirectory(sk_sp<SkData> data,
106                        bool littleEndian,
107                        uint32_t offset,
108                        uint16_t ifdNumEntries,
109                        uint32_t ifdNextOffset);
110 
111     /*
112      * Return the tag, type, count, and data for the specified entry. Return false if the type
113      * is invalid, or if the data in the IFD is out of bounds.
114      */
115     bool getEntryRawData(uint16_t entryIndex,
116                          uint16_t* outTag,
117                          uint16_t* outType,
118                          uint32_t* outCount,
119                          const uint8_t** outData,
120                          size_t* outDataSize) const;
121 
122     /*
123      * Helper function for assorted getTag functions.
124      */
125     bool getEntryValuesGeneric(uint16_t entryIndex,
126                                uint16_t type,
127                                uint32_t count,
128                                void* values) const;
129 
130     // The data that the IFD indexes into.
131     const sk_sp<SkData> fData;
132 
133     // True if the data is little endian.
134     const bool fLittleEndian;
135 
136     // The offset where the IFD starts.
137     const uint32_t fOffset;
138 
139     // The number of entries of the IFD (read from the first 2 bytes at the IFD offset).
140     const uint16_t fNumEntries;
141 
142     // The offset of the next IFD (read from the next 4 bytes after the IFD entries).
143     const uint32_t fNextIfdOffset;
144 };
145 
146 }  // namespace SkTiff
147 
148 #endif
149