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