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