17dd7cddfSDavid du Colombier /* jpeg parser by tom szymanski */
27dd7cddfSDavid du Colombier #include <stddef.h>
37dd7cddfSDavid du Colombier #include <stdlib.h>
47dd7cddfSDavid du Colombier #include <stdio.h>
57dd7cddfSDavid du Colombier #include <string.h>
67dd7cddfSDavid du Colombier #include <math.h>
77dd7cddfSDavid du Colombier #include <ctype.h>
87dd7cddfSDavid du Colombier
97dd7cddfSDavid du Colombier /* subroutines done by macros */
107dd7cddfSDavid du Colombier #define min(A,B) ((A)<(B) ? (A) : (B))
117dd7cddfSDavid du Colombier #define max(A,B) ((A)>(B) ? (A) : (B))
127dd7cddfSDavid du Colombier #define maxeql(A,B) if (A < (B)) A = (B);
137dd7cddfSDavid du Colombier #define mineql(A,B) if (A > (B)) A = (B);
147dd7cddfSDavid du Colombier #define eatarg0 (argc--, argv++)
157dd7cddfSDavid du Colombier #define arrayLength(A) ((sizeof A)/ (sizeof A[0]))
167dd7cddfSDavid du Colombier
177dd7cddfSDavid du Colombier FILE *infile;
187dd7cddfSDavid du Colombier char *fname;
197dd7cddfSDavid du Colombier
207dd7cddfSDavid du Colombier /* Routines to print error messages of varying severity */
217dd7cddfSDavid du Colombier
227dd7cddfSDavid du Colombier /* externally visible variables */
237dd7cddfSDavid du Colombier int warncnt;
247dd7cddfSDavid du Colombier char *myname;
257dd7cddfSDavid du Colombier
getname(char * arg)267dd7cddfSDavid du Colombier void getname (char *arg) {
277dd7cddfSDavid du Colombier /* Save name of invoking program for use by error routines */
287dd7cddfSDavid du Colombier register char *p;
297dd7cddfSDavid du Colombier p = strrchr (arg, '/');
307dd7cddfSDavid du Colombier if (p == NULL)
317dd7cddfSDavid du Colombier myname = arg;
327dd7cddfSDavid du Colombier else
337dd7cddfSDavid du Colombier myname = ++p;
347dd7cddfSDavid du Colombier }
357dd7cddfSDavid du Colombier
introduction(void)367dd7cddfSDavid du Colombier static void introduction (void) {
377dd7cddfSDavid du Colombier warncnt++;
387dd7cddfSDavid du Colombier fflush (stdout);
397dd7cddfSDavid du Colombier if (myname != NULL)
407dd7cddfSDavid du Colombier fprintf (stderr, "%s: ", myname);
417dd7cddfSDavid du Colombier }
427dd7cddfSDavid du Colombier
warn(char * fmt,...)437dd7cddfSDavid du Colombier void warn (char *fmt, ...) {
447dd7cddfSDavid du Colombier va_list args;
457dd7cddfSDavid du Colombier introduction ();
467dd7cddfSDavid du Colombier va_start (args, fmt);
477dd7cddfSDavid du Colombier vfprintf (stderr, fmt, args);
487dd7cddfSDavid du Colombier va_end (args);
497dd7cddfSDavid du Colombier fputc ('\n', stderr);
507dd7cddfSDavid du Colombier fflush (stderr);
517dd7cddfSDavid du Colombier }
527dd7cddfSDavid du Colombier
quit(char * fmt,...)537dd7cddfSDavid du Colombier void quit (char *fmt, ...) {
547dd7cddfSDavid du Colombier va_list args;
557dd7cddfSDavid du Colombier introduction ();
567dd7cddfSDavid du Colombier va_start (args, fmt);
577dd7cddfSDavid du Colombier vfprintf (stderr, fmt, args);
587dd7cddfSDavid du Colombier va_end (args);
597dd7cddfSDavid du Colombier fputc ('\n', stderr);
607dd7cddfSDavid du Colombier fflush (stderr);
617dd7cddfSDavid du Colombier exit (1);
627dd7cddfSDavid du Colombier }
637dd7cddfSDavid du Colombier
fatal(char * fmt,...)647dd7cddfSDavid du Colombier void fatal (char *fmt, ...) {
657dd7cddfSDavid du Colombier va_list args;
667dd7cddfSDavid du Colombier introduction ();
677dd7cddfSDavid du Colombier va_start (args, fmt);
687dd7cddfSDavid du Colombier vfprintf (stderr, fmt, args);
697dd7cddfSDavid du Colombier va_end (args);
707dd7cddfSDavid du Colombier fprintf (stderr, "\nbetter get help!\n");
717dd7cddfSDavid du Colombier fflush (stderr);
727dd7cddfSDavid du Colombier abort ();
737dd7cddfSDavid du Colombier }
747dd7cddfSDavid du Colombier
757dd7cddfSDavid du Colombier int toption = 0;
767dd7cddfSDavid du Colombier int dqt[16][64];
777dd7cddfSDavid du Colombier
get1(void)787dd7cddfSDavid du Colombier int get1 (void) {
797dd7cddfSDavid du Colombier unsigned char x;
807dd7cddfSDavid du Colombier if (fread(&x, 1, 1, infile) == 0)
817dd7cddfSDavid du Colombier quit ("unexpected EOF");
827dd7cddfSDavid du Colombier return x;
837dd7cddfSDavid du Colombier }
847dd7cddfSDavid du Colombier
get2(void)857dd7cddfSDavid du Colombier int get2 (void) {
867dd7cddfSDavid du Colombier int x;
877dd7cddfSDavid du Colombier
887dd7cddfSDavid du Colombier x = get1() << 8;
897dd7cddfSDavid du Colombier return x | get1();
907dd7cddfSDavid du Colombier }
917dd7cddfSDavid du Colombier
eatmarker(int kind)927dd7cddfSDavid du Colombier void eatmarker (int kind) {
937dd7cddfSDavid du Colombier int l, c;
947dd7cddfSDavid du Colombier l = get2();
957dd7cddfSDavid du Colombier printf ("%02x len=%d\n", kind, l);
967dd7cddfSDavid du Colombier for (l -= 2; l > 0; l--)
977dd7cddfSDavid du Colombier get1();
987dd7cddfSDavid du Colombier }
997dd7cddfSDavid du Colombier
1007dd7cddfSDavid du Colombier char *sofName[16] = {
1017dd7cddfSDavid du Colombier "Baseline sequential DCT - Huffman coding",
1027dd7cddfSDavid du Colombier "Extended sequential DCT - Huffman coding",
1037dd7cddfSDavid du Colombier "Progressive DCT - Huffman coding",
1047dd7cddfSDavid du Colombier "Lossless - Huffman coding",
1057dd7cddfSDavid du Colombier "4 is otherwise used",
1067dd7cddfSDavid du Colombier "Sequential DCT - differential Huffman coding",
1077dd7cddfSDavid du Colombier "Progressive DCT - differential Huffman coding",
1087dd7cddfSDavid du Colombier "Lossless - differential Huffman coding",
1097dd7cddfSDavid du Colombier "8 is reserved",
1107dd7cddfSDavid du Colombier "Extended Sequential DCT - arithmetic coding",
1117dd7cddfSDavid du Colombier "Progressive DCT - arithmetic coding",
1127dd7cddfSDavid du Colombier "Lossless - arithmetic coding",
1137dd7cddfSDavid du Colombier "c is otherwise used",
1147dd7cddfSDavid du Colombier "Sequential DCT - differential arithmetic coding",
1157dd7cddfSDavid du Colombier "Progressive DCT - differential arithmetic coding",
1167dd7cddfSDavid du Colombier "Lossless - differential arithmetic coding",
1177dd7cddfSDavid du Colombier };
1187dd7cddfSDavid du Colombier
get_sof(int kind)1197dd7cddfSDavid du Colombier void get_sof (int kind) {
1207dd7cddfSDavid du Colombier int i, length, height, width, precision, ncomponents;
1217dd7cddfSDavid du Colombier int id, sf, tab;
1227dd7cddfSDavid du Colombier length = get2();
1237dd7cddfSDavid du Colombier precision = get1();
1247dd7cddfSDavid du Colombier height = get2();
1257dd7cddfSDavid du Colombier width = get2();
1267dd7cddfSDavid du Colombier ncomponents = get1();
1277dd7cddfSDavid du Colombier printf ("SOF%d:\t%s\n", kind - 0xc0, sofName[kind - 0xc0]);
1287dd7cddfSDavid du Colombier printf ("\t%d wide, %d high, %d deep, %d components\n",
1297dd7cddfSDavid du Colombier width, height, precision, ncomponents);
1307dd7cddfSDavid du Colombier for (i = 0; i < ncomponents; i++) {
1317dd7cddfSDavid du Colombier id = get1();
1327dd7cddfSDavid du Colombier sf = get1();
1337dd7cddfSDavid du Colombier tab = get1();
1347dd7cddfSDavid du Colombier printf ("\tcomponent %d: %d hsample, %d vsample, quantization table %d\n",
1357dd7cddfSDavid du Colombier id, sf >> 4, sf & 0xf, tab);
1367dd7cddfSDavid du Colombier }
1377dd7cddfSDavid du Colombier }
1387dd7cddfSDavid du Colombier
get_com(int kind)1397dd7cddfSDavid du Colombier void get_com (int kind) {
1407dd7cddfSDavid du Colombier int l, c;
1417dd7cddfSDavid du Colombier l = get2();
1427dd7cddfSDavid du Colombier printf ("COM len=%d '", l);
1437dd7cddfSDavid du Colombier for (l -= 2; l > 0; l--)
1447dd7cddfSDavid du Colombier putchar (c = get1());
1457dd7cddfSDavid du Colombier printf ("'\n");
1467dd7cddfSDavid du Colombier }
1477dd7cddfSDavid du Colombier
get_app(int kind)1487dd7cddfSDavid du Colombier void get_app (int kind) {
149*9a747e4fSDavid du Colombier int l, c, first;
150*9a747e4fSDavid du Colombier char buf[6];
151*9a747e4fSDavid du Colombier int nbuf, nok;
1527dd7cddfSDavid du Colombier l = get2();
1537dd7cddfSDavid du Colombier printf ("APP%d len=%d\n", kind - 0xe0, l);
154*9a747e4fSDavid du Colombier nbuf = 0;
155*9a747e4fSDavid du Colombier nok = 0;
156*9a747e4fSDavid du Colombier first = 1;
157*9a747e4fSDavid du Colombier /* dump printable strings in comment */
158*9a747e4fSDavid du Colombier for (l -= 2; l > 0; l--){
159*9a747e4fSDavid du Colombier c = get1();
160*9a747e4fSDavid du Colombier if(isprint(c)){
161*9a747e4fSDavid du Colombier if(nbuf >= sizeof buf){
162*9a747e4fSDavid du Colombier if(!first && nbuf == nok)
163*9a747e4fSDavid du Colombier printf(" ");
164*9a747e4fSDavid du Colombier printf("%.*s", nbuf, buf);
165*9a747e4fSDavid du Colombier nbuf = 0;
166*9a747e4fSDavid du Colombier first = 0;
167*9a747e4fSDavid du Colombier }
168*9a747e4fSDavid du Colombier buf[nbuf++] = c;
169*9a747e4fSDavid du Colombier nok++;
170*9a747e4fSDavid du Colombier }else{
171*9a747e4fSDavid du Colombier if(nok >= sizeof buf)
172*9a747e4fSDavid du Colombier if(nbuf > 0)
173*9a747e4fSDavid du Colombier printf("%.*s", nbuf, buf);
174*9a747e4fSDavid du Colombier nbuf = 0;
175*9a747e4fSDavid du Colombier nok = 0;
176*9a747e4fSDavid du Colombier }
177*9a747e4fSDavid du Colombier }
178*9a747e4fSDavid du Colombier if(nok >= sizeof buf)
179*9a747e4fSDavid du Colombier if(nbuf > 0){
180*9a747e4fSDavid du Colombier if(!first && nbuf == nok)
181*9a747e4fSDavid du Colombier printf(" ");
182*9a747e4fSDavid du Colombier printf("%.*s", nbuf, buf);
183*9a747e4fSDavid du Colombier }
1847dd7cddfSDavid du Colombier }
1857dd7cddfSDavid du Colombier
get_dac(int kind)1867dd7cddfSDavid du Colombier void get_dac (int kind) {
1877dd7cddfSDavid du Colombier eatmarker (kind);
1887dd7cddfSDavid du Colombier }
1897dd7cddfSDavid du Colombier
get1dqt(void)1907dd7cddfSDavid du Colombier int get1dqt (void) {
1917dd7cddfSDavid du Colombier int t, p, i, *tab;
1927dd7cddfSDavid du Colombier t = get1();
1937dd7cddfSDavid du Colombier p = t >> 4;
1947dd7cddfSDavid du Colombier t = t & 0xf;
1957dd7cddfSDavid du Colombier printf ("DQT:\tp = %d, table = %d\n", p, t);
1967dd7cddfSDavid du Colombier tab = &dqt[t][0];
1977dd7cddfSDavid du Colombier for (i = 0; i < 64; i++)
1987dd7cddfSDavid du Colombier tab[i] = p ? get2() : get1();
1997dd7cddfSDavid du Colombier if (toption) {
2007dd7cddfSDavid du Colombier for (i = 0; i < 64; i++)
2017dd7cddfSDavid du Colombier printf ("\t%q[%02d] = %d\n", i, tab[i]);
2027dd7cddfSDavid du Colombier }
2037dd7cddfSDavid du Colombier return p ? 65 : 129;
2047dd7cddfSDavid du Colombier }
2057dd7cddfSDavid du Colombier
get_dqt(int kind)2067dd7cddfSDavid du Colombier void get_dqt (int kind) {
2077dd7cddfSDavid du Colombier int length;
2087dd7cddfSDavid du Colombier length = get2() - 2;
2097dd7cddfSDavid du Colombier while (length > 0)
2107dd7cddfSDavid du Colombier length -= get1dqt();
2117dd7cddfSDavid du Colombier }
2127dd7cddfSDavid du Colombier
get1dht(void)2137dd7cddfSDavid du Colombier int get1dht (void) {
2147dd7cddfSDavid du Colombier int l, tcth, p, i, j, v[16], vv[16][256];
2157dd7cddfSDavid du Colombier tcth = get1();
2167dd7cddfSDavid du Colombier printf ("DHT:\tclass = %d, table = %d\n", tcth >> 4, tcth & 0xf);
2177dd7cddfSDavid du Colombier for (i = 0; i < 16; i++)
2187dd7cddfSDavid du Colombier v[i] = get1();
2197dd7cddfSDavid du Colombier l = 17;
2207dd7cddfSDavid du Colombier for (i = 0; i < 16; i++)
2217dd7cddfSDavid du Colombier for (j = 0; j < v[i]; j++) {
2227dd7cddfSDavid du Colombier vv[i][j] = get1();
2237dd7cddfSDavid du Colombier l += 1;
2247dd7cddfSDavid du Colombier }
2257dd7cddfSDavid du Colombier if (toption) {
2267dd7cddfSDavid du Colombier for (i = 0; i < 16; i++)
2277dd7cddfSDavid du Colombier printf ("\t%l[%02d] = %d\n", i+1, v[i]);
2287dd7cddfSDavid du Colombier for (i = 0; i < 16; i++)
2297dd7cddfSDavid du Colombier for (j = 0; j < v[i]; j++)
2307dd7cddfSDavid du Colombier printf ("\t%v[%02d,%02d] = %d\n", i+1, j+1, vv[i][j]);
2317dd7cddfSDavid du Colombier }
2327dd7cddfSDavid du Colombier return l;
2337dd7cddfSDavid du Colombier }
2347dd7cddfSDavid du Colombier
get_dht(int kind)2357dd7cddfSDavid du Colombier void get_dht (int kind) {
2367dd7cddfSDavid du Colombier int length;
2377dd7cddfSDavid du Colombier length = get2() - 2;
2387dd7cddfSDavid du Colombier while (length > 0)
2397dd7cddfSDavid du Colombier length -= get1dht();
2407dd7cddfSDavid du Colombier }
2417dd7cddfSDavid du Colombier
get_sos(int kind)2427dd7cddfSDavid du Colombier void get_sos (int kind) {
2437dd7cddfSDavid du Colombier int i, length, ncomponents, id, dcac, ahal;
2447dd7cddfSDavid du Colombier length = get2();
2457dd7cddfSDavid du Colombier ncomponents = get1();
2467dd7cddfSDavid du Colombier printf ("SOS:\t%d components\n", ncomponents);
2477dd7cddfSDavid du Colombier for (i = 0; i < ncomponents; i++) {
2487dd7cddfSDavid du Colombier id = get1();
2497dd7cddfSDavid du Colombier dcac = get1();
2507dd7cddfSDavid du Colombier printf ("\tcomponent %d: %d DC, %d AC\n", id, dcac >> 4, dcac & 0xf);
2517dd7cddfSDavid du Colombier }
2527dd7cddfSDavid du Colombier printf ("\tstart spectral %d\n", get1());
2537dd7cddfSDavid du Colombier printf ("\tend spectral %d\n", get1());
2547dd7cddfSDavid du Colombier ahal = get1();
2557dd7cddfSDavid du Colombier printf ("\tah = %d, al = %d\n", ahal >> 4, ahal &0xf);
2567dd7cddfSDavid du Colombier }
2577dd7cddfSDavid du Colombier
main(int argc,char * argv[])2587dd7cddfSDavid du Colombier main (int argc, char *argv[]) {
2597dd7cddfSDavid du Colombier int l, stuff, i, j, c;
2607dd7cddfSDavid du Colombier while (argc > 1 && argv[1][0] == '-') {
2617dd7cddfSDavid du Colombier switch (argv[1][1]) {
2627dd7cddfSDavid du Colombier case 't':
2637dd7cddfSDavid du Colombier toption = 1;
2647dd7cddfSDavid du Colombier break;
2657dd7cddfSDavid du Colombier default:
2667dd7cddfSDavid du Colombier warn ("bad option '%c'", argv[1][1]);
2677dd7cddfSDavid du Colombier }
2687dd7cddfSDavid du Colombier eatarg0;
2697dd7cddfSDavid du Colombier }
2707dd7cddfSDavid du Colombier fname = argv[1];
2717dd7cddfSDavid du Colombier infile = fopen (fname, "r");
2727dd7cddfSDavid du Colombier if (infile == NULL)
2737dd7cddfSDavid du Colombier quit ("can't open %s\n", fname);
2747dd7cddfSDavid du Colombier Start:
2757dd7cddfSDavid du Colombier // if (get1() != 0xff || get1() != 0xd8)
2767dd7cddfSDavid du Colombier // quit ("not JFIF");
2777dd7cddfSDavid du Colombier // printf ("SOI\n");
2787dd7cddfSDavid du Colombier // get_app (0xe0);
2797dd7cddfSDavid du Colombier for (;;) {
2807dd7cddfSDavid du Colombier c = get1();
2817dd7cddfSDavid du Colombier if (c != 0xff)
2827dd7cddfSDavid du Colombier quit ("expected marker, got %2x", c);
2837dd7cddfSDavid du Colombier do {
2847dd7cddfSDavid du Colombier c = get1();
2857dd7cddfSDavid du Colombier } while (c == 0xff);
2867dd7cddfSDavid du Colombier marker:
2877dd7cddfSDavid du Colombier switch (c) {
2887dd7cddfSDavid du Colombier case 0xc0: case 0xc1: case 0xc2: case 0xc3:
2897dd7cddfSDavid du Colombier case 0xc5: case 0xc6: case 0xc7:
2907dd7cddfSDavid du Colombier case 0xc8: case 0xc9: case 0xca: case 0xcb:
2917dd7cddfSDavid du Colombier case 0xcd: case 0xce: case 0xcf:
2927dd7cddfSDavid du Colombier get_sof (c);
2937dd7cddfSDavid du Colombier break;
2947dd7cddfSDavid du Colombier case 0xc4:
2957dd7cddfSDavid du Colombier get_dht (c);
2967dd7cddfSDavid du Colombier break;
2977dd7cddfSDavid du Colombier case 0xcc:
2987dd7cddfSDavid du Colombier get_dac (c);
2997dd7cddfSDavid du Colombier break;
3007dd7cddfSDavid du Colombier case 0xd8:
3017dd7cddfSDavid du Colombier printf ("SOI\n");
3027dd7cddfSDavid du Colombier break;
3037dd7cddfSDavid du Colombier case 0xe0: case 0xe1: case 0xe2: case 0xe3:
3047dd7cddfSDavid du Colombier case 0xe4: case 0xe5: case 0xe6: case 0xe7:
3057dd7cddfSDavid du Colombier case 0xe8: case 0xe9: case 0xea: case 0xeb:
3067dd7cddfSDavid du Colombier case 0xec: case 0xed: case 0xee: case 0xef:
3077dd7cddfSDavid du Colombier get_app(c);
3087dd7cddfSDavid du Colombier break;
3097dd7cddfSDavid du Colombier case 0xda:
3107dd7cddfSDavid du Colombier get_sos (c);
3117dd7cddfSDavid du Colombier goto newentropy;
3127dd7cddfSDavid du Colombier case 0xdb:
3137dd7cddfSDavid du Colombier get_dqt (c);
3147dd7cddfSDavid du Colombier break;
3157dd7cddfSDavid du Colombier case 0xfe:
3167dd7cddfSDavid du Colombier get_com (c);
3177dd7cddfSDavid du Colombier break;
3187dd7cddfSDavid du Colombier case 0xd9:
3197dd7cddfSDavid du Colombier printf ("EOI\n");
3207dd7cddfSDavid du Colombier if((c=getc(infile)) == EOF)
3217dd7cddfSDavid du Colombier exit(0);
3227dd7cddfSDavid du Colombier ungetc(c, infile);
3237dd7cddfSDavid du Colombier goto Start;
3247dd7cddfSDavid du Colombier default:
3257dd7cddfSDavid du Colombier eatmarker (c);
3267dd7cddfSDavid du Colombier }
3277dd7cddfSDavid du Colombier continue;
3287dd7cddfSDavid du Colombier newentropy:
3297dd7cddfSDavid du Colombier l = stuff = 0;
3307dd7cddfSDavid du Colombier entropy:
3317dd7cddfSDavid du Colombier while ((c = get1()) != 0xff)
3327dd7cddfSDavid du Colombier l += 1;
3337dd7cddfSDavid du Colombier while (c == 0xff)
3347dd7cddfSDavid du Colombier c = get1();
3357dd7cddfSDavid du Colombier if (c == 0) {
3367dd7cddfSDavid du Colombier stuff += 1;
3377dd7cddfSDavid du Colombier goto entropy;
3387dd7cddfSDavid du Colombier }
3397dd7cddfSDavid du Colombier printf ("sequence length %d with %d stuffs\n", l, stuff);
3407dd7cddfSDavid du Colombier if (0xd0 <= c && c <= 0xd7) {
3417dd7cddfSDavid du Colombier printf ("restart %d\n", c - 0xd0);
3427dd7cddfSDavid du Colombier goto newentropy;
3437dd7cddfSDavid du Colombier }
3447dd7cddfSDavid du Colombier goto marker;
3457dd7cddfSDavid du Colombier }
3467dd7cddfSDavid du Colombier }
347