blob: 6a0a7a00746760d7c79851ede59de066d82675d2 [file] [log] [blame]
/* jpeg parser by tom szymanski */
#include <stddef.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <ctype.h>
#include <stdarg.h>
/* 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;
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, 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);
}
int main (int argc, char *argv[]) {
int l, stuff, 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;
}
}