2017-01-03 22:31:09 +01:00
|
|
|
/* jpeg parser by tom szymanski */
|
|
|
|
#include <stddef.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <math.h>
|
2020-09-10 22:38:28 +02:00
|
|
|
#include <jehanne/ctype.h>
|
2017-01-03 22:31:09 +01:00
|
|
|
|
|
|
|
/* subroutines done by macros */
|
|
|
|
#define min(A,B) ((A)<(B) ? (A) : (B))
|
|
|
|
#define max(A,B) ((A)>(B) ? (A) : (B))
|
|
|
|
#define maxeql(A,B) if (A < (B)) A = (B);
|
|
|
|
#define mineql(A,B) if (A > (B)) A = (B);
|
|
|
|
#define eatarg0 (argc--, argv++)
|
|
|
|
#define arrayLength(A) ((sizeof A)/ (sizeof A[0]))
|
|
|
|
|
|
|
|
FILE *infile;
|
|
|
|
char *fname;
|
|
|
|
|
|
|
|
/* Routines to print error messages of varying severity */
|
|
|
|
|
|
|
|
/* externally visible variables */
|
|
|
|
int warncnt;
|
|
|
|
char *myname;
|
|
|
|
|
|
|
|
void getname (char *arg) {
|
|
|
|
/* Save name of invoking program for use by error routines */
|
|
|
|
register char *p;
|
|
|
|
p = strrchr (arg, '/');
|
|
|
|
if (p == NULL)
|
|
|
|
myname = arg;
|
|
|
|
else
|
|
|
|
myname = ++p;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void introduction (void) {
|
|
|
|
warncnt++;
|
|
|
|
fflush (stdout);
|
|
|
|
if (myname != NULL)
|
|
|
|
fprintf (stderr, "%s: ", myname);
|
|
|
|
}
|
|
|
|
|
|
|
|
void warn (char *fmt, ...) {
|
|
|
|
va_list args;
|
|
|
|
introduction ();
|
|
|
|
va_start (args, fmt);
|
|
|
|
vfprintf (stderr, fmt, args);
|
|
|
|
va_end (args);
|
|
|
|
fputc ('\n', stderr);
|
|
|
|
fflush (stderr);
|
|
|
|
}
|
|
|
|
|
|
|
|
void quit (char *fmt, ...) {
|
|
|
|
va_list args;
|
|
|
|
introduction ();
|
|
|
|
va_start (args, fmt);
|
|
|
|
vfprintf (stderr, fmt, args);
|
|
|
|
va_end (args);
|
|
|
|
fputc ('\n', stderr);
|
|
|
|
fflush (stderr);
|
|
|
|
exit (1);
|
|
|
|
}
|
|
|
|
|
|
|
|
void fatal (char *fmt, ...) {
|
|
|
|
va_list args;
|
|
|
|
introduction ();
|
|
|
|
va_start (args, fmt);
|
|
|
|
vfprintf (stderr, fmt, args);
|
|
|
|
va_end (args);
|
|
|
|
fprintf (stderr, "\nbetter get help!\n");
|
|
|
|
fflush (stderr);
|
|
|
|
abort ();
|
|
|
|
}
|
|
|
|
|
|
|
|
int toption = 0;
|
|
|
|
int dqt[16][64];
|
|
|
|
|
|
|
|
int get1 (void) {
|
|
|
|
unsigned char x;
|
|
|
|
if (fread(&x, 1, 1, infile) == 0)
|
|
|
|
quit ("unexpected EOF");
|
|
|
|
return x;
|
|
|
|
}
|
|
|
|
|
|
|
|
int get2 (void) {
|
|
|
|
int x;
|
|
|
|
|
|
|
|
x = get1() << 8;
|
|
|
|
return x | get1();
|
|
|
|
}
|
|
|
|
|
|
|
|
void eatmarker (int kind) {
|
|
|
|
int l, c;
|
|
|
|
l = get2();
|
|
|
|
printf ("%02x len=%d\n", kind, l);
|
|
|
|
for (l -= 2; l > 0; l--)
|
|
|
|
get1();
|
|
|
|
}
|
|
|
|
|
|
|
|
char *sofName[16] = {
|
|
|
|
"Baseline sequential DCT - Huffman coding",
|
|
|
|
"Extended sequential DCT - Huffman coding",
|
|
|
|
"Progressive DCT - Huffman coding",
|
|
|
|
"Lossless - Huffman coding",
|
|
|
|
"4 is otherwise used",
|
|
|
|
"Sequential DCT - differential Huffman coding",
|
|
|
|
"Progressive DCT - differential Huffman coding",
|
|
|
|
"Lossless - differential Huffman coding",
|
|
|
|
"8 is reserved",
|
|
|
|
"Extended Sequential DCT - arithmetic coding",
|
|
|
|
"Progressive DCT - arithmetic coding",
|
|
|
|
"Lossless - arithmetic coding",
|
|
|
|
"c is otherwise used",
|
|
|
|
"Sequential DCT - differential arithmetic coding",
|
|
|
|
"Progressive DCT - differential arithmetic coding",
|
|
|
|
"Lossless - differential arithmetic coding",
|
|
|
|
};
|
|
|
|
|
|
|
|
void get_sof (int kind) {
|
|
|
|
int i, length, height, width, precision, ncomponents;
|
|
|
|
int id, sf, tab;
|
|
|
|
length = get2();
|
|
|
|
precision = get1();
|
|
|
|
height = get2();
|
|
|
|
width = get2();
|
|
|
|
ncomponents = get1();
|
|
|
|
printf ("SOF%d:\t%s\n", kind - 0xc0, sofName[kind - 0xc0]);
|
|
|
|
printf ("\t%d wide, %d high, %d deep, %d components\n",
|
|
|
|
width, height, precision, ncomponents);
|
|
|
|
for (i = 0; i < ncomponents; i++) {
|
|
|
|
id = get1();
|
|
|
|
sf = get1();
|
|
|
|
tab = get1();
|
|
|
|
printf ("\tcomponent %d: %d hsample, %d vsample, quantization table %d\n",
|
|
|
|
id, sf >> 4, sf & 0xf, tab);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void get_com (int kind) {
|
|
|
|
int l, c;
|
|
|
|
l = get2();
|
|
|
|
printf ("COM len=%d '", l);
|
|
|
|
for (l -= 2; l > 0; l--)
|
|
|
|
putchar (c = get1());
|
|
|
|
printf ("'\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
void get_app (int kind) {
|
|
|
|
int l, c, first;
|
|
|
|
char buf[6];
|
|
|
|
int nbuf, nok;
|
|
|
|
l = get2();
|
|
|
|
printf ("APP%d len=%d\n", kind - 0xe0, l);
|
|
|
|
nbuf = 0;
|
|
|
|
nok = 0;
|
|
|
|
first = 1;
|
|
|
|
/* dump printable strings in comment */
|
|
|
|
for (l -= 2; l > 0; l--){
|
|
|
|
c = get1();
|
|
|
|
if(isprint(c)){
|
|
|
|
if(nbuf >= sizeof buf){
|
|
|
|
if(!first && nbuf == nok)
|
|
|
|
printf(" ");
|
|
|
|
printf("%.*s", nbuf, buf);
|
|
|
|
nbuf = 0;
|
|
|
|
first = 0;
|
|
|
|
}
|
|
|
|
buf[nbuf++] = c;
|
|
|
|
nok++;
|
|
|
|
}else{
|
|
|
|
if(nok >= sizeof buf)
|
|
|
|
if(nbuf > 0)
|
|
|
|
printf("%.*s", nbuf, buf);
|
|
|
|
nbuf = 0;
|
|
|
|
nok = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if(nok >= sizeof buf)
|
|
|
|
if(nbuf > 0){
|
|
|
|
if(!first && nbuf == nok)
|
|
|
|
printf(" ");
|
|
|
|
printf("%.*s", nbuf, buf);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void get_dac (int kind) {
|
|
|
|
eatmarker (kind);
|
|
|
|
}
|
|
|
|
|
|
|
|
int get1dqt (void) {
|
|
|
|
int t, p, i, *tab;
|
|
|
|
t = get1();
|
|
|
|
p = t >> 4;
|
|
|
|
t = t & 0xf;
|
|
|
|
printf ("DQT:\tp = %d, table = %d\n", p, t);
|
|
|
|
tab = &dqt[t][0];
|
|
|
|
for (i = 0; i < 64; i++)
|
|
|
|
tab[i] = p ? get2() : get1();
|
|
|
|
if (toption) {
|
|
|
|
for (i = 0; i < 64; i++)
|
|
|
|
printf ("\t%q[%02d] = %d\n", i, tab[i]);
|
|
|
|
}
|
|
|
|
return p ? 65 : 129;
|
|
|
|
}
|
|
|
|
|
|
|
|
void get_dqt (int kind) {
|
|
|
|
int length;
|
|
|
|
length = get2() - 2;
|
|
|
|
while (length > 0)
|
|
|
|
length -= get1dqt();
|
|
|
|
}
|
|
|
|
|
|
|
|
int get1dht (void) {
|
|
|
|
int l, tcth, p, i, j, v[16], vv[16][256];
|
|
|
|
tcth = get1();
|
|
|
|
printf ("DHT:\tclass = %d, table = %d\n", tcth >> 4, tcth & 0xf);
|
|
|
|
for (i = 0; i < 16; i++)
|
|
|
|
v[i] = get1();
|
|
|
|
l = 17;
|
|
|
|
for (i = 0; i < 16; i++)
|
|
|
|
for (j = 0; j < v[i]; j++) {
|
|
|
|
vv[i][j] = get1();
|
|
|
|
l += 1;
|
|
|
|
}
|
|
|
|
if (toption) {
|
|
|
|
for (i = 0; i < 16; i++)
|
|
|
|
printf ("\t%l[%02d] = %d\n", i+1, v[i]);
|
|
|
|
for (i = 0; i < 16; i++)
|
|
|
|
for (j = 0; j < v[i]; j++)
|
|
|
|
printf ("\t%v[%02d,%02d] = %d\n", i+1, j+1, vv[i][j]);
|
|
|
|
}
|
|
|
|
return l;
|
|
|
|
}
|
|
|
|
|
|
|
|
void get_dht (int kind) {
|
|
|
|
int length;
|
|
|
|
length = get2() - 2;
|
|
|
|
while (length > 0)
|
|
|
|
length -= get1dht();
|
|
|
|
}
|
|
|
|
|
|
|
|
void get_sos (int kind) {
|
|
|
|
int i, length, ncomponents, id, dcac, ahal;
|
|
|
|
length = get2();
|
|
|
|
ncomponents = get1();
|
|
|
|
printf ("SOS:\t%d components\n", ncomponents);
|
|
|
|
for (i = 0; i < ncomponents; i++) {
|
|
|
|
id = get1();
|
|
|
|
dcac = get1();
|
|
|
|
printf ("\tcomponent %d: %d DC, %d AC\n", id, dcac >> 4, dcac & 0xf);
|
|
|
|
}
|
|
|
|
printf ("\tstart spectral %d\n", get1());
|
|
|
|
printf ("\tend spectral %d\n", get1());
|
|
|
|
ahal = get1();
|
|
|
|
printf ("\tah = %d, al = %d\n", ahal >> 4, ahal &0xf);
|
|
|
|
}
|
|
|
|
|
|
|
|
main (int argc, char *argv[]) {
|
|
|
|
int l, stuff, i, j, c;
|
|
|
|
while (argc > 1 && argv[1][0] == '-') {
|
|
|
|
switch (argv[1][1]) {
|
|
|
|
case 't':
|
|
|
|
toption = 1;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
warn ("bad option '%c'", argv[1][1]);
|
|
|
|
}
|
|
|
|
eatarg0;
|
|
|
|
}
|
|
|
|
fname = argv[1];
|
|
|
|
infile = fopen (fname, "r");
|
|
|
|
if (infile == NULL)
|
|
|
|
quit ("can't open %s\n", fname);
|
|
|
|
Start:
|
|
|
|
// if (get1() != 0xff || get1() != 0xd8)
|
|
|
|
// quit ("not JFIF");
|
|
|
|
// printf ("SOI\n");
|
|
|
|
// get_app (0xe0);
|
|
|
|
for (;;) {
|
|
|
|
c = get1();
|
|
|
|
if (c != 0xff)
|
|
|
|
quit ("expected marker, got %2x", c);
|
|
|
|
do {
|
|
|
|
c = get1();
|
|
|
|
} while (c == 0xff);
|
|
|
|
marker:
|
|
|
|
switch (c) {
|
|
|
|
case 0xc0: case 0xc1: case 0xc2: case 0xc3:
|
|
|
|
case 0xc5: case 0xc6: case 0xc7:
|
|
|
|
case 0xc8: case 0xc9: case 0xca: case 0xcb:
|
|
|
|
case 0xcd: case 0xce: case 0xcf:
|
|
|
|
get_sof (c);
|
|
|
|
break;
|
|
|
|
case 0xc4:
|
|
|
|
get_dht (c);
|
|
|
|
break;
|
|
|
|
case 0xcc:
|
|
|
|
get_dac (c);
|
|
|
|
break;
|
|
|
|
case 0xd8:
|
|
|
|
printf ("SOI\n");
|
|
|
|
break;
|
|
|
|
case 0xe0: case 0xe1: case 0xe2: case 0xe3:
|
|
|
|
case 0xe4: case 0xe5: case 0xe6: case 0xe7:
|
|
|
|
case 0xe8: case 0xe9: case 0xea: case 0xeb:
|
|
|
|
case 0xec: case 0xed: case 0xee: case 0xef:
|
|
|
|
get_app(c);
|
|
|
|
break;
|
|
|
|
case 0xda:
|
|
|
|
get_sos (c);
|
|
|
|
goto newentropy;
|
|
|
|
case 0xdb:
|
|
|
|
get_dqt (c);
|
|
|
|
break;
|
|
|
|
case 0xfe:
|
|
|
|
get_com (c);
|
|
|
|
break;
|
|
|
|
case 0xd9:
|
|
|
|
printf ("EOI\n");
|
|
|
|
if((c=getc(infile)) == EOF)
|
|
|
|
exit(0);
|
|
|
|
ungetc(c, infile);
|
|
|
|
goto Start;
|
|
|
|
default:
|
|
|
|
eatmarker (c);
|
|
|
|
}
|
|
|
|
continue;
|
|
|
|
newentropy:
|
|
|
|
l = stuff = 0;
|
|
|
|
entropy:
|
|
|
|
while ((c = get1()) != 0xff)
|
|
|
|
l += 1;
|
|
|
|
while (c == 0xff)
|
|
|
|
c = get1();
|
|
|
|
if (c == 0) {
|
|
|
|
stuff += 1;
|
|
|
|
goto entropy;
|
|
|
|
}
|
|
|
|
printf ("sequence length %d with %d stuffs\n", l, stuff);
|
|
|
|
if (0xd0 <= c && c <= 0xd7) {
|
|
|
|
printf ("restart %d\n", c - 0xd0);
|
|
|
|
goto newentropy;
|
|
|
|
}
|
|
|
|
goto marker;
|
|
|
|
}
|
|
|
|
}
|