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