blob: 2c310507316b804e42a7a04d04160d6a36794dc5 [file] [log] [blame]
/*
* Copyright 2023 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef SkTiffUtility_codec_DEFINED
#define SkTiffUtility_codec_DEFINED
#include "include/core/SkData.h"
#include "include/core/SkRefCnt.h"
#include <cstddef>
#include <cstdint>
#include <memory>
namespace SkTiff {
// Constants for endian signature.
inline constexpr size_t kEndianSize = 4;
inline constexpr uint8_t kEndianBig[kEndianSize] = {'M', 'M', 0, 42};
inline constexpr uint8_t kEndianLittle[kEndianSize] = {'I', 'I', 42, 0};
// Constants for types.
inline constexpr uint16_t kTypeUnsignedByte = 1;
inline constexpr uint16_t kTypeAsciiString = 2;
inline constexpr uint16_t kTypeUnsignedShort = 3;
inline constexpr uint16_t kTypeUnsignedLong = 4;
inline constexpr uint16_t kTypeUnsignedRational = 5;
inline constexpr uint16_t kTypeSignedByte = 6;
inline constexpr uint16_t kTypeUndefined = 7;
inline constexpr uint16_t kTypeSignedShort = 8;
inline constexpr uint16_t kTypeSignedLong = 9;
inline constexpr uint16_t kTypeSignedRational = 10;
inline constexpr uint16_t kTypeSingleFloat = 11;
inline constexpr uint16_t kTypeDoubleFloat = 12;
/*
* Helper function for parsing a Tiff Image File Directory (IFD) structure. This structure is used
* by EXIF tags, multi-picture, and maker note metadata.
*/
class ImageFileDirectory {
public:
/*
* Parse |data| to read the endian-ness into |outLittleEndian| and the IFD offset into
* |outIfdOffset|. Return true if the endian-ness was successfully parsed and there was
* the IFD offset was read.
*/
static bool ParseHeader(const SkData* data, bool* outLittleEndian, uint32_t* outIfdOffset);
/*
* Create an object for parsing an IFD at offset |ifdOffset| inside |data| which has endianness
* indicated by |littleEndian|. If |allowTruncated| is true, then parse as much of |data| as is
* possible, otherwise reject any incomplete IFDs.
*/
static std::unique_ptr<ImageFileDirectory> MakeFromOffset(sk_sp<SkData> data,
bool littleEndian,
uint32_t ifdOffset,
bool allowTruncated = false);
/*
* Return the number of entries.
*/
uint16_t getNumEntries() const { return fNumEntries; }
/*
* Return the offset (within the specified SkData) of the next IFD in the list of IFDs.
*/
uint32_t nextIfdOffset() const { return fNextIfdOffset; }
/*
* Return the tag, of a specific entry.
*/
uint16_t getEntryTag(uint16_t entryIndex) const;
/*
* If |entryIndex| has type unsigned short (3), unsigned long (4), or signed rational (10), and
* count |count|, then populate |values| with the data for the tag and return true. Otherwise
* return false.
*/
bool getEntryUnsignedShort(uint16_t entryIndex, uint32_t count, uint16_t* values) const {
return getEntryValuesGeneric(entryIndex, kTypeUnsignedShort, count, values);
}
bool getEntryUnsignedLong(uint16_t entryIndex, uint32_t count, uint32_t* values) const {
return getEntryValuesGeneric(entryIndex, kTypeUnsignedLong, count, values);
}
bool getEntrySignedRational(uint16_t entryIndex, uint32_t count, float* values) const {
return getEntryValuesGeneric(entryIndex, kTypeSignedRational, count, values);
}
bool getEntryUnsignedRational(uint16_t entryIndex, uint32_t count, float* values) const {
return getEntryValuesGeneric(entryIndex, kTypeUnsignedRational, count, values);
}
/*
* If |entryIndex| has type undefined (7), then return the bytes specified by the count field
* and the offset (read from the value field as an unsigned long).
*/
sk_sp<SkData> getEntryUndefinedData(uint16_t entryIndex) const;
private:
static bool IsValidType(uint16_t type);
static size_t BytesForType(uint16_t type);
ImageFileDirectory(sk_sp<SkData> data,
bool littleEndian,
uint32_t offset,
uint16_t ifdNumEntries,
uint32_t ifdNextOffset);
/*
* Return the tag, type, count, and data for the specified entry. Return false if the type
* is invalid, or if the data in the IFD is out of bounds.
*/
bool getEntryRawData(uint16_t entryIndex,
uint16_t* outTag,
uint16_t* outType,
uint32_t* outCount,
const uint8_t** outData,
size_t* outDataSize) const;
/*
* Helper function for assorted getTag functions.
*/
bool getEntryValuesGeneric(uint16_t entryIndex,
uint16_t type,
uint32_t count,
void* values) const;
// The data that the IFD indexes into.
const sk_sp<SkData> fData;
// True if the data is little endian.
const bool fLittleEndian;
// The offset where the IFD starts.
const uint32_t fOffset;
// The number of entries of the IFD (read from the first 2 bytes at the IFD offset).
const uint16_t fNumEntries;
// The offset of the next IFD (read from the next 4 bytes after the IFD entries).
const uint32_t fNextIfdOffset;
};
} // namespace SkTiff
#endif