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