diff options
| author | Přemysl Eric Janouch <p@janouch.name> | 2023-05-23 02:09:15 +0200 | 
|---|---|---|
| committer | Přemysl Eric Janouch <p@janouch.name> | 2023-05-26 15:32:34 +0200 | 
| commit | bb4b895cb5938712bd09fbd2b5f49bea811d7551 (patch) | |
| tree | 586902190b9fe52b1c6cb14309b852267fc9ee1e /tools | |
| parent | 0f1c61ae3325dda14be8f98ee7047ac5eda02108 (diff) | |
| download | fiv-bb4b895cb5938712bd09fbd2b5f49bea811d7551.tar.gz fiv-bb4b895cb5938712bd09fbd2b5f49bea811d7551.tar.xz fiv-bb4b895cb5938712bd09fbd2b5f49bea811d7551.zip  | |
Extract some full-size raw previews without LibRaw
Not all image/x-nikon-nef will work like this,
so don't claim their MIME type.
Diffstat (limited to 'tools')
| -rw-r--r-- | tools/info.h | 363 | 
1 files changed, 23 insertions, 340 deletions
diff --git a/tools/info.h b/tools/info.h index 28cfb36..8dcd3d2 100644 --- a/tools/info.h +++ b/tools/info.h @@ -21,348 +21,10 @@  #include <stdlib.h>  #include <string.h> -// --- Utilities --------------------------------------------------------------- - -static char * -binhex(const uint8_t *data, size_t len) -{ -	static const char *alphabet = "0123456789abcdef"; -	char *buf = calloc(1, len * 2 + 1), *p = buf; -	for (size_t i = 0; i < len; i++) { -		*p++ = alphabet[data[i] >> 4]; -		*p++ = alphabet[data[i] & 0xF]; -	} -	return buf; -} - -static uint64_t -u64be(const uint8_t *p) -{ -	return (uint64_t) p[0] << 56 | (uint64_t) p[1] << 48 | -		(uint64_t) p[2] << 40 | (uint64_t) p[3] << 32 | -		(uint64_t) p[4] << 24 | p[5] << 16 | p[6] << 8 | p[7]; -} - -static uint32_t -u32be(const uint8_t *p) -{ -	return (uint32_t) p[0] << 24 | p[1] << 16 | p[2] << 8 | p[3]; -} - -static uint16_t -u16be(const uint8_t *p) -{ -	return (uint16_t) p[0] << 8 | p[1]; -} - -static uint64_t -u64le(const uint8_t *p) -{ -	return (uint64_t) p[7] << 56 | (uint64_t) p[6] << 48 | -		(uint64_t) p[5] << 40 | (uint64_t) p[4] << 32 | -		(uint64_t) p[3] << 24 | p[2] << 16 | p[1] << 8 | p[0]; -} - -static uint32_t -u32le(const uint8_t *p) -{ -	return (uint32_t) p[3] << 24 | p[2] << 16 | p[1] << 8 | p[0]; -} - -static uint16_t -u16le(const uint8_t *p) -{ -	return (uint16_t) p[1] << 8 | p[0]; -} - -// --- TIFF -------------------------------------------------------------------- -// libtiff is a mess, and the format is not particularly complicated. -// Exiv2 is senselessly copylefted, and cannot do much. -// libexif is only marginally better. -// ExifTool is too user-oriented. - -static struct un { -	uint64_t (*u64) (const uint8_t *); -	uint32_t (*u32) (const uint8_t *); -	uint16_t (*u16) (const uint8_t *); -} unbe = {u64be, u32be, u16be}, unle = {u64le, u32le, u16le}; - -struct tiffer { -	struct un *un; -	const uint8_t *begin, *p, *end; -	uint16_t remaining_fields; -}; - -static bool -tiffer_u32(struct tiffer *self, uint32_t *u) -{ -	if (self->p < self->begin || self->p + 4 > self->end) -		return false; - -	*u = self->un->u32(self->p); -	self->p += 4; -	return true; -} - -static bool -tiffer_u16(struct tiffer *self, uint16_t *u) -{ -	if (self->p < self->begin || self->p + 2 > self->end) -		return false; - -	*u = self->un->u16(self->p); -	self->p += 2; -	return true; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -static bool -tiffer_init(struct tiffer *self, const uint8_t *tiff, size_t len) -{ -	self->un = NULL; -	self->begin = self->p = tiff; -	self->end = tiff + len; -	self->remaining_fields = 0; - -	const uint8_t -		le[4] = {'I', 'I', 42, 0}, -		be[4] = {'M', 'M', 0, 42}; - -	if (tiff + 8 > self->end) -		return false; -	else if (!memcmp(tiff, le, sizeof le)) -		self->un = &unle; -	else if (!memcmp(tiff, be, sizeof be)) -		self->un = &unbe; -	else -		return false; - -	self->p = tiff + 4; -	// The first IFD needs to be read by caller explicitly, -	// even though it's required to be present by TIFF 6.0. -	return true; -} - -/// Read the next IFD in a sequence. -static bool -tiffer_next_ifd(struct tiffer *self) -{ -	// All fields from any previous IFD need to be read first. -	if (self->remaining_fields) -		return false; - -	uint32_t ifd_offset = 0; -	if (!tiffer_u32(self, &ifd_offset)) -		return false; - -	// There is nothing more to read, this chain has terminated. -	if (!ifd_offset) -		return false; - -	// Note that TIFF 6.0 requires there to be at least one entry, -	// but there is no need for us to check it. -	self->p = self->begin + ifd_offset; -	return tiffer_u16(self, &self->remaining_fields); -} - -/// Initialize a derived TIFF reader for a subIFD at the given location. -static bool -tiffer_subifd(struct tiffer *self, uint32_t offset, struct tiffer *subreader) -{ -	*subreader = *self; -	subreader->p = subreader->begin + offset; -	return tiffer_u16(subreader, &subreader->remaining_fields); -} - -enum tiffer_type { -	BYTE = 1, ASCII, SHORT, LONG, RATIONAL, -	SBYTE, UNDEFINED, SSHORT, SLONG, SRATIONAL, FLOAT, DOUBLE, -	IFD  // This last type from TIFF Technical Note 1 isn't really used much. -}; - -static size_t -tiffer_value_size(enum tiffer_type type) -{ -	switch (type) { -	case BYTE: -	case SBYTE: -	case ASCII: -	case UNDEFINED: -		return 1; -	case SHORT: -	case SSHORT: -		return 2; -	case LONG: -	case SLONG: -	case FLOAT: -	case IFD: -		return 4; -	case RATIONAL: -	case SRATIONAL: -	case DOUBLE: -		return 8; -	default: -		return 0; -	} -} - -/// A lean iterator for values within entries. -struct tiffer_entry { -	uint16_t tag; -	enum tiffer_type type; -	// For {S,}BYTE, ASCII, UNDEFINED, use these fields directly. -	const uint8_t *p; -	uint32_t remaining_count; -}; - -static bool -tiffer_next_value(struct tiffer_entry *entry) -{ -	if (!entry->remaining_count) -		return false; - -	entry->p += tiffer_value_size(entry->type); -	entry->remaining_count--; -	return true; -} - -static bool -tiffer_integer( -	const struct tiffer *self, const struct tiffer_entry *entry, int64_t *out) -{ -	if (!entry->remaining_count) -		return false; - -	// Somewhat excessively lenient, intended for display. -	// TIFF 6.0 only directly suggests that a reader is should accept -	// any of BYTE/SHORT/LONG for unsigned integers. -	switch (entry->type) { -	case BYTE: -	case ASCII: -	case UNDEFINED: -		*out = *entry->p; -		return true; -	case SBYTE: -		*out = (int8_t) *entry->p; -		return true; -	case SHORT: -		*out = self->un->u16(entry->p); -		return true; -	case SSHORT: -		*out = (int16_t) self->un->u16(entry->p); -		return true; -	case LONG: -	case IFD: -		*out = self->un->u32(entry->p); -		return true; -	case SLONG: -		*out = (int32_t) self->un->u32(entry->p); -		return true; -	default: -		return false; -	} -} - -static bool -tiffer_rational(const struct tiffer *self, const struct tiffer_entry *entry, -	int64_t *numerator, int64_t *denominator) -{ -	if (!entry->remaining_count) -		return false; - -	// Somewhat excessively lenient, intended for display. -	switch (entry->type) { -	case RATIONAL: -		*numerator = self->un->u32(entry->p); -		*denominator = self->un->u32(entry->p + 4); -		return true; -	case SRATIONAL: -		*numerator = (int32_t) self->un->u32(entry->p); -		*denominator = (int32_t) self->un->u32(entry->p + 4); -		return true; -	default: -		if (tiffer_integer(self, entry, numerator)) { -			*denominator = 1; -			return true; -		} -		return false; -	} -} - -static bool -tiffer_real( -	const struct tiffer *self, const struct tiffer_entry *entry, double *out) -{ -	if (!entry->remaining_count) -		return false; - -	// Somewhat excessively lenient, intended for display. -	// Assuming the host architecture uses IEEE 754. -	switch (entry->type) { -		int64_t numerator, denominator; -	case FLOAT: -		*out = *(float *) entry->p; -		return true; -	case DOUBLE: -		*out = *(double *) entry->p; -		return true; -	default: -		if (tiffer_rational(self, entry, &numerator, &denominator)) { -			*out = (double) numerator / denominator; -			return true; -		} -		return false; -	} -} - -static bool -tiffer_next_entry(struct tiffer *self, struct tiffer_entry *entry) -{ -	if (!self->remaining_fields) -		return false; - -	uint16_t type = entry->type = 0xFFFF; -	if (!tiffer_u16(self, &entry->tag) || !tiffer_u16(self, &type) || -		!tiffer_u32(self, &entry->remaining_count)) -		return false; - -	// Short values may and will be inlined, rather than pointed to. -	size_t values_size = tiffer_value_size(type) * entry->remaining_count; -	uint32_t offset = 0; -	if (values_size <= sizeof offset) { -		entry->p = self->p; -		self->p += sizeof offset; -	} else if (tiffer_u32(self, &offset)) { -		entry->p = self->begin + offset; -	} else { -		return false; -	} - -	// All entries are pre-checked not to overflow. -	if (entry->p + values_size > self->end) -		return false; - -	// Setting it at the end may provide an indication while debugging. -	entry->type = type; -	self->remaining_fields--; -	return true; -} - -// --- TIFF/Exif tags ---------------------------------------------------------- - -struct tiff_value { -	const char *name; -	uint16_t value; -}; - -struct tiff_entry { -	const char *name; -	uint16_t tag; -	struct tiff_value *values; -}; +// --- TIFF/Exif ---------------------------------------------------------------  #include "tiff-tables.h" +#include "tiffer.h"  // TODO(p): Consider if these can't be inlined into `tiff_entries`.  static struct { @@ -376,6 +38,27 @@ static struct {  	{}  }; +// --- Utilities --------------------------------------------------------------- + +#define u64be tiffer_u64be +#define u32be tiffer_u32be +#define u16be tiffer_u16be +#define u64le tiffer_u64le +#define u32le tiffer_u32le +#define u16le tiffer_u16le + +static char * +binhex(const uint8_t *data, size_t len) +{ +	static const char *alphabet = "0123456789abcdef"; +	char *buf = calloc(1, len * 2 + 1), *p = buf; +	for (size_t i = 0; i < len; i++) { +		*p++ = alphabet[data[i] >> 4]; +		*p++ = alphabet[data[i] & 0xF]; +	} +	return buf; +} +  // --- Analysis ----------------------------------------------------------------  static jv  | 
