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