1 /*
2 * Copyright (c) 2001-2007, 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: exiftags.c,v 1.28 2007/12/16 02:12:01 ejohnst Exp $
33 */
34
35 /*
36 * exiftags: dump Exif information embedded in JPEG images.
37 *
38 */
39
40 #include <stdio.h>
41 #include <stdlib.h>
42 #include <string.h>
43 #include <errno.h>
44
45 /* For getopt(). */
46
47 #ifndef WIN32
48 #include <unistd.h>
49 #else
50 extern char *optarg;
51 extern int optind, opterr, optopt;
52 int getopt(int, char * const [], const char *);
53 #endif
54
55 #include "jpeg.h"
56 #include "exif.h"
57
58
59 int quiet;
60 static const char *version = "1.01";
61 static int fnum;
62 static const char *delim = ": ";
63
64
65 static void
printprops(struct exifprop * list,unsigned short lvl,int pas)66 printprops(struct exifprop *list, unsigned short lvl, int pas)
67 {
68 static int prevf = -1;
69 const char *n;
70
71 if (!quiet) {
72 if (prevf == fnum)
73 printf("\n");
74 else
75 prevf = fnum;
76
77 switch (lvl) {
78 case ED_UNK:
79 printf("Unsupported Properties:\n\n");
80 break;
81 case ED_CAM:
82 printf("Camera-Specific Properties:\n\n");
83 break;
84 case ED_IMG:
85 printf("Image-Specific Properties:\n\n");
86 break;
87 case ED_VRB:
88 printf("Other Properties:\n\n");
89 break;
90 case ED_BAD:
91 printf("Invalid Properties:\n\n");
92 break;
93 }
94 }
95
96 while (list) {
97
98 /* Take care of point-and-shoot values. */
99
100 if (list->lvl == ED_PAS)
101 list->lvl = pas ? ED_CAM : ED_IMG;
102
103 /* For now, just treat overridden values as verbose. */
104
105 if (list->lvl == ED_OVR)
106 list->lvl = ED_VRB;
107
108 if (list->lvl == lvl) {
109 n = list->descr ? list->descr : list->name;
110 if (list->str)
111 printf("%s%s%s\n", n, delim, list->str);
112 else
113 printf("%s%s%d\n", n, delim, list->value);
114 }
115
116 list = list->next;
117 }
118 }
119
120
121 static int
doit(FILE * fp,int dumplvl,int pas)122 doit(FILE *fp, int dumplvl, int pas)
123 {
124 int mark, gotexif, first;
125 unsigned int len, rlen;
126 unsigned char *exifbuf;
127 struct exiftags *t;
128
129 gotexif = FALSE;
130 first = 0;
131 exifbuf = NULL;
132
133 while (jpegscan(fp, &mark, &len, !(first++))) {
134
135 if (mark != JPEG_M_APP1) {
136 if (fseek(fp, len, SEEK_CUR))
137 exifdie((const char *)strerror(errno));
138 continue;
139 }
140
141 exifbuf = (unsigned char *)malloc(len);
142 if (!exifbuf)
143 exifdie((const char *)strerror(errno));
144
145 rlen = fread(exifbuf, 1, len, fp);
146 if (rlen != len) {
147 exifwarn("error reading JPEG (length mismatch)");
148 free(exifbuf);
149 return (1);
150 }
151
152 t = exifparse(exifbuf, len);
153
154 if (t && t->props) {
155 gotexif = TRUE;
156
157 if (dumplvl & ED_CAM)
158 printprops(t->props, ED_CAM, pas);
159 if (dumplvl & ED_IMG)
160 printprops(t->props, ED_IMG, pas);
161 if (dumplvl & ED_VRB)
162 printprops(t->props, ED_VRB, pas);
163 if (dumplvl & ED_UNK)
164 printprops(t->props, ED_UNK, pas);
165 if (dumplvl & ED_BAD)
166 printprops(t->props, ED_BAD, pas);
167 }
168 exiffree(t);
169 free(exifbuf);
170 }
171
172 if (!gotexif) {
173 exifwarn("couldn't find Exif data");
174 return (1);
175 }
176
177 return (0);
178 }
179
180
181 static
usage()182 void usage()
183 {
184 fprintf(stderr, "Usage: %s [options] [files]\nDisplays Exif data "
185 "from the specified files or standard input.\n", progname);
186 fprintf(stderr, "Version: %s\n\n", version);
187 fprintf(stderr, "Available options:\n");
188 fprintf(stderr, " -a\tDisplay camera-specific, image-specific, "
189 "and verbose properties.\n");
190 fprintf(stderr, " -c\tDisplay camera-specific properties.\n");
191 fprintf(stderr, " -i\tDisplay image-specific properties.\n");
192 fprintf(stderr, " -v\tDisplay verbose properties.\n");
193 fprintf(stderr, " -u\tDisplay unknown/unsupported properties (also "
194 "invalid props w/debug).\n");
195 fprintf(stderr, " -l\tCamera has a removable lens.\n");
196 fprintf(stderr, " -d\tDisplay parse debug information.\n");
197 fprintf(stderr, " -q\tSuppress section headers.\n");
198 fprintf(stderr, " -s\tSet delimiter to provided string "
199 "(default: \": \").\n");
200
201 exit(1);
202 }
203
204
205 int
main(int argc,char ** argv)206 main(int argc, char **argv)
207 {
208 register int ch;
209 int dumplvl, pas, eval;
210 char *mode;
211 FILE *fp;
212
213 progname = argv[0];
214 dumplvl = eval = 0;
215 debug = quiet = FALSE;
216 pas = TRUE;
217 #ifdef WIN32
218 mode = "rb";
219 #else
220 mode = "r";
221 #endif
222
223 while ((ch = getopt(argc, argv, "acivuldqs:")) != -1)
224 switch (ch) {
225 case 'a':
226 dumplvl |= (ED_CAM | ED_IMG | ED_VRB);
227 break;
228 case 'c':
229 dumplvl |= ED_CAM;
230 break;
231 case 'i':
232 dumplvl |= ED_IMG;
233 break;
234 case 'v':
235 dumplvl |= ED_VRB;
236 break;
237 case 'u':
238 dumplvl |= ED_UNK;
239 break;
240 case 'l':
241 pas = FALSE;
242 break;
243 case 'd':
244 debug = TRUE;
245 break;
246 case 'q':
247 quiet = TRUE;
248 break;
249 case 's':
250 delim = optarg;
251 break;
252 case '?':
253 default:
254 usage();
255 }
256 argc -= optind;
257 argv += optind;
258
259 if (!dumplvl && !debug)
260 dumplvl |= (ED_CAM | ED_IMG);
261
262 if (debug && (dumplvl & ED_UNK))
263 dumplvl |= ED_BAD;
264
265 if (*argv) {
266 for (fnum = 0; *argv; ++argv) {
267 if ((fp = fopen(*argv, mode)) == NULL) {
268 exifwarn2(strerror(errno), *argv);
269 eval = 1;
270 continue;
271 }
272
273 fnum++;
274
275 /* Print filenames if more than one. */
276
277 if (argc > 1)
278 printf("%s%s:\n", fnum == 1 ? "" : "\n", *argv);
279
280 if (doit(fp, dumplvl, pas))
281 eval = 1;
282 fclose(fp);
283 }
284 } else {
285 if (doit(stdin, dumplvl, pas))
286 eval = 1;
287 }
288
289 exit(eval);
290 }
291