xref: /plan9-contrib/sys/src/cmd/jpg/jpegdump.c (revision 9a747e4fd48b9f4522c70c07e8f882a15030f964)
1 /* jpeg parser by tom szymanski */
2 #include <stddef.h>
3 #include <stdlib.h>
4 #include <stdio.h>
5 #include <string.h>
6 #include <math.h>
7 #include <ctype.h>
8 
9 /* subroutines done by macros */
10 #define min(A,B)	((A)<(B) ? (A) : (B))
11 #define max(A,B)	((A)>(B) ? (A) : (B))
12 #define maxeql(A,B)	if (A < (B)) A = (B);
13 #define mineql(A,B)	if (A > (B)) A = (B);
14 #define eatarg0		(argc--, argv++)
15 #define arrayLength(A) ((sizeof A)/ (sizeof A[0]))
16 
17 FILE *infile;
18 char *fname;
19 
20 /* Routines to print error messages of varying severity */
21 
22 /* externally visible variables */
23 int   warncnt;
24 char *myname;
25 
getname(char * arg)26 void getname (char *arg) {
27 	/* Save name of invoking program for use by error routines */
28 	register char *p;
29 	p = strrchr (arg, '/');
30 	if (p == NULL)
31 		myname = arg;
32 	else
33 		myname = ++p;
34 }
35 
introduction(void)36 static void introduction (void) {
37 	warncnt++;
38 	fflush (stdout);
39 	if (myname != NULL)
40 		fprintf (stderr, "%s: ", myname);
41 }
42 
warn(char * fmt,...)43 void warn (char *fmt, ...) {
44 	va_list args;
45 	introduction ();
46 	va_start (args, fmt);
47 	vfprintf (stderr, fmt, args);
48 	va_end (args);
49 	fputc ('\n', stderr);
50 	fflush (stderr);
51 }
52 
quit(char * fmt,...)53 void quit (char *fmt, ...) {
54 	va_list args;
55 	introduction ();
56 	va_start (args, fmt);
57 	vfprintf (stderr, fmt, args);
58 	va_end (args);
59 	fputc ('\n', stderr);
60 	fflush (stderr);
61 	exit (1);
62 }
63 
fatal(char * fmt,...)64 void fatal (char *fmt, ...) {
65 	va_list args;
66 	introduction ();
67 	va_start (args, fmt);
68 	vfprintf (stderr, fmt, args);
69 	va_end (args);
70 	fprintf (stderr, "\nbetter get help!\n");
71 	fflush (stderr);
72 	abort ();
73 }
74 
75 int toption = 0;
76 int dqt[16][64];
77 
get1(void)78 int get1 (void) {
79 	unsigned char x;
80 	if (fread(&x, 1, 1, infile) == 0)
81 		quit ("unexpected EOF");
82 	return x;
83 }
84 
get2(void)85 int get2 (void) {
86 	int x;
87 
88 	x = get1() << 8;
89 	return x | get1();
90 }
91 
eatmarker(int kind)92 void eatmarker (int kind) {
93 	int l, c;
94 	l = get2();
95 	printf ("%02x len=%d\n", kind, l);
96 	for (l -= 2; l > 0; l--)
97 		get1();
98 }
99 
100 char *sofName[16] = {
101 	"Baseline sequential DCT - Huffman coding",
102 	"Extended sequential DCT - Huffman coding",
103 	"Progressive DCT - Huffman coding",
104 	"Lossless - Huffman coding",
105 	"4 is otherwise used",
106 	"Sequential DCT - differential Huffman coding",
107 	"Progressive DCT - differential Huffman coding",
108 	"Lossless - differential Huffman coding",
109 	"8 is reserved",
110 	"Extended Sequential DCT - arithmetic coding",
111 	"Progressive DCT - arithmetic coding",
112 	"Lossless - arithmetic coding",
113 	"c is otherwise used",
114 	"Sequential DCT - differential arithmetic coding",
115 	"Progressive DCT - differential arithmetic coding",
116 	"Lossless - differential arithmetic coding",
117 };
118 
get_sof(int kind)119 void get_sof (int kind) {
120 	int i, length, height, width, precision, ncomponents;
121 	int id, sf, tab;
122 	length = get2();
123 	precision = get1();
124 	height = get2();
125 	width = get2();
126 	ncomponents = get1();
127 	printf ("SOF%d:\t%s\n", kind - 0xc0, sofName[kind - 0xc0]);
128 	printf ("\t%d wide, %d high, %d deep, %d components\n",
129 		width, height, precision, ncomponents);
130 	for (i = 0; i < ncomponents; i++) {
131 		id = get1();
132 		sf = get1();
133 		tab = get1();
134 		printf ("\tcomponent %d: %d hsample, %d vsample, quantization table %d\n",
135 			id, sf >> 4, sf & 0xf, tab);
136 	}
137 }
138 
get_com(int kind)139 void get_com (int kind) {
140 	int l, c;
141 	l = get2();
142 	printf ("COM len=%d '", l);
143 	for (l -= 2; l > 0; l--)
144 		putchar (c = get1());
145 	printf ("'\n");
146 }
147 
get_app(int kind)148 void get_app (int kind) {
149 	int l, c, first;
150 	char buf[6];
151 	int nbuf, nok;
152 	l = get2();
153 	printf ("APP%d len=%d\n", kind - 0xe0, l);
154 	nbuf = 0;
155 	nok = 0;
156 	first = 1;
157 	/* dump printable strings in comment */
158 	for (l -= 2; l > 0; l--){
159 		c = get1();
160 		if(isprint(c)){
161 			if(nbuf >= sizeof buf){
162 				if(!first && nbuf == nok)
163 					printf(" ");
164 				printf("%.*s", nbuf, buf);
165 				nbuf = 0;
166 				first = 0;
167 			}
168 			buf[nbuf++] = c;
169 			nok++;
170 		}else{
171 			if(nok >= sizeof buf)
172 				if(nbuf > 0)
173 					printf("%.*s", nbuf, buf);
174 			nbuf = 0;
175 			nok = 0;
176 		}
177 	}
178 	if(nok >= sizeof buf)
179 		if(nbuf > 0){
180 			if(!first && nbuf == nok)
181 				printf(" ");
182 			printf("%.*s", nbuf, buf);
183 		}
184 }
185 
get_dac(int kind)186 void get_dac (int kind) {
187 	eatmarker (kind);
188 }
189 
get1dqt(void)190 int get1dqt (void) {
191 	int t, p, i, *tab;
192 	t = get1();
193 	p = t >> 4;
194 	t = t & 0xf;
195 	printf ("DQT:\tp = %d, table = %d\n", p, t);
196 	tab = &dqt[t][0];
197 	for (i = 0; i < 64; i++)
198 		tab[i] = p ? get2() : get1();
199 	if (toption) {
200 		for (i = 0; i < 64; i++)
201 			printf ("\t%q[%02d] = %d\n", i, tab[i]);
202 	}
203 	return p ? 65 : 129;
204 }
205 
get_dqt(int kind)206 void get_dqt (int kind) {
207 	int length;
208 	length = get2() - 2;
209 	while (length > 0)
210 		length -= get1dqt();
211 }
212 
get1dht(void)213 int get1dht (void) {
214 	int l, tcth, p, i, j, v[16], vv[16][256];
215 	tcth = get1();
216 	printf ("DHT:\tclass = %d, table = %d\n", tcth >> 4, tcth & 0xf);
217 	for (i = 0; i < 16; i++)
218 		v[i] = get1();
219 	l = 17;
220 	for (i = 0; i < 16; i++)
221 		for (j = 0; j < v[i]; j++) {
222 			vv[i][j] = get1();
223 			l += 1;
224 		}
225 	if (toption) {
226 		for (i = 0; i < 16; i++)
227 			printf ("\t%l[%02d] = %d\n", i+1, v[i]);
228 		for (i = 0; i < 16; i++)
229 			for (j = 0; j < v[i]; j++)
230 				printf ("\t%v[%02d,%02d] = %d\n", i+1, j+1, vv[i][j]);
231 	}
232 	return l;
233 }
234 
get_dht(int kind)235 void get_dht (int kind) {
236 	int length;
237 	length = get2() - 2;
238 	while (length > 0)
239 		length -= get1dht();
240 }
241 
get_sos(int kind)242 void get_sos (int kind) {
243 	int i, length, ncomponents, id, dcac, ahal;
244 	length = get2();
245 	ncomponents = get1();
246 	printf ("SOS:\t%d components\n", ncomponents);
247 	for (i = 0; i < ncomponents; i++) {
248 		id = get1();
249 		dcac = get1();
250 		printf ("\tcomponent %d: %d DC, %d AC\n", id, dcac >> 4, dcac & 0xf);
251 	}
252 	printf ("\tstart spectral %d\n", get1());
253 	printf ("\tend spectral %d\n", get1());
254 	ahal = get1();
255 	printf ("\tah = %d, al = %d\n", ahal >> 4, ahal &0xf);
256 }
257 
main(int argc,char * argv[])258 main (int argc, char *argv[]) {
259 	int l, stuff, i, j, c;
260 	while (argc > 1 && argv[1][0] == '-') {
261 		switch (argv[1][1]) {
262 		case 't':
263 			toption = 1;
264 			break;
265 		default:
266 			warn ("bad option '%c'", argv[1][1]);
267 		}
268 		eatarg0;
269 	}
270 	fname = argv[1];
271 	infile = fopen (fname, "r");
272 	if (infile == NULL)
273 		quit ("can't open %s\n", fname);
274     Start:
275 //	if (get1() != 0xff || get1() != 0xd8)
276 //		quit ("not JFIF");
277 //	printf ("SOI\n");
278 //	get_app (0xe0);
279 	for (;;) {
280 		c = get1();
281 		if (c != 0xff)
282 			quit ("expected marker, got %2x", c);
283 		do {
284 			c = get1();
285 		} while (c == 0xff);
286 marker:
287 		switch (c) {
288 		case 0xc0: case 0xc1: case 0xc2: case 0xc3:
289 		case 0xc5: case 0xc6: case 0xc7:
290 		case 0xc8: case 0xc9: case 0xca: case 0xcb:
291 		case 0xcd: case 0xce: case 0xcf:
292 			get_sof (c);
293 			break;
294 		case 0xc4:
295 			get_dht (c);
296 			break;
297 		case 0xcc:
298 			get_dac (c);
299 			break;
300 		case 0xd8:
301 			printf ("SOI\n");
302 			break;
303 		case 0xe0: case 0xe1: case 0xe2: case 0xe3:
304 		case 0xe4: case 0xe5: case 0xe6: case 0xe7:
305 		case 0xe8: case 0xe9: case 0xea: case 0xeb:
306 		case 0xec: case 0xed: case 0xee: case 0xef:
307 			get_app(c);
308 			break;
309 		case 0xda:
310 			get_sos (c);
311 			goto newentropy;
312 		case 0xdb:
313 			get_dqt (c);
314 			break;
315 		case 0xfe:
316 			get_com (c);
317 			break;
318 		case 0xd9:
319 			printf ("EOI\n");
320 			if((c=getc(infile)) == EOF)
321 				exit(0);
322 			ungetc(c, infile);
323 			goto Start;
324 		default:
325 			eatmarker (c);
326 		}
327 		continue;
328 newentropy:
329 		l = stuff = 0;
330 entropy:
331 		while ((c = get1()) != 0xff)
332 			l += 1;
333 		while (c == 0xff)
334 			c = get1();
335 		if (c == 0) {
336 			stuff += 1;
337 			goto entropy;
338 		}
339 		printf ("sequence length %d with %d stuffs\n", l, stuff);
340 		if (0xd0 <= c && c <= 0xd7) {
341 			printf ("restart %d\n", c - 0xd0);
342 			goto newentropy;
343 		}
344 		goto marker;
345 	}
346 }
347