1 /*
2  * Copyright (c) 2001, 2002, Eric M. Johnston <emj@postal.net>
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. All advertising materials mentioning features or use of this software
14  *    must display the following acknowledgement:
15  *      This product includes software developed by Eric M. Johnston.
16  * 4. Neither the name of the author nor the names of any co-contributors
17  *    may be used to endorse or promote products derived from this software
18  *    without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
24  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30  * SUCH DAMAGE.
31  *
32  * $Id: jpeg.c,v 1.5 2002/10/15 02:57:09 ejohnst Exp $
33  */
34 
35 /*
36  * This module contains a minimal set of functions for parsing a JPEG
37  * file, specific for use in extracting EXIF information.  Primarily, it
38  * reads the input file and looks for the markers which indicate the start
39  * of APP1 and APP2 sections.
40  *
41  * Portions of this code were developed while referencing the public domain
42  * 'Jhead' program (version 1.2) by Matthias Wandel <mwandel@rim.net>.
43  */
44 
45 #include <stdio.h>
46 
47 #include "jpeg.h"
48 #include "exif.h"
49 
50 
51 static FILE *infile;
52 
53 /* Some data we collect from a start of frame. */
54 
55 static int jpg_prcsn;			/* Precision. */
56 static int jpg_cmpnts;			/* Number of components. */
57 static unsigned int jpg_height;		/* Image height. */
58 static unsigned int jpg_width;		/* Image width. */
59 static const char *jpg_prcss;		/* Process. */
60 
61 static int seensof;
62 
63 
64 /* Process string lookup table. */
65 
66 static struct jpgprocess {
67 	int sof;
68 	const char *str;
69 } process[] = {
70 	{ JPEG_M_SOF0,	"Baseline" },
71 	{ JPEG_M_SOF1,	"Extended sequential" },
72 	{ JPEG_M_SOF2,	"Progressive" },
73 	{ JPEG_M_SOF3,	"Lossless" },
74 	{ JPEG_M_SOF5,	"Differential sequential" },
75 	{ JPEG_M_SOF6,	"Differential progressive" },
76 	{ JPEG_M_SOF7,	"Differential lossless" },
77 	{ JPEG_M_SOF9,	"Extended sequential, arithmetic coding" },
78 	{ JPEG_M_SOF10,	"Progressive, arithmetic coding" },
79 	{ JPEG_M_SOF11,	"Lossless, arithmetic coding" },
80 	{ JPEG_M_SOF13,	"Differential sequential, arithmetic coding" },
81 	{ JPEG_M_SOF14,	"Differential progressive, arithmetic coding" },
82 	{ JPEG_M_SOF15,	"Differential lossless, arithmetic coding" },
83 	{ JPEG_M_ERR,	"Unknown" },
84 };
85 
86 
87 /*
88  * Fetch one byte of the JPEG file.
89  */
90 static int
jpg1byte(void)91 jpg1byte(void)
92 {
93 	int b;
94 
95 	b = fgetc(infile);
96 	if (b == EOF)
97 		exifdie("invalid JPEG format");
98 	return (b);
99 }
100 
101 
102 /*
103  * Fetch two bytes of the JPEG file.
104  */
105 static unsigned int
jpg2byte(void)106 jpg2byte(void)
107 {
108 	unsigned int b1, b2;
109 
110 	b1 = fgetc(infile);
111 	b2 = fgetc(infile);
112 	if (b1 == EOF || b2 == EOF)
113 		exifdie("invalid JPEG format");
114 
115 	return ((b1 << 8) | b2);
116 }
117 
118 
119 /*
120  * Fetch the length of a marker.
121  */
122 static unsigned int
mkrlen(void)123 mkrlen(void)
124 {
125 	unsigned int l;
126 
127 	/* Length includes itself. */
128 
129 	if ((l = jpg2byte()) < 2)
130 		exifdie("invalid JPEG marker (length mismatch)");
131 	return (l - 2);
132 }
133 
134 
135 /*
136  * Skip over an uninteresting marker.
137  */
138 static void
skipmkr(void)139 skipmkr(void)
140 {
141 	unsigned int l;
142 
143 	l = mkrlen();
144 	while (l) {
145 		jpg1byte();
146 		l--;
147 	}
148 }
149 
150 
151 /*
152  * Check the first bytes of the file for a marker.
153  */
154 static int
topmkr(void)155 topmkr(void)
156 {
157 
158 	if (jpg1byte() != JPEG_M_BEG)
159 		return (JPEG_M_ERR);
160 	return (jpg1byte());
161 }
162 
163 
164 /*
165  * Find the next JPEG marker in the file.
166  */
167 static int
nxtmkr(void)168 nxtmkr(void)
169 {
170 	int b;
171 	int bad = 0;
172 
173 	/* Read until we see JPEG_MARKER. */
174 
175 	while ((b = jpg1byte()) != JPEG_M_BEG)
176 		bad++;
177 
178 	/* Read all JPEG_M_BEGs (which may be used for padding). */
179 
180 	while ((b = jpg1byte()) == JPEG_M_BEG);
181 
182 	if (bad)
183 		exifwarn("skipped spurious bytes in JPEG");
184 
185 	return (b);
186 }
187 
188 
189 /*
190  * Collect image data from the start of frame.
191  * XXX Note that we clobber any previously collected info...
192  */
193 static void
sofmrk(int mark)194 sofmrk(int mark)
195 {
196 	int i;
197 	unsigned int l;
198 
199 	l = mkrlen();
200 	jpg_prcsn = jpg1byte();
201 	jpg_height = jpg2byte();
202 	jpg_width = jpg2byte();
203 	jpg_cmpnts = jpg1byte();
204 
205 	for (i = 0; process[i].sof < JPEG_M_ERR; i++)
206 		if (process[i].sof == mark)
207 			break;
208 	jpg_prcss = process[i].str;
209 
210 	/* Verify length. */
211 
212 	if (l != (unsigned int)(6 + jpg_cmpnts * 3))
213 		exifdie("invalid JPEG SOF marker (length mismatch)");
214 
215 	/* Skip over component info we don't care about. */
216 
217 	for (i = 0; i < jpg_cmpnts; i++) {
218 		jpg1byte(); jpg1byte(); jpg1byte();
219 	}
220 
221 	seensof = TRUE;
222 }
223 
224 
225 /*
226  * Scan through a JPEG file for markers, returning interesting ones.
227  * Returns false when it's done with the file.
228  */
229 int
jpegscan(FILE * fp,int * mark,unsigned int * len,int first)230 jpegscan(FILE *fp, int *mark, unsigned int *len, int first)
231 {
232 	infile = fp;
233 
234 	/* First time through. */
235 
236 	if (first && topmkr() != JPEG_M_SOI) {
237 		exifwarn("doesn't appear to be a JPEG file; "
238 		    "searching for start of image");
239 		if (nxtmkr() != JPEG_M_SOI)
240 			exifdie("start of image not found");
241 	}
242 
243 	/* Look for interesting markers. */
244 
245 	for (;;) {
246 		switch ((*mark = nxtmkr())) {
247 		case JPEG_M_EOI:
248 		case JPEG_M_SOS:
249 			return (FALSE);
250 
251 		case JPEG_M_APP1:
252 		case JPEG_M_APP2:
253 			*len = mkrlen();
254 			return (TRUE);
255 
256 		/* We might as well collect some useful info from SOFs. */
257 
258 		case JPEG_M_SOF0:
259 		case JPEG_M_SOF1:
260 		case JPEG_M_SOF3:
261 		case JPEG_M_SOF5:
262 		case JPEG_M_SOF6:
263 		case JPEG_M_SOF7:
264 		case JPEG_M_SOF9:
265 		case JPEG_M_SOF10:
266 		case JPEG_M_SOF11:
267 		case JPEG_M_SOF13:
268 		case JPEG_M_SOF14:
269 		case JPEG_M_SOF15:
270 			sofmrk(*mark);
271 			break;
272 
273 		/* Just skip past markers we don't care about. */
274 
275 		default:
276 			skipmkr();
277 		}
278 	}
279 
280 	return (FALSE);
281 }
282 
283 
284 /*
285  * Returns some basic image info about the JPEG, gleaned from start of
286  * frame sections.
287  */
288 int
jpeginfo(int * prcsn,int * cmpnts,unsigned int * height,unsigned int * width,const char * prcss)289 jpeginfo(int *prcsn, int *cmpnts, unsigned int *height, unsigned int *width,
290     const char *prcss)
291 {
292 
293 	*prcsn = jpg_prcsn;
294 	*cmpnts = jpg_cmpnts;
295 	*height = jpg_height;
296 	*width = jpg_width;
297 	prcss = jpg_prcss;
298 
299 	return (seensof);
300 }
301