1 /* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- */
2 /* EXIFPROBE - TIFF/JPEG/EXIF image file probe */
3 /* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- */
4 /* Copyright (C) 2002, 2005 by Duane H. Hesser. All rights reserved. */
5 /* */
6 /* See the file LICENSE.EXIFPROBE for terms of use. */
7 /* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- */
8
9 #ifndef lint
10 static char *ModuleId = "@(#) $Id: options.c,v 1.21 2005/07/24 17:18:27 alex Exp $";
11 #endif
12
13 #include <stdio.h>
14 #include <stdlib.h>
15 #include <unistd.h>
16 #include <limits.h>
17 #include <string.h>
18 #include "version.h"
19 #include "defs.h"
20 #include "summary.h"
21 #include "datadefs.h"
22 #include "extern.h"
23 #include "maker_extern.h"
24
25 int Debug = 0;
26
27 int
process_options(int argc,char ** argv)28 process_options(int argc,char **argv)
29 {
30 int opt;
31 unsigned long bits;
32 int nv;
33
34 if((CHECK_TTY_FOR_COLOR))
35 {
36 if(isatty(fileno(stdout)) == 0)
37 Print_options &= ~PCOLOR;
38 }
39 while((opt = getopt(argc,argv,"ace:hil:m:np:s:tuA:B:C:DILM:N:O:RSU:VXY:Z")) != EOF)
40 {
41 switch(opt & 0xff)
42 {
43 case 'I': /* Indent: after -> before -> none -> after */
44 if(PRINT_INDENT_AFTER_ADDRESS)
45 {
46 Print_options &= ~INDENT_AFTER_ADDRESS;
47 Print_options |= INDENT_BEFORE_ADDRESS;
48 }
49 else if(PRINT_INDENT_BEFORE_ADDRESS)
50 Print_options &= ~(INDENT_BEFORE_ADDRESS|INDENT_AFTER_ADDRESS);
51 else
52 {
53 Print_options &= ~INDENT_BEFORE_ADDRESS;
54 Print_options |= INDENT_AFTER_ADDRESS;
55 }
56 break;
57 /* Modes: structural (default), report, or list */
58 case 'S': Print_options = DEFAULT_OPTIONS; break;
59 case 'R': Print_options = REPORT_OPTIONS; break;
60 case 'L': Print_options = LIST_OPTIONS; break;
61
62
63 /* Want hex?...or decimal */
64 case 'D': bits = Print_options & HEX_ONLY;
65 bits = (bits << 1) & DECIMAL_ONLY;
66 Print_options &= ~HEX_ONLY;
67 Print_options |= bits;
68 break;
69 case 'X': bits = Print_options & DECIMAL_ONLY;
70 bits = (bits >> 1) & HEX_ONLY;
71 Print_options &= ~DECIMAL_ONLY;
72 Print_options |= bits;
73 break;
74
75 /* Zero all print options; leaves only image summary and */
76 /* filetype/fileformat. Leave LONGNAMES on. */
77 case 'Z': Print_options = LONGNAMES_FLAG; break;
78
79 /* toggle use of color highlighting */
80 case 'c': Print_options = toggle(Print_options,PCOLOR); break;
81 /* toggle printing of offset values in IFDs "(i)nline" */
82 /* with the directory entry (not at the value offset) */
83 case 'i': Print_options = toggle(Print_options,VALUE_AT_OFFSET); break;
84
85 case 'a': Print_options = toggle(Print_options,HEXADDRESS | DECADDRESS); break;
86
87 /* 'e'ntry options; which parts of an entry to */
88 /* (de)activate */
89 case 'e': while(*optarg)
90 {
91 switch(*optarg)
92 {
93 case 't': Print_options = toggle(Print_options,TAGNAME); break;
94 case 'n': Print_options = toggle(Print_options,DECTAGNO); break;
95 case 'N': Print_options = toggle(Print_options,HEXTAGNO); break;
96 case 'T': Print_options = toggle(Print_options,TYPE); break;
97 case 'v': Print_options = toggle(Print_options,DECVALUE); break;
98 case 'V': Print_options = toggle(Print_options,HEXVALUE); break;
99 case 'o': Print_options = toggle(Print_options,DECOFFSET); break;
100 case 'O': Print_options = toggle(Print_options,HEXOFFSET); break;
101 case 'r': Print_options = toggle(Print_options,RELOFFSET); break;
102 case 'R': Print_options = toggle(Print_options,RAW_VALUES); break;
103 case 'a': Print_options = toggle(Print_options,ASCII_IGNORE_LENGTH); break;
104 case 'A': Print_options = toggle(Print_options,MULTIVAL_PRINT_ALL); break;
105 }
106 ++optarg;
107 }
108 break;
109
110 case 'n': Print_options = toggle(Print_options,FILENAMES); break;
111
112 /* 'p'rint options; which sections/features to */
113 /* (de)activeate */
114 case 'p': while(*optarg)
115 {
116 switch(*optarg)
117 {
118 case 'l': Print_options = toggle(Print_options,LONGNAMES_FLAG); break;
119 case 's': Print_options = toggle(Print_options,SECTION); break;
120 case 'a': Print_options = toggle(Print_options,APP_ENTRY); break;
121 case 'g': Print_options = toggle(Print_options,SEGMENT); break;
122 case 'm': Print_options |= MAKERNOTE_SCHEME; break;
123 case 'M': Print_options |= MAKERNOTE_SCHEME|SCHEME_DEBUG; break;
124 case 'e': Print_options = toggle(Print_options,ENTRY); break;
125 }
126 ++optarg;
127 }
128 break;
129
130 case 'B': /* dump binary image segments and failed Jpeg */
131 /* image segments */
132 if(optarg)
133 {
134 if(*optarg == 'a')
135 Max_imgdump = DUMPALL;
136 else
137 Max_imgdump = strtoul(optarg,NULL,0);
138 }
139 else
140 Max_imgdump = DUMPALL;
141 break;
142 case 'U': /* dump UNDEFINED segments */
143 /* Also affects raw image sections */
144 if(optarg)
145 {
146 if(*optarg == 'a')
147 Max_undefined = DUMPALL;
148 else
149 Max_undefined = strtoul(optarg,NULL,0);
150 }
151 else
152 Max_undefined = DUMPALL;
153 break;
154 case 'M': /* dump MakerNotes */
155 Print_options |= MAKERDUMP;
156 if(optarg)
157 {
158 if(*optarg == 'a')
159 Max_makerdump = DUMPALL;
160 else
161 Max_makerdump = strtoul(optarg,NULL,0);
162 }
163 break;
164 case 'N': /* force a noteversion */
165 if(optarg)
166 {
167 nv = atoi(optarg);
168 setoptionnoteversion(nv);
169 }
170 break;
171 case 'A': /* dump APPn segments */
172 Print_options |= APPNDUMP;
173 if(optarg)
174 {
175 if(*optarg == 'a')
176 Max_appdump = DUMPALL;
177 else
178 Max_appdump = strtoul(optarg,NULL,0);
179 }
180 break;
181 /* Options to force makernote routines to use a specific */
182 /* set of routines to interpret MakerNotes. Scheme */
183 /* detection is automatic and (largely) unaffected */
184 /* (except for certain details which are unavoidably */
185 /* maker-specific). This may be used to check whether a */
186 /* set of MakerNote tags for an undocumented camera */
187 /* actually match a set for which routines exist for */
188 /* another camera */
189
190 /* "Software" has proven unreliable for identification */
191 /* purposes, and is not used for anything. Changing it */
192 /* here will accomplish nothing. */
193
194 case 'm': Use_Make_name = optarg;
195 break;
196 case 'l': Use_Model_name = optarg;
197 break;
198 case 's': Use_Software_name = optarg; /* useless */
199 break;
200
201 /* help and version */
202 case 'h': usage(); exit(0); break;
203 case 'V': print_version(); break;
204
205 /* Y is this happpening? Random debug for development */
206 /* only; e.g bit 0x4 shows summary debug, bit 0x8 shows */
207 /* noteversion debug... */
208 case 'Y': Debug = strtoul(optarg,(char **)0,0); break;
209
210 /* Print make and/or model names of digital cameras */
211 /* "known" to the program. The format is -C make+model, */
212 /* where 'make' and 'model' are strings subjected to a */
213 /* simple substring match with known info. A missing */
214 /* pattern matches everything, so "-C +" prints all known */
215 /* makes and models. As a special case "-C -" prints all */
216 /* makes. Make and Model are significant only for */
217 /* MakerNotes. */
218 case 'C': Camera_name_pattern = optarg;
219 Print_options = toggle(Print_options,CAMERA_NAMES);
220 break;
221 case 'O': Start_offset = strtoul(optarg,0,0);
222 break;
223 case 't': Print_options = toggle(Print_options,TTY_COLOR_CHECK);
224 break;
225 case 'u': Print_options = toggle(Print_options,UNICODE_FLAG);
226 break;
227 default: usage();
228 exit(1);
229 break;
230 }
231 }
232 return(optind);
233 }
234
235
236 /* Grab options from the environment. */
237 #define MAXARGV 256
238
239 extern int vector();
240
241 void
env_options()242 env_options()
243 {
244 char *argv[MAXARGV];
245 char *envopts;
246 int argc;
247
248 envopts = getenv("EXIFPROBE_OPTIONS");
249 if(envopts && *envopts)
250 {
251 optind = 0;
252 /* make an argument vector */
253 argc = vector(envopts,argv," \t",0,MAXARGV);
254 (void)process_options(argc,argv);
255 optind = 1;
256 }
257 }
258
259 void
usage()260 usage()
261 {
262 printf("Usage:\n%s [options] filenames(s)\n",Progname);
263 printf("\t-h - print this help message\n");
264 printf("\t-V - print program version and copyright\n");
265 (void)putchar('\n');
266 printf("\t-R - Report mode: only tagnames and decimal values, indented, inline\n");
267 printf("\t-S - Structure mode: everything, offset values not inline (default)\n");
268 printf("\t-L - List mode: list all tags and values (only); no structure\n");
269 printf("\t-Z - Zero (turn off) all output flags\n");
270 (void)putchar('\n');
271 printf("\t-a - toggle print addresses in hex and decimal\n");
272 printf("\t-D - toggle print enabled addresses, tag numbers and values in decimal only\n");
273 printf("\t-X - toggle print enabled addresses, tag numbers and values in hex only\n");
274 printf("\t-I - toggle indent (after address -> before -> none)\n");
275 printf("\t-i - toggle \"inline\" print of IFD values\n");
276 printf("\t-n - toggle printing of filename at start of each output line\n");
277 printf("\t-c - toggle use of color to highlight certain sections\n");
278 printf("\t-u - print all 16 bits of unicode data\n");
279 (void)putchar('\n');
280
281 printf("\t-p[items] - toggle print identifiers for:\n");
282 printf("\t\ts - sections\n");
283 printf("\t\tg - segments\n");
284 printf("\t\te - IFD entries\n");
285 printf("\t\ta - expand known entries in APP0...APPN segents\n");
286 printf("\t\tm - print MakerNote scheme detection info\n");
287 printf("\t\tM - debug MakerNote scheme detection info\n");
288 printf("\t\tl - long tagnames (default in List mode)\n");
289 (void)putchar('\n');
290
291 printf("\t-e[items] - toggle print IFD entry items:\n");
292 printf("\t\tt - tagname\n");
293 printf("\t\tn - tag number in decimal\n");
294 printf("\t\tN - tag number in hex\n");
295 printf("\t\tT - entry type\n");
296 printf("\t\tv - value in decimal\n");
297 printf("\t\tV - value in hex\n");
298 printf("\t\to - file offset to value in decimal\n");
299 printf("\t\tO - file offset to value in hex\n");
300 printf("\t\tr - relative (unadjusted) offset in decimal\n");
301 printf("\t\tR - print \"raw\" values where expansion of values is needed\n");
302 printf("\t\ta - print ascii strings until null, rather than by length\n");
303 printf("\t\tA - print ALL elements of multiple-value tags\n");
304 (void)putchar('\n');
305
306 printf("\t-M[len|a] - hex/ascii dump 'len' (or all) bytes of unknown MakerNotes\n");
307 printf("\t-A[len|a] - hex/ascii dump 'len' (or all) bytes of unknown APPn segments\n");
308 printf("\t-U[len|a] - hex/ascii dump 'len' (or all) bytes of UNDEFINED data of unknown format\n");
309 printf("\t-B[len|a] - hex/ascii dump 'len' (or all) bytes of binary images or invalid JPEG data\n");
310 printf("\t-N[num] - force noteversion 'num' for MakerNote interpretation\n");
311 printf("\t-m[name] - force use of maker 'name' to select MakerNote interpretation routines\n");
312 printf("\t-l[model] - force use of 'model' to select MakerNote interpretation routines\n");
313 (void)putchar('\n');
314 printf("\t-O[offset] - start processing at 'offset' in file\n");
315 printf("\t-C[make]+[model] - print makes matching 'make', models matching 'model' (substrings)\n");
316 (void)putchar('\n');
317 print_version();
318 }
319
320 extern char *Comptime;
321
322 void
print_version()323 print_version()
324 {
325 printf("\tProgram: '%s' version %s",Progname,Program_version);
326 if(PATCHLEVEL > 0)
327 printf(" patchlevel %d",PATCHLEVEL);
328 (void)putchar('\n');
329 if(Comptime)
330 printf("\tCompiled: %s\n",Comptime);
331 printf("\t%s\n",Copyright);
332 printf("\t\t(open source; see LICENSE.EXIFPROBE)\n");
333 }
334