Main read functions return boolean
This commit is contained in:
		| @@ -62,49 +62,29 @@ struct strip_data_field { | |||||||
|   u16 type_byte_count; |   u16 type_byte_count; | ||||||
| }; | }; | ||||||
|  |  | ||||||
| internal void read_tiff_header(TiffReader *reader); | internal bool read_tiff_header(TiffReader *reader); | ||||||
| internal void read_ifd(TiffReader *reader, Arena *arena); | internal bool read_ifd(TiffReader *reader, Arena *arena); | ||||||
| internal void read_ifd_fields(TiffReader *reader); | internal bool read_ifd_fields(TiffReader *reader); | ||||||
| internal void read_alpha(TiffReader *reader); | internal void read_alpha(TiffReader *reader); | ||||||
| internal void read_bits_per_sample(TiffReader *reader); | internal void read_bits_per_sample(TiffReader *reader); | ||||||
| internal void read_image_pixels(TiffReader *reader, Arena *arena); | internal bool read_image_pixels(TiffReader *reader, Arena *arena); | ||||||
| internal bool read_strip_data(TiffReader *reader, Arena *arena); | internal bool read_strip_data(TiffReader *reader, Arena *arena); | ||||||
| internal void read_strips(TiffReader *reader); | internal void read_strips(TiffReader *reader); | ||||||
| internal void read_strip_data_field(const TiffReader *reader, | internal void read_strip_data_field(const TiffReader *reader, | ||||||
|                                     StripDataField *field); |                                     StripDataField *field); | ||||||
| internal bool read_field(const TiffField *field, TiffImage *img); | internal bool read_field(const TiffField *field, TiffImage *img); | ||||||
| internal bool validate_image_type(const TiffImage *img); | internal bool validate_image_type(const TiffImage *img); | ||||||
| internal void read_from_file_with_offset(FILE *fp, void *dst, u64 count, | internal void fread_with_offset(FILE *fp, void *dst, u64 count, u64 offset); | ||||||
|                                          u64 offset); | internal bool valid_tiff_file(const char *file); | ||||||
|  |  | ||||||
| Image *read_baseline_tiff(const char *file, Arena *arena) { | Image *read_baseline_tiff(const char *file, Arena *arena) { | ||||||
|   Image *img_out = NULL; |   Image *img_out = NULL; | ||||||
|  |  | ||||||
|   if (!file || !arena) { |   if (!file || !arena || !valid_tiff_file(file)) { | ||||||
|     goto READ_BASELINE_RETURN_IMG; |     goto READ_BASELINE_RETURN_IMG; | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   u64 name_length = strlen(file); |   TiffReader reader = {.fp = fopen(file, "rb")}; | ||||||
|   if (name_length < TIFF_FILENAME_MIN_LENGTH) { |  | ||||||
|     goto READ_BASELINE_RETURN_IMG; |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   const char *ext = NULL; |  | ||||||
|   for (u32 i = name_length - 1; i >= name_length - TIFF_FILENAME_MIN_LENGTH; |  | ||||||
|        --i) { |  | ||||||
|     if (file[i] == '.') { |  | ||||||
|       ext = &(file[i]); |  | ||||||
|       break; |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   if (!ext || !IS_TIFF_EXTENSION(ext)) { |  | ||||||
|     goto READ_BASELINE_RETURN_IMG; |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   TiffReader reader = {0}; |  | ||||||
|  |  | ||||||
|   reader.fp = fopen(file, "rb"); |  | ||||||
|   if (!reader.fp) { |   if (!reader.fp) { | ||||||
|     goto READ_BASELINE_RETURN_IMG; |     goto READ_BASELINE_RETURN_IMG; | ||||||
|   } |   } | ||||||
| @@ -114,18 +94,15 @@ Image *read_baseline_tiff(const char *file, Arena *arena) { | |||||||
|     goto READ_BASELINE_FILE_CLEANUP; |     goto READ_BASELINE_FILE_CLEANUP; | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   read_tiff_header(&reader); |   if (!read_tiff_header(&reader)) { | ||||||
|   if (IS_NULL_HEADER(reader.header)) { |  | ||||||
|     goto READ_BASELINE_DESTROY_ARENA; |     goto READ_BASELINE_DESTROY_ARENA; | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   read_ifd(&reader, temp_arena); |   if (!read_ifd(&reader, temp_arena)) { | ||||||
|   if (IS_NULL_IFD(reader.ifd)) { |  | ||||||
|     goto READ_BASELINE_DESTROY_ARENA; |     goto READ_BASELINE_DESTROY_ARENA; | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   read_ifd_fields(&reader); |   if (!read_ifd_fields(&reader)) { | ||||||
|   if (IS_NULL_IMAGE(reader.img)) { |  | ||||||
|     goto READ_BASELINE_DESTROY_ARENA; |     goto READ_BASELINE_DESTROY_ARENA; | ||||||
|   } |   } | ||||||
|  |  | ||||||
| @@ -139,8 +116,7 @@ Image *read_baseline_tiff(const char *file, Arena *arena) { | |||||||
|        reader.img.rgba_bits_per_sample.a == MIN_BITS_PER_SAMPLE); |        reader.img.rgba_bits_per_sample.a == MIN_BITS_PER_SAMPLE); | ||||||
|   assert(image_is_8_bit && "Currently, only 8-bit images are supported"); |   assert(image_is_8_bit && "Currently, only 8-bit images are supported"); | ||||||
|  |  | ||||||
|   read_image_pixels(&reader, temp_arena); |   if (!read_image_pixels(&reader, temp_arena)) { | ||||||
|   if (!reader.pixels) { |  | ||||||
|     goto READ_BASELINE_DESTROY_ARENA; |     goto READ_BASELINE_DESTROY_ARENA; | ||||||
|   } |   } | ||||||
|  |  | ||||||
| @@ -157,9 +133,9 @@ READ_BASELINE_RETURN_IMG: | |||||||
|   return img_out; |   return img_out; | ||||||
| } | } | ||||||
|  |  | ||||||
| internal void read_tiff_header(TiffReader *reader) { | internal bool read_tiff_header(TiffReader *reader) { | ||||||
|   reader->header = NULL_TIFF_HEADER; |   reader->header = NULL_TIFF_HEADER; | ||||||
|   read_from_file_with_offset(reader->fp, &(reader->header), sizeof(TiffHdr), 0); |   fread_with_offset(reader->fp, &(reader->header), sizeof(TiffHdr), 0); | ||||||
|  |  | ||||||
|   switch (reader->header.order) { |   switch (reader->header.order) { | ||||||
|   case TIFF_ORDER_LITTLE_ENDIAN: |   case TIFF_ORDER_LITTLE_ENDIAN: | ||||||
| @@ -177,19 +153,20 @@ internal void read_tiff_header(TiffReader *reader) { | |||||||
|  |  | ||||||
|     break; |     break; | ||||||
|   default: |   default: | ||||||
|     reader->header = NULL_TIFF_HEADER; |     return false; | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   if (reader->header.magic != TIFF_MAGIC) { |   if (reader->header.magic != TIFF_MAGIC) { | ||||||
|     reader->header = NULL_TIFF_HEADER; |     return false; | ||||||
|   } |   } | ||||||
|  |  | ||||||
|  |   return true; | ||||||
| } | } | ||||||
|  |  | ||||||
| internal void read_ifd(TiffReader *reader, Arena *arena) { | internal bool read_ifd(TiffReader *reader, Arena *arena) { | ||||||
|   reader->ifd = NULL_TIFF_IFD; |   reader->ifd = NULL_TIFF_IFD; | ||||||
|   read_from_file_with_offset(reader->fp, &(reader->ifd.count), |   fread_with_offset(reader->fp, &(reader->ifd.count), sizeof(reader->ifd.count), | ||||||
|                              sizeof(reader->ifd.count), |                     reader->header.first_ifd_offset); | ||||||
|                              reader->header.first_ifd_offset); |  | ||||||
|  |  | ||||||
|   switch (reader->header.order) { |   switch (reader->header.order) { | ||||||
|   case TIFF_ORDER_LITTLE_ENDIAN: |   case TIFF_ORDER_LITTLE_ENDIAN: | ||||||
| @@ -210,14 +187,16 @@ internal void read_ifd(TiffReader *reader, Arena *arena) { | |||||||
|   reader->ifd.fields = |   reader->ifd.fields = | ||||||
|       (TiffField *)wapp_mem_arena_alloc(arena, field_byte_count); |       (TiffField *)wapp_mem_arena_alloc(arena, field_byte_count); | ||||||
|   if (!(reader->ifd.fields)) { |   if (!(reader->ifd.fields)) { | ||||||
|     reader->ifd = NULL_TIFF_IFD; |     return false; | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   fread(reader->ifd.fields, field_byte_count, 1, reader->fp); |   fread(reader->ifd.fields, field_byte_count, 1, reader->fp); | ||||||
|   fread(&(reader->ifd.next_ifd), sizeof(reader->ifd.next_ifd), 1, reader->fp); |   fread(&(reader->ifd.next_ifd), sizeof(reader->ifd.next_ifd), 1, reader->fp); | ||||||
|  |  | ||||||
|  |   return true; | ||||||
| } | } | ||||||
|  |  | ||||||
| internal void read_ifd_fields(TiffReader *reader) { | internal bool read_ifd_fields(TiffReader *reader) { | ||||||
|   reader->img = NULL_TIFF_IMAGE; |   reader->img = NULL_TIFF_IMAGE; | ||||||
|   reader->img.type = TIFF_IMAGE_TYPE_BILEVEL; |   reader->img.type = TIFF_IMAGE_TYPE_BILEVEL; | ||||||
|  |  | ||||||
| @@ -256,14 +235,12 @@ internal void read_ifd_fields(TiffReader *reader) { | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     if (!read_field(field, &(reader->img))) { |     if (!read_field(field, &(reader->img))) { | ||||||
|       reader->img = NULL_TIFF_IMAGE; |       return false; | ||||||
|       return; |  | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   if (!validate_image_type(&(reader->img))) { |   if (!validate_image_type(&(reader->img))) { | ||||||
|     reader->img = NULL_TIFF_IMAGE; |     return false; | ||||||
|     return; |  | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   read_alpha(reader); |   read_alpha(reader); | ||||||
| @@ -282,23 +259,24 @@ internal void read_ifd_fields(TiffReader *reader) { | |||||||
|   printf("STRIP BYTES (byte count, is offset)           :   %u, %u\n", reader->img.strip_byte_counts.long_val, reader->img.strip_byte_counts_offset); |   printf("STRIP BYTES (byte count, is offset)           :   %u, %u\n", reader->img.strip_byte_counts.long_val, reader->img.strip_byte_counts_offset); | ||||||
|   // clang-format on |   // clang-format on | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
|  |   return true; | ||||||
| } | } | ||||||
|  |  | ||||||
| internal void read_alpha(TiffReader *reader) { | internal void read_alpha(TiffReader *reader) { | ||||||
|   reader->img.alpha = NULL_TIFF_ALPHA; |   reader->img.alpha = NULL_TIFF_ALPHA; | ||||||
|   u16 samples[reader->img.extra_samples_count]; |  | ||||||
|  |  | ||||||
|   if (reader->img.extra_samples_count == 0) { |   if (reader->img.extra_samples_count == 0) { | ||||||
|     reader->img.alpha = NULL_TIFF_ALPHA; |  | ||||||
|     return; |     return; | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   u64 byte_count = TIFF_SHORT_BYTE_COUNT * reader->img.extra_samples_count; |   u64 byte_count = TIFF_SHORT_BYTE_COUNT * reader->img.extra_samples_count; | ||||||
|  |   u16 samples[reader->img.extra_samples_count]; | ||||||
|   memset(samples, 0, byte_count); |   memset(samples, 0, byte_count); | ||||||
|  |  | ||||||
|   if (reader->img.extra_samples_offset) { |   if (reader->img.extra_samples_offset) { | ||||||
|     read_from_file_with_offset(reader->fp, samples, byte_count, |     fread_with_offset(reader->fp, samples, byte_count, | ||||||
|                                reader->img.extra_samples); |                       reader->img.extra_samples); | ||||||
|  |  | ||||||
|     switch (reader->header.order) { |     switch (reader->header.order) { | ||||||
|     case TIFF_ORDER_BIG_ENDIAN: |     case TIFF_ORDER_BIG_ENDIAN: | ||||||
| @@ -342,8 +320,8 @@ internal void read_bits_per_sample(TiffReader *reader) { | |||||||
|   memset(bits_per_sample, 0, byte_count); |   memset(bits_per_sample, 0, byte_count); | ||||||
|  |  | ||||||
|   if (reader->img.bits_per_sample_offset) { |   if (reader->img.bits_per_sample_offset) { | ||||||
|     read_from_file_with_offset(reader->fp, bits_per_sample, byte_count, |     fread_with_offset(reader->fp, bits_per_sample, byte_count, | ||||||
|                                reader->img.bits_per_sample); |                       reader->img.bits_per_sample); | ||||||
|  |  | ||||||
|     switch (reader->header.order) { |     switch (reader->header.order) { | ||||||
|     case TIFF_ORDER_BIG_ENDIAN: |     case TIFF_ORDER_BIG_ENDIAN: | ||||||
| @@ -391,13 +369,13 @@ internal void read_bits_per_sample(TiffReader *reader) { | |||||||
|   bits->a = bits->a < MIN_BITS_PER_SAMPLE ? MIN_BITS_PER_SAMPLE : bits->a; |   bits->a = bits->a < MIN_BITS_PER_SAMPLE ? MIN_BITS_PER_SAMPLE : bits->a; | ||||||
| } | } | ||||||
|  |  | ||||||
| internal void read_image_pixels(TiffReader *reader, Arena *arena) { | internal bool read_image_pixels(TiffReader *reader, Arena *arena) { | ||||||
|   reader->pixels = NULL; |   reader->pixels = NULL; | ||||||
|   u64 img_byte_count = |   u64 img_byte_count = | ||||||
|       sizeof(Pixel) * reader->img.image_width * reader->img.image_length; |       sizeof(Pixel) * reader->img.image_width * reader->img.image_length; | ||||||
|  |  | ||||||
|   if (!read_strip_data(reader, arena)) { |   if (!read_strip_data(reader, arena)) { | ||||||
|     return; |     return false; | ||||||
|   } |   } | ||||||
|  |  | ||||||
| #ifdef DEBUG | #ifdef DEBUG | ||||||
| @@ -409,10 +387,12 @@ internal void read_image_pixels(TiffReader *reader, Arena *arena) { | |||||||
|  |  | ||||||
|   reader->pixels = wapp_mem_arena_alloc(arena, img_byte_count); |   reader->pixels = wapp_mem_arena_alloc(arena, img_byte_count); | ||||||
|   if (!reader->pixels) { |   if (!reader->pixels) { | ||||||
|     return; |     return false; | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   read_strips(reader); |   read_strips(reader); | ||||||
|  |  | ||||||
|  |   return true; | ||||||
| } | } | ||||||
|  |  | ||||||
| internal bool read_strip_data(TiffReader *reader, Arena *arena) { | internal bool read_strip_data(TiffReader *reader, Arena *arena) { | ||||||
| @@ -478,12 +458,12 @@ internal void read_strips(TiffReader *reader) { | |||||||
|       start_offset = strip->offset + j * reader->img.sample_count; |       start_offset = strip->offset + j * reader->img.sample_count; | ||||||
|       alpha_offset = start_offset + main_samples + alpha.sample_offset; |       alpha_offset = start_offset + main_samples + alpha.sample_offset; | ||||||
|  |  | ||||||
|       read_from_file_with_offset(reader->fp, p, main_samples, start_offset); |       fread_with_offset(reader->fp, p, main_samples, start_offset); | ||||||
|  |  | ||||||
|       if (alpha.type == ALPHA_TYPE_UNDEFINED) { |       if (alpha.type == ALPHA_TYPE_UNDEFINED) { | ||||||
|         p->a = 255; |         p->a = 255; | ||||||
|       } else { |       } else { | ||||||
|         read_from_file_with_offset(reader->fp, &(p->a), 1, alpha_offset); |         fread_with_offset(reader->fp, &(p->a), 1, alpha_offset); | ||||||
|       } |       } | ||||||
|  |  | ||||||
|       ++position; |       ++position; | ||||||
| @@ -505,9 +485,8 @@ internal void read_strip_data_field(const TiffReader *reader, | |||||||
|     return; |     return; | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   read_from_file_with_offset(reader->fp, field->strip_value, |   fread_with_offset(reader->fp, field->strip_value, field->type_byte_count, | ||||||
|                              field->type_byte_count, |                     field->value_from_file->long_val + offset); | ||||||
|                              field->value_from_file->long_val + offset); |  | ||||||
|  |  | ||||||
|   switch (reader->header.order) { |   switch (reader->header.order) { | ||||||
|   case TIFF_ORDER_BIG_ENDIAN: |   case TIFF_ORDER_BIG_ENDIAN: | ||||||
| @@ -699,8 +678,7 @@ internal bool validate_image_type(const TiffImage *img) { | |||||||
|   return true; |   return true; | ||||||
| } | } | ||||||
|  |  | ||||||
| internal void read_from_file_with_offset(FILE *fp, void *dst, u64 count, | internal void fread_with_offset(FILE *fp, void *dst, u64 count, u64 offset) { | ||||||
|                                          u64 offset) { |  | ||||||
|   if (!fp || !dst) { |   if (!fp || !dst) { | ||||||
|     return; |     return; | ||||||
|   } |   } | ||||||
| @@ -709,3 +687,25 @@ internal void read_from_file_with_offset(FILE *fp, void *dst, u64 count, | |||||||
|  |  | ||||||
|   fread(dst, count, 1, fp); |   fread(dst, count, 1, fp); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | internal bool valid_tiff_file(const char *file) { | ||||||
|  |   u64 name_length = strlen(file); | ||||||
|  |   if (name_length < TIFF_FILENAME_MIN_LENGTH) { | ||||||
|  |     return false; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   const char *ext = NULL; | ||||||
|  |   for (u32 i = name_length - 1; i >= name_length - TIFF_FILENAME_MIN_LENGTH; | ||||||
|  |        --i) { | ||||||
|  |     if (file[i] == '.') { | ||||||
|  |       ext = &(file[i]); | ||||||
|  |       break; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   if (!ext || !IS_TIFF_EXTENSION(ext)) { | ||||||
|  |     return false; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   return true; | ||||||
|  | } | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user