|  | /* 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; | 
|  | } | 
|  | } |