add app0 loading

This commit is contained in:
Lauchmelder 2022-10-28 21:13:54 +02:00
parent 75c9fc23b2
commit af827f2c7f
5 changed files with 158 additions and 24 deletions

View file

@ -3,7 +3,7 @@
#
cmake_minimum_required (VERSION 3.8)
project ("jpeg-dissect")
project ("jpeg-dissect" C)
# Include sub-projects.
add_subdirectory ("src")

View file

@ -3,4 +3,6 @@
add_executable (jpeg-dissect
"main.c"
"loader.c"
"util.h")
)
set_property(TARGET jpeg-dissect PROPERTY C_STANDARD 11)

View file

@ -1,39 +1,61 @@
#include "loader.h"
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <memory.h>
#include <assert.h>
#include "util.h"
#define memzero(buffer, size) memset(buffer, 0, size)
static int load_segment(FILE* fp);
static int load_segment(JPEG* jpeg, FILE* fp);
static int load_rst_segment(FILE* fp, uint8_t n);
static int load_app_segment(FILE* fp, uint8_t n);
static int load_rst_segment(JPEG* jpeg, FILE* fp, uint8_t n);
static int load_app_segment(JPEG* jpeg, FILE* fp, uint8_t n);
static int load_app0_segment(FILE* fp);
static int load_app0_segment(JPEG* jpeg, FILE* fp);
int load_jpeg(const char* filename)
JPEG* load_jpeg(const char* filename)
{
FILE* fp = fopen(filename, "r");
if (fp == NULL)
{
return 1;
return NULL;
}
JPEG* jpeg = (JPEG*)malloc(sizeof(jpeg));
memzero(jpeg, sizeof(JPEG));
while (!feof(fp))
{
if (load_segment(fp) != 0)
if (load_segment(jpeg, fp) != 0)
{
fprintf(stderr, "Segment loading failed\n");
return 1;
free_jpeg(jpeg);
return NULL;
}
}
fclose(fp);
return 0;
return jpeg;
}
int load_segment(FILE* fp)
void free_jpeg(JPEG* jpeg)
{
if (jpeg == NULL)
return;
if (jpeg->app0)
{
if (jpeg->app0->thumbnail_data)
{
free(jpeg->app0->thumbnail_data);
}
free(jpeg->app0);
}
}
int load_segment(JPEG* jpeg, FILE* fp)
{
uint8_t segment_marker[2];
size_t segment_marker_size = sizeof(segment_marker);
@ -53,14 +75,14 @@ int load_segment(FILE* fp)
// Handle special APPn/RSTn markers
if (segment_marker[1] >= 0xD0 && segment_marker[1] <= 0xD7)
{
if (load_rst_segment(fp, segment_marker[1] | 0x0F) != 0)
if (load_rst_segment(jpeg, fp, segment_marker[1] | 0x0F) != 0)
{
return 1;
}
}
else if ((segment_marker[1] & 0xF0) == 0xE0)
{
if (load_app_segment(fp, segment_marker[1] & 0x0F) != 0)
if (load_app_segment(jpeg, fp, segment_marker[1] & 0x0F) != 0)
{
return 1;
}
@ -82,19 +104,19 @@ int load_segment(FILE* fp)
return 0;
}
int load_rst_segment(FILE* fp, uint8_t n)
int load_rst_segment(JPEG* jpeg, FILE* fp, uint8_t n)
{
DEBUG_LOG("RST%d marker encountered", n);
return 1;
}
int load_app_segment(FILE* fp, uint8_t n)
int load_app_segment(JPEG* jpeg, FILE* fp, uint8_t n)
{
DEBUG_LOG("APP%d marker encountered", n);
switch (n)
{
case 0: return load_app0_segment();
case 0: return load_app0_segment(jpeg, fp);
default:
fprintf(stderr, "Unknown APP segment ID %d\n", n);
@ -104,7 +126,68 @@ int load_app_segment(FILE* fp, uint8_t n)
return 0;
}
int load_app0_segment(FILE* fp)
int load_app0_segment(JPEG* jpeg, FILE* fp)
{
if (jpeg->app0 != NULL)
{
fprintf(stderr, "Found more than one APP0 marker\n");
return 1;
}
assert(fp);
jpeg->app0 = (JFIFAPP0Segment*)malloc(sizeof(JFIFAPP0Segment));
memzero(jpeg->app0, sizeof(JFIFAPP0Segment));
if (jpeg->app0 == NULL)
{
fprintf(stderr, "Failed to allocate memory for APP0 header\n");
return 1;
}
// Extract header without thumbnail data
size_t jfif_header_size = sizeof(JFIFAPP0Segment) - sizeof(uint8_t*);
if (fread(jpeg->app0, sizeof(uint8_t), jfif_header_size, fp) != jfif_header_size)
{
fprintf(stderr, "Incomplete APP0 header\n");
return 1;
}
jpeg->app0->length = bswap_16(jpeg->app0->length);
jpeg->app0->density_x = bswap_16(jpeg->app0->density_x);
jpeg->app0->density_y = bswap_16(jpeg->app0->density_y);
size_t thumbnail_data_size = jpeg->app0->thumbnail_x * jpeg->app0->thumbnail_y;
if (thumbnail_data_size > 0)
{
jpeg->app0->thumbnail_data = (uint8_t*)malloc(thumbnail_data_size * sizeof(uint8_t));
if (jpeg->app0->thumbnail_data == NULL)
{
fprintf(stderr, "Failed to allocate memory for thumbnail data\n");
return 1;
}
if (fread(jpeg->app0->thumbnail_data, sizeof(uint8_t), thumbnail_data_size, fp) != thumbnail_data_size)
{
fprintf(stderr, "Incomplete thumbnail data\n");
return 1;
}
}
DEBUG_LOG(
"JFIFAPP0Segment\n"
"length = %u\n"
"identifier = %s\n"
"version = %u.%02u\n"
"density units = %u\n"
"density x, y = %u, %u\n"
"thumbnail x, y = %u, %u",
jpeg->app0->length,
jpeg->app0->identifier,
jpeg->app0->version.major, jpeg->app0->version.minor,
jpeg->app0->density_units,
jpeg->app0->density_x, jpeg->app0->density_y,
jpeg->app0->thumbnail_x, jpeg->app0->thumbnail_y
);
return 0;
}

View file

@ -1,6 +1,37 @@
#ifndef _LODAER_H
#define _LOADER_H
int load_jpeg(const char* filename);
#include <stdint.h>
#include "util.h"
PACK (
typedef struct JFIFAPP0Segment
{
uint16_t length;
const char identifier[5];
struct {
uint8_t major;
uint8_t minor;
} version;
uint8_t density_units;
uint16_t density_x;
uint16_t density_y;
uint8_t thumbnail_x;
uint8_t thumbnail_y;
uint8_t* thumbnail_data;
} JFIFAPP0Segment;
)
typedef struct JPEG
{
JFIFAPP0Segment* app0;
} JPEG;
JPEG* load_jpeg(const char* filename);
void free_jpeg(JPEG* jpeg);
#endif // _LOADER_H

View file

@ -6,7 +6,25 @@
#ifdef NDEBUG
#define DEBUG_LOG
#else
#define DEBUG_LOG(msg, ...) printf("[DEBUG] " ##msg "\n", __VA_ARGS__);
#define DEBUG_LOG(...) printf("[DEBUG] "); printf(__VA_ARGS__); printf("\n")
#endif
#if defined(__GNUC__)
#define PACK( data ) data __attribute((__packed__))
#include <byteswap.h>
#define bswap_16 bswap_16
#define bswap_32 bswap_32
#define bswap_64 bswap_64
#elif defined(_MSC_VER)
#define PACK( data ) __pragma(pack(push, 1)) data __pragma(pack(pop))
#include <stdlib.h>
#define bswap_16 _byteswap_ushort
#define bswap_32 _byteswap_ulong
#define bswap_64 _byteswap_uint64
#endif
#endif // _UTIL_H