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: main.c,v 1.30 2005/07/24 15:58:05 alex Exp $";
11 #endif
12
13 /* This program reads and reports the structure of and auxilliary */
14 /* data contained within images produced by digital cameras or */
15 /* similar devices. The program understands several file formats, */
16 /* including TIFF, JPEG, MRW, CIFF, JP2, RAF, and X3F, and will read */
17 /* most TIFF-derived formats such as EXIF, ORF, CR2, NEF, K25, KDC, */
18 /* DNG, and PEF. The RAF code is "preliminary". */
19
20 /* MakerNote sections found in Exif IFDs are reported and expanded if */
21 /* the note is in a semblance of TIFF IFD format (determined */
22 /* automatically, without reference to device make or model). */
23 /* Information which has been published on the internet is used to */
24 /* interpret notes where possible. */
25
26 /* The default output attempts to describe the structure of the file, */
27 /* showing location, size and content of auxilliary data and image */
28 /* sections. Multiple images contained in a single file are noted */
29 /* (and JPEG sub-image markers examined for useful data). A summary */
30 /* of images found is printed at the end of output for each file, */
31 /* including a report of "file format" composed of the major sections */
32 /* found, and the size of the file. */
33
34 /* Many options are provided for detail control of output format. For */
35 /* convenience, two pre-set formats (in addition to the default */
36 /* 'structural' format) provide a "report" format (which shows */
37 /* "structure" of TIFF ifds, but with values printed inline), and a */
38 /* "list" format which eliminates structural elements and presents */
39 /* data in a human (or script) readable format for possible use in */
40 /* gallery applications. */
41
42
43 #include <sys/types.h>
44 #include <stdio.h>
45 #include <stdlib.h>
46 #include <limits.h>
47 #include "defs.h"
48 #include "summary.h"
49 #include "global.h"
50 #include "datadefs.h"
51 #include "misc.h"
52 #include "tags.h"
53 #include "extern.h"
54 #include "ciff_extern.h"
55 #include "x3f_extern.h"
56 #include "jp2_extern.h"
57 #include "mrw_extern.h"
58 #include "maker_extern.h"
59
60 int
main(int argc,char ** argv)61 main(int argc,char **argv)
62 {
63 char *file;
64 char *name = CNULL;
65 FILE *inptr;
66 int status = -1;
67 unsigned long max_offset = 0UL;
68 unsigned long ifd_offset = 0UL;
69 unsigned long dumplength = 0UL;
70 struct fileheader *header = NULL;
71 struct image_summary *summary_entry = NULL;
72 unsigned long filesize = 0UL;
73 int chpr = 0;
74
75
76 Progname = *argv;
77
78 /* Gather options from EXIFPROBE_OPTIONS first */
79 env_options();
80
81 /* Now the command line */
82 argv += process_options(argc,argv);
83
84 while((file = *argv++))
85 {
86 inptr = fopen(file,"r");
87 if(inptr == FNULL)
88 {
89 fprintf(stderr,"%s: failed to open file %s\n",Progname,file);
90 why(stderr);
91 max_offset = 0L;
92 }
93 else
94 {
95 PUSHCOLOR(BLACK);
96 setfilename(file); /* for '-n' option */
97 filesize = get_filesize(inptr);
98
99 if(Start_offset > filesize)
100 {
101 PUSHCOLOR(RED);
102 print_filename();
103 chpr += printf(" start offset %lu > filesize %lu\n",
104 Start_offset,filesize);
105 POPCOLOR();
106 continue;
107 }
108 else if(Start_offset)
109 {
110 if(fseek(inptr,Start_offset,0) == -1)
111 {
112 fprintf(stderr,"%s: FAILED to seek to start offset %lu\n",
113 Progname,Start_offset);
114 why(stdout);
115 continue;
116 }
117 printf("# Start at %ld\n",ftell(inptr));
118 }
119
120 print_filename(); /* for '-n' option */
121 if((LIST_MODE))
122 chpr += printf("FileName = %s",file);
123 else
124 chpr += printf("File Name = %s",file);
125 chpr = newline(chpr);
126
127 header = read_imageheader(inptr,Start_offset);
128 if(ferror(inptr))
129 continue;
130 print_filename();
131 if((LIST_MODE))
132 chpr += printf("FileType = ");
133 else
134 chpr += printf("File Type = ");
135 status = print_filetype(header->probe_magic,header->file_marker);
136 chpr = newline(chpr);
137
138 print_filename();
139 if((LIST_MODE))
140 chpr += printf("FileSize = %lu",filesize);
141 else
142 chpr += printf("File Size = %lu",filesize);
143 chpr = newline(chpr);
144
145 if(status == 0)
146 {
147 switch(header->probe_magic)
148 {
149 case ORF1_MAGIC:
150 case ORF2_MAGIC:
151 case TIFF_MAGIC:
152 ifd_offset = read_ulong(inptr,header->file_marker,HERE);
153 if(ifd_offset > filesize)
154 {
155 hexdump(inptr,Start_offset,10,10,12,0,0);
156 chpr = newline(chpr);
157 if(Max_undefined > 0L)
158 dumplength = Max_undefined - 10;
159 else
160 dumplength = 60;
161 if(dumplength)
162 {
163 hexdump(inptr,Start_offset + 10,
164 filesize - 10 - Start_offset,
165 dumplength,12,0,0);
166 chpr = newline(1);
167 }
168 status = -1;
169 break;
170 }
171 summary_entry = new_summary_entry(NULL,header->probe_magic,TIFF_IFD);
172 name = "TIFF";
173 switch(header->probe_magic)
174 {
175 case ORF1_MAGIC:
176 name = "ORF1";
177 break;
178 case ORF2_MAGIC:
179 name = "ORF2";
180 break;
181 case TIFF_MAGIC:
182 default:
183 break;
184 }
185
186 if(PRINT_SECTION)
187 {
188 print_tag_address(SECTION,Start_offset,0,"@");
189 status = print_header(header,SECTION);
190 chpr += printf(" ifd offset = %#lx/%lu",ifd_offset,ifd_offset);
191 if(Start_offset)
192 {
193 chpr += printf(" (+ %lu = %#lx/%lu)",Start_offset,
194 Start_offset + ifd_offset,
195 Start_offset + ifd_offset);
196 }
197 chpr = newline(chpr);
198 }
199 max_offset = process_tiff_ifd(inptr,header->file_marker,
200 ifd_offset,Start_offset,0L,summary_entry,name,
201 TIFF_IFD,0,-1,0);
202 if(max_offset > 0L)
203 status = 0;
204 fflush(stdout);
205 break;
206 case JPEG_SOI:
207 summary_entry = new_summary_entry(NULL,FILEFMT_JPEG,IMGFMT_JPEG);
208 if(summary_entry)
209 summary_entry->subfiletype = PRIMARY_TYPE;
210 max_offset = process_jpeg_segments(inptr,Start_offset,JPEG_SOI,0L,summary_entry,
211 "JPEG","@",0);
212 status = jpeg_status(0);
213 fflush(stdout);
214 break;
215 case PROBE_CIFFMAGIC:
216 summary_entry = new_summary_entry(NULL,FILEFMT_CIFF,IMGFMT_CRW);
217 if(PRINT_SECTION)
218 {
219 print_tag_address(SECTION,Start_offset,0,"@");
220 status = print_header(header,SECTION);
221 }
222 max_offset = process_ciff(inptr,header,Start_offset,0L,summary_entry,"CIFF",0,0);
223 if(max_offset > 0L)
224 status = 0;
225 fflush(stdout);
226 break;
227 case PROBE_JP2MAGIC:
228 summary_entry = new_summary_entry(NULL,FILEFMT_JP2,IMGFMT_JPEG2000);
229 if(PRINT_SECTION)
230 {
231 print_tag_address(SECTION,Start_offset,0,"@");
232 status = print_header(header,SECTION);
233 }
234 max_offset = process_jp2(inptr,Start_offset + 12L,summary_entry,"JP2",0L);
235 if(max_offset > 0L)
236 status = 0;
237 fflush(stdout);
238 break;
239 case PROBE_MRWMAGIC:
240 summary_entry = new_summary_entry(NULL,FILEFMT_MRW,IMGFMT_MRW);
241 if(PRINT_SECTION)
242 {
243 print_tag_address(SECTION,Start_offset,0,"@");
244 status = print_header(header,SECTION);
245 }
246 max_offset =
247 process_mrw(inptr,Start_offset + 8L,
248 header->mrw_header.mrw_dataoffset,
249 filesize - header->mrw_header.mrw_dataoffset,
250 summary_entry,"MRW",0L);
251 if(max_offset > 0L)
252 status = 0;
253 fflush(stdout);
254 break;
255 case PROBE_RAFMAGIC:
256 summary_entry = new_summary_entry(NULL,FILEFMT_RAF,IMGFMT_RAF);
257 if(PRINT_SECTION)
258 {
259 print_tag_address(SECTION,Start_offset,0,"@");
260 status = print_raf_header(inptr,header,SECTION);
261 }
262 if(status == 0)
263 {
264 max_offset = process_raf(inptr,Start_offset + 48,summary_entry,"RAF",0L);
265 if(max_offset > 0L)
266 status = 0;
267 }
268 fflush(stdout);
269 break;
270 case PROBE_X3FMAGIC:
271 summary_entry = new_summary_entry(NULL,FILEFMT_X3F,IMGFMT_X3F);
272 if(PRINT_SECTION)
273 {
274 print_tag_address(SECTION,Start_offset,0,"@");
275 status = print_x3f_header(inptr,header,SECTION);
276 }
277 if(status == 0)
278 {
279 max_offset = process_x3f(inptr,header,Start_offset,summary_entry,
280 "X3F",0,0);
281 if(max_offset > 0L)
282 status = 0;
283 }
284 break;
285 default:
286 status = -1;
287 break;
288 }
289 if(status == JPEG_EARLY_EOI)
290 chpr = newline(chpr);
291 print_tag_address(SECTION,filesize - 1,0,"-");
292 if(PRINT_SECTION)
293 {
294 chpr += printf("END OF FILE");
295 if(status == JPEG_EARLY_EOI)
296 {
297 jpeg_status(status);
298 print_jpeg_status();
299 }
300 }
301 chpr = newline(chpr);
302 /* Print a summary of image sections found */
303 print_summary(summary_entry);
304 }
305 else
306 {
307 /* Allow hex/ascii dump of unregcognized file */
308 /* formats. In fact, always dump a little bit. */
309 if(Max_undefined == DUMPALL)
310 dumplength = filesize;
311 else if(Max_undefined > 0L)
312 dumplength = Max_undefined;
313 else
314 dumplength = DEF_DUMPLENGTH;
315 if(dumplength)
316 {
317 hexdump(inptr,Start_offset,filesize,dumplength,16,0,0);
318 chpr = newline(chpr);
319 }
320 }
321 print_fileformat(summary_entry);
322 summary_entry = destroy_summary(summary_entry);
323 chpr = newline(1);
324 if(inptr && fclose(inptr))
325 {
326 fprintf(stderr,"%s: FAILED to close stream for file \"%s\"\n",Progname,file);
327 why(stderr);
328 }
329 }
330 clear_memory(); /* Make, Model, Software... */
331 chpr = newline(1);
332 }
333 if(PRINT_CAMERA_NAMES)
334 print_camera_makes();
335 return(status);
336 }
337