Refactor read_fields function

This commit is contained in:
Abdelrahman Said 2024-04-30 22:17:17 +01:00
parent e371ca7160
commit d508af1809

View File

@ -35,6 +35,10 @@
TiffHdr read_tiff_header(FILE *fp); TiffHdr read_tiff_header(FILE *fp);
TiffIFD read_ifd(FILE *fp, const TiffHdr *header, u32 offset, Arena *arena); TiffIFD read_ifd(FILE *fp, const TiffHdr *header, u32 offset, Arena *arena);
TiffImage read_fields(FILE *fp, const TiffHdr *header, const TiffIFD *ifd); TiffImage read_fields(FILE *fp, const TiffHdr *header, const TiffIFD *ifd);
bool read_field(const TiffField *field, TiffImage *img,
u32 *image_type_identifier);
bool validate_image_type(const TiffImage *img,
const u32 *image_type_identifier);
void read_from_file_with_offset(FILE *fp, void *dst, u64 count, u64 offset); void read_from_file_with_offset(FILE *fp, void *dst, u64 count, u64 offset);
Image *read_baseline_tiff(const char *file, Arena *arena) { Image *read_baseline_tiff(const char *file, Arena *arena) {
@ -195,172 +199,13 @@ TiffImage read_fields(FILE *fp, const TiffHdr *header, const TiffIFD *ifd) {
break; break;
} }
switch (field->tag) { if (!read_field(field, &img_out, &image_type_identifier)) {
case TIFF_PUBLIC_TAG_IMAGE_WIDTH:
if (field->count > 1) {
img_out = NULL_TIFF_IMAGE; img_out = NULL_TIFF_IMAGE;
goto READ_FIELDS_RETURN_IMAGE; goto READ_FIELDS_RETURN_IMAGE;
} }
img_out.image_width = field->value_offset;
break;
case TIFF_PUBLIC_TAG_IMAGE_LENGTH:
if (field->count > 1) {
img_out = NULL_TIFF_IMAGE;
goto READ_FIELDS_RETURN_IMAGE;
} }
img_out.image_length = field->value_offset; if (!validate_image_type(&img_out, &image_type_identifier)) {
break;
case TIFF_PUBLIC_TAG_BITS_PER_SAMPLE:
image_type_identifier |= field->tag;
if (img_out.sample_count == INVALID_SAMPLE_COUNT) {
img_out.sample_count = field->count;
} else if (img_out.sample_count != field->count) {
img_out = NULL_TIFF_IMAGE;
goto READ_FIELDS_RETURN_IMAGE;
}
img_out.bits_per_sample = field->value_offset;
img_out.bits_per_sample_offset =
img_out.sample_count * field_types[field->type].byte_count > 4;
break;
case TIFF_PUBLIC_TAG_COMPRESSION:
if (field->count > 1 ||
field->value_offset != TIFF_COMPRESSION_UNCOMPRESSED) {
img_out = NULL_TIFF_IMAGE;
goto READ_FIELDS_RETURN_IMAGE;
}
img_out.compression = field->value_offset;
break;
case TIFF_PUBLIC_TAG_PHOTOMETRIC_INTERPRETATION:
if (field->count > 1) {
img_out = NULL_TIFF_IMAGE;
goto READ_FIELDS_RETURN_IMAGE;
}
img_out.photometric_interpretation = field->value_offset;
break;
case TIFF_PUBLIC_TAG_STRIP_OFFSETS:
img_out.strip_offsets = field->value_offset;
if (img_out.strip_count == INVALID_STRIP_COUNT) {
img_out.strip_count = field->count;
} else if (img_out.strip_count != field->count) {
img_out = NULL_TIFF_IMAGE;
goto READ_FIELDS_RETURN_IMAGE;
}
img_out.strip_offsets_offset =
img_out.strip_count * field_types[field->type].byte_count > 4;
break;
case TIFF_PUBLIC_TAG_SAMPLES_PER_PIXEL:
image_type_identifier |= field->tag;
if (field->count > 1) {
img_out = NULL_TIFF_IMAGE;
goto READ_FIELDS_RETURN_IMAGE;
}
img_out.sample_count = field->value_offset;
break;
case TIFF_PUBLIC_TAG_ROWS_PER_STRIP:
if (field->count > 1) {
img_out = NULL_TIFF_IMAGE;
goto READ_FIELDS_RETURN_IMAGE;
}
img_out.rows_per_strip = field->value_offset;
if (img_out.image_length > 0) {
img_out.strip_count =
floor((f64)(img_out.image_length + img_out.rows_per_strip - 1) /
img_out.rows_per_strip);
} else {
img_out.strip_count = INVALID_STRIP_COUNT;
}
break;
case TIFF_PUBLIC_TAG_STRIP_BYTE_COUNTS:
img_out.strip_byte_counts = field->value_offset;
if (img_out.strip_count == INVALID_STRIP_COUNT) {
img_out.strip_count = field->count;
} else if (img_out.strip_count != field->count) {
img_out = NULL_TIFF_IMAGE;
goto READ_FIELDS_RETURN_IMAGE;
}
img_out.strip_byte_counts_offset =
img_out.strip_count * field_types[field->type].byte_count > 4;
break;
case TIFF_PUBLIC_TAG_COLOR_MAP:
image_type_identifier |= field->tag;
break;
case TIFF_PUBLIC_TAG_EXTRA_SAMPLES:
img_out.extra_samples_count = field->count;
img_out.extra_samples = field->value_offset;
img_out.extra_samples_offset =
img_out.extra_samples_count * field_types[field->type].byte_count > 4;
break;
case TIFF_PUBLIC_TAG_PLANAR_CONFIGURATION:
if (field->count > 1 ||
field->value_offset != TIFF_PLANAR_CONFIG_CHUNKY) {
img_out = NULL_TIFF_IMAGE;
goto READ_FIELDS_RETURN_IMAGE;
}
break;
}
}
if (image_type_identifier < TIFF_IMAGE_TYPE_BILEVEL ||
image_type_identifier > TIFF_IMAGE_TYPE_RGB) {
img_out = NULL_TIFF_IMAGE;
goto READ_FIELDS_RETURN_IMAGE;
}
switch (image_type_identifier) {
case TIFF_IMAGE_TYPE_BILEVEL:
case TIFF_IMAGE_TYPE_GRAYSCALE:
if (img_out.photometric_interpretation >
TIFF_PHOTOMETRIC_INTERPRETATION_BLACK_IS_ZERO) {
img_out = NULL_TIFF_IMAGE;
goto READ_FIELDS_RETURN_IMAGE;
}
break;
case TIFF_IMAGE_TYPE_PALETTE:
if (img_out.photometric_interpretation !=
TIFF_PHOTOMETRIC_INTERPRETATION_RGB_PALETTE) {
img_out = NULL_TIFF_IMAGE;
goto READ_FIELDS_RETURN_IMAGE;
}
break;
case TIFF_IMAGE_TYPE_RGB:
if (img_out.photometric_interpretation !=
TIFF_PHOTOMETRIC_INTERPRETATION_RGB) {
img_out = NULL_TIFF_IMAGE;
goto READ_FIELDS_RETURN_IMAGE;
}
break;
default:
img_out = NULL_TIFF_IMAGE; img_out = NULL_TIFF_IMAGE;
goto READ_FIELDS_RETURN_IMAGE; goto READ_FIELDS_RETURN_IMAGE;
} }
@ -384,6 +229,169 @@ READ_FIELDS_RETURN_IMAGE:
return img_out; return img_out;
} }
bool read_field(const TiffField *field, TiffImage *img,
u32 *image_type_identifier) {
switch (field->tag) {
case TIFF_PUBLIC_TAG_IMAGE_WIDTH:
if (field->count > 1) {
return false;
}
img->image_width = field->value_offset;
break;
case TIFF_PUBLIC_TAG_IMAGE_LENGTH:
if (field->count > 1) {
return false;
}
img->image_length = field->value_offset;
break;
case TIFF_PUBLIC_TAG_BITS_PER_SAMPLE:
*image_type_identifier |= field->tag;
if (img->sample_count == INVALID_SAMPLE_COUNT) {
img->sample_count = field->count;
} else if (img->sample_count != field->count) {
return false;
}
img->bits_per_sample = field->value_offset;
img->bits_per_sample_offset =
img->sample_count * field_types[field->type].byte_count > 4;
break;
case TIFF_PUBLIC_TAG_COMPRESSION:
if (field->count > 1 ||
field->value_offset != TIFF_COMPRESSION_UNCOMPRESSED) {
return false;
}
img->compression = field->value_offset;
break;
case TIFF_PUBLIC_TAG_PHOTOMETRIC_INTERPRETATION:
if (field->count > 1) {
return false;
}
img->photometric_interpretation = field->value_offset;
break;
case TIFF_PUBLIC_TAG_STRIP_OFFSETS:
img->strip_offsets = field->value_offset;
if (img->strip_count == INVALID_STRIP_COUNT) {
img->strip_count = field->count;
} else if (img->strip_count != field->count) {
return false;
}
img->strip_offsets_offset =
img->strip_count * field_types[field->type].byte_count > 4;
break;
case TIFF_PUBLIC_TAG_SAMPLES_PER_PIXEL:
*image_type_identifier |= field->tag;
if (field->count > 1) {
return false;
}
img->sample_count = field->value_offset;
break;
case TIFF_PUBLIC_TAG_ROWS_PER_STRIP:
if (field->count > 1) {
return false;
}
img->rows_per_strip = field->value_offset;
if (img->image_length > 0) {
img->strip_count =
floor((f64)(img->image_length + img->rows_per_strip - 1) /
img->rows_per_strip);
} else {
img->strip_count = INVALID_STRIP_COUNT;
}
break;
case TIFF_PUBLIC_TAG_STRIP_BYTE_COUNTS:
img->strip_byte_counts = field->value_offset;
if (img->strip_count == INVALID_STRIP_COUNT) {
img->strip_count = field->count;
} else if (img->strip_count != field->count) {
return false;
}
img->strip_byte_counts_offset =
img->strip_count * field_types[field->type].byte_count > 4;
break;
case TIFF_PUBLIC_TAG_COLOR_MAP:
*image_type_identifier |= field->tag;
break;
case TIFF_PUBLIC_TAG_EXTRA_SAMPLES:
img->extra_samples_count = field->count;
img->extra_samples = field->value_offset;
img->extra_samples_offset =
img->extra_samples_count * field_types[field->type].byte_count > 4;
break;
case TIFF_PUBLIC_TAG_PLANAR_CONFIGURATION:
if (field->count > 1 || field->value_offset != TIFF_PLANAR_CONFIG_CHUNKY) {
return false;
}
break;
}
return true;
}
bool validate_image_type(const TiffImage *img,
const u32 *image_type_identifier) {
if (*image_type_identifier < TIFF_IMAGE_TYPE_BILEVEL ||
*image_type_identifier > TIFF_IMAGE_TYPE_RGB) {
return false;
}
switch (*image_type_identifier) {
case TIFF_IMAGE_TYPE_BILEVEL:
case TIFF_IMAGE_TYPE_GRAYSCALE:
if (img->photometric_interpretation >
TIFF_PHOTOMETRIC_INTERPRETATION_BLACK_IS_ZERO) {
return false;
}
break;
case TIFF_IMAGE_TYPE_PALETTE:
if (img->photometric_interpretation !=
TIFF_PHOTOMETRIC_INTERPRETATION_RGB_PALETTE) {
return false;
}
break;
case TIFF_IMAGE_TYPE_RGB:
if (img->photometric_interpretation !=
TIFF_PHOTOMETRIC_INTERPRETATION_RGB) {
return false;
}
break;
default:
return false;
}
return true;
}
void read_from_file_with_offset(FILE *fp, void *dst, u64 count, u64 offset) { void read_from_file_with_offset(FILE *fp, void *dst, u64 count, u64 offset) {
if (!fp || !dst) { if (!fp || !dst) {
return; return;