196 lines
4.7 KiB
C
196 lines
4.7 KiB
C
|
// x-run: gcc % -o main -g && ./main /home/hkc/images/wallpapers/photo_2020-09-18_10-05-14.jpg
|
||
|
|
||
|
#include <endian.h>
|
||
|
#include <stdio.h>
|
||
|
#include <stdint.h>
|
||
|
#include <stdlib.h>
|
||
|
#include <string.h>
|
||
|
#include <errno.h>
|
||
|
#include <ctype.h>
|
||
|
#define HEXDUMP_RAINBOW
|
||
|
#define HEXDUMP_PRINTABLE
|
||
|
#define HEXDUMP_IMPLEMENTATION
|
||
|
#include "./hexdump.h"
|
||
|
|
||
|
typedef uint16_t marker_t;
|
||
|
|
||
|
typedef enum {
|
||
|
SOF0 = 0xFFC0, // Baseline DCT
|
||
|
SOF1 = 0xFFC1, // Extended seq DCT
|
||
|
SOF2 = 0xFFC2, // Progressive DCT
|
||
|
SOF3 = 0xFFC3, // Lossless
|
||
|
DHT = 0xFFC4, // Define Huffman Table
|
||
|
SOF5 = 0xFFC5, //
|
||
|
SOF6 = 0xFFC6,
|
||
|
SOF7 = 0xFFC7,
|
||
|
JPG = 0xFFC8,
|
||
|
SOF9 = 0xFFC9,
|
||
|
SOF10 = 0xFFCA,
|
||
|
SOF11 = 0xFFCB,
|
||
|
DAC = 0xFFCC,
|
||
|
SOF13 = 0xFFCD,
|
||
|
SOF14 = 0xFFCE,
|
||
|
SOF15 = 0xFFCF,
|
||
|
|
||
|
|
||
|
} marker_type_t;
|
||
|
|
||
|
struct JFIF_SOF0_Component {
|
||
|
uint8_t id;
|
||
|
uint8_t TODO_0 : 4;
|
||
|
uint8_t TODO_1 : 4;
|
||
|
} __attribute__((packed));
|
||
|
|
||
|
struct JFIF_SOF0 {
|
||
|
uint16_t bit_depth;
|
||
|
uint16_t height;
|
||
|
uint8_t width;
|
||
|
uint8_t n_components;
|
||
|
struct JFIF_SOF0_Component *components;
|
||
|
} __attribute__((packed));
|
||
|
|
||
|
#define panic(...) { \
|
||
|
fprintf(stderr, "!PANIC! at %s:%d\n", __FILE__, __LINE__);\
|
||
|
fprintf(stderr, __VA_ARGS__); \
|
||
|
fprintf(stderr, "\nerrno=%d (%s)\n", errno, strerror(errno)); \
|
||
|
abort(); \
|
||
|
}
|
||
|
|
||
|
marker_t read_and_print_block(FILE *fp);
|
||
|
const char *marker_name(int marker);
|
||
|
|
||
|
int main(int argc, char **argv) {
|
||
|
static uint8_t tmp[8192];
|
||
|
FILE *fp = fopen(argv[1], "rb");
|
||
|
fread(tmp, 1, 2, fp);
|
||
|
if (memcmp(tmp, "\xFF\xD8", 2)) {
|
||
|
panic("Invalid header!");
|
||
|
}
|
||
|
|
||
|
marker_t last_marker;
|
||
|
do {
|
||
|
last_marker = read_and_print_block(fp);
|
||
|
} while (last_marker != 0xFFD9);
|
||
|
}
|
||
|
|
||
|
|
||
|
marker_t read_and_print_block(FILE *fp) {
|
||
|
static uint8_t buffer[65536];
|
||
|
marker_t marker;
|
||
|
uint16_t length;
|
||
|
|
||
|
long int pos = ftell(fp);
|
||
|
|
||
|
fread(&marker, sizeof(marker_t), 1, fp);
|
||
|
marker = be16toh(marker);
|
||
|
|
||
|
if ((marker & 0xFF00) != 0xFF00) {
|
||
|
printf("!!!!!!!!\n");
|
||
|
fseek(fp, pos & ~0xF, SEEK_SET);
|
||
|
fread(buffer, 1, 32, fp);
|
||
|
hexdump(buffer, 32);
|
||
|
panic("Invalid marker %04x at %ld (0x%lx)", marker, pos, pos);
|
||
|
}
|
||
|
|
||
|
if (marker == 0xFFD9) return marker;
|
||
|
|
||
|
fread(&length, sizeof(uint16_t), 1, fp);
|
||
|
length = be16toh(length) - 2;
|
||
|
printf("marker: %04x %8s (%d long) at %ld %lx\n", marker, marker_name(marker), length, pos, pos);
|
||
|
|
||
|
fread(buffer, 1, length, fp);
|
||
|
|
||
|
switch (marker) {
|
||
|
case SOF0:
|
||
|
printf("\033[91mSTART OF FRAME\033[0m\n");
|
||
|
hexdump(buffer, length);
|
||
|
break;
|
||
|
|
||
|
case 0xFFDA: // Start Of Scan
|
||
|
{
|
||
|
uint8_t n_components = buffer[0];
|
||
|
uint8_t *cur = &buffer[1];
|
||
|
|
||
|
printf("components: %d\n", n_components);
|
||
|
for (uint8_t i = 0; i < n_components; i++) {
|
||
|
uint8_t selector = *cur++,
|
||
|
tables = *cur++;
|
||
|
printf("\t%d: %d in %d/%d\n", i, selector, tables >> 4, tables & 0xf);
|
||
|
}
|
||
|
uint8_t spectral_selector_start = *cur++,
|
||
|
spectral_selector_end = *cur++,
|
||
|
successive_approx = *cur++;
|
||
|
printf("spectral selector: %d..%d\n", spectral_selector_start, spectral_selector_end);
|
||
|
|
||
|
int n_read = -1;
|
||
|
do {
|
||
|
n_read++;
|
||
|
fread(&buffer[n_read], 1, 1, fp);
|
||
|
} while (!(buffer[n_read - 1] == 0xFF && (buffer[n_read] & 0xF0) == 0xF0));
|
||
|
printf("stopped after %d bytes\n", n_read);
|
||
|
hexdump(buffer, n_read);
|
||
|
fseek(fp, ftell(fp) - 1, SEEK_SET);
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case 0xFFDB: // Quantization table
|
||
|
{
|
||
|
uint8_t destination = buffer[0];
|
||
|
printf("\tdestination: %d\n", destination);
|
||
|
for (int y = 0; y < 8; y++) {
|
||
|
printf("\t");
|
||
|
for (int x = 0; x < 8; x++) {
|
||
|
printf("%3d ", buffer[1 + x + y * 8]);
|
||
|
}
|
||
|
printf("\n");
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case 0xFFE0: // APP*
|
||
|
case 0xFFE1:
|
||
|
case 0xFFE2:
|
||
|
case 0xFFE3:
|
||
|
case 0xFFE4:
|
||
|
case 0xFFE5:
|
||
|
case 0xFFE6:
|
||
|
case 0xFFE7:
|
||
|
case 0xFFE8:
|
||
|
case 0xFFE9:
|
||
|
case 0xFFEA:
|
||
|
case 0xFFEB:
|
||
|
case 0xFFEC:
|
||
|
case 0xFFED:
|
||
|
case 0xFFEE:
|
||
|
case 0xFFEF:
|
||
|
break;
|
||
|
default:
|
||
|
hexdump(buffer, length);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
return marker;
|
||
|
}
|
||
|
|
||
|
const char *marker_name(int marker) {
|
||
|
switch (marker) {
|
||
|
case SOF0: return " SOF0";
|
||
|
case SOF1: return " SOF1";
|
||
|
case SOF2: return " SOF2";
|
||
|
case SOF3: return " SOF3";
|
||
|
case DHT: return " DHT";
|
||
|
case SOF5: return " SOF5";
|
||
|
case SOF6: return " SOF6";
|
||
|
case SOF7: return " SOF7";
|
||
|
case JPG: return " JPG";
|
||
|
case SOF9: return " SOF9";
|
||
|
case SOF10: return "SOF10";
|
||
|
case SOF11: return "SOF11";
|
||
|
case DAC: return " DAC";
|
||
|
case SOF13: return "SOF13";
|
||
|
case SOF14: return "SOF14";
|
||
|
case SOF15: return "SOF15";
|
||
|
default: return "N/A";
|
||
|
}
|
||
|
}
|