1 /* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- */
2 /* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- */
3 /*          EXIFPROBE - TIFF/JPEG/EXIF image file probe               */
4 /* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- */
5 /* Copyright (C) 2002, 2005 by Duane H. Hesser. All rights reserved.  */
6 /*                                                                    */
7 /* See the file LICENSE.EXIFPROBE for terms of use.                   */
8 /* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- */
9 
10 #ifndef lint
11 static char *ModuleId = "@(#) $Id: process.c,v 1.47 2005/07/25 22:05:10 alex Exp $";
12 #endif
13 
14 /* Process segment types such as TIFF IFD, JPEG APP segments, and     */
15 /* JPEG basic segments.                                               */
16 
17 #include <sys/types.h>
18 #include <stdio.h>
19 #include <stdlib.h>
20 #include <string.h>
21 #include <ctype.h>
22 
23 #include "defs.h"
24 #include "summary.h"
25 #include "maker.h"
26 #include "datadefs.h"
27 #include "misc.h"
28 #include "tags.h"
29 #include "extern.h"
30 #include "ciff.h"
31 
32 /* Read and decode a TIFF IFD, attempting to describe the location    */
33 /* and structure of the data as it is read. Entry values which live   */
34 /* at an offset from the entry are displayed following the last entry */
35 /* in the IFD (actually after the "next ifd offset") if               */
36 /* VALUE_AT_OFFSET is set in Print_options, so that most IFDS will    */
37 /* have a VALUES section following the entry lines, in just the       */
38 /* manner that the file is laid out by spec. Tag names for offset     */
39 /* values are repeated when the value is printed. If VALUE_AT_OFFSET  */
40 /* is not set, the value is printed immediately, unless the tag       */
41 /* represents a subsection, in which case the offset of the           */
42 /* subsection is printed as the tag value, and the subsection handled */
43 /* in a second pass, after all entries are done.                      */
44 
45 /* Returns a file offset which represents the "highest" position of   */
46 /* the file pointer read by this routine and its subroutines, which   */
47 /* may be used by the caller to read the remainder of the file. This  */
48 /* number (less one) is printed as the offset of the end of the IFD.  */
49 
50 /* At the same time, the function notices non-zero values of "next    */
51 /* ifd offset" which may be contained in this ifd, and passes it as   */
52 /* "max_offset" to routines which read subifds, on the assumption     */
53 /* that this ifd should not write into the next ifd. That value is    */
54 /* used to mark segments which appear to be out of order in the file. */
55 /* If the routine detects by this means that *this* ifd is outside    */
56 /* its natural bounds, and cannot be contained within its parent, it  */
57 /* returns 0, rather than the maximum value offset, so that the       */
58 /* parent routine will not improperly alter its maximum offset.       */
59 
60 /* The arguments are the byteorder to be used when reading integer    */
61 /* data (usually taken from the TIFF header), the offset of the start */
62 /* of the directory, relative to the TIFF header, the offset of the   */
63 /* TIFF header from the beginning of the file, the sequence number of */
64 /* the IFD, and formatting values (indent and address width) to be    */
65 /* used when printing.                                                */
66 
67 /* The routine also attempts to record the location, size, image type */
68 /* and compression method used for actual image data contained within */
69 /* or referenced by a tiff IFD. This information is printed at the    */
70 /* end, as a summary of images found in the file.                     */
71 
72 unsigned long
process_tiff_ifd(FILE * inptr,unsigned short byteorder,unsigned long ifd_offset,unsigned long fileoffset_base,unsigned long max_offset,struct image_summary * summary_entry,char * parent_name,int ifdtype,int ifdnum,int subifdnum,int indent)73 process_tiff_ifd(FILE *inptr,unsigned short byteorder,unsigned long ifd_offset,
74                     unsigned long fileoffset_base,unsigned long max_offset,
75                     struct image_summary *summary_entry,char *parent_name,
76                     int ifdtype,int ifdnum,int subifdnum,int indent)
77 {
78     struct ifd_entry *entry_ptr = NULL;
79     struct image_summary *tmp_summary_entry;
80     unsigned long cur_ifd_offset,next_ifd_offset,current_offset;
81     unsigned long start_entry_offset,entry_offset,value_offset;
82     unsigned long value_start_offset = 0UL;
83     unsigned long offset_limit = 0UL;
84     unsigned long max_value_offset = 0UL;
85     unsigned long max_ifd_offset = 0UL;
86     unsigned long thn_offset = 0UL;     /* JPegInterchangeFormat      */
87     unsigned long thn_length = 0UL;     /* JpegInterChangeFormat      */
88     unsigned long tmp_length = 0L;
89     unsigned long alt_length = 0L;
90     unsigned long limit_offset = 0L;
91     unsigned long filesize = 0UL;
92     unsigned short marker,alt_byteorder = 0;
93     int invalid_entry = 0;
94     int value_is_offset = 0;
95     int use_second_pass = 0;
96     int status = 0;
97     int chpr = 0;
98     int entry_num,num_entries,i;
99     char dirnamebuf[16];
100     char *ifdname,*prefix,*dirname,*nameoftag,*tprefix;
101     char *fulldirname = CNULL;
102     char *listname = CNULL;
103 
104     if(inptr == (FILE *)0)
105     {
106         fprintf(stderr,"%s: no open file pointer to read TIFF IFD\n",
107                 Progname);
108         return(0L);
109     }
110     if(Debug & OUT_DEBUG)
111     {
112         printf("PS=%d,",(Print_options & PRINT_SECTION) > 0);
113         printf("PV=%d,",(Print_options & PRINT_VALUE) > 0);
114         printf("PO=%d,",(Print_options & PRINT_OFFSET) > 0);
115         printf("PVAO=%d\n",(Print_options & PRINT_VALUE_AT_OFFSET) > 0);
116     }
117 
118     filesize = get_filesize(inptr);
119     next_ifd_offset = ifd_offset + fileoffset_base;
120     while(next_ifd_offset)
121     {
122         clearerr(inptr);
123         /* max_offset, if set, is the maximum offset which the parent */
124         /* is willing to claim. max_ifd_offset is the maximum offset  */
125         /* reached by this ifd, which may be constrained by the       */
126         /* "next_ifd_offset" of chained ifds.                         */
127         cur_ifd_offset = next_ifd_offset;
128         if(max_offset && (cur_ifd_offset > max_offset))
129             prefix = ">";   /* outside the parent                     */
130         else
131             prefix = "@";
132 
133         print_tag_address(SECTION,cur_ifd_offset,indent,prefix);
134         switch(ifdtype)
135         {
136             case TIFF_IFD:
137                 if(PRINT_SECTION)
138                     chpr += printf("<IFD %d>",ifdnum);
139                 ifdname = "IFD";
140                 sprintf(dirnamebuf,"Ifd%d",ifdnum);
141                 dirname = dirnamebuf;
142                 break;
143             case TIFF_SUBIFD:
144                 if(PRINT_SECTION)
145                     chpr += printf("<SubIFD %d of IFD %d>",subifdnum,ifdnum);
146                 ifdname = "SubIFD";
147                 sprintf(dirnamebuf,"SubIfd%d",subifdnum);
148                 dirname = dirnamebuf;
149                 break;
150             case INTEROP_IFD:
151                 if(PRINT_SECTION)
152                     chpr += printf("<Interoperability SubIFD>");
153                 ifdname = "Interoperability SubIFD";
154                 dirname = "Interop";
155                 break;
156             case GPS_IFD:
157                 if(PRINT_SECTION)
158                     chpr += printf("<GPS SubIFD>");
159                 ifdname = "GPS SubIFD";
160                 dirname = "Gps";
161                 break;
162             case EXIF_IFD:  /* This shouldn't happen                  */
163                 if(PRINT_SECTION)
164                     chpr += printf("<EXIF IFD>");
165                 ifdname = "EXIF IFD";
166                 dirname = "Exif";
167                 break;
168             case MAKER_SUBIFD:
169                 ifdname = "MakerNote SubIFD";
170                 if(PRINT_SECTION)
171                     chpr += printf("<%s>",ifdname);
172                 dirname = CNULL;
173                 break;
174             default:
175                 if(PRINT_SECTION)
176                     chpr += printf("<UNKNOWN IFD TYPE %d>",ifdtype);    /* SECTION */
177                 ifdname = "UNKNOWN IFD TYPE";
178                 dirname = CNULL;
179                 break;
180         }
181         if(dirname)
182             listname = fulldirname = splice(parent_name,".",dirname);
183         else
184             listname = parent_name;
185 
186         num_entries = read_ushort(inptr,byteorder,cur_ifd_offset);
187         max_value_offset = max_ifd_offset = 0L;
188         if(ferror(inptr) || feof(inptr))
189         {
190             chpr = newline(chpr);
191             printred("#========= WARNING: FAILED to read number of entries for IFD at offset ");
192             chpr += printf("%lu",cur_ifd_offset);
193             if(ferror(inptr))
194                 why(stdout);
195             chpr = newline(chpr);
196             goto blewit;
197         }
198 
199         /* The file pointer is now at the start of the IFD entries    */
200         current_offset = entry_offset = start_entry_offset = ftell(inptr);
201         if(PRINT_SECTION)
202         {
203             chpr += printf(" %d entries ",num_entries);
204             chpr += printf("starting at file offset %#lx=%lu",
205                                             start_entry_offset,start_entry_offset);
206             chpr = newline(chpr);
207         }
208 
209         if((summary_entry == NULL) || summary_entry->entry_lock)
210             summary_entry = new_summary_entry(summary_entry,0,ifdtype);
211         else
212             summary_entry = last_summary_entry(summary_entry);
213         if(summary_entry)
214         {
215             summary_entry->datatype = ifdtype;
216             summary_entry->imageformat = IMGFMT_NOIMAGE;
217             summary_entry->filesubformat |= FILESUBFMT_TIFF;
218             if((ifdtype == TIFF_IFD) || (ifdtype == TIFF_SUBIFD) || (ifdtype == MAKER_SUBIFD))
219             {
220                 summary_entry->ifdnum = ifdnum;
221                 summary_entry->subifdnum = subifdnum;
222             }
223         }
224         use_second_pass = value_is_offset = 0;
225 
226         indent += SMALLINDENT;
227         for(entry_num = 0; entry_num < num_entries; ++entry_num)
228         {
229             entry_ptr = read_ifd_entry(inptr,byteorder,entry_offset);
230 
231             if((entry_ptr->value_type == 0) || (entry_ptr->value_type > DOUBLE) ||
232                 ferror(inptr) || feof(inptr))
233             {
234                 print_tag_address(ENTRY,entry_offset,indent,prefix);
235                 print_taginfo(entry_ptr,listname,SMALLINDENT,ifdtype,ifdnum,subifdnum);
236                 if((PRINT_ENTRY))
237                     printred(" INVALID ENTRY");
238                 chpr = newline(chpr);
239 
240                 /* If there are a few invalid entries in an otherwise */
241                 /* valid IFD, the invalid entries should be reported. */
242                 /* An invalid IFD, with 50,000 entries or so, all     */
243                 /* invalid, should be nipped in the bud.              */
244 
245                 clearerr(inptr);
246                 current_offset = ftell(inptr);
247                 if(max_offset > 0)
248                     limit_offset = max_offset;
249                 else
250                 {
251                     if(fseek(inptr,0L,2) != -1)
252                     {
253                         limit_offset = ftell(inptr);
254                         fseek(inptr,0L,current_offset);
255                     }
256                 }
257                 /* If there's an error on input, or we can't check    */
258                 /* for absurd num_entries, give up.                   */
259                 if(!ferror(inptr) && !feof(inptr) && (limit_offset > 0))
260                 {
261                     /* If the number of entries would read past the   */
262                     /* size of the IFD, or past EOF, give up          */
263                     if((ifd_offset + (12 * num_entries)) < limit_offset)
264                     {
265                         /* Limit the number of consecutive failures.  */
266                         /* An apparently valid entry resets the count */
267                         /* to 0.                                      */
268                         if(invalid_entry++ < MAX_INVALID_ENTRIES)
269                         {
270                             entry_offset = current_offset;
271                             clearerr(inptr);
272                             continue;
273                         }
274                     }
275                 }
276                 chpr = newline(chpr);
277                 goto blewit;
278             }
279             invalid_entry = 0;
280             current_offset = ftell(inptr);
281 
282             switch(entry_ptr->tag)
283             {
284                 case TIFFTAG_OldSubFileType:   /* old, deprecated        */
285                     if(summary_entry)
286                     {
287                         summary_entry->filesubformat |= FILESUBFMT_TIFFEP;
288                         if(entry_ptr->value == 1)
289                             summary_entry->subfiletype = PRIMARY_TYPE;
290                         else if(entry_ptr->value == 2)
291                             summary_entry->subfiletype = REDUCED_RES_TYPE;
292                         else if(entry_ptr->value == 3)
293                             summary_entry->subfiletype = PAGE_TYPE;
294                     }
295                     break;
296                 case TIFFTAG_NewSubFileType:
297                     if(summary_entry)
298                     {
299                         summary_entry->filesubformat |= FILESUBFMT_TIFFEP;
300                         if(entry_ptr->value == 0)
301                             summary_entry->subfiletype = PRIMARY_TYPE;
302                         else if(entry_ptr->value == 1)
303                             summary_entry->subfiletype = REDUCED_RES_TYPE;
304                         else if(entry_ptr->value == 2)
305                             summary_entry->subfiletype = PAGE_TYPE;
306                         else if(entry_ptr->value == 3)
307                             summary_entry->subfiletype = MASK_TYPE;
308                     }
309                     break;
310                 case INTEROPTAG_RelatedImageWidth: /* ###%%% ???      */
311                 case TIFFTAG_ImageWidth:
312                     if(summary_entry)
313                         summary_entry->pixel_width = entry_ptr->value;
314                     break;
315                 case INTEROPTAG_RelatedImageLength: /* ###%%% ???     */
316                 case TIFFTAG_ImageLength:
317                     if(summary_entry)
318                         summary_entry->pixel_height = entry_ptr->value;
319                     break;
320                 case TIFFTAG_Compression:
321                     if(summary_entry)
322                     {
323                         summary_entry->compression = entry_ptr->value;
324                         if((entry_ptr->value == 7) || (entry_ptr->value == 6))
325                         {
326                             if(entry_ptr->value == 6)
327                                 summary_entry->filesubformat |= FILESUBFMT_TIFFOLD;
328                             /* Some of this may have to be undone     */
329                             /* later, if we find out they lied        */
330                             summary_entry->entry_lock = lock_number(summary_entry);
331                             if(summary_entry->imageformat == 0)
332                                 summary_entry->imageformat = IMGFMT_JPEG;
333                         }
334                         else
335                         {
336                             summary_entry->entry_lock = lock_number(summary_entry);
337 
338                             if(summary_entry->imageformat == 0)
339                                 summary_entry->imageformat = IMGFMT_TIFF;
340                             if(summary_entry->compression == 34713)
341                                 summary_entry->filesubformat |= FILESUBFMT_NEF;
342                             /* If there is no subfiletype tag, this   */
343                             /* could be the primary, or it could be a */
344                             /* thumbnail                              */
345                             if(summary_entry->subfiletype <= POSSIBLE_PRIMARY_TYPE)
346                                 summary_entry->subfiletype = POSSIBLE_PRIMARY_TYPE;
347                         }
348                     }
349                     break;
350                 case TIFFTAG_PhotometricInterpretation:
351                     /* It appears that the PMI values used in Olympus */
352                     /* ORF files (1 or 2 for the primary image) do    */
353                     /* not correspond to legitimate TIFF PMI values.  */
354                     /* Record them "as is" here, but they shouldn't   */
355                     /* be *interpreted* in the same way as TIFF files */
356                     if(summary_entry)
357                         summary_entry->imagesubformat = entry_ptr->value | IMGSUBFMT_VALUE_IS_PMI;
358                     break;
359                 case TIFFTAG_JPEGInterchangeFormat:
360                     /* actually an offset...                          */
361                     /* This method of JPEG-in-TIFF is discouraged by  */
362                     /* the TIFF spec (after Technote 2), for good and */
363                     /* sufficient reason>                             */
364                     thn_offset = entry_ptr->value + fileoffset_base;
365                     break;
366                 case TIFFTAG_JPEGInterchangeFormatLength:
367                     thn_length = entry_ptr->value;
368                     break;
369                 case TIFFTAG_StripOffsets:
370                 case TIFFTAG_TileOffsets:
371                     /* If there are multiple strips, this will be     */
372                     /* wrong, but will be overwritten in the second   */
373                     /* pass.                                          */
374                     if(summary_entry)
375                     {
376                         summary_entry->offset = entry_ptr->value;
377                         if((summary_entry->compression != 6) &&
378                                         (summary_entry->compression != 7))
379                         {
380                             summary_entry->entry_lock = lock_number(summary_entry);
381                         }
382                     }
383                     break;
384                 case TIFFTAG_StripByteCounts:
385                 case TIFFTAG_TileByteCounts:
386                     /* This may also be overwritten in the second     */
387                     /* pass                                           */
388                     if(summary_entry)
389                     {
390                         summary_entry->length = entry_ptr->value;
391                         if((summary_entry->compression != 6) &&
392                                         (summary_entry->compression != 7))
393                         {
394                             summary_entry->entry_lock = lock_number(summary_entry);
395                         }
396                     }
397                     break;
398                 case TIFFEPTAG_TIFF_EPStandardID:
399                     if(summary_entry)
400                         summary_entry->filesubformat |= FILESUBFMT_TIFFEP;
401                     break;
402                 case TIFFTAG_Make:
403                 case TIFFTAG_Model:
404                 case TIFFTAG_Software:
405                     {
406                         char *makename,*modelname,*swname;
407 
408                         /* These items will be read and printed in    */
409                         /* the second pass, if one is made. This      */
410                         /* grabs them and records them in globals,    */
411                         /* which may be used later by the makernote   */
412                         /* code.                                      */
413                         switch(entry_ptr->tag)
414                         {
415                             case TIFFTAG_Make:
416                                 if(Make_name == NULL)
417                                 {
418                                     makename =
419                                         (char *)read_bytes(inptr,
420                                                         entry_ptr->count,
421                                                         fileoffset_base +
422                                                         entry_ptr->value);
423                                     Make_name = strdup(makename);
424                                 }
425                                 break;
426                             case TIFFTAG_Model:
427                                 if(Model_name == NULL)
428                                 {
429                                     modelname =
430                                         (char *)read_bytes(inptr,
431                                                         entry_ptr->count,
432                                                         fileoffset_base +
433                                                         entry_ptr->value);
434                                     Model_name = strdup(modelname);
435                                 }
436                                 break;
437                             case TIFFTAG_Software:
438                                 if(Software_name == NULL)
439                                 {
440                                     swname =
441                                         (char *)read_bytes(inptr,
442                                                         entry_ptr->count,
443                                                         fileoffset_base +
444                                                         entry_ptr->value);
445                                     Software_name = strdup(swname);
446                                 }
447                                 break;
448                         }
449                     }
450                     break;
451                     case TIFFTAG_BitsPerSample:
452                         if(summary_entry)
453                         {
454                             /* Do not override information from       */
455                             /* earlier sections; the tiff section in  */
456                             /* e.g. MRW sections can lie if the image */
457                             /* has been improperly handled by         */
458                             /* other-party software.                  */
459                             if(summary_entry->bps[0] == 0)
460                             {
461                                 if(entry_ptr->count < 3)
462                                 {
463                                     summary_entry->bps[0] = (unsigned short)entry_ptr->value & 0xffff;
464                                     if(entry_ptr->count == 2)
465                                         summary_entry->bps[1] =
466                                             (unsigned short)((entry_ptr->value & 0xffff0000) >> 16);
467                                 }
468                                 else
469                                 {
470                                     summary_entry->bps[0] = read_ushort(inptr,byteorder,entry_ptr->value);
471                                     for(i = 1; (i < entry_ptr->count) && (i < MAXSAMPLE); ++i)
472                                         summary_entry->bps[i] = read_ushort(inptr,byteorder,HERE);
473                                 }
474                             }
475                         }
476                         break;
477                     case TIFFTAG_SamplesPerPixel:
478                         if((summary_entry) && (summary_entry->spp == 0))
479                             summary_entry->spp = entry_ptr->value;
480                         break;
481                     case DNGTAG_DNGVersion:    /* A DNG-specific tag */
482                         if(summary_entry)
483                             summary_entry->filesubformat |= FILESUBFMT_DNG;
484                         break;
485                     case TIFFTAG_CR2_0xc5d9:    /* A CR2-specific tag */
486                         if(summary_entry)
487                         {
488                             summary_entry->filesubformat |= FILESUBFMT_CR2;
489                             if((summary_entry->compression == 6) &&
490                                             (summary_entry->imagesubformat == IMGSUBFMT_RGB))
491                             {
492                                 summary_entry->subfiletype = REDUCED_RES_TYPE;
493                             }
494                         }
495                         break;
496                     case TIFFTAG_CR2_0xc5d8:
497                     case TIFFTAG_CR2_0xc5e0:
498                     case TIFFTAG_CR2_0xc640:
499                         /* These tags appear (so far) only in the     */
500                         /* weird IFD containing the lossless jpeg     */
501                         /* primary. It is possible to check for other */
502                         /* things, e.g. just compression, strip       */
503                         /* offset and bytecount (1 each), but for now */
504                         /* just assume that any of these tags means   */
505                         /* CR2. The compression at this point will be */
506                         /* 6, but will be re-marked JPEG_SOF_3 when   */
507                         /* the image is scanned.                      */
508                         if(summary_entry)
509                         {
510                             summary_entry->filesubformat |= FILESUBFMT_CR2;
511                             summary_entry->subfiletype = PRIMARY_TYPE;
512                         }
513                         break;
514                 case TIFFTAG_SubIFDtag:
515                 case EXIFTAG_ExifIFDPointer:
516                 case EXIFTAG_GPSInfoIFDPointer:
517                 case EXIFTAG_Interoperability:
518                 case TIFFTAG_PrintIM:
519                     use_second_pass++;
520                     break;
521                 default:
522                     break;
523             }
524             print_tag_address(ENTRY,entry_offset,indent,prefix);
525             value_offset = print_entry(inptr,byteorder,entry_ptr,fileoffset_base,
526                                                 summary_entry,listname,ifdtype,
527                                                 ifdnum, subifdnum, SMALLINDENT);
528 
529             /* Keep track of how far into the file reading progresses */
530             if(value_offset == 0UL)
531                 value_offset = current_offset;
532             if(value_offset > max_value_offset)
533                 max_value_offset = value_offset;
534             if((is_offset(entry_ptr)))
535                 ++use_second_pass;
536             entry_offset = current_offset;
537         }
538 
539         next_ifd_offset = read_ulong(inptr,byteorder,current_offset);
540         if(next_ifd_offset > 0UL)
541         {
542             if((PRINT_VALUE) && (PRINT_SECTION) && (PRINT_VALUE_AT_OFFSET))
543             {
544                 print_tag_address(SECTION,current_offset,indent,prefix);
545                 chpr += printf("**** next IFD offset %lu",next_ifd_offset);
546                 next_ifd_offset += fileoffset_base;
547                 chpr += printf("(+ %lu = %#lx/%lu)",fileoffset_base,
548                             next_ifd_offset,next_ifd_offset);
549             }
550             else
551                 next_ifd_offset += fileoffset_base;
552             if((next_ifd_offset < ftell(inptr)) ||
553                 ((ifdtype != TIFF_IFD) && (ifdtype != TIFF_SUBIFD)))
554             {
555                 if(PRINT_SECTION)
556                     printred(" INVALID NEXT IFD OFFSET ");
557                 else
558                 {
559                     chpr = newline(chpr);
560                     printred("# ========= WARNING: INVALID NEXT IFD OFFSET ");
561                     chpr += printf("%ld in ",next_ifd_offset);
562                     /* Until someone creates a subifd in a subifd,    */
563                     /* this is enough.                                */
564                     if(ifdtype == TIFF_IFD)
565                         chpr += printf("IFD %d =========",ifdnum);
566                     else if(ifdtype == TIFF_SUBIFD)
567                         chpr += printf("SUBIFD %d of IFD %d =========",subifdnum,ifdnum);
568                     else
569                         chpr += printf("%s =========",ifdname);
570                 }
571                 next_ifd_offset = 0L;
572             }
573             /* This is the limit of offsets which should be part of   */
574             /* this ifd; a limit may have been passed in from the     */
575             /* parent, if it had a length of this section. This will  */
576             /* replace that number unconditionally, although it may   */
577             /* be that one should be checked against the other...     */
578             /* This can be checked against max_value_offset, and      */
579             /* value_offset in the second pass.                       */
580             max_offset = next_ifd_offset;
581             chpr = newline(chpr);
582         }
583         else
584         {
585             if((PRINT_VALUE) && (PRINT_SECTION) && (PRINT_VALUE_AT_OFFSET))
586             {
587                 print_tag_address(SECTION,current_offset,indent,prefix);
588                 chpr += printf("**** next IFD offset 0");
589                 chpr = newline(chpr);
590             }
591         }
592 
593         if(max_value_offset < current_offset)
594             max_ifd_offset = current_offset;
595         else
596             max_ifd_offset = max_value_offset;
597 
598         if(Debug & END_OF_SECTION_DEBUG)
599             printf("mo=%lu, mvo=%lu, mio=%lu, nio=%lu, ol=%lu\n",max_offset,max_value_offset,max_ifd_offset,next_ifd_offset,offset_limit);
600 
601         /* If we made it through the first pass, we should be able to */
602         /* get some info from the second pass, so don't let a failure */
603         /* here stop us. It will fail later.                          */
604         if(ferror(inptr) || feof(inptr))
605         {
606             chpr += printf("#========= WARNING: READ NEXT IFD OFFSET FAILED =========");
607             chpr = newline(chpr);
608             why(stdout);
609             clearerr(inptr);    /* keep going...                      */
610         }
611         else
612             current_offset = ftell(inptr);
613 
614         value_offset = current_offset;
615         if(use_second_pass)
616         {
617             if((PRINT_VALUE) && (PRINT_SECTION) && (PRINT_VALUE_AT_OFFSET))
618             {
619                 print_tag_address(SECTION,value_offset,indent,prefix);
620                 chpr += printf("============= VALUES, ");
621 
622                 if(ifdtype == TIFF_IFD)
623                     chpr += printf("IFD %d",ifdnum);
624                 else if(ifdtype == TIFF_SUBIFD)
625                     chpr += printf("SubIFD %d of IFD %d",subifdnum,ifdnum);
626                 else if(ifdtype == INTEROP_IFD)
627                     chpr += printf("Interoperability SubIFD");
628                 else if(ifdtype == EXIF_IFD)    /* shouldn't happen   */
629                     chpr += printf("EXIF IFD");
630                 else if(ifdtype == MAKER_SUBIFD)
631                     chpr += printf("%s",ifdname);
632                 else
633                     chpr += printf("UNKNOWN IFD TYPE %d",ifdtype);
634                 chpr += printf(" ============");
635                 chpr = newline(chpr);
636             }
637 
638             /* Second pass, to evaluate entries which are stored      */
639             /* indirectly (the value requires more than 4 bytes).     */
640 
641             /* This time we have to explicitly seek to each entry,    */
642             /* since the value processing may send the file pointer   */
643             /* off to exotic places.                                  */
644             entry_offset = start_entry_offset;
645             for(entry_num = 0; entry_num < num_entries; ++entry_num)
646             {
647                 entry_ptr = read_ifd_entry(inptr,byteorder,entry_offset);
648                 if((entry_ptr->value_type == 0) || (entry_ptr->value_type > DOUBLE) ||
649                     ferror(inptr) || feof(inptr))
650                 {
651                     /* If the first pass made it through invalid      */
652                     /* entries, this pass should just ignore them and */
653                     /* quietly continue.                              */
654                     clearerr(inptr);
655                     entry_offset = current_offset = ftell(inptr);
656                     continue;
657                 }
658                 entry_offset = current_offset = ftell(inptr);
659                 value_is_offset = is_offset(entry_ptr);
660                 switch(entry_ptr->tag)
661                 {
662                     case TIFFTAG_SubIFDtag:
663                         value_offset = process_subifd(inptr,byteorder,
664                                             entry_ptr, fileoffset_base,0L,
665                                             summary_entry,listname,
666                                             ifdnum,++subifdnum,TIFF_SUBIFD,
667                                             indent);
668                         /* subifds are not part of the IFD; throw     */
669                         /* away this value for now.                   */
670                         value_offset = 0;
671                         break;
672                     case EXIFTAG_ExifIFDPointer:
673                         value_start_offset = entry_ptr->value + fileoffset_base;
674                         value_offset = process_exif_ifd(inptr,byteorder,
675                                             entry_ptr->value,fileoffset_base,
676                                             next_ifd_offset,summary_entry,listname,
677                                             ifdnum,indent);
678                         if(max_offset && (value_offset > max_offset))
679                             offset_limit = value_offset;
680                         break;
681                     case EXIFTAG_GPSInfoIFDPointer:
682                         value_offset = process_gps_ifd(inptr,byteorder,
683                                             entry_ptr->value,fileoffset_base,
684                                             next_ifd_offset,summary_entry,listname,
685                                             ifdnum,indent);
686                         break;
687                     case EXIFTAG_Interoperability:
688                         /* This doesn't belong in a TIFF IFD, but     */
689                         /* be prepared.                               */
690                         PUSHCOLOR(INTEROP_COLOR);
691                         value_offset = process_tiff_ifd(inptr,byteorder,
692                                                 entry_ptr->value,fileoffset_base,
693                                                 next_ifd_offset,summary_entry,
694                                                 listname,INTEROP_IFD,ifdnum,0,
695                                                 indent);
696                         value_offset = 0;
697                         POPCOLOR();
698                         break;
699                     case TIFFTAG_StripOffsets:
700                     case TIFFTAG_TileOffsets:
701                         /* Update the summary values set in the first */
702                         /* pass                                       */
703                         /* Bad strip offsets seem to be one of the    */
704                         /* more common errors, especially when images */
705                         /* have been processed by editing software.   */
706                         /* Offsets greater than filesize are easy to  */
707                         /* detect, so check for them, and test to see */
708                         /* if they're just written with the wrong     */
709                         /* byteorder.                                 */
710 
711                         /* ###%%% need to record number of offsets    */
712                         /* and location of offsets for multi-tile     */
713                         /* (multi-strip?) images jpeg-compressed by   */
714                         /* tile (seen in DNG)                         */
715 
716                        if((value_is_offset) && summary_entry)
717                         {
718                             alt_byteorder = byteorder;
719                             summary_entry->chunkhow = entry_ptr->tag;
720                             summary_entry->chunktype = entry_ptr->value_type;
721                             /* ###%%% combine short and long cases; just switch read_xxx() */
722                             if(entry_ptr->value_type == LONG)
723                             {
724                                 unsigned long tmp_offset;
725 
726                                 tmp_offset = read_ulong(inptr,byteorder,entry_ptr->value + fileoffset_base);
727                                 summary_entry->offset = tmp_offset;
728                                 summary_entry->offset_loc = entry_ptr->value +fileoffset_base;
729                                 summary_entry->noffsets = entry_ptr->count;
730                                 if(tmp_offset > filesize)
731                                 {
732                                     chpr = newline(chpr);
733                                     PUSHCOLOR(HI_RED);
734                                     print_filename();
735                                     chpr += printf("# WARNING: initial stripoffset (%#lx/%lu) > filesize...wrong byteorder? ",
736                                                     tmp_offset,tmp_offset);
737                                     print_byteorder(byteorder,1);
738                                     chpr = newline(chpr);
739                                     if(byteorder == TIFF_MOTOROLA)
740                                         alt_byteorder = TIFF_INTEL;
741                                     else
742                                         alt_byteorder = TIFF_MOTOROLA;
743                                     tmp_offset = read_ulong(inptr,alt_byteorder,
744                                             entry_ptr->value + fileoffset_base);
745                                     print_filename();
746                                     chpr += printf("# WARNING: initial stripoffset using alt byteorder [");
747                                     print_byteorder(alt_byteorder,1);
748                                     chpr += printf("] is %#lx/%lu ",
749                                                     tmp_offset,tmp_offset);
750                                     chpr = newline(chpr);
751                                     if(tmp_offset < filesize)
752                                         summary_entry->offset = tmp_offset;
753                                     POPCOLOR();
754                                 }
755                             }
756                             else
757                             {
758                                 unsigned short tmp_offset;
759 
760                                 tmp_offset = read_ushort(inptr,byteorder,entry_ptr->value + fileoffset_base);
761                                 summary_entry->offset = tmp_offset;
762                                 summary_entry->offset_loc = entry_ptr->value +fileoffset_base;
763                                 summary_entry->noffsets = entry_ptr->count;
764                                 if((unsigned long)tmp_offset > filesize)
765                                 {
766                                     chpr = newline(chpr);
767                                     PUSHCOLOR(HI_RED);
768                                     print_filename();
769                                     chpr += printf("# WARNING: initial stripoffset (%#x/%u) > filesize...wrong byteorder? ",
770                                                     tmp_offset,tmp_offset);
771                                     print_byteorder(byteorder,1);
772                                     chpr = newline(chpr);
773                                     if(byteorder == TIFF_MOTOROLA)
774                                         alt_byteorder = TIFF_INTEL;
775                                     else
776                                         alt_byteorder = TIFF_MOTOROLA;
777                                     tmp_offset = read_ushort(inptr,alt_byteorder,
778                                                 entry_ptr->value + fileoffset_base);
779                                     print_filename();
780                                     chpr += printf("# WARNING: initial stripoffset using alt byteorder  [");
781                                     print_byteorder(alt_byteorder,1);
782                                     chpr += printf("] is %#x/%u ",
783                                                     tmp_offset,tmp_offset);
784                                     chpr = newline(chpr);
785                                     if(tmp_offset < filesize)
786                                         summary_entry->offset = tmp_offset;
787                                     POPCOLOR();
788                                 }
789                             }
790                         }
791                         if((PRINT_VALUE) && ((PRINT_VALUE_AT_OFFSET) && value_is_offset))
792                         {
793                             print_tag_address(ENTRY,fileoffset_base + entry_ptr->value,
794                                                 indent,prefix);
795                             print_tagid(entry_ptr,SMALLINDENT,ifdtype);
796                             value_offset =
797                                 print_offset_value(inptr,byteorder,entry_ptr,
798                                                 fileoffset_base,listname,
799                                                 ifdtype,indent,1);
800                         }
801                         break;
802                     case TIFFTAG_StripByteCounts:
803                     case TIFFTAG_TileByteCounts:
804                         if((value_is_offset) && summary_entry)
805                         {
806                             tmp_length =
807                                 sum_strip_bytecounts(inptr,byteorder,
808                                             entry_ptr->value + fileoffset_base,
809                                             entry_ptr->count,entry_ptr->value_type);
810 
811                             summary_entry->length = tmp_length;
812                             summary_entry->length_loc = entry_ptr->value + fileoffset_base;
813                             if(summary_entry->noffsets != entry_ptr->count)
814                                 printred(" # Warning: number of bytecounts != number of offsets");
815                             if(tmp_length > filesize)
816                             {
817                                 chpr = newline(chpr);
818                                 PUSHCOLOR(HI_RED);
819                                     print_filename();
820                                 chpr += printf("# WARNING: total stripbytecount (%#lx/%lu) > filesize (%lu) ... wrong byteorder? ",
821                                                 tmp_length,tmp_length,filesize);
822                                 print_byteorder(byteorder,1);
823                                 chpr = newline(chpr);
824                                 if(byteorder == TIFF_MOTOROLA)
825                                     alt_byteorder = TIFF_INTEL;
826                                 else
827                                     alt_byteorder = TIFF_MOTOROLA;
828                                 alt_length =
829                                     sum_strip_bytecounts(inptr,alt_byteorder,
830                                                 entry_ptr->value + fileoffset_base,
831                                                 entry_ptr->count,entry_ptr->value_type);
832                                 print_filename();
833                                 chpr += printf("# WARNING: total stripbytecount using alt byteorder [");
834                                 print_byteorder(alt_byteorder,1);
835                                 chpr += printf("] is %#lx/%lu ",
836                                                 alt_length,alt_length);
837                                 chpr = newline(chpr);
838                                 if(alt_length < filesize)
839                                     summary_entry->length = alt_length;
840                                 else
841                                 {
842                                     print_filename();
843                                     chpr += printf("# WARNING: file may be truncated");
844                                     chpr = newline(chpr);
845                                 }
846                                 POPCOLOR();
847                             }
848                         }
849                         if((PRINT_VALUE) && ((PRINT_VALUE_AT_OFFSET) && value_is_offset))
850                         {
851                             print_tag_address(ENTRY,fileoffset_base + entry_ptr->value,
852                                                 indent,prefix);
853                             print_tagid(entry_ptr,SMALLINDENT,ifdtype);
854                             value_offset =
855                                 print_offset_value(inptr,byteorder,entry_ptr,
856                                                 fileoffset_base,listname,
857                                                 ifdtype,indent,1);
858                             /* ###%%% find a way to print total       */
859                             /* ByteCount, at least in LIST mode       */
860                         }
861                         break;
862                     case TIFFTAG_JPEGTables:
863                         nameoftag = tagname(entry_ptr->tag);
864                         if((PRINT_VALUE) && ((PRINT_VALUE_AT_OFFSET) && value_is_offset))
865                         {
866                             if(PRINT_SECTION)
867                             {
868                                 chpr = newline(chpr);
869                                 print_tag_address(ENTRY,fileoffset_base + entry_ptr->value,
870                                                     indent,prefix);
871                                 chpr += printf("# Start of %s length %lu",nameoftag,
872                                                             entry_ptr->count);
873                                 chpr = newline(chpr);
874                             }
875                         }
876                         marker = read_ushort(inptr,TIFF_MOTOROLA,fileoffset_base + entry_ptr->value);
877                         /* Need a new entry; this IFD's entry may be  */
878                         /* used for an image, but may not be locked   */
879                         /* yet.                                       */
880                         tmp_summary_entry = new_summary_entry(summary_entry,0,IMGFMT_JPEG);
881                         value_offset = process_jpeg_segments(inptr,
882                                                     fileoffset_base + entry_ptr->value,
883                                                     marker,entry_ptr->count,
884                                                     tmp_summary_entry,listname,
885                                                     prefix,indent+SMALLINDENT);
886                         if(tmp_summary_entry)
887                             tmp_summary_entry->imagesubformat = TIFFTAG_JPEGTables;
888                         if((PRINT_VALUE) && ((PRINT_VALUE_AT_OFFSET) && value_is_offset))
889                         {
890                             if((PRINT_SECTION))
891                             {
892                                 /* ###%% check for early EOI;         */
893                                 if((status = jpeg_status(0) == JPEG_EARLY_EOI))
894                                     chpr = newline(chpr);
895                                 jpeg_status(status);
896                                 print_tag_address(ENTRY,fileoffset_base + entry_ptr->value + entry_ptr->count + 1,
897                                                     indent,prefix);
898                                 chpr += printf("# End of %s",nameoftag);
899                                 print_jpeg_status();
900                                 chpr = newline(chpr);
901                             }
902                         }
903                         break;
904                     case TIFFTAG_PrintIM:
905                         if(next_ifd_offset && (cur_ifd_offset > next_ifd_offset))
906                             prefix = "+";
907                         else
908                             prefix = "@";
909                         process_pim(inptr,byteorder,entry_ptr->value,fileoffset_base,
910                                     entry_ptr->count,tagname(entry_ptr->tag),
911                                     listname,prefix,indent);
912                         chpr = newline(0);
913                         break;
914                     default:
915                         if((PRINT_VALUE) && ((PRINT_VALUE_AT_OFFSET) && value_is_offset))
916                         {
917                             print_tag_address(ENTRY,fileoffset_base + entry_ptr->value,
918                                                     indent,prefix);
919                             print_tagid(entry_ptr,SMALLINDENT,ifdtype);
920                             value_offset =
921                                 print_offset_value(inptr,byteorder,entry_ptr,
922                                                 fileoffset_base,listname,
923                                                 ifdtype,indent,1);
924                         }
925                         break;
926                 }
927                 if(value_offset == 0L) /* bad entry; try the next one */
928                     clearerr(inptr);
929                 else if(value_offset > max_value_offset)
930                     max_value_offset = value_offset;
931             }
932         }
933         else if(current_offset > max_value_offset)
934             max_value_offset = current_offset;
935         max_ifd_offset = max_value_offset;
936 
937         indent -= SMALLINDENT;
938 
939         /* max_ifd_offset is the maximum offset we've read so far;    */
940         /* max_offset, if set, is the highest offset of this ifd,     */
941         /* according to either the parent or the recently-read        */
942         /* next_ifd_offset.                                           */
943 
944         if(max_offset && (max_ifd_offset > max_offset))
945             prefix = "?";
946         if(Debug & END_OF_SECTION_DEBUG)
947             printf("mo=%lu, mvo=%lu, mio=%lu, nio=%lu, ol=%lu, prefix=%s\n",
948                                 max_offset,max_value_offset,max_ifd_offset,
949                                 next_ifd_offset,offset_limit,prefix);
950 
951         /* ================== show jpeg thumbnail =================== */
952         if(thn_offset || thn_length)
953         {
954             int startindent;
955 
956             if(Debug & END_OF_SECTION_DEBUG)
957                 printf("mo=%lu, ol=%lu, thno=%lu\n",max_offset,offset_limit,thn_offset);
958             /* This will be set only if a JpegInterchangeFormat tag   */
959             /* has been seen, so this must be a JPEG thumbnail. The   */
960             /* Exif spec indicates that the data should be written    */
961             /* within the values section of the IFD, so scan and      */
962             /* report here. If it appears to be written outside the   */
963             /* bounds of the IFD, mark it. "max_offset" is the        */
964             /* parent's idea (if any) of the extent of the IFD.       */
965             /* "offset_limit" is the beginning of the Exif section,   */
966             /* if present.                                            */
967 
968             if(max_offset && (thn_offset > max_offset))
969                 tprefix = ">";
970             else if(offset_limit && (thn_offset > offset_limit))
971                 tprefix = "+";
972             else
973                 tprefix = prefix;
974             startindent = charsprinted();
975             print_tag_address(SECTION,thn_offset,indent + SMALLINDENT,tprefix);
976             if(PRINT_SECTION)
977             {
978                 if(thn_length)
979                     chpr += printf("#### Start of JPEG thumbnail data for IFD %d",ifdnum);
980                 else
981                 {
982                     PUSHCOLOR(RED);
983                     chpr += printf("#### ZERO LENGTH JPEG thumbnail for IFD %d",ifdnum);
984                     POPCOLOR();
985                 }
986                 if((ifdtype == TIFF_SUBIFD) || (subifdnum >= 0))
987                     chpr += printf(" SubIFD %d",subifdnum);
988                 if(ifdtype == MAKER_IFD)
989                     chpr += printf(" %s",ifdname);
990                 else if(ifdtype == MAKER_SUBIFD)
991                     chpr += printf(" %s",ifdname);
992                 if(thn_length)
993                     chpr += printf(", length %lu ####",thn_length);
994                 else
995                 {
996                     if(summary_entry && (summary_entry->imageformat == IMGFMT_JPEG)
997                         && ((summary_entry->compression == 6) || (summary_entry->compression == 7)))
998                     {
999                         summary_entry->offset = thn_offset;
1000                     }
1001                 }
1002                 chpr = newline(chpr);
1003             }
1004 
1005             if(thn_length)
1006             {
1007                 unsigned short tmp_marker;
1008 
1009                 marker = read_ushort(inptr,TIFF_MOTOROLA,thn_offset);
1010                 if(marker != JPEG_SOI)
1011                 {
1012                     if((marker & 0xff) != 0xd) /* possibly BAD_SOI    */
1013                     {
1014                         tmp_marker = read_ushort(inptr,TIFF_MOTOROLA,thn_offset - fileoffset_base);
1015                         if(tmp_marker == JPEG_SOI)
1016                         {
1017                             chpr = newline(chpr);
1018                             print_filename();
1019                             putchar('#');
1020                             if((PRINT_SECTION))
1021                                 putindent(startindent - 1);
1022                             PUSHCOLOR(HI_RED);
1023                             chpr += printf(" WARNING: JPEGInterChangeFormat offset is botched");
1024                             chpr = newline(chpr);
1025                             if((PRINT_SECTION))
1026                             {
1027                                 print_filename();
1028                                 putchar('#');
1029                                 putindent(startindent - 1);
1030                                 chpr += printf(" WARNING: (possibly) correct offset follows:");
1031                                 chpr = newline(chpr);
1032                             }
1033                             marker = tmp_marker;
1034                             thn_offset -= fileoffset_base;
1035                             print_tag_address(SECTION,thn_offset,indent + SMALLINDENT,tprefix);
1036                             if((LIST_MODE))
1037                             {
1038                                 /* mock up the entry; the last read   */
1039                                 /* entry is finished, so it can be    */
1040                                 /* overwritten                        */
1041                                 entry_ptr->tag = TIFFTAG_JPEGInterchangeFormat;
1042                                 entry_ptr->value_type = LONG;
1043                                 entry_ptr->count = 1;
1044                                 entry_ptr->value = thn_offset - fileoffset_base;
1045                                 value_offset = print_entry(inptr,byteorder,entry_ptr,fileoffset_base,
1046                                                             summary_entry,parent_name,ifdtype,
1047                                                             ifdnum, subifdnum,MEDIUMINDENT);
1048                             }
1049                             else if((PRINT_SECTION))
1050                                 chpr += printf("#### Start of JPEG thumbnail data for IFD %d",ifdnum);
1051                             POPCOLOR();
1052                             chpr = newline(chpr);
1053                         }
1054                     }
1055                 }
1056                 /* Is this the image described by this ifd, or an     */
1057                 /* add-on?  ...or both...                             */
1058                 if(summary_entry &&
1059                     ((summary_entry->compression == 7) || (summary_entry->compression == 6)))
1060                 {
1061                     /* If there's a length set in the summary, assume */
1062                     /* there's already an image associated with this  */
1063                     /* entry.                                         */
1064                     if((summary_entry->length == 0UL))
1065                     {
1066                         /* Othersise, make sure the jpeg processor    */
1067                         /* uses the current summary entry             */
1068                         summary_entry->entry_lock = 0;
1069                         summary_entry->imageformat = IMGFMT_NOIMAGE;
1070                         if(Debug & SCAN_DEBUG)
1071                         {
1072                             chpr = newline(chpr);
1073                             printred("DEBUG:");
1074                             chpr += printf(" UNLOCK **** ");
1075                             chpr += printf(" offset=%lu, length=%lu ",summary_entry->offset,
1076                                                                     summary_entry->length);
1077                             chpr = newline(chpr);
1078                         }
1079                     }
1080                 }
1081 
1082                 value_offset = 0;
1083                 if(marker)
1084                     value_offset = process_jpeg_segments(inptr,thn_offset,marker,
1085                                                 thn_length,summary_entry,parent_name,
1086                                                 tprefix,indent+SMALLINDENT);
1087 
1088                 /* Even if the jpeg was bad, there will be a summary  */
1089                 /* entry for it.  It may not be the current one.      */
1090                 tmp_summary_entry = last_summary_entry(summary_entry);
1091                 tmp_summary_entry->ifdnum = ifdnum;
1092                 tmp_summary_entry->subifdnum = subifdnum;
1093                 tmp_summary_entry->datatype = ifdtype;
1094 
1095                 if(PRINT_SECTION)
1096                 {
1097                     if((status = jpeg_status(0) == JPEG_EARLY_EOI))
1098                         chpr = newline(chpr);
1099                     jpeg_status(status);
1100                     print_tag_address(SECTION,thn_offset + thn_length - 1,indent + SMALLINDENT,tprefix);
1101                     chpr += printf("#### End of JPEG thumbnail data for IFD %d",ifdnum);
1102                     if((ifdtype == TIFF_SUBIFD) || (subifdnum >= 0))
1103                         chpr += printf(" SubIFD %d",subifdnum);
1104                     if(ifdtype == MAKER_IFD)
1105                         chpr += printf(" %s",ifdname);
1106                     else if(ifdtype == MAKER_SUBIFD)
1107                         chpr += printf(" %s",ifdname);
1108                     chpr += printf(", length %lu ####",thn_length);
1109                     print_jpeg_status();
1110                     chpr = newline(chpr);
1111                 }
1112 
1113                 if(Debug & END_OF_SECTION_DEBUG)
1114                     printf("vo=%lu, mo=%lu, mvo=%lu, mio=%lu, nio=%lu, ol=%lu\n",value_offset,
1115                             max_offset,max_value_offset,max_ifd_offset,next_ifd_offset,offset_limit);
1116                 if((value_offset == 0L) || (value_offset > (thn_offset + thn_length)))
1117                     value_offset = thn_offset + thn_length;
1118                 if(value_offset > max_value_offset)
1119                     max_value_offset = value_offset;
1120             }
1121             /* done with this thumbnail                               */
1122             thn_offset = thn_length = 0;
1123             if((max_value_offset > max_ifd_offset) &&
1124                                     ((offset_limit == 0) ||
1125                                         (max_value_offset < offset_limit)))
1126             {
1127                 max_ifd_offset = max_value_offset;
1128             }
1129         }
1130         /* ================== end show jpeg thumbnail =============== */
1131 
1132         /* The TIFF spec does not specify, directly, where an IFD     */
1133         /* ends. If there is a next IFD, the start of that IFD        */
1134         /* (next_ifd_offset) gives an upper bound for the current     */
1135         /* IFD, but for the last IFD, guessing is necessary. The IFD  */
1136         /* should end when the last offset value given in the         */
1137         /* directory entries is written; MANY camera files which use  */
1138         /* this format write items, particularly thumbnails, at       */
1139         /* arbitrary offsets, and the TIFF spec itself allows offsets */
1140         /* to point anywhere in the file. The Exif spec declares that */
1141         /* "thumbnails" should be written within the values section   */
1142         /* of the IFD, but (oddly) not the "primary". Add subifds,    */
1143         /* disagreements between TIFF and TIFFEP about which IFD      */
1144         /* should describe the primary, multiple "thumbnails" of      */
1145         /* various sizes, etc. and it is very difficult to think of   */
1146         /* an IFD as a "container" (as it should be) or to decide     */
1147         /* where it ends.                                             */
1148 
1149         /* The thumbnails written above should be a part of the IFD,  */
1150         /* according to the Exif spec and common sense. All other     */
1151         /* offset values for the IFD have been written, so it is time */
1152         /* to declare that the IFD ends. If there is information      */
1153         /* giving the maximum size of this IFD, items outside the     */
1154         /* bounds have already been marked so.                        */
1155 
1156         if(Debug & END_OF_SECTION_DEBUG)
1157             printf("vo=%lu, mo=%lu, mvo=%lu, mio=%lu, nio=%lu, ol=%lu\n",value_offset,
1158                     max_offset,max_value_offset,max_ifd_offset,next_ifd_offset,offset_limit);
1159 
1160         /* ========= show end of ifd ===========                      */
1161         if((prefix && (*prefix == '>')) || (max_offset == 0) ||
1162                                                     (max_ifd_offset < max_offset))
1163         {
1164             display_end_of_ifd(max_ifd_offset,ifdtype,ifdnum,subifdnum,indent,
1165                                                             ifdname,prefix);
1166         }
1167         else
1168             display_end_of_ifd(max_offset,ifdtype,ifdnum,subifdnum,indent,
1169                                                             ifdname,prefix);
1170 
1171         /* =  ================= show ifd image ========  =========== */
1172         /* ###%%% not showing offset and length in LIST MODE */
1173         if(summary_entry &&
1174                     ((summary_entry->fileformat == TIFF_MAGIC) ||
1175                         (summary_entry->fileformat == ORF1_MAGIC) ||
1176                             (summary_entry->fileformat == ORF2_MAGIC)) &&
1177                             ((ifdtype == TIFF_IFD) || (ifdtype == TIFF_SUBIFD)) &&
1178                                 (summary_entry->length > 0))
1179         {
1180             if(Debug & END_OF_SECTION_DEBUG)
1181                 printf("mo=%lu, ol=%lu, seo=%lu\n",max_offset,offset_limit,summary_entry->offset);
1182             /* These are being displayed "inline" with the IFD that   */
1183             /* describes them; try to mark them as shown out of       */
1184             /* place.                                                 */
1185             if(max_offset && (summary_entry->offset > max_offset))
1186                 tprefix = ">";
1187             else if(offset_limit && (summary_entry->offset > offset_limit))
1188                 tprefix = "+";
1189             else
1190                 tprefix = prefix;
1191             /* Scan jpeg images and check for mismarked compression   */
1192             /* types                                                  */
1193             switch(summary_entry->compression)
1194             {
1195             case 6:
1196                 if(summary_entry->imagesubformat & IMGSUBFMT_RGB)
1197                 {
1198                     /* Perhaps this should be done unconditionally... */
1199                     max_value_offset = summary_entry->offset + summary_entry->length;
1200                     if(summary_entry->filesubformat & FILESUBFMT_CR2)
1201                     {
1202                         /* Actually uncompressed RGB                  */
1203                         summary_entry->compression = 1;
1204                         summary_entry->imageformat = IMGFMT_JPEG | IMGFMT_MISMARKED;
1205                     }
1206                     print_tag_address(SECTION,summary_entry->offset,indent,tprefix);
1207                     if(PRINT_SECTION)
1208                     {
1209                         chpr += printf("<=-=-=> Start of RGB data for IFD %d,",
1210                                                             summary_entry->ifdnum);
1211                         if(summary_entry->datatype == TIFF_SUBIFD)
1212                             chpr += printf(" SubIFD %d,",summary_entry->subifdnum);
1213                         chpr += printf(" data length %lu",summary_entry->length);
1214                         chpr = newline(chpr);
1215 
1216                         chpr = newline(chpr);
1217                         if((PRINT_VALUE))
1218                             dumpsection(inptr,summary_entry->offset,summary_entry->length,
1219                                                                     indent + SMALLINDENT);
1220                         print_tag_address(SECTION,max_value_offset - 1,indent,"-");
1221                         chpr += printf("</=-=-=> End of RGB data");
1222                         if((max_value_offset - 1) > filesize)
1223                         {
1224                             PUSHCOLOR(RED);
1225                             chpr += printf(" (TRUNCATED at %lu)",filesize);
1226                             POPCOLOR();
1227                             summary_entry->imagesubformat |= IMGSUBFMT_TRUNCATED;
1228                         }
1229                         chpr = newline(chpr);
1230                     }
1231                     else if((PRINT_ENTRY))
1232                     {
1233                         /* ###%%% pseudo-tags fpr LIST Mode here */
1234                         print_tag_address(ENTRY,HERE,indent,"*");
1235                         if((PRINT_TAGINFO))
1236                         {
1237                             if((PRINT_LONGNAMES))
1238                                 chpr += printf("%s.",listname);
1239                             chpr += printf("%-*.*s",TAGWIDTH,TAGWIDTH,"RGBImageData");
1240                         }
1241                         if((PRINT_VALUE))
1242                             chpr += printf(" = @%lu:%-9lu",summary_entry->offset,summary_entry->length);
1243                         chpr = newline(chpr);
1244                     }
1245                     /* done                                           */
1246                     break;
1247 
1248                 }
1249                 /* fall through */
1250             case 7:
1251                 print_tag_address(SECTION,summary_entry->offset,indent,tprefix);
1252                 if(PRINT_SECTION)
1253                 {
1254                     chpr += printf("<=====> Start of JPEG data for IFD %d,",summary_entry->ifdnum);
1255                     if(summary_entry->datatype == TIFF_SUBIFD)
1256                         chpr += printf(" SubIFD %d,",summary_entry->subifdnum);
1257                     chpr += printf(" data length %lu",summary_entry->length);
1258                     chpr = newline(chpr);
1259                 }
1260                 else if((PRINT_ENTRY))
1261                 {
1262                     /* ###%%% pseudo-tags fpr LIST Mode here */
1263                     print_tag_address(ENTRY,HERE,indent,"*");
1264                     if((PRINT_TAGINFO))
1265                     {
1266                         if((PRINT_LONGNAMES))
1267                             chpr += printf("%s.",listname);
1268                         chpr += printf("%-*.*s",TAGWIDTH,TAGWIDTH,"JpegImageData");
1269                     }
1270                     if((PRINT_VALUE))
1271                         chpr += printf(" = @%lu:%-9lu",summary_entry->offset,summary_entry->length);
1272                     chpr = newline(chpr);
1273                 }
1274 
1275                 /* If this IFD describes a JPEG image, the    */
1276                 /* entry must go unlocked to the jpeg         */
1277                 /* processor, which will lock it. This may    */
1278                 /* cause problems if the IFD *also* contains  */
1279                 /* JpegInterchangeFormat tags. It happens.    */
1280                 if(Debug & SCAN_DEBUG)
1281                 {
1282                     chpr = newline(chpr);
1283                     printred("DEBUG:");
1284                     chpr += printf(" UNLOCK **** ");
1285                     chpr += printf(" offset=%lu, length=%lu ",summary_entry->offset,
1286                                                             summary_entry->length);
1287                     chpr = newline(chpr);
1288                 }
1289                 summary_entry->entry_lock = 0;
1290                 summary_entry->imageformat = IMGFMT_NOIMAGE;
1291                 value_offset = 0;
1292 
1293                 /* If compression == 7, PMI is CFA, and there are     */
1294                 /* multiple tile offsets, each tile may be separately */
1295                 /* compressed.                                        */
1296                 marker = read_ushort(inptr,TIFF_MOTOROLA,summary_entry->offset);
1297                 if((PRINT_SECTION) && (summary_entry->compression == 7) &&
1298                         (summary_entry->chunkhow == TIFFTAG_TileOffsets) &&
1299                                 (summary_entry->noffsets > 1))
1300                 {
1301                     unsigned long tmp_offset;
1302                     unsigned long offset_loc;
1303                     unsigned long length_loc;
1304 
1305                     /* Individually compressed tiles Show the first   */
1306                     /* and last, and just check for JPEG_SOI for      */
1307                     /* those in the middle. There should be an option */
1308                     /* to display them all and/or dump the section    */
1309                     /* (although '-O' can be used for that).          */
1310                     offset_loc = summary_entry->offset_loc;
1311                     length_loc = summary_entry->length_loc;
1312                     if(marker)
1313                     {
1314                         tmp_length = read_ulong(inptr,byteorder,length_loc);
1315                         value_offset = process_jpeg_segments(inptr,summary_entry->offset,marker,
1316                                             tmp_length,summary_entry,parent_name,
1317                                             tprefix,indent+MEDIUMINDENT);
1318                     }
1319                     for(i = 1; i < summary_entry->noffsets; ++i)
1320                     {
1321                         if(summary_entry->chunktype == LONG)
1322                         {
1323                             offset_loc += 4;
1324                             length_loc += 4;
1325                             tmp_offset = read_ulong(inptr,byteorder,offset_loc);
1326                             tmp_length = read_ulong(inptr,byteorder,length_loc);
1327                         }
1328                         else
1329                         {
1330                             offset_loc += 2;
1331                             length_loc += 2;
1332                             tmp_offset = read_ushort(inptr,byteorder,offset_loc);
1333                             tmp_length = read_ushort(inptr,byteorder,length_loc);
1334                         }
1335                         marker = read_ushort(inptr,TIFF_MOTOROLA,tmp_offset);
1336                         if(feof(inptr) || ferror(inptr))
1337                         {
1338                             value_offset = summary_entry->offset + summary_entry->length;
1339                             clearerr(inptr);
1340                             break;
1341                         }
1342                         if((i + 1) == summary_entry->noffsets)
1343                         {
1344                             /* Note that this one goes into the       */
1345                             /* summary                                */
1346                             chpr = newline(chpr);
1347                             value_offset = process_jpeg_segments(inptr,tmp_offset,marker,
1348                                                         tmp_length,summary_entry,parent_name,
1349                                                         tprefix,indent+MEDIUMINDENT);
1350                         }
1351                         else if(marker == JPEG_SOI)
1352                         {
1353                             /* This checks that there is at least an  */
1354                             /* SOI where it is supposed to be, but    */
1355                             /* avoids putting every tile in the       */
1356                             /* summary, which would be very boring.   */
1357                             if(i != 1)
1358                                 chpr += printf(",");
1359                             if((i == 1) || ((i % 10) == 0))
1360                             {
1361                                 chpr = newline(chpr);
1362                                 print_tag_address(SECTION,HERE,indent + MEDIUMINDENT,"JPEG TILES");
1363                             }
1364                             chpr += printf("[%d]",i + 1);
1365                         }
1366                         else
1367                         {
1368                             ;
1369                         }
1370                         if(feof(inptr) || ferror(inptr))
1371                         {
1372                             clearerr(inptr);
1373                             value_offset = summary_entry->offset + summary_entry->length;
1374                             break;
1375                         }
1376                     }
1377 
1378                 }
1379                 else
1380                 {
1381                     if(marker)
1382                         value_offset = process_jpeg_segments(inptr,summary_entry->offset,marker,
1383                                             summary_entry->length,summary_entry,parent_name,
1384                                             tprefix,indent+MEDIUMINDENT);
1385                 }
1386                 if(PRINT_SECTION)
1387                 {
1388                     if((status = jpeg_status(0) == JPEG_EARLY_EOI))
1389                         chpr = newline(chpr);
1390                     jpeg_status(status);
1391                     print_tag_address(SECTION,summary_entry->offset + summary_entry->length - 1,
1392                                         indent,tprefix);
1393                     chpr += printf("</=====> End of JPEG data ====");
1394                     if(value_offset > (summary_entry->offset + summary_entry->length))
1395                         value_offset = summary_entry->offset + summary_entry->length;
1396                     print_jpeg_status();
1397                     if((value_offset - 1) > filesize)
1398                     {
1399                         PUSHCOLOR(RED);
1400                         chpr += printf(" (TRUNCATED at %lu)",filesize);
1401                         POPCOLOR();
1402                         summary_entry->imagesubformat |= IMGSUBFMT_TRUNCATED;
1403                     }
1404                     chpr = newline(chpr);
1405                 }
1406                 if(value_offset == 0L)
1407                     clearerr(inptr);
1408                 else if(value_offset > max_value_offset)
1409                     max_value_offset = value_offset;
1410                 if((max_value_offset - 1) > filesize)
1411                     summary_entry->imagesubformat |= IMGSUBFMT_TRUNCATED;
1412                 break;
1413             case 0:     /* this shouldn't happen...                   */
1414             default:
1415                 if((summary_entry) && (summary_entry->imageformat != IMGFMT_JPEG))
1416                 {
1417                     max_value_offset = summary_entry->offset + summary_entry->length;
1418                     if(PRINT_SECTION)
1419                     {
1420                         print_tag_address(SECTION,summary_entry->offset,indent,tprefix);
1421                         chpr += printf("<=-=-=> Start of ");
1422                         print_imageformat(summary_entry);
1423                         print_imagesubformat(summary_entry);
1424                         print_imagecompression(summary_entry);
1425                         chpr += printf(" image data for IFD %d,",
1426                                                             summary_entry->ifdnum);
1427                         if(summary_entry->datatype == TIFF_SUBIFD)
1428                             chpr += printf(" SubIFD %d,",summary_entry->subifdnum);
1429                         chpr += printf(" data length %lu",summary_entry->length);
1430                         chpr = newline(chpr);
1431 
1432                         chpr = newline(chpr);
1433                         if((PRINT_VALUE))
1434                             dumpsection(inptr,summary_entry->offset,summary_entry->length,
1435                                                                     indent + SMALLINDENT);
1436                         print_tag_address(SECTION,max_value_offset - 1,indent,tprefix);
1437                         chpr += printf("</=-=-=> End of image data");
1438                         if((max_value_offset - 1) > filesize)
1439                         {
1440                             PUSHCOLOR(RED);
1441                             chpr += printf(" (TRUNCATED at %lu)",filesize);
1442                             POPCOLOR();
1443                             summary_entry->imagesubformat |= IMGSUBFMT_TRUNCATED;
1444                         }
1445                         chpr = newline(chpr);
1446                     }
1447                     else if((PRINT_ENTRY))
1448                     {
1449                         /* ###%%% pseudo-tags fpr LIST Mode here */
1450                         print_tag_address(ENTRY,HERE,indent,"*");
1451                         if((PRINT_TAGINFO))
1452                         {
1453                             if((PRINT_LONGNAMES))
1454                                 chpr += printf("%s.",listname);
1455                             chpr += printf("%-*.*s",TAGWIDTH,TAGWIDTH,"ImageData");
1456                         }
1457                         if((PRINT_VALUE))
1458                             chpr += printf(" = @%lu:%-9lu",summary_entry->offset,summary_entry->length);
1459                         if((max_value_offset - 1) > filesize)
1460                         {
1461                             PUSHCOLOR(RED);
1462                             chpr += printf(" # TRUNCATED at %lu",filesize);
1463                             POPCOLOR();
1464                             summary_entry->imagesubformat |= IMGSUBFMT_TRUNCATED;
1465                         }
1466                         chpr = newline(chpr);
1467                     }
1468                     else if((max_value_offset -1) > filesize)
1469                             summary_entry->imagesubformat |= IMGSUBFMT_TRUNCATED;
1470                 }
1471                 break;
1472             }
1473             if((max_value_offset > max_ifd_offset) &&
1474                     ((offset_limit == 0) || (max_value_offset < offset_limit)))
1475                 max_ifd_offset = max_value_offset;
1476         }
1477         /* =========== end show ifd image ============                */
1478 
1479         /* ###%%% temporary debug                                     */
1480         if(Debug & END_OF_SECTION_DEBUG)
1481             printf("mo=%lu, mvo=%lu, mio=%lu, nio=%lu, ol=%lu\n",
1482                     max_offset,max_value_offset,max_ifd_offset,next_ifd_offset,offset_limit);
1483 
1484         /* lock the summary entry for this ifd, even if it doesn't    */
1485         /* describe an actual image                                   */
1486         if(summary_entry && (summary_entry->entry_lock  <= 0))
1487             summary_entry->entry_lock = lock_number(summary_entry);
1488 
1489         /* Prepare for the next ifd                                   */
1490         if(ifdtype == TIFF_IFD)
1491         {
1492             ++ifdnum;
1493             subifdnum = -1;
1494         }
1495         else if(ifdtype == TIFF_SUBIFD)
1496             ++subifdnum;
1497         if(fulldirname)
1498             free(fulldirname);
1499         fulldirname = CNULL;
1500 
1501         /* If there is a next ifd, "max_offset" must be reset.        */
1502         if(next_ifd_offset)
1503             max_offset = 0;
1504     }
1505     newline(chpr);
1506 
1507     return(max_ifd_offset);
1508 blewit:
1509     clearerr(inptr);
1510     if(PRINT_SECTION)
1511     {
1512         /* Indicate the end of the IFD                                    */
1513         indent -= SMALLINDENT;
1514         current_offset = ftell(inptr);
1515         if((prefix && (*prefix == '>')) || (max_offset == 0) ||
1516                                                     (max_ifd_offset < max_offset))
1517         {
1518             display_end_of_ifd(max_ifd_offset,ifdtype,ifdnum,subifdnum,indent,
1519                                                             ifdname,prefix);
1520         }
1521         else
1522             display_end_of_ifd(max_offset,ifdtype,ifdnum,subifdnum,indent,
1523                                                             ifdname,prefix);
1524     }
1525     if(fulldirname)
1526         free(fulldirname);
1527     return(0L);
1528 }
1529 
1530 /* Create a summary entry and link it into a list of image            */
1531 /* descriptions to be printed at the end of the file output.          */
1532 
1533 struct image_summary *
new_summary_entry(struct image_summary * prev_entry,int fileformat,int datatype)1534 new_summary_entry(struct image_summary *prev_entry,int fileformat,int datatype)
1535 {
1536     struct image_summary *new = NULL;
1537     int chpr = 0;
1538 
1539     /* Make entries only for types which describe image data, i.e.    */
1540     /* not EXIF, Interop, etc.                                        */
1541     switch(datatype)
1542     {
1543         case EXIF_IFD:
1544         case INTEROP_IFD:
1545         case GPS_IFD:
1546             break;
1547         default:
1548             if(Debug & SCAN_DEBUG)
1549             {
1550                 chpr = newline(1);
1551                 printred("DEBUG: NEW SUMMARY ");
1552             }
1553             new = (struct image_summary *)malloc(sizeof(struct image_summary));
1554             if(new)
1555             {
1556                 if(Debug & SCAN_DEBUG)
1557                     printf("%#lx\n",(unsigned long)new);
1558                 memset(new,0,sizeof(struct image_summary));
1559                 new->datatype = datatype;
1560                 new->ifdnum = -1;
1561                 new->subifdnum = -1;
1562                 new->length = 0;
1563                 new->offset = 0;
1564                 new->subfiletype = -1;
1565                 memset(new->filesubformatAPPN,0,16);
1566                 if(prev_entry)
1567                 {
1568                     if(Debug & SCAN_DEBUG)
1569                     {
1570                         printred("DEBUG: PREV ENTRY ");
1571                         chpr += printf("%#x, next=%#x, offset=%ld, lock=%d",
1572                                         (unsigned int)prev_entry,
1573                                         (unsigned int)prev_entry->next_entry,
1574                                         prev_entry->offset,prev_entry->entry_lock);
1575                         chpr = newline(chpr);
1576                     }
1577                     /* make sure to attach at the end of the chain        */
1578                     while(prev_entry->next_entry)
1579                     {
1580                         prev_entry = prev_entry->next_entry;
1581                         if(Debug & SCAN_DEBUG)
1582                         {
1583                             printred(" PREV ENTRY ");
1584                             chpr += printf("%#x, next=%#x, offset=%ld, lock=%d",
1585                                             (unsigned int)prev_entry,
1586                                             (unsigned int)prev_entry->next_entry,
1587                                             prev_entry->offset,prev_entry->entry_lock);
1588                             chpr = newline(chpr);
1589                         }
1590                     }
1591                     new->prev_entry = prev_entry;
1592                     if(Debug & SCAN_DEBUG)
1593                     {
1594                         printred("DEBUG: FOUND PREV ENTRY ");
1595                         chpr += printf("%#x, next=%#x, offset=%ld, lock=%d",
1596                                             (unsigned int)prev_entry,
1597                                             (unsigned int)prev_entry->next_entry,
1598                                             prev_entry->offset,prev_entry->entry_lock);
1599                         chpr = newline(chpr);
1600                     }
1601                     if(prev_entry->fileformat)
1602                         new->fileformat = prev_entry->fileformat;
1603                     prev_entry->next_entry = new;
1604                     if(Debug & SCAN_DEBUG)
1605                     {
1606                         printred("DEBUG: NEW ENTRY ");
1607                         chpr += printf(" next=%#x, prev offset=%d, prev lock=%d",
1608                                             (unsigned int)prev_entry->next_entry,
1609                                             (unsigned int)prev_entry->offset,prev_entry->entry_lock);
1610                         chpr = newline(chpr);
1611                     }
1612                 }
1613                 else
1614                     new->fileformat = fileformat;
1615             }
1616             else
1617             {
1618                 printred("Memory allocation for image summary failed");
1619                 if(prev_entry)
1620                     chpr += printf(" summary will be incomplete");
1621                 else
1622                     chpr += printf(" no summary will be printed");
1623                 newline(chpr);
1624             }
1625             if(Debug & SCAN_DEBUG)
1626                 chpr = newline(1);
1627             break;
1628     }
1629     return(new);
1630 }
1631 
1632 /* Move to the end of the summary entry chain passed as argument      */
1633 struct image_summary *
last_summary_entry(struct image_summary * summary_entry)1634 last_summary_entry(struct image_summary *summary_entry)
1635 {
1636     if(summary_entry)
1637     {
1638         while(summary_entry->next_entry)
1639             summary_entry = summary_entry->next_entry;
1640     }
1641     return(summary_entry);
1642 }
1643 
1644 /* Lock an entry with a sequence number, primarily so entries can be  */
1645 /* tracked while debugging. A locked entry is "in use', requiring     */
1646 /* creation of a new entry for a new image                            */
1647 
1648 int
lock_number(struct image_summary * summary_entry)1649 lock_number(struct image_summary *summary_entry)
1650 {
1651     int number = 0;
1652     struct image_summary *prev_entry,*last_entry;
1653 
1654     if(summary_entry)
1655     {
1656         if(summary_entry->entry_lock)
1657             number = summary_entry->entry_lock;  /* don't change it */
1658         else if((last_entry = last_summary_entry(summary_entry)))
1659         {
1660             /* Find the highest existing lock number; go to the end   */
1661             /* and scan back to the head                              */
1662             if(last_entry->entry_lock > 0)
1663                 number = last_entry->entry_lock + 1;
1664             prev_entry = last_entry->prev_entry;
1665             while(prev_entry)
1666             {
1667                 if(prev_entry->entry_lock >= number)
1668                     number = prev_entry->entry_lock + 1;
1669                 prev_entry = prev_entry->prev_entry;
1670             }
1671             if(number <= 0)
1672                 number = 1;
1673         }
1674         else
1675             number = 1;
1676     }
1677     if(Debug & SCAN_DEBUG)
1678     {
1679         (void)newline(1);
1680         printred("DEBUG: LOCK SUMMARY");
1681         printf(" %#x ==> %d",(unsigned int)summary_entry,number);
1682         (void)newline(1);
1683         (void)newline(1);
1684     }
1685     return(number);
1686 }
1687 
1688 
1689 struct image_summary *
destroy_summary(struct image_summary * summary_entry)1690 destroy_summary(struct image_summary *summary_entry)
1691 {
1692     struct image_summary *prev_entry = NULL;
1693 
1694     /* start at the end and work back to the head                     */
1695     if(Debug & SCAN_DEBUG)
1696         printred("DEBUG: DESTROY SUMMARY ");
1697     if(summary_entry)
1698     {
1699         while(summary_entry->next_entry)
1700             summary_entry = summary_entry->next_entry;
1701         while(summary_entry)
1702         {
1703             prev_entry = summary_entry->prev_entry;
1704             free(summary_entry);
1705             summary_entry = prev_entry;
1706         }
1707     }
1708     return(prev_entry);
1709 }
1710 
1711 
1712 /* Read, decode, and print an EXIF IFD at 'exif_offset', noticing     */
1713 /* MakerNotes and "Interoperability" IFDs as they go by. The offset   */
1714 /* of each entry and offset value is recorded and printed, and the    */
1715 /* offset of the last byte read is reported as the end of the IFD. If */
1716 /* all goes well, the offset at which the caller should next read     */
1717 /* (just past the end of the offset values) is returned. If an        */
1718 /* unrecoverable error occurs, 0UL is returned.                       */
1719 
1720 /* This looks remoarkably like process_tiff_ifd(), except that it     */
1721 /* expects EXIF tags, and doesn't expect further IFDs to be chained   */
1722 /* from it. If it does find a chained IFD, it processes it as a       */
1723 /* normal IFD (not another EXIF IFD). It should probably just warn    */
1724 /* and ignore it.                                                     */
1725 
1726 unsigned long
process_exif_ifd(FILE * inptr,unsigned short byteorder,unsigned long exif_offset,unsigned long fileoffset_base,unsigned long max_offset,struct image_summary * summary_entry,char * parent_name,int ifdnum,int indent)1727 process_exif_ifd(FILE *inptr,unsigned short byteorder,
1728                     unsigned long exif_offset,unsigned long fileoffset_base,
1729                     unsigned long max_offset,struct image_summary *summary_entry,
1730                     char *parent_name,int ifdnum,int indent)
1731 {
1732     struct ifd_entry *entry_ptr;
1733     unsigned long max_value_offset = 0L;
1734     unsigned long next_ifd_offset,current_offset,max_exif_offset;
1735     unsigned long start_entry_offset,entry_offset,value_offset;
1736     unsigned long value_start_offset = 0UL;
1737     unsigned long next_max_offset = 0UL;
1738     int entry_num,num_entries,value_is_offset,use_second_pass;
1739     int chpr = 0;
1740     char *prefix;
1741     char *fulldirname = CNULL;
1742 
1743     if(inptr == (FILE *)0)
1744     {
1745         fprintf(stderr,"%s: no open file pointer to read EXIF IFD\n",
1746                 Progname);
1747         return(0L);
1748     }
1749 
1750     PUSHCOLOR(EXIF_COLOR);
1751     /* If the exif segment appears to be beyond the end of the parent */
1752     /* ifd, mark the start address to call attention.                 */
1753     if(max_offset && (exif_offset > max_offset))
1754         prefix = "+";
1755     else
1756         prefix = "@";
1757     if(summary_entry)
1758         summary_entry->filesubformat |= FILESUBFMT_EXIF;
1759     max_exif_offset = max_offset;
1760     print_tag_address(SECTION,exif_offset + fileoffset_base,indent,prefix);
1761     if(PRINT_SECTION)
1762         chpr += printf("<EXIF IFD> (in IFD %d)",ifdnum);
1763 
1764     num_entries = read_ushort(inptr,byteorder,exif_offset + fileoffset_base);
1765     if(ferror(inptr) || feof(inptr))
1766         goto blewit;
1767     current_offset = entry_offset = start_entry_offset = ftell(inptr);
1768     if(PRINT_SECTION)
1769     {
1770         chpr += printf(" %d entries ",num_entries);
1771         chpr += printf("starting at file offset %#lx=%lu",
1772                                             current_offset,current_offset);
1773             chpr = newline(chpr);
1774     }
1775     use_second_pass = value_is_offset = 0;
1776     fulldirname = splice(parent_name,".","Exif");
1777 
1778     indent += SMALLINDENT;
1779     /* The direct entries                                             */
1780     for(entry_num = 0; entry_num < num_entries; ++entry_num)
1781     {
1782         entry_ptr = read_ifd_entry(inptr,byteorder,entry_offset);
1783         if((entry_ptr->value_type == 0) || (entry_ptr->value_type > DOUBLE) ||
1784             ferror(inptr) || feof(inptr))
1785         {
1786             int invalid_entry = 0;
1787             unsigned long limit_offset = 0L;
1788 
1789             print_tag_address(ENTRY,entry_offset,indent,prefix);
1790             chpr += printf(" INVALID EXIF ENTRY (%lu)",entry_ptr->value);
1791             chpr = newline(chpr);
1792             clearerr(inptr);
1793             current_offset = ftell(inptr);
1794             if(max_offset > 0)
1795                 limit_offset = max_offset;
1796             else
1797             {
1798                 if(fseek(inptr,0L,2) != -1)
1799                 {
1800                     limit_offset = ftell(inptr);
1801                     fseek(inptr,0L,current_offset);
1802                 }
1803             }
1804             /* If there's an error on input, or we can't check    */
1805             /* for absurd num_entries, give up.                   */
1806             if(!ferror(inptr) && !feof(inptr) && (limit_offset > 0))
1807             {
1808                 /* If the number of entries would read past the   */
1809                 /* size of the IFD, or past EOF, give up          */
1810                 if((entry_offset + (12 * num_entries)) < limit_offset)
1811                 {
1812                     /* Limit the number of consecutive failures.  */
1813                     /* An apparently valid entry resets the count */
1814                     /* to 0.                                      */
1815                     if(invalid_entry++ < MAX_INVALID_ENTRIES)
1816                     {
1817                         entry_offset = current_offset;
1818                         continue;
1819                     }
1820                 }
1821             }
1822             chpr = newline(chpr);
1823             goto blewit;
1824         }
1825         current_offset = ftell(inptr);
1826         switch(entry_ptr->tag)
1827         {
1828             case EXIFTAG_PixelXDimension:
1829                 if(summary_entry)
1830                     summary_entry->primary_width = entry_ptr->value;
1831                 break;
1832             case EXIFTAG_PixelYDimension:
1833                 if(summary_entry)
1834                     summary_entry->primary_height = entry_ptr->value;
1835                 break;
1836             case EXIFTAG_Interoperability:
1837             case EXIFTAG_MakerNote:
1838                 use_second_pass++;
1839                 break;
1840             default:
1841                 break;
1842         }
1843 
1844         print_tag_address(ENTRY,entry_offset,indent,prefix);
1845         value_offset = print_entry(inptr,byteorder,entry_ptr,fileoffset_base,
1846                                         summary_entry,fulldirname,EXIF_IFD,
1847                                         ifdnum,-1,SMALLINDENT);
1848         if(value_offset == 0UL)
1849             value_offset = current_offset;
1850         if(value_offset > max_value_offset)
1851             max_value_offset = value_offset;
1852         if((PRINT_VALUE_AT_OFFSET) && (is_offset(entry_ptr)))
1853             ++use_second_pass;
1854         entry_offset = current_offset;
1855     }
1856 
1857     next_ifd_offset = read_ulong(inptr,byteorder,current_offset);
1858 
1859     /* There should be no next_ifd_offset for the Exif Ifd.           */
1860     /* I am not confident, however, that someone won't eventually     */
1861     /* chain Exif ifds, so just handle them, and let the error        */
1862     /* messages fly.                                                  */
1863     if(next_ifd_offset > 0L)
1864     {
1865         if((PRINT_VALUE) && (PRINT_SECTION) && (PRINT_VALUE_AT_OFFSET))
1866         {
1867             print_tag_address(SECTION,current_offset,indent + SMALLINDENT,prefix);
1868             chpr += printf("**** next IFD offset %lu  ",next_ifd_offset);
1869             next_ifd_offset += fileoffset_base;
1870             if(next_ifd_offset < ftell(inptr))
1871             {
1872                 printred("BAD NEXT IFD OFFSET");
1873                 next_ifd_offset = 0L;
1874             }
1875             else
1876                 chpr += printf("(+ %lu = %#lx/%lu)",fileoffset_base,
1877                                         next_ifd_offset,next_ifd_offset);
1878             chpr = newline(chpr);
1879         }
1880         else
1881             next_ifd_offset += fileoffset_base;
1882         /* This should never happen                                   */
1883         max_exif_offset = next_ifd_offset;
1884     }
1885     else
1886     {
1887         if((PRINT_VALUE) && (PRINT_SECTION) && (PRINT_VALUE_AT_OFFSET))
1888         {
1889             print_tag_address(SECTION,current_offset,indent,prefix);
1890             chpr += printf("**** next IFD offset 0");
1891             chpr = newline(chpr);
1892         }
1893     }
1894 
1895     if(ferror(inptr) || feof(inptr))
1896     {
1897         chpr += printf(" READ NEXT IFD OFFSET FAILED ");
1898         chpr = newline(chpr);
1899         why(stdout);
1900         clearerr(inptr);    /* keep going...                          */
1901     }
1902     else
1903         current_offset = ftell(inptr);
1904 
1905     value_offset = current_offset;
1906 
1907     /* Second pass, to evaluate entries which are stored indirectly.  */
1908     /* This occurs when the value requires more than 4 bytes, AND for */
1909     /* certain LONG values which are intended to be used as offsets   */
1910     /* (and should have their own type defined in the spec),          */
1911     if(use_second_pass)
1912     {
1913         if((PRINT_VALUE) && (PRINT_SECTION) && (PRINT_VALUE_AT_OFFSET))
1914         {
1915             print_tag_address(SECTION,value_offset,indent,prefix);
1916             chpr += printf("============= VALUES, EXIF IFD ============");
1917             chpr = newline(chpr);
1918         }
1919 
1920         entry_offset = start_entry_offset;
1921         for(entry_num = 0; entry_num < num_entries; ++entry_num)
1922         {
1923             entry_ptr = read_ifd_entry(inptr,byteorder,entry_offset);
1924             if((entry_ptr->value_type == 0) || (entry_ptr->value_type > DOUBLE) ||
1925                 ferror(inptr) || feof(inptr))
1926             {
1927                 /* If the first pass made it through invalid entries, */
1928                 /* this pass should just ignore them and quietly      */
1929                 /* continue.                                          */
1930                 entry_offset = current_offset = ftell(inptr);
1931                 continue;
1932             }
1933             current_offset = entry_offset = ftell(inptr);
1934             switch(entry_ptr->tag)
1935             {
1936                 case EXIFTAG_Interoperability:
1937                     PUSHCOLOR(INTEROP_COLOR);
1938                     value_offset = process_tiff_ifd(inptr,byteorder,
1939                                             entry_ptr->value,fileoffset_base,
1940                                             max_exif_offset,summary_entry,
1941                                             fulldirname,INTEROP_IFD,ifdnum,0,
1942                                             indent);
1943                     POPCOLOR();
1944                     break;
1945                 case EXIFTAG_MakerNote:
1946         /* ###%%% temporary debug                                     */
1947                     if(Debug & END_OF_SECTION_DEBUG)
1948                         printf("mo=%lu, mvo=%lu, ",
1949                                 max_offset,max_value_offset);
1950                     value_start_offset = entry_ptr->value + fileoffset_base;
1951                     if(max_offset && (value_start_offset > max_offset) &&
1952                             (entry_ptr->count > 4))
1953                     {
1954                         next_max_offset = value_start_offset;
1955                     }
1956                     if(Debug & END_OF_SECTION_DEBUG)
1957                         printf("vso=%lu, nmo=%lu\n",value_start_offset,next_max_offset);
1958                     value_offset = process_makernote(inptr,byteorder,
1959                                             entry_ptr,fileoffset_base,max_exif_offset,
1960                                                     summary_entry,fulldirname,indent);
1961                     if(Debug & END_OF_SECTION_DEBUG)
1962                         printf("mo=%lu, mvo=%lu, ",max_offset,max_value_offset);
1963                     if(Debug & END_OF_SECTION_DEBUG)
1964                         printf("MNvo=%lu, mo=%lu\n",value_offset,max_offset);
1965                     break;
1966                 default:
1967                     if((PRINT_VALUE) && ((PRINT_VALUE_AT_OFFSET) && is_offset(entry_ptr)))
1968                     {
1969                         print_tag_address(ENTRY,fileoffset_base + entry_ptr->value,
1970                                             indent,prefix);
1971                         print_tagid(entry_ptr,SMALLINDENT,EXIF_IFD);
1972                         value_offset =
1973                                     print_offset_value(inptr,byteorder,entry_ptr,
1974                                                     fileoffset_base,fulldirname,
1975                                                     EXIF_IFD,indent,1);
1976                     }
1977                     break;
1978             }
1979             if(value_offset > max_value_offset)
1980                 max_value_offset = value_offset;
1981             if(max_offset && (value_offset > max_offset))
1982             {
1983                 next_max_offset = value_start_offset;
1984                 if(Debug & END_OF_SECTION_DEBUG)
1985                     printf("nmo=%lu\n",next_max_offset);
1986             }
1987         }
1988     }
1989     else if(current_offset > max_value_offset)
1990         max_value_offset = current_offset;
1991 
1992     indent -= SMALLINDENT;
1993     if(max_offset && (max_value_offset > max_offset))
1994         print_tag_address(SECTION,max_offset - 1,indent,"<");
1995     else
1996         print_tag_address(SECTION,max_value_offset - 1,indent,"-");
1997     if(PRINT_SECTION)
1998     {
1999         chpr += printf("</EXIF IFD>");
2000         chpr = newline(chpr);
2001     }
2002     POPCOLOR();
2003 
2004     /* This shouldn't happen.                                         */
2005     if(next_ifd_offset)
2006     {
2007         printred("#========= WARNING! CHAINING NEXT IFD FROM EXIF IFD =========");
2008         chpr = newline(1);
2009         value_offset = process_tiff_ifd(inptr,byteorder,next_ifd_offset,
2010                                 fileoffset_base,max_offset,summary_entry,fulldirname,
2011                                 EXIF_IFD,++ifdnum,-1,indent);
2012         if(value_offset > max_value_offset)
2013             max_value_offset = value_offset;
2014     }
2015     if(fulldirname)
2016         free(fulldirname);
2017     if(next_max_offset)
2018         max_value_offset = next_max_offset;
2019     if(Debug & END_OF_SECTION_DEBUG)
2020         printf("exmvo=%lu\n",max_value_offset);
2021     return(max_value_offset);
2022 blewit:
2023     clearerr(inptr);
2024     current_offset = ftell(inptr);
2025     print_tag_address(SECTION,current_offset - 1,indent,"-");
2026     if(PRINT_SECTION)
2027     {
2028         chpr += printf("</EXIF IFD>");
2029         chpr = newline(chpr);
2030     }
2031     if(fulldirname)
2032         free(fulldirname);
2033     POPCOLOR();
2034     return(0L);
2035 }
2036 
2037 /* Read an ifd entry describing one or more subifd offsets, and       */
2038 /* process the IFDs found at those offsets as TIFF image file         */
2039 /* directories. This is used for TIFF6/TIFFEP SubIFDtags. The return  */
2040 /* is 0L if something went wrong.                                     */
2041 
2042 unsigned long
process_subifd(FILE * inptr,unsigned short byteorder,struct ifd_entry * subfile_entry,unsigned long fileoffset_base,unsigned long max_offset,struct image_summary * summary_entry,char * parent_name,int ifdnum,int subifdnum,int ifdtype,int indent)2043 process_subifd(FILE *inptr,unsigned short byteorder,
2044                     struct ifd_entry *subfile_entry,
2045                     unsigned long fileoffset_base,unsigned long max_offset,
2046                     struct image_summary *summary_entry,char *parent_name,
2047                     int ifdnum,int subifdnum,int ifdtype,int indent)
2048 {
2049     unsigned long entry_offset;
2050     unsigned long subifd_offset;
2051     unsigned long max_value_offset = 0L;
2052     int chpr = 0;
2053     int nsubifds,num;
2054 
2055     if(inptr && subfile_entry)
2056     {
2057         entry_offset = subfile_entry->value + fileoffset_base;
2058         nsubifds = subfile_entry->count;
2059 
2060         if(subifdnum >= 0)
2061         {
2062             if(nsubifds > 1)
2063             {
2064                 if((PRINT_VALUE_AT_OFFSET))
2065                 {
2066                     if(max_offset && (entry_offset > max_offset))
2067                         print_tag_address(SECTION,entry_offset,indent,"+");
2068                     else
2069                         print_tag_address(SECTION,entry_offset,indent,"@");
2070                     if(PRINT_SECTION)
2071                     {
2072                         chpr += printf("%s - %lu offsets: [max parent offset = %lu]",
2073                                 tagname(subfile_entry->tag),subfile_entry->count,
2074                                 max_offset);
2075                     }
2076                     for(num = 0; num < nsubifds; ++num)
2077                     {
2078                         subifd_offset = read_ulong(inptr,byteorder,entry_offset)
2079                                                             + fileoffset_base;
2080                         entry_offset = ftell(inptr); /* where to get next one */
2081                         if((PRINT_SECTION))
2082                             chpr += printf(" %lu",subifd_offset);
2083                         if(ferror(inptr) || feof(inptr))
2084                             break;
2085                         /* goto blewit;                               */
2086                     }
2087                     if(PRINT_SECTION)
2088                         chpr = newline(chpr);
2089                 }
2090 
2091                 entry_offset = subfile_entry->value + fileoffset_base;
2092                 for(num = 0; num < nsubifds; ++num)
2093                 {
2094                     subifd_offset = read_ulong(inptr,byteorder,entry_offset) +
2095                                                         fileoffset_base;
2096                     /* where to get next one                          */
2097                     entry_offset = ftell(inptr);
2098                     /* The next subifd offset suggests a maximum for  */
2099                     /* this subifd; at least until some nitwit writes */
2100                     /* the second one first. Doesn't help for the     */
2101                     /* last one, though.                              */
2102                     if(num < (nsubifds - 1))
2103                         max_offset = read_ulong(inptr,byteorder,HERE);
2104                     else
2105                         max_offset = 0;
2106                     if(ferror(inptr) || feof(inptr))
2107                         goto blewit;
2108                     max_value_offset = process_tiff_ifd(inptr,byteorder,
2109                                             subifd_offset,fileoffset_base,
2110                                             max_offset,summary_entry,parent_name,
2111                                             ifdtype,ifdnum,subifdnum + num,
2112                                             indent);
2113                     /* ###%%% don't we check for errors here???           */
2114                 }
2115             }
2116             else
2117             {
2118                 max_value_offset = process_tiff_ifd(inptr,byteorder,
2119                                             subfile_entry->value,fileoffset_base,
2120                                             max_offset,summary_entry,parent_name,
2121                                             ifdtype,ifdnum,subifdnum,
2122                                             indent);
2123             }
2124         }
2125         else
2126         {
2127             printred("Negative subifd number");
2128             chpr += printf(" %d, ifdtype %d not processed for IFD %d",subifdnum,ifdtype,ifdnum);
2129             chpr = newline(chpr);
2130             goto blewit;
2131         }
2132     }
2133     else
2134     {
2135         fprintf(stderr,"%s: no open file pointer to read EXIF\n",Progname);
2136         max_value_offset = 0L;
2137     }
2138     setcharsprinted(chpr);
2139     return(max_value_offset);
2140 blewit:
2141     /* we're going to keep trying, because the caller's next offset   */
2142     /* may be ok.                                                     */
2143     clearerr(inptr);
2144     return(0L);
2145 }
2146 
2147 /* Just a bare bones GPS routine; no interpretation is done.          */
2148 
2149 unsigned long
process_gps_ifd(FILE * inptr,unsigned short byteorder,unsigned long gps_offset,unsigned long fileoffset_base,unsigned long max_offset,struct image_summary * summary_entry,char * parent_name,int ifdnum,int indent)2150 process_gps_ifd(FILE *inptr,unsigned short byteorder,
2151                     unsigned long gps_offset,unsigned long fileoffset_base,
2152                     unsigned long max_offset,struct image_summary *summary_entry,
2153                     char *parent_name,int ifdnum,int indent)
2154 {
2155     struct ifd_entry *entry_ptr;
2156     unsigned long max_value_offset = 0L;
2157     unsigned long next_ifd_offset,current_offset,max_gps_offset;
2158     unsigned long start_entry_offset,entry_offset,value_offset;
2159     int entry_num,num_entries,value_is_offset,use_second_pass;
2160     int chpr = 0;
2161     char *fulldirname = CNULL;
2162 
2163     if(inptr == (FILE *)0)
2164     {
2165         fprintf(stderr,"%s: no open file pointer to read GPS IFD\n",
2166                 Progname);
2167         return(0L);
2168     }
2169 
2170     PUSHCOLOR(GPS_COLOR);
2171     /* If the gps segment appears to be beyond the start of the       */
2172     /* parent ifd, mark the start address funny.                      */
2173     if(max_offset && (gps_offset > max_offset))
2174         print_tag_address(SECTION,gps_offset + fileoffset_base,indent,"^");
2175     else
2176         print_tag_address(SECTION,gps_offset + fileoffset_base,indent,"@");
2177     if(PRINT_SECTION)
2178         chpr += printf("<GPS IFD> (in IFD %d)",ifdnum);
2179 
2180     num_entries = read_ushort(inptr,byteorder,gps_offset + fileoffset_base);
2181     if(ferror(inptr) || feof(inptr))
2182         goto blewit;
2183     current_offset = entry_offset = start_entry_offset = ftell(inptr);
2184     if(PRINT_SECTION)
2185     {
2186         chpr += printf(" %d entries ",num_entries);
2187         chpr += printf("starting at file offset %#lx=%lu",
2188                                         current_offset,current_offset);
2189         chpr = newline(chpr);
2190     }
2191     use_second_pass = value_is_offset = 0;
2192     fulldirname = splice(parent_name,".","Gps");
2193 
2194     indent += SMALLINDENT;
2195     /* The direct entries                                             */
2196     for(entry_num = 0; entry_num < num_entries; ++entry_num)
2197     {
2198         print_tag_address(ENTRY,entry_offset,indent,"@");
2199         entry_ptr = read_ifd_entry(inptr,byteorder,entry_offset);
2200         if((entry_ptr->value_type == 0) || (entry_ptr->value_type > DOUBLE) ||
2201             ferror(inptr) || feof(inptr))
2202         {
2203             print_tag_address(ENTRY,entry_offset,indent,"@");
2204             chpr += printf(" INVALID (%lu)",entry_ptr->value);
2205             chpr = newline(chpr);
2206             /* ###%%% replace with check code from process_tiff_ifd() */
2207             goto blewit;
2208         }
2209         entry_offset = current_offset = ftell(inptr);
2210         value_offset = print_entry(inptr,byteorder,entry_ptr,fileoffset_base,
2211                                             summary_entry,fulldirname,GPS_IFD,
2212                                             ifdnum,-1,SMALLINDENT);
2213         if(value_offset == 0UL)
2214             value_offset = entry_offset;
2215         if(value_offset > max_value_offset)
2216             max_value_offset = value_offset;
2217         if((PRINT_VALUE_AT_OFFSET) && (is_offset(entry_ptr)))
2218             ++use_second_pass;
2219     }
2220 
2221     next_ifd_offset = read_ulong(inptr,byteorder,current_offset);
2222 
2223     /* offsets found in the next pass should be within the bounds of  */
2224     /* the ifd. The following helps to detect chunks that are written */
2225     /* "out of place".                                                */
2226     if(next_ifd_offset > 0L)
2227     {
2228         if((PRINT_VALUE) && (PRINT_SECTION) && (PRINT_VALUE_AT_OFFSET))
2229         {
2230             print_tag_address(SECTION,current_offset,indent,"@");
2231             chpr += printf("**** next IFD offset %lu  ",next_ifd_offset);
2232             next_ifd_offset += fileoffset_base;
2233             if(next_ifd_offset < ftell(inptr))
2234             {
2235                 printred("BAD NEXT IFD OFFSET");
2236                 next_ifd_offset = 0L;
2237             }
2238             else
2239                 chpr += printf("(+ %lu = %#lx/%lu)",fileoffset_base,
2240                             next_ifd_offset,next_ifd_offset);
2241             chpr = newline(chpr);
2242         }
2243         else
2244             next_ifd_offset += fileoffset_base;
2245         /* This should never happen                                   */
2246         max_gps_offset = next_ifd_offset;
2247         if(max_offset && (max_gps_offset > max_offset))
2248             max_gps_offset = max_offset;
2249     }
2250     else
2251     {
2252         max_gps_offset = max_offset;
2253         if((PRINT_VALUE) && (PRINT_SECTION) && (PRINT_VALUE_AT_OFFSET))
2254         {
2255             print_tag_address(SECTION,current_offset,indent,"@");
2256             chpr += printf("**** next IFD offset 0");
2257             chpr = newline(chpr);
2258         }
2259     }
2260 
2261     if(ferror(inptr) || feof(inptr))
2262     {
2263         chpr += printf(" READ NEXT IFD OFFSET FAILED ");
2264         chpr = newline(chpr);
2265         why(stdout);
2266         clearerr(inptr);    /* keep going...                          */
2267     }
2268     else
2269         current_offset = ftell(inptr);
2270 
2271     value_offset = current_offset;
2272 
2273     /* Make a second pass to print offset values.                     */
2274     if(use_second_pass)
2275     {
2276         if((PRINT_VALUE) && (PRINT_SECTION) && (PRINT_VALUE_AT_OFFSET))
2277         {
2278             print_tag_address(SECTION,value_offset,indent,"@");
2279             chpr += printf("============= VALUES, GPS IFD ============");
2280             chpr = newline(chpr);
2281         }
2282 
2283         /* Second pass, to evaluate entries which are stored          */
2284         /* indirectly (the value requires more than 4 bytes).         */
2285         entry_offset = start_entry_offset;
2286         for(entry_num = 0; entry_num < num_entries; ++entry_num)
2287         {
2288             entry_ptr = read_ifd_entry(inptr,byteorder,entry_offset);
2289             if((entry_ptr->value_type == 0) || (entry_ptr->value_type > DOUBLE) ||
2290                 ferror(inptr) || feof(inptr))
2291             {
2292                 print_tag_address(ENTRY,entry_offset,indent,"@");
2293                 chpr += printf(" INVALID (%lu)",entry_ptr->value);
2294                 chpr = newline(chpr);
2295                 goto blewit;
2296             }
2297             current_offset = entry_offset = ftell(inptr);
2298             switch(entry_ptr->tag)
2299             {
2300                 default:
2301                     if((PRINT_VALUE) && ((PRINT_VALUE_AT_OFFSET) && is_offset(entry_ptr)))
2302                     {
2303                         print_tag_address(ENTRY,fileoffset_base + entry_ptr->value,
2304                                             indent,"@");
2305                         print_tagid(entry_ptr,SMALLINDENT,GPS_IFD);
2306                         value_offset =
2307                                     print_offset_value(inptr,byteorder,entry_ptr,
2308                                                     fileoffset_base,fulldirname,
2309                                                     GPS_IFD,indent,1);
2310                     }
2311                     break;
2312             }
2313             if(value_offset > max_value_offset)
2314                 max_value_offset = value_offset;
2315         }
2316     }
2317     else if(current_offset > max_value_offset)
2318         max_value_offset = current_offset;
2319 
2320     indent -= SMALLINDENT;
2321     if(max_offset && (gps_offset > max_offset))
2322     {
2323         print_tag_address(SECTION,max_value_offset - 1,indent,">");
2324         max_value_offset = 0L;  /* let the caller know.               */
2325     }
2326     else
2327         print_tag_address(SECTION,max_value_offset - 1,indent,"-");
2328     if(PRINT_SECTION)
2329     {
2330         chpr += printf("</GPS IFD>");
2331         chpr = newline(chpr);
2332     }
2333     POPCOLOR();
2334     if(next_ifd_offset)
2335     {
2336         printred("#========= WARNING! CHAINING NEXT IFD FROM GPS IFD =========");
2337         chpr = newline(1);
2338         value_offset = process_tiff_ifd(inptr,byteorder,next_ifd_offset,
2339                                 fileoffset_base,max_offset,NULL,fulldirname,
2340                                 GPS_IFD,-1,-1,indent);
2341         if(value_offset > max_value_offset)
2342             max_value_offset = value_offset;
2343     }
2344     if(fulldirname)
2345         free(fulldirname);
2346     return(max_value_offset);
2347 blewit:
2348     clearerr(inptr);
2349     current_offset = ftell(inptr);
2350     print_tag_address(SECTION,current_offset - 1,indent,"-");
2351     if(PRINT_SECTION)
2352     {
2353         chpr += printf("</GPS IFD>");
2354         chpr = newline(chpr);
2355     }
2356     if(fulldirname)
2357         free(fulldirname);
2358     POPCOLOR();
2359     return(0L);
2360 }
2361 
2362 /* Process JPEG the marker segments between JPEG SOI and EOI.         */
2363 /* For the moment, that means just printing them (offset, id, length) */
2364 /* and then moving to the next tag.                                   */
2365 
2366 /* The first marker has been read, it's identity and offset are       */
2367 /* passed in as arguments. No assumptions are made about the current  */
2368 /* file pointer; the first read always begins at the passed           */
2369 /* marker_offset.                                                     */
2370 
2371 /* APP section are noticed, and APP0, APP1, and APP12 section         */
2372 /* processed appropriately. Other APP section are reported without    */
2373 /* expansion of the section, but may be hex/ascii dumped by option.   */
2374 
2375 extern unsigned long forward_scan_for_eoi(FILE *,unsigned long,
2376                             unsigned long,char *,int);
2377 
2378 unsigned long
process_jpeg_segments(FILE * inptr,unsigned long marker_offset,unsigned short tag,unsigned long data_length,struct image_summary * summary_entry,char * parent_name,char * prefix,int indent)2379 process_jpeg_segments(FILE *inptr,unsigned long marker_offset,unsigned short tag,
2380                         unsigned long data_length,struct image_summary *summary_entry,
2381                         char *parent_name,char *prefix,int indent)
2382 {
2383     static unsigned long img_pixels = 0L;
2384     unsigned long max_offset = 0L;
2385     unsigned long dumplength = 0L;
2386     unsigned long start_of_jpeg_data;
2387     unsigned long found_eoi_offset,after_sos,end_of_section,eof;
2388     unsigned short seg_length,tmp;
2389     unsigned short img_height = 0;
2390     unsigned short img_width = 0;
2391     unsigned short bad_soi = 0;
2392     int chpr = 0;
2393     int had_soi = 0;
2394     int status = 0;
2395     int i;
2396     char *name;
2397     static unsigned long max_eoi = 0UL;
2398 
2399     if(inptr)
2400     {
2401         start_of_jpeg_data = marker_offset;
2402         if(start_of_jpeg_data == 0UL)
2403             max_eoi = 0UL;
2404         if((summary_entry == NULL) ||
2405                 summary_entry->entry_lock ||
2406                         (summary_entry->imageformat != IMGFMT_NOIMAGE))
2407         {
2408             summary_entry = new_summary_entry(summary_entry,0,IMGFMT_JPEG);
2409         }
2410         if(summary_entry)
2411         {
2412             if(summary_entry->length <= 0)
2413                 summary_entry->length = data_length;
2414             if(summary_entry->offset <= 0)
2415                 summary_entry->offset = start_of_jpeg_data;
2416             summary_entry->imageformat = IMGFMT_JPEG;
2417             summary_entry->entry_lock = lock_number(summary_entry);
2418             if(tag == 0)
2419             {
2420                 clearerr(inptr);
2421                 (void)jpeg_status(JPEG_NO_SOI);
2422                 if(summary_entry)
2423                     summary_entry->imagesubformat |= IMGSUBFMT_NO_JPEG;
2424             }
2425         }
2426         PUSHCOLOR(JPEG_COLOR);
2427         while(tag != 0)
2428         {
2429             switch(tag)
2430             {
2431                 case JPEG_SOS:  /* image data                         */
2432                     name = tagname(tag);
2433                     if(PRINT_SEGMENT)
2434                     {
2435                         print_tag_address(SEGMENT,marker_offset,indent + SMALLINDENT,prefix);
2436                         chpr += printf("<%s>",name);
2437                     }
2438                     seg_length = read_ushort(inptr,TIFF_MOTOROLA,marker_offset + 2);
2439                     if(!ferror(inptr) && !feof(inptr))
2440                     {
2441                         unsigned char ns,c,t,td,ta,ss,se,a,ah,al;
2442                         int i;
2443 
2444                         /* number of components in scan               */
2445                         ns = read_ubyte(inptr,HERE);
2446                         if(PRINT_SEGMENT)
2447                         {
2448                             chpr += printf(" length %u",seg_length);
2449                             chpr += printf("  start of JPEG data, %d components %lu pixels",
2450                                                                       ns & 0xff,img_pixels);
2451                             chpr = newline(chpr);
2452                         }
2453                         if(Debug & JPEG_MARKER_DEBUG)
2454                         {
2455                             for(i = 0; i < ns; ++i)
2456                             {
2457                                 /* ###%%% */
2458                                 putindent(6 + (2 * ADDRWIDTH) + indent + 16);
2459                                 /* component selector                 */
2460                                 c = read_ubyte(inptr,HERE);
2461                                 t = read_ubyte(inptr,HERE);
2462                                 td = t & 0xf;
2463                                 ta = ((t & 0xf0) >> 4) & 0xf;
2464                                 if((ferror(inptr) == 0) && (feof(inptr) == 0) && (PRINT_SEGMENT))
2465                                 {
2466                                     chpr += printf("Cs%d=%d, Td%d=%#04x, Ta%d=%#04x",i,c,i,td,i,ta);
2467                                     chpr = newline(chpr);
2468                                 }
2469                             }
2470                             ss = read_ubyte(inptr,HERE);
2471                             se = read_ubyte(inptr,HERE);
2472                             a = read_ubyte(inptr,HERE);
2473                             ah = a & 0xf;
2474                             al = ((a & 0xf0) >> 4) & 0xf;
2475                             putindent(6 + (2 * ADDRWIDTH) + indent + 16);
2476                             chpr += printf("Ss=%u, Se=%u, Ah=%u, Al=%u",ss,se,ah,al);
2477                             chpr = newline(chpr);
2478                         }
2479                     }
2480                     else
2481                     {
2482                         tag = 0;
2483                         chpr += printf("ERROR reading length of SOS");
2484                         chpr = newline(chpr);
2485                         why(stdout);
2486                         (void)jpeg_status(JPEG_HAD_ERROR);
2487                         if(summary_entry)
2488                             summary_entry->imagesubformat |= IMGSUBFMT_JPEGFAILED;
2489                         continue;
2490                     }
2491                     if(data_length > 0L)
2492                     {
2493 
2494                         after_sos = marker_offset + 2 + seg_length;
2495                         marker_offset = start_of_jpeg_data + data_length - 2L;
2496                         tag = read_ushort(inptr,TIFF_MOTOROLA,marker_offset);
2497                         if(ferror(inptr) || feof(inptr))
2498                         {
2499                             tag = 0;
2500                             printred("# WARNING: ERROR reading JPEG_EOI at end of section");
2501                             chpr = newline(chpr);
2502                             clearerr(inptr);
2503                             /* Skip the backward scan and check       */
2504                             /* forward from the end of the SOS        */
2505                             /* section, to see where the file is      */
2506                             /* truncated.                             */
2507                             status = JPEG_HAD_ERROR;
2508                             (void)jpeg_status(status);
2509                             if(summary_entry)
2510                                 summary_entry->imagesubformat |= IMGSUBFMT_JPEGFAILED;
2511 #if 0
2512 /* Wrong if multiple compressed tiles/strips in passed length; status */
2513 /* set to HAD_ERROR allows skippping backward scan and going direct   */
2514 /* to forward scan. Should pass just tile/strip length and handle     */
2515 /* multiples in parent.                                               */
2516                             continue;
2517 #endif
2518                         }
2519                         if(tag == JPEG_EOI)
2520                         {
2521                             max_offset = ftell(inptr);
2522                             continue;
2523                         }
2524                         else    /* Try a little harder to find EOI    */
2525                         {
2526                             int i;
2527 
2528                             end_of_section = start_of_jpeg_data + data_length;
2529                             if(status == 0)
2530                             {
2531                                 /* Try a quick scan backward from the end */
2532                                 /* of the section, in case there's just a */
2533                                 /* little padding.                        */
2534                                 for(i = 1; i < 512; ++i)
2535                                 {
2536                                     tag = read_ushort(inptr,TIFF_MOTOROLA,marker_offset);
2537                                     if(Debug & JPEG_EOI_DEBUG)
2538                                         printf("DEBUG: %#lx/%ld: %#04x\n",marker_offset,marker_offset,tag);
2539                                     if(ferror(inptr) || feof(inptr))
2540                                         break;
2541                                     status = 0;
2542                                     if(tag == JPEG_EOI)
2543                                         break;
2544                                     --marker_offset;
2545                                 }
2546                                 if(ferror(inptr) || feof(inptr))
2547                                 {
2548                                     tag = 0;
2549                                     printred("# WARNING: ERROR reading JPEG data looking for JPEG_EOI");
2550                                     chpr = newline(chpr);
2551                                     clearerr(inptr);
2552                                     (void)jpeg_status(JPEG_HAD_ERROR);
2553                                     if(summary_entry)
2554                                         summary_entry->imagesubformat |= IMGSUBFMT_JPEGFAILED;
2555                                     continue;
2556                                 }
2557                                 if(tag == JPEG_EOI)
2558                                 {
2559                                     if(start_of_jpeg_data > 0UL)
2560                                     {
2561                                         if(feof(inptr) || ((end_of_section + 5) >= get_filesize(inptr)))
2562                                             max_eoi = start_of_jpeg_data;
2563                                     }
2564                                     max_offset = ftell(inptr);
2565                                     (void)jpeg_status(JPEG_EARLY_EOI);
2566                                     if(summary_entry)
2567                                         summary_entry->imagesubformat |= IMGSUBFMT_JPEG_EARLY_EOI;
2568                                     if(Debug & JPEG_EOI_DEBUG)
2569                                         printf("DEBUG: start_of_jpeg_data=%lu, max_eoi=%lu\n",start_of_jpeg_data,max_eoi);
2570                                     continue;
2571                                 }
2572                             }
2573                             /* If the quick scan didn't work, try a   */
2574                             /* forward scan from the offset given by  */
2575                             /* the start of scan header.              */
2576                             found_eoi_offset = forward_scan_for_eoi(inptr,after_sos,
2577                                                             end_of_section,"!",indent);
2578                             if(start_of_jpeg_data > 0UL)
2579                             {
2580                                 if(feof(inptr) || ((found_eoi_offset + 5) >= get_filesize(inptr)))
2581                                     max_eoi = start_of_jpeg_data;
2582                             }
2583                             if(Debug & JPEG_EOI_DEBUG)
2584                                 printf("DEBUG: start_of_jpeg_data=%lu, max_eoi=%lu\n",start_of_jpeg_data,max_eoi);
2585                             if(found_eoi_offset)
2586                             {
2587                                 max_offset = found_eoi_offset + 2;
2588                                 (void)jpeg_status(JPEG_EARLY_EOI);
2589                                 if(summary_entry)
2590                                     summary_entry->imagesubformat |= IMGSUBFMT_JPEG_EARLY_EOI;
2591                                 marker_offset = max_offset - 2UL;
2592                                 tag = JPEG_EOI;
2593                                 continue;
2594                             }
2595                             else
2596                             {
2597                                 if(ferror(inptr) || feof(inptr))
2598                                 {
2599                                     tag = 0;
2600                                     clearerr(inptr);
2601                                     (void)jpeg_status(status);
2602                                     if(summary_entry)
2603                                         summary_entry->imagesubformat |= IMGSUBFMT_JPEGFAILED;
2604                                     continue;
2605                                 }
2606                                 else
2607                                 {
2608                                     max_offset = 0;
2609                                     (void)fseek(inptr,start_of_jpeg_data + data_length - 2L,0);
2610                                     (void)jpeg_status(JPEG_NO_EOI);
2611                                 }
2612                             }
2613                         }
2614                     }
2615                     else
2616                     {
2617                         /* See if there's a JPEG_EOI at (or somewhere */
2618                         /* near) EOF. If a previous subimage was      */
2619                         /* found at or very near eof, indicating a    */
2620                         /* thumbnail tacked on to the end of the      */
2621                         /* file, use the start of that image as the   */
2622                         /* limit for the search,                      */
2623                         if(Debug & JPEG_EOI_DEBUG)
2624                             printf("DEBUG: max_eoi=%lu\n",max_eoi);
2625                         if(fseek(inptr,0L,2) == 0)
2626                         {
2627                             /* Values to use if a forward scan is     */
2628                             /* required.                              */
2629                             after_sos = marker_offset + 2 + seg_length;
2630                             eof = ftell(inptr);
2631                             if(max_eoi)
2632                             {
2633                                 end_of_section = max_eoi - 1;
2634                                 marker_offset = max_eoi - 2;
2635                             }
2636                             else
2637                             {
2638                                 end_of_section = eof - 1;
2639                                 marker_offset = eof - 2;
2640                             }
2641                             tag = read_ushort(inptr,TIFF_MOTOROLA,marker_offset);
2642                             if(ferror(inptr) || feof(inptr))
2643                             {
2644                                 tag = 0;
2645                                 printred("# WARNING: ERROR reading JPEG data looking for JPEG_EOI");
2646                                 chpr = newline(chpr);
2647                                 clearerr(inptr);
2648                                 (void)jpeg_status(JPEG_HAD_ERROR);
2649                                 if(summary_entry)
2650                                     summary_entry->imagesubformat |= IMGSUBFMT_JPEGFAILED;
2651                                 continue;
2652                             }
2653                             if(Debug & JPEG_EOI_DEBUG)
2654                                 printf("DEBUG: %#lx/%ld: %#04x\n",marker_offset,marker_offset,tag);
2655                             if(tag != JPEG_EOI) /* try harder         */
2656                             {
2657                                 for(i = 1; i < 512; ++i)
2658                                 {
2659                                     --marker_offset;
2660                                     tag = read_ushort(inptr,TIFF_MOTOROLA,marker_offset);
2661                                     if(ferror(inptr) || feof(inptr))
2662                                         break;
2663                                     if(Debug & JPEG_EOI_DEBUG)
2664                                         printf("DEBUG: %#lx/%ld: %#04x\n",marker_offset,marker_offset,tag);
2665                                     if(tag == JPEG_EOI)
2666                                         break;
2667                                 }
2668                             }
2669                             if(ferror(inptr) || feof(inptr))
2670                             {
2671                                 tag = 0;
2672                                 printred("# WARNING: ERROR reading JPEG data looking for JPEG_EOI");
2673                                 chpr = newline(chpr);
2674                                 clearerr(inptr);
2675                                 (void)jpeg_status(JPEG_HAD_ERROR);
2676                                 if(summary_entry)
2677                                     summary_entry->imagesubformat |= IMGSUBFMT_JPEGFAILED;
2678                                 continue;
2679                             }
2680                             if(tag == JPEG_EOI)
2681                             {
2682                                 max_offset = ftell(inptr);
2683                                 if(Debug & JPEG_EOI_DEBUG)
2684                                     printf("DEBUG: max_offset=%lu, eof=%lu, marker_offset=%lu\n",max_offset,eof,marker_offset);
2685                                 if(marker_offset < (eof - 2))
2686                                 {
2687                                     (void)jpeg_status(JPEG_EARLY_EOI);
2688                                     if(summary_entry)
2689                                     {
2690                                         summary_entry->imagesubformat |= IMGSUBFMT_JPEG_EARLY_EOI;
2691                                         if(summary_entry->length <= 0)
2692                                             summary_entry->length = eof - start_of_jpeg_data;
2693                                     }
2694                                 }
2695                                 continue;
2696                             }
2697                             else
2698                             {
2699                                 found_eoi_offset = forward_scan_for_eoi(inptr,after_sos,end_of_section,
2700                                                                                             "!",indent);
2701                                 if(found_eoi_offset)
2702                                 {
2703                                     max_offset = found_eoi_offset + 2;
2704                                     marker_offset = found_eoi_offset;
2705                                     if(Debug & JPEG_EOI_DEBUG)
2706                                     {
2707                                         printf("DEBUG: max_offset=%lu, eof=%lu, marker_offset=%lu\n",max_offset,eof,marker_offset);
2708                                         printf("found_eof_offset=%lu, ftell=%lu\n",found_eoi_offset,ftell(inptr));
2709                                     }
2710                                     if(found_eoi_offset < (eof - 2))
2711                                     {
2712                                         (void)jpeg_status(JPEG_EARLY_EOI);
2713                                         if(summary_entry)
2714                                             summary_entry->imagesubformat |= IMGSUBFMT_JPEG_EARLY_EOI;
2715                                     }
2716                                     if((summary_entry) && (summary_entry->length <= 0))
2717                                         summary_entry->length = eof - start_of_jpeg_data;
2718                                     tag = JPEG_EOI;
2719                                     continue;
2720                                 }
2721                                 else
2722                                 {
2723                                     if((summary_entry) && (summary_entry->length <= 0))
2724                                         summary_entry->length = eof - start_of_jpeg_data;
2725                                     print_tag_address(SEGMENT,eof - 1,indent + SMALLINDENT,prefix);
2726                                     printred(" # WARNING: at EOF: JPEG_EOI not found");
2727                                     if(!(LIST_MODE))
2728                                         chpr = newline(chpr);
2729                                     max_offset = 0;
2730                                     /* ###%%% this may not be needed, */
2731                                     /* since it's already been        */
2732                                     /* reported                       */
2733                                     (void)jpeg_status(JPEG_NO_EOI);
2734                                 }
2735                             }
2736                         }
2737                         if(ferror(inptr) || feof(inptr))
2738                         {
2739                             (void)jpeg_status(JPEG_HAD_ERROR);
2740                             if(summary_entry)
2741                                 summary_entry->imagesubformat |= IMGSUBFMT_JPEGFAILED;
2742                         }
2743                     }
2744                     tag = 0;    /* break the loop                     */
2745                     break;
2746                 case JPEG_DHT:  /* image data                         */
2747                     name = tagname(tag);
2748                     if(PRINT_SEGMENT)
2749                     {
2750                         print_tag_address(SEGMENT,marker_offset,indent + SMALLINDENT,prefix);
2751                         chpr += printf("<%s>",name);
2752                     }
2753                     seg_length = read_ushort(inptr,TIFF_MOTOROLA,marker_offset + 2);
2754                     if(!ferror(inptr) && !feof(inptr))
2755                     {
2756                         unsigned char t,tc,th,l;
2757                         int i;
2758 
2759                         t = read_ubyte(inptr,HERE);
2760                         tc = t & 0xf;
2761                         th = ((t & 0xf0) >> 4) & 0xf;
2762                         if(PRINT_SEGMENT)
2763                         {
2764                             chpr += printf(" length %u",seg_length);
2765                             chpr += printf(" table class = %u",tc & 0xff);
2766                             chpr += printf(" table id = %u",th & 0xff);
2767                             chpr = newline(chpr);
2768                         }
2769                         if(Debug & JPEG_MARKER_DEBUG)
2770                         {
2771                             for(i = 0; i < 16; ++i)
2772                             {
2773                                 if((i % 5) == 0)
2774                                 {
2775                                     chpr = newline(chpr);
2776                                     putindent(6 + (2 * ADDRWIDTH) + indent + 16);
2777                                 }
2778                                 /* component selector                 */
2779                                 l = read_ubyte(inptr,HERE);
2780                                 if((ferror(inptr) == 0) && (feof(inptr) == 0) && (PRINT_SEGMENT))
2781                                 {
2782                                     chpr += printf("l%-2d=%u",i,l);
2783                                     if(i < 15)
2784                                         chpr += printf(", ");
2785                                 }
2786                             }
2787                             chpr = newline(chpr);
2788                         }
2789 
2790                         /* next tag                                       */
2791                         marker_offset += seg_length + 2;
2792                         if(marker_offset > 0L)
2793                             tag = read_ushort(inptr,TIFF_MOTOROLA,marker_offset);
2794                         else
2795                             tag = 0;
2796                         if(ferror(inptr) || feof(inptr))
2797                         {
2798                             tag = 0;
2799                             clearerr(inptr);
2800                             (void)jpeg_status(JPEG_HAD_ERROR);
2801                             if(summary_entry)
2802                                 summary_entry->imagesubformat |= IMGSUBFMT_JPEGFAILED;
2803                             continue;
2804                         }
2805                     }
2806                     else
2807                     {
2808                         chpr += printf("ERROR reading length of DHT");
2809                         chpr = newline(chpr);
2810                         why(stdout);
2811                         (void)jpeg_status(JPEG_HAD_ERROR);
2812                         if(summary_entry)
2813                             summary_entry->imagesubformat |= IMGSUBFMT_JPEGFAILED;
2814                     }
2815                     break;
2816                 case JPEG_COM:
2817                     name = tagname(tag);
2818                     if(PRINT_SEGMENT)
2819                     {
2820                         print_tag_address(SEGMENT,marker_offset,indent + SMALLINDENT,prefix);
2821                         chpr += printf("<%s>",name);
2822                     }
2823                     seg_length = read_ushort(inptr,TIFF_MOTOROLA,marker_offset + 2);
2824 
2825                     if(!ferror(inptr) && !feof(inptr))
2826                     {
2827                         if(PRINT_SEGMENT)
2828                         {
2829                             chpr += printf(" length %u: \'",seg_length);
2830                             (void)print_ascii(inptr,seg_length - 2,HERE);
2831                             chpr += printf("\'");
2832                             chpr = newline(chpr);
2833                         }
2834                         marker_offset += seg_length + 2;
2835                         /* next tag                                   */
2836                         tag = read_ushort(inptr,TIFF_MOTOROLA,marker_offset);
2837                         if(ferror(inptr) || feof(inptr))
2838                         {
2839                             tag = 0;
2840                             clearerr(inptr);
2841                             (void)jpeg_status(JPEG_HAD_ERROR);
2842                             if(summary_entry)
2843                                 summary_entry->imagesubformat |= IMGSUBFMT_JPEGFAILED;
2844                         }
2845                         else
2846                             max_offset = ftell(inptr);
2847                     }
2848                     else
2849                     {
2850                         tag = 0;
2851                         clearerr(inptr);
2852                         (void)jpeg_status(JPEG_HAD_ERROR);
2853                         if(summary_entry)
2854                             summary_entry->imagesubformat |= IMGSUBFMT_JPEGFAILED;
2855                     }
2856                     break;
2857                 case JPEG_SOF_0:
2858                 case JPEG_SOF_1:
2859                 case JPEG_SOF_2:
2860                 case JPEG_SOF_3:
2861                 case JPEG_SOF_5:
2862                 case JPEG_SOF_6:
2863                 case JPEG_SOF_7:
2864                 case JPEG_SOF_9:
2865                 case JPEG_SOF_10:
2866                 case JPEG_SOF_11:
2867                 case JPEG_SOF_13:
2868                 case JPEG_SOF_14:
2869                 case JPEG_SOF_15:
2870                     name = tagname(tag);
2871                     /* If this is a TIFF format file, record the      */
2872                     /* actual compression type as indicated by the    */
2873                     /* SOF tag, for printing in the image summary at  */
2874                     /* the end.                                       */
2875                     if(summary_entry)
2876                         summary_entry->compression = tag;
2877                     if(PRINT_SEGMENT)
2878                     {
2879                         print_tag_address(SEGMENT,marker_offset,indent + SMALLINDENT,prefix);
2880                         chpr += printf("<%s>",name);
2881                     }
2882                     seg_length = read_ushort(inptr,TIFF_MOTOROLA,marker_offset + 2);
2883                     if(!ferror(inptr) && !feof(inptr))
2884                     {
2885                         unsigned char nf = 0;
2886                         unsigned char c,h,v,t,p;
2887                         int i;
2888 
2889                         if(PRINT_SEGMENT)
2890                             chpr += printf(" length %u",seg_length);
2891                         p = read_ubyte(inptr,HERE); /* precision    */
2892                         if(!ferror(inptr) && !feof(inptr))
2893                             img_height = read_ushort(inptr,TIFF_MOTOROLA,HERE);
2894                         if(!ferror(inptr) && !feof(inptr))
2895                             img_width = read_ushort(inptr,TIFF_MOTOROLA,HERE);
2896                         if(!ferror(inptr) && !feof(inptr))
2897                             img_pixels = img_height * img_width;
2898                         if(!ferror(inptr) && !feof(inptr))
2899                             nf = read_ubyte(inptr,HERE); /* components */
2900                         if(!ferror(inptr) && !feof(inptr))
2901                         {
2902                             max_offset = ftell(inptr);
2903                             if(PRINT_SEGMENT)
2904                                 chpr += printf(", %d bits/sample, components=%d, width=%d, height=%d",
2905                                                             p,(int)nf,(int)img_width,(int)img_height);
2906                             if(summary_entry)
2907                             {
2908                                 summary_entry->spp = nf;
2909                                 for(i = 0; i < nf; i++)
2910                                     summary_entry->bps[i] = p;
2911                             }
2912                         }
2913                         if(ferror(inptr) || feof(inptr))
2914                         {
2915                             tag = 0;
2916                             clearerr(inptr);
2917                             (void)jpeg_status(JPEG_HAD_ERROR);
2918                             if(summary_entry)
2919                                 summary_entry->imagesubformat |= IMGSUBFMT_JPEGFAILED;
2920                             continue;
2921                         }
2922                         if(PRINT_SEGMENT)
2923                             chpr = newline(chpr);
2924                         if(Debug & JPEG_MARKER_DEBUG)
2925                         {
2926                             for(i = 0; i < nf; ++i)
2927                             {
2928                                 putindent(6 + (2 * ADDRWIDTH) + indent + 16);
2929                                 c = read_ubyte(inptr,HERE); /* component id */
2930                                 tmp = read_ubyte(inptr,HERE); /* H | V    */
2931                                 h = tmp & 0xf;
2932                                 v = ((tmp & 0xf0) >> 4) & 0xf;
2933                                 t = read_ubyte(inptr,HERE); /* Q tbl sel    */
2934                                 if((ferror(inptr) == 0) && (PRINT_SEGMENT))
2935                                 {
2936                                     chpr += printf("C%d=%d, H%d=%d, V%d=%d, T%d=%#04x",i,c,i,h,i,v,i,t);
2937                                     chpr = newline(chpr);
2938                                 }
2939                             }
2940                         }
2941                         if(summary_entry && (img_height > 0) &&
2942                                                 (summary_entry->pixel_height < img_height))
2943                         {
2944                             summary_entry->pixel_height = img_height;
2945                         }
2946                         if(summary_entry && (img_width > 0) &&
2947                                                 (summary_entry->pixel_width < img_width))
2948                         {
2949                             summary_entry->pixel_width = img_width;
2950                         }
2951                         switch(tag)
2952                         {
2953                             /* lossless types are likely primary;     */
2954                             /* mark them for scan_summary()           */
2955                             case JPEG_SOF_3:
2956                             case JPEG_SOF_7:
2957                             case JPEG_SOF_11:
2958                             case JPEG_SOF_15:
2959                                 summary_entry->subfiletype = POSSIBLE_PRIMARY_TYPE;
2960                                 break;
2961                             default:
2962                                 break;
2963                         }
2964                     }
2965 
2966                     if(!ferror(inptr) && !feof(inptr))
2967                     {
2968                         max_offset = ftell(inptr);
2969                         marker_offset += seg_length + 2;
2970                         /* next tag                                   */
2971                         tag = read_ushort(inptr,TIFF_MOTOROLA,marker_offset);
2972                         if(ferror(inptr) || feof(inptr))
2973                         {
2974                             tag = 0;
2975                             clearerr(inptr);
2976                             (void)jpeg_status(JPEG_HAD_ERROR);
2977                             if(summary_entry)
2978                                 summary_entry->imagesubformat |= IMGSUBFMT_JPEGFAILED;
2979                         }
2980                         else
2981                             max_offset = ftell(inptr);
2982                     }
2983                     else
2984                     {
2985                         tag = 0;
2986                         clearerr(inptr);
2987                         (void)jpeg_status(JPEG_HAD_ERROR);
2988                         if(summary_entry)
2989                             summary_entry->imagesubformat |= IMGSUBFMT_JPEGFAILED;
2990                     }
2991                     break;
2992 
2993                 case JPEG_BADSOI:   /* minolta                        */
2994                     if(bad_soi == 0)
2995                         bad_soi = tag;
2996                     /* fall through                                   */
2997                 case JPEG_SOI:
2998                     name = tagname(tag);
2999                     if((PRINT_SECTION) || (PRINT_SEGMENT))
3000                     {
3001                         print_tag_address(SECTION|SEGMENT,marker_offset,indent,prefix);
3002                         if(bad_soi)
3003                         {
3004                             printred("<JPEG_BADSOI>");
3005                             chpr += printf(" (%#06x)",bad_soi);
3006                         }
3007                         else
3008                             chpr += printf("<%s>",name);
3009                         chpr = newline(chpr);
3010                     }
3011                     start_of_jpeg_data = marker_offset;
3012                     if(bad_soi == 0)
3013                         ++had_soi;
3014                     /* next tag                                       */
3015                     tag = read_ushort(inptr,TIFF_MOTOROLA,marker_offset + 2);
3016                     if(!ferror(inptr) && !feof(inptr))
3017                     {
3018                         marker_offset += 2;
3019                         max_offset = ftell(inptr);
3020                     }
3021                     else
3022                     {
3023                         tag = 0;
3024                         clearerr(inptr);
3025                         (void)jpeg_status(JPEG_HAD_ERROR);
3026                         if(summary_entry)
3027                             summary_entry->imagesubformat |= IMGSUBFMT_JPEGFAILED;
3028                     }
3029                     break;
3030                 case JPEG_EOI:
3031                     name = tagname(tag);
3032                     max_offset = ftell(inptr);
3033                     if((PRINT_SECTION) || (PRINT_SEGMENT))
3034                     {
3035                         print_tag_address(SECTION|SEGMENT,marker_offset,indent,prefix);
3036                         if((status = jpeg_status(0)) == JPEG_EARLY_EOI)
3037                         {
3038                             PUSHCOLOR(RED);
3039                             chpr += printf("<%s> JPEG length %lu",name,max_offset - start_of_jpeg_data);
3040                             POPCOLOR();
3041                         }
3042                         else
3043                             chpr += printf("<%s> JPEG length %lu",name,max_offset - start_of_jpeg_data);
3044                         /* re-set the cleared status                  */
3045                         jpeg_status(status);
3046                         if((PRINT_SECTION) && (status != JPEG_EARLY_EOI))
3047                             chpr = newline(chpr);
3048                     }
3049                     if((summary_entry) && (summary_entry->length <= 0))
3050                     {
3051                         /* Use specified length, if any, even if      */
3052                         /* early EOI                                  */
3053                         if(data_length > 0)
3054                         {
3055                             summary_entry->length = data_length;
3056                             max_offset = start_of_jpeg_data + data_length;
3057                         }
3058                         else
3059                             summary_entry->length = max_offset - start_of_jpeg_data;
3060                     }
3061                     tag = 0;  /* break the loop                       */
3062                     break;
3063                 case JPEG_APP0:
3064                     marker_offset = process_app0(inptr,marker_offset,tag,summary_entry,
3065                                                             parent_name,indent + SMALLINDENT);
3066                     /* next tag                                       */
3067                     if(marker_offset > 0L)
3068                         tag = read_ushort(inptr,TIFF_MOTOROLA,marker_offset);
3069                     else
3070                         tag = 0;
3071                     if(ferror(inptr) || feof(inptr))
3072                     {
3073                         clearerr(inptr);
3074                         (void)jpeg_status(JPEG_HAD_ERROR);
3075                         if(summary_entry)
3076                             summary_entry->imagesubformat |= IMGSUBFMT_JPEGFAILED;
3077                     }
3078                     else
3079                         max_offset = ftell(inptr);
3080                     break;
3081                 case JPEG_APP1:
3082                     marker_offset = process_app1(inptr,marker_offset,tag,summary_entry,
3083                                                             parent_name,indent + SMALLINDENT);
3084                     /* next tag                                       */
3085                     if(marker_offset > 0L)
3086                         tag = read_ushort(inptr,TIFF_MOTOROLA,marker_offset);
3087                     else
3088                         tag = 0;
3089                     if(ferror(inptr) || feof(inptr))
3090                     {
3091                         clearerr(inptr);
3092                         (void)jpeg_status(JPEG_HAD_ERROR);
3093                         if(summary_entry)
3094                             summary_entry->imagesubformat |= IMGSUBFMT_JPEGFAILED;
3095                     }
3096                     break;
3097                 case JPEG_APP3:
3098                     marker_offset = process_app3(inptr,marker_offset,tag,summary_entry,
3099                                                             parent_name,indent + SMALLINDENT);
3100                     /* next tag                                       */
3101                     if(marker_offset > 0L)
3102                         tag = read_ushort(inptr,TIFF_MOTOROLA,marker_offset);
3103                     else
3104                         tag = 0;
3105                     if(ferror(inptr) || feof(inptr))
3106                     {
3107                         clearerr(inptr);
3108                         (void)jpeg_status(JPEG_HAD_ERROR);
3109                         if(summary_entry)
3110                             summary_entry->imagesubformat |= IMGSUBFMT_JPEGFAILED;
3111                     }
3112                     break;
3113                 case JPEG_APP12:
3114                     marker_offset = process_app12(inptr,marker_offset,tag,
3115                                             summary_entry,parent_name,indent + SMALLINDENT);
3116                     /* next tag                                       */
3117                     if(marker_offset > 0L)
3118                         tag = read_ushort(inptr,TIFF_MOTOROLA,marker_offset);
3119                     else
3120                         tag = 0;
3121                     if(ferror(inptr) || feof(inptr))
3122                     {
3123                         clearerr(inptr);
3124                         (void)jpeg_status(JPEG_HAD_ERROR);
3125                         if(summary_entry)
3126                             summary_entry->imagesubformat |= IMGSUBFMT_JPEGFAILED;
3127                     }
3128                     else
3129                         max_offset = ftell(inptr);
3130                     break;
3131                 case JPEG_APP2:
3132                 case JPEG_APP4:
3133                 case JPEG_APP5:
3134                 case JPEG_APP6:
3135                 case JPEG_APP7:
3136                 case JPEG_APP8:
3137                 case JPEG_APP9:
3138                 case JPEG_APP10:
3139                 case JPEG_APP11:
3140                 case JPEG_APP13:
3141                 case JPEG_APP14:
3142                 case JPEG_APP15:
3143                     marker_offset = process_appn(inptr,marker_offset,tag,
3144                                             summary_entry,parent_name,indent + SMALLINDENT);
3145                     /* next tag                                       */
3146                     if(marker_offset > 0L)
3147                         tag = read_ushort(inptr,TIFF_MOTOROLA,marker_offset);
3148                     else
3149                         tag = 0;
3150                     if(ferror(inptr) || feof(inptr))
3151                     {
3152                         tag = 0;
3153                         clearerr(inptr);
3154                     }
3155                     else
3156                         max_offset = ftell(inptr);
3157                     break;
3158                 default:
3159                     /* Minolta sometimes writes garbage in the high   */
3160                     /* byte of SOI tags; assume that 0xd8 in the low  */
3161                     /* byte is a bad SOI.                             */
3162                     if(((tag & 0xff00) != 0xff00) && ((tag & 0x00ff) == 0xd8))
3163                     {
3164                         /* Only if no SOI yet                         */
3165                         if((had_soi == 0) && (bad_soi == 0))
3166                         {
3167                             bad_soi = tag;
3168                             tag &= 0x00ff;  /* This will match        */
3169                                             /* JPEG_BADSOI above.     */
3170                             continue;
3171                         }
3172                         else if(bad_soi)
3173                             had_soi = 0;
3174                         /* ###%%% this should be handled better;      */
3175                         /* don't set had_soi on a bad_soi but set it  */
3176                         /* after a legitimate marker is found NEXT;   */
3177                         /* I.e. we have a legitimate jpeg only if a   */
3178                         /* good marker is found, after which an error */
3179                         /* indicates corrupted jpeg data, otherwise   */
3180                         /* an error should indicate no jpeg data      */
3181                         /* found.                                     */
3182                     }
3183                     name = tagname(tag);
3184                     if(PRINT_SEGMENT)
3185                     {
3186                         print_tag_address(SEGMENT,marker_offset,indent + SMALLINDENT,prefix);
3187                         chpr += printf("<%s>",name);
3188                     }
3189                     if((tag & 0xff00) != 0xff00)
3190                     {
3191                         if(PRINT_SEGMENT)
3192                         {
3193                             printred(" INVALID JPEG TAG");
3194                             chpr = newline(chpr);
3195                         }
3196                         tag = 0;
3197                         if(had_soi)
3198                             (void)jpeg_status(JPEG_HAD_ERROR);
3199                         else
3200                             (void)jpeg_status(JPEG_NO_SOI);
3201                         if(summary_entry)
3202                         {
3203                             /* If this is the first tag, we have no   */
3204                             /* reason to believe that this is really  */
3205                             /* jpeg data. If not, data is corrupted   */
3206                             if(had_soi)
3207                                 summary_entry->imagesubformat |= IMGSUBFMT_JPEGFAILED;
3208                             else
3209                             {
3210                                 summary_entry->imagesubformat |= IMGSUBFMT_NO_JPEG;
3211                                 /* ###%%% hmmm...                     */
3212                                 /* summary_entry->compression = 0;    */
3213                             }
3214                         }
3215                         else
3216                             printred("JPEG: NO SUMMARY ENTRY ");
3217                         clearerr(inptr);
3218                         if(Max_imgdump > 0)
3219                         {
3220                             /* If the length of the data is unknown,  */
3221                             /* limit the dump to something reasonable */
3222                             if(Max_imgdump == DUMPALL)
3223                             {
3224                                 if(data_length > 0)
3225                                     dumplength = data_length;
3226                                 else
3227                                     data_length = dumplength = 1024;
3228                             }
3229                             else if(Max_imgdump > data_length)
3230                             {
3231                                 if(data_length > 0)
3232                                     dumplength = data_length;
3233                                 else
3234                                     data_length = dumplength = 1024;
3235                             }
3236                             else
3237                                 dumplength = Max_imgdump;
3238                             chpr = newline(0);
3239                             hexdump(inptr,start_of_jpeg_data,data_length,
3240                                         dumplength,16,indent,SMALLINDENT);
3241                             chpr = newline(1);
3242                         }
3243                         max_offset = start_of_jpeg_data + data_length;
3244                     }
3245                     else
3246                     {
3247                         seg_length = read_ushort(inptr,TIFF_MOTOROLA,marker_offset + 2);
3248                         if(!ferror(inptr) && !feof(inptr))
3249                         {
3250                             if(PRINT_SEGMENT)
3251                             {
3252                                 chpr += printf(" length %u",seg_length);
3253                                 chpr = newline(chpr);
3254                             }
3255                             marker_offset = marker_offset + 2 + seg_length;
3256                             tag = read_ushort(inptr,TIFF_MOTOROLA,marker_offset);
3257                             if(ferror(inptr) || feof(inptr))
3258                             {
3259                                 tag = 0;
3260                                 clearerr(inptr);
3261                                 (void)jpeg_status(JPEG_HAD_ERROR);
3262                                 if(summary_entry)
3263                                     summary_entry->imagesubformat |= IMGSUBFMT_JPEGFAILED;
3264                             }
3265                             else
3266                                 max_offset = ftell(inptr);
3267                         }
3268                         else
3269                         {
3270                             tag = 0;
3271                             clearerr(inptr);
3272                             (void)jpeg_status(JPEG_HAD_ERROR);
3273                             if(summary_entry)
3274                                 summary_entry->imagesubformat |= IMGSUBFMT_JPEGFAILED;
3275                         }
3276                     }
3277                     break;
3278             }
3279         }
3280         POPCOLOR();
3281     }
3282     setcharsprinted(chpr);
3283     return(max_offset);
3284 }
3285 
3286 /* set and report errors in jpeg files "out of band".                 */
3287 
3288 int
jpeg_status(int setstatus)3289 jpeg_status(int setstatus)
3290 {
3291     static int status = 0;
3292     int retvalue;
3293 
3294     retvalue = status;
3295     status = setstatus;
3296     return(retvalue);
3297 }
3298 
3299 #define JPEG_HIBYTE 0xff
3300 #define EOI_LOBYTE  0xd9
3301 
3302 unsigned long
forward_scan_for_eoi(FILE * inptr,unsigned long start_of_data,unsigned long end_of_section,char * prefix,int indent)3303 forward_scan_for_eoi(FILE *inptr,unsigned long start_of_data,
3304                             unsigned long end_of_section,char *prefix,int indent)
3305 {
3306     int highbyte,lobyte;
3307     unsigned long eoi_offset = 0UL;
3308     unsigned long tagloc;
3309     int chpr = 0;
3310 
3311     if(inptr && (fseek(inptr,start_of_data,0) != -1))
3312     {
3313         if(Debug & JPEG_EOI_DEBUG)
3314             printf("DEBUG: start scan at %lu\n",start_of_data);
3315         while(((highbyte = fgetc(inptr)) != EOF) && (ftell(inptr) < end_of_section))
3316         {
3317             if(highbyte != JPEG_HIBYTE)
3318                 continue;
3319             tagloc = ftell(inptr) - 1;
3320             lobyte = fgetc(inptr);
3321             if(lobyte == EOI_LOBYTE)
3322             {
3323                 eoi_offset = tagloc;
3324                 if(Debug & JPEG_EOI_DEBUG)
3325                 {
3326                     if(!(LIST_MODE) && (PRINT_SEGMENT))
3327                     {
3328                         print_tag_address(SEGMENT,eoi_offset,indent + SMALLINDENT,prefix);
3329                         PUSHCOLOR(RED);
3330                         putindent(2);
3331                         chpr += printf("possible JPEG_EOI found at %lu",eoi_offset);
3332                     }
3333                     POPCOLOR();
3334                     chpr = newline(chpr);
3335                 }
3336                 break;
3337             }
3338         }
3339     }
3340     if(Debug & JPEG_EOI_DEBUG)
3341         printf("DEBUG: end scan at %lu\n",ftell(inptr));
3342     return(eoi_offset);
3343 }
3344 
3345 
3346 /* JFIF format files                                                  */
3347 
3348 unsigned long
process_app0(FILE * inptr,unsigned long app0_offset,unsigned short tag,struct image_summary * summary_entry,char * parent_name,int indent)3349 process_app0(FILE *inptr,unsigned long app0_offset,unsigned short tag,
3350                 struct image_summary *summary_entry,char *parent_name,
3351                 int indent)
3352 {
3353     unsigned long max_offset = 0L;
3354     unsigned long data_offset,dumplength;
3355     unsigned long filesize = 0UL;
3356     char *app_string,*name;
3357     unsigned short app_length = 0L;
3358     int status = 0;
3359     int chpr = 0;
3360     unsigned short marker,xt,yt,tmp;
3361     struct fileheader *header = NULL;
3362     char *fulldirname = CNULL;
3363     char *subdirname = CNULL;
3364 
3365     if(inptr)
3366     {
3367         filesize = get_filesize(inptr);
3368         if(summary_entry)
3369         {
3370             summary_entry->filesubformat |= FILESUBFMT_APPN;
3371             summary_entry->filesubformatAPPN[0] = 1;
3372         }
3373         name = tagname(tag);
3374         app_length = read_ushort(inptr,TIFF_MOTOROLA,app0_offset + 2);
3375         if((PRINT_SECTION))
3376             print_tag_address(SECTION,app0_offset,indent,"@");
3377         data_offset = app0_offset + 4L;
3378         app_string = read_appstring(inptr,JPEG_APP0,data_offset);
3379         app_string = app_string ? app_string : QSTRING;
3380         if(PRINT_SECTION)
3381             chpr += printf("<%s> %#x length %u, ",name,tag,app_length);
3382         else if((PRINT_ENTRY))
3383         {
3384             /* ###%%% pseudo-tags fpr LIST Mode here */
3385             print_tag_address(ENTRY,HERE,indent,"*");
3386             if((PRINT_TAGINFO))
3387             {
3388                 if((PRINT_LONGNAMES))
3389                     chpr += printf("%s.",parent_name);
3390                 chpr += printf("%-14.14s","APP0");
3391             }
3392             if((PRINT_VALUE))
3393                 chpr += printf(" = @%lu:%-9u",app0_offset,app_length);
3394             chpr = newline(chpr);
3395         }
3396 
3397         fulldirname = splice(parent_name,".","APP0");
3398         if((strncmp(app_string,"JFIF",4) == 0) && (app_string[4] == '\0'))
3399         {
3400             if(summary_entry)
3401                 summary_entry->filesubformat |= FILESUBFMT_JFIF;
3402             data_offset += 5;
3403             if((PRINT_SECTION))
3404             {
3405                 chpr += printf("\'%s\'",app_string);
3406                 chpr = newline(chpr);
3407             }
3408             tmp = read_ushort(inptr,TIFF_MOTOROLA,data_offset);
3409             if((PRINT_APPENTRY) && (PRINT_ENTRY))
3410             {
3411                 print_tag_address(APP_ENTRY,data_offset,indent,"@");
3412                 if(PRINT_SECTION)
3413                     extraindent(SMALLINDENT);
3414                 if((PRINT_TAGINFO))
3415                 {
3416                     if((PRINT_LONGNAMES))
3417                         chpr += printf("%s.",fulldirname);
3418                     chpr += printf("%-14.14s","Version");
3419                 }
3420                 if((PRINT_VALUE))
3421                     chpr += printf("= %d.%d",(int)((tmp >> 8) & 0xff),(int)(tmp & 0xff));
3422                 chpr = newline(chpr);
3423             }
3424             data_offset = ftell(inptr);
3425             tmp = read_ubyte(inptr,data_offset);
3426             if((PRINT_APPENTRY) && (PRINT_ENTRY))
3427             {
3428                 print_tag_address(APP_ENTRY,data_offset,indent,"@");
3429                 if(PRINT_SECTION)
3430                     extraindent(SMALLINDENT);
3431                 if((PRINT_TAGINFO))
3432                 {
3433                     if((PRINT_LONGNAMES))
3434                         chpr += printf("%s.",fulldirname);
3435                     chpr += printf("%-14.14s","Units");
3436                 }
3437                 if((PRINT_VALUE))
3438                     chpr += printf("= %s",tmp? tmp == 1 ? "'dots/inch'" : "'dots/cm'" : "'aspect ratio'");
3439                 chpr = newline(chpr);
3440             }
3441             data_offset = ftell(inptr);
3442             tmp = read_ushort(inptr,TIFF_MOTOROLA,data_offset);
3443             if((PRINT_APPENTRY) && (PRINT_ENTRY))
3444             {
3445                 print_tag_address(APP_ENTRY,data_offset,indent,"@");
3446                 if(PRINT_SECTION)
3447                     extraindent(SMALLINDENT);
3448                 if((PRINT_TAGINFO))
3449                 {
3450                     if((PRINT_LONGNAMES))
3451                         chpr += printf("%s.",fulldirname);
3452                     chpr += printf("%-14.14s","Xdensity");
3453                 }
3454                 if((PRINT_VALUE))
3455                     chpr += printf("= %u",tmp);
3456                 chpr = newline(chpr);
3457             }
3458             data_offset = ftell(inptr);
3459             tmp = read_ushort(inptr,TIFF_MOTOROLA,data_offset);
3460             if((PRINT_APPENTRY) && (PRINT_ENTRY))
3461             {
3462                 print_tag_address(APP_ENTRY,data_offset,indent,"@");
3463                 if(PRINT_SECTION)
3464                     extraindent(SMALLINDENT);
3465                 if((PRINT_TAGINFO))
3466                 {
3467                     if((PRINT_LONGNAMES))
3468                         chpr += printf("%s.",fulldirname);
3469                     chpr += printf("%-14.14s","Ydensity");
3470                 }
3471                 if((PRINT_VALUE))
3472                     chpr += printf("= %u",tmp);
3473                 chpr = newline(chpr);
3474             }
3475             data_offset = ftell(inptr);
3476             xt = read_ubyte(inptr,data_offset);
3477             if((PRINT_APPENTRY) && (PRINT_ENTRY))
3478             {
3479                 print_tag_address(APP_ENTRY,data_offset,indent,"@");
3480                 if(PRINT_SECTION)
3481                     extraindent(SMALLINDENT);
3482                 if((PRINT_TAGINFO))
3483                 {
3484                     if((PRINT_LONGNAMES))
3485                         chpr += printf("%s.",fulldirname);
3486                     chpr += printf("%-14.14s","XThumbnail");
3487                 }
3488                 if((PRINT_VALUE))
3489                     chpr += printf("= %d",(int)xt);
3490                 chpr = newline(chpr);
3491             }
3492             data_offset = ftell(inptr);
3493             yt = read_ubyte(inptr,data_offset);
3494             if((PRINT_APPENTRY) && (PRINT_ENTRY))
3495             {
3496                 print_tag_address(APP_ENTRY,data_offset,indent,"@");
3497                 if(PRINT_SECTION)
3498                     extraindent(SMALLINDENT);
3499                 if((PRINT_TAGINFO))
3500                 {
3501                     if((PRINT_LONGNAMES))
3502                         chpr += printf("%s.",fulldirname);
3503                     chpr += printf("%-14.14s","YThumbnail");
3504                 }
3505                 if((PRINT_VALUE))
3506                     chpr += printf("= %d",(int)yt);
3507                 chpr = newline(chpr);
3508             }
3509             if(xt && yt)
3510             {
3511                 data_offset = ftell(inptr);
3512                 print_tag_address(APP_ENTRY,data_offset,indent,"@");
3513                 if((PRINT_APPENTRY) && (PRINT_SECTION))
3514                     extraindent(SMALLINDENT);
3515                 if((PRINT_TAGINFO))
3516                 {
3517                     if(PRINT_LONGNAMES)
3518                         chpr += printf("%s.",fulldirname);
3519                     chpr += printf("%-14.14s","Thumbnail");
3520                 }
3521                 if((PRINT_VALUE))
3522                 {
3523                     chpr += printf(" = '%u RGB bytes (%u) pixels'",3 * xt * yt,xt * yt);
3524                     chpr = newline(chpr);
3525                 }
3526             }
3527             max_offset = data_offset + 1 + (3 * xt * yt);
3528         }
3529         else if((strncmp(app_string,"JFXX",4) == 0) && (app_string[4] == '\0'))
3530         {
3531             if(summary_entry)
3532                 summary_entry->filesubformat |= FILESUBFMT_JFXX;
3533             data_offset += 5;
3534             tmp = read_ubyte(inptr,data_offset);
3535             if((PRINT_SECTION))
3536             {
3537                 chpr += printf("\'%s\'",app_string);
3538                 chpr = newline(chpr);
3539                 print_tag_address(SECTION,data_offset,indent,"@");
3540                 if((PRINT_SECTION))
3541                 {
3542                     extraindent(SMALLINDENT);
3543                     chpr += printf(" extension code %#x",tmp);
3544                 }
3545             }
3546             else
3547                 chpr = newline(chpr);
3548             ++data_offset;
3549             switch(tmp)
3550             {
3551             case 0x10:  if((PRINT_SECTION))
3552                         {
3553                             chpr += printf(" - JPEG thumbnail");
3554                             chpr = newline(chpr);
3555                         }
3556                         marker = read_ushort(inptr,TIFF_MOTOROLA,HERE);
3557                         summary_entry = new_summary_entry(summary_entry,0,IMGFMT_JPEG);
3558                         if(summary_entry)
3559                         {
3560                             summary_entry->filesubformat |= FILESUBFMT_JFXX;
3561                             summary_entry->subfiletype = REDUCED_RES_TYPE;
3562                         }
3563                         if((LIST_MODE))
3564                         {
3565                             if((PRINT_SEGMENT))
3566                                 chpr = newline(chpr);
3567                             print_tag_address(ENTRY,data_offset,indent + SMALLINDENT,"@");
3568                             if((PRINT_TAGINFO))
3569                             {
3570                                 if(PRINT_LONGNAMES)
3571                                     chpr += printf("%s.JFXX.",fulldirname);
3572                                 chpr += printf("%-14.14s","JpegThumbnail");
3573                             }
3574                             if((PRINT_VALUE))
3575                             {
3576                                 max_offset = app0_offset + app_length + 2;
3577                                 chpr += printf(" = @%lu:%lu",data_offset,max_offset - data_offset);
3578                                 chpr = newline(chpr);
3579                             }
3580                         }
3581                         max_offset = process_jpeg_segments(inptr,data_offset,marker,
3582                                             app_length - 8,summary_entry,parent_name,
3583                                             "@",indent + SMALLINDENT);
3584                         if((max_offset - 1) > filesize)
3585                         {
3586                             PUSHCOLOR(RED);
3587                             chpr += printf(" (TRUNCATED at %lu)",filesize);
3588                             POPCOLOR();
3589                             summary_entry->imagesubformat |= IMGSUBFMT_TRUNCATED;
3590                         }
3591                         max_offset = app0_offset + app_length + 2;
3592                         if((PRINT_SECTION))
3593                         {
3594                             if((status = jpeg_status(0) == JPEG_EARLY_EOI))
3595                                 chpr = newline(chpr);
3596                             jpeg_status(status);
3597                             print_tag_address(SECTION,max_offset - 1,indent + SMALLINDENT,"@");
3598                             chpr += printf("#### End of JPEG thumbnail data for APP0");
3599                             chpr += printf(", length %lu ####",max_offset - data_offset);
3600                             print_jpeg_status();
3601                             chpr = newline(chpr);
3602                         }
3603                         break;
3604             case 0x11:  if((PRINT_APPENTRY) && (PRINT_SECTION))
3605                             chpr += printf(" - thumbnail stored using 1 byte/pixel");
3606                         xt = read_ubyte(inptr,data_offset++);
3607                         yt = read_ubyte(inptr,data_offset++);
3608                         /* The RGB palette is 768 bytes               */
3609                         max_offset = data_offset + 768 + (xt * yt) ;
3610                         summary_entry = new_summary_entry(summary_entry,0,IMGFMT_JPEG);
3611                         if(summary_entry)
3612                         {
3613                             summary_entry->filesubformat |= FILESUBFMT_JFXX;
3614                             summary_entry->subfiletype = REDUCED_RES_TYPE;
3615                             summary_entry->imagesubformat = IMGSUBFMT_PALETTE;
3616                             summary_entry->offset = data_offset;
3617                             summary_entry->length = xt * yt + 768;
3618                             summary_entry->pixel_width = xt;
3619                             summary_entry->pixel_height = yt;
3620                             summary_entry->compression = 1;
3621                             summary_entry->spp = 1;
3622                             summary_entry->sample_size = 8;
3623                             summary_entry->datatype = JPEG_APP0;
3624                             summary_entry->entry_lock = lock_number(summary_entry);
3625                         }
3626                         break;
3627             case 0x13:  if((PRINT_APPENTRY) && (PRINT_SECTION))
3628                             chpr += printf(" - thumbnail stored using 3 bytes/pixel");
3629                         xt = read_ubyte(inptr,data_offset++);
3630                         yt = read_ubyte(inptr,data_offset++);
3631                         max_offset = data_offset + (3 * xt * yt) ;
3632                         summary_entry = new_summary_entry(summary_entry,0,IMGFMT_JPEG);
3633                         if(summary_entry)
3634                         {
3635                             summary_entry->filesubformat |= FILESUBFMT_JFXX;
3636                             summary_entry->subfiletype = REDUCED_RES_TYPE;
3637                             summary_entry->imagesubformat = IMGSUBFMT_RGB;
3638                             summary_entry->offset = data_offset;
3639                             summary_entry->length = xt * yt * 3;
3640                             summary_entry->pixel_width = xt;
3641                             summary_entry->pixel_height = yt;
3642                             summary_entry->compression = 1;
3643                             summary_entry->spp = 3;
3644                             summary_entry->sample_size = 8;
3645                             summary_entry->datatype = JPEG_APP0;
3646                             summary_entry->entry_lock = lock_number(summary_entry);
3647                         }
3648                         break;
3649             default:
3650                         if((PRINT_APPENTRY) && (PRINT_SECTION))
3651                             chpr += printf(" - UNKNOWN JFXX extension");
3652                         max_offset = data_offset;
3653                         break;
3654             }
3655             chpr = newline(chpr);
3656         }
3657         else if(((strncmp(app_string,"II",2) == 0) || (strncmp(app_string,"MM",2) == 0)) &&
3658                     (app_string[2] == 0x1a))    /* maybe CIFF     */
3659         {
3660             if((header = read_imageheader(inptr,data_offset)))
3661             {
3662                 if(summary_entry)
3663                     summary_entry->filesubformat |= FILESUBFMT_CIFF;
3664                 if((PRINT_APPENTRY) && (PRINT_SECTION))
3665                     chpr = newline(chpr);
3666                 if((PRINT_SECTION))
3667                 {
3668                     print_tag_address(SECTION,data_offset,indent+SMALLINDENT,"@");
3669                     print_header(header,SECTION);
3670                 }
3671                 if(header->probe_magic == PROBE_CIFFMAGIC)
3672                 {
3673                     subdirname = splice(fulldirname,".","CIFF");
3674                     if(!(PRINT_SECTION))
3675                     {
3676                         print_tag_address(ENTRY|VALUE,data_offset,indent+SMALLINDENT,"@");
3677                         if((PRINT_TAGINFO))
3678                         {
3679                             if((PRINT_LONGNAMES))
3680                                 chpr += printf("%s.",subdirname);
3681                             chpr += printf("%-*.*s",CIFFTAGWIDTH,CIFFTAGWIDTH,"HeaderOffset");
3682                         }
3683                         if((PRINT_VALUE))
3684                         {
3685                             if(PRINT_BOTH_OFFSET)
3686                                 chpr += printf(" = @%#lx=%lu",data_offset,data_offset);
3687                             else if(PRINT_HEX_OFFSET)
3688                                 chpr += printf(" = @%#lx",data_offset);
3689                             else
3690                                 chpr += printf(" = @%lu",data_offset);
3691                         }
3692                         chpr = newline(chpr);
3693                     }
3694                     max_offset = process_ciff(inptr,header,data_offset,app_length - 2,
3695                                         summary_entry,subdirname,0,indent+SMALLINDENT);
3696                     if(subdirname)
3697                         free(subdirname);
3698                     subdirname = CNULL;
3699                 }
3700                 else
3701                     goto appdump;
3702             }
3703             else
3704                 goto appdump;
3705         }
3706         else
3707             goto appdump;
3708 
3709         if(fulldirname)
3710             free(fulldirname);
3711     /* If there's data unaccounted for, allow the data that isn't */
3712         /* accounted for to be dumped                                 */
3713         if(max_offset < (app0_offset + app_length + 2))
3714         {
3715             print_tag_address(SEGMENT,max_offset,indent,"@");
3716             extraindent(SMALLINDENT);
3717             dumplength = app0_offset + app_length + 1 - max_offset;
3718             chpr += printf("---- End of data before end of APP0 (%lu bytes)",dumplength);
3719             chpr = newline(chpr);
3720             /* dump at least the first couple of rows, just to see... */
3721             if(PRINT_APPNDUMP)
3722             {
3723                 if((Max_appdump == DUMPALL) || (Max_appdump > (app_length + 2)))
3724                     dumplength = app_length - 2;
3725                 else if(Max_appdump > 0L)
3726                     dumplength = Max_appdump;
3727                 else if(Max_undefined > 0L)
3728                     dumplength = Max_undefined;
3729                 else
3730                     dumplength = app_length - 2;
3731             }
3732             else
3733                 dumplength = dumplength > 48 ? 48 : dumplength;
3734             if(dumplength)
3735             {
3736                 hexdump(inptr,app0_offset + 4,app_length - 2,dumplength,16,
3737                             indent + SMALLINDENT,SMALLINDENT);
3738                 chpr = newline(1);
3739             }
3740         }
3741         /* ###%%% if max_offset >, warn */
3742 
3743         /* close off the section.                                     */
3744         if((PRINT_SECTION))
3745         {
3746             print_tag_address(SECTION,app0_offset + app_length + 1,indent,"@");
3747             chpr += printf("</%s>",name);
3748             chpr = newline(chpr);
3749         }
3750     }
3751 
3752     return(app0_offset + app_length + 2);
3753 appdump:
3754     /* Something went haywire...dump starting at the marker           */
3755     /* At the moment, this happens only for imaginative APP0 markers  */
3756     if(app_length > 0L)
3757     {
3758         if(PRINT_APPNDUMP)
3759         {
3760             if((Max_appdump == DUMPALL) || (Max_appdump > (app_length + 2)))
3761                 dumplength = app_length + 2;
3762             else if(Max_appdump > 0L)
3763                 dumplength = Max_appdump;
3764             else
3765                 dumplength = Max_undefined;
3766             if(dumplength)
3767             {
3768                 chpr = newline(1);
3769                 hexdump(inptr,app0_offset,app_length + 2,dumplength,16,
3770                             indent + SMALLINDENT,SMALLINDENT);
3771                 chpr = newline(1);
3772             }
3773         }
3774         else
3775         {
3776             if(PRINT_SECTION)
3777             {
3778                 chpr += printf(" - (not dumped: use -A)");
3779                 chpr = newline(chpr);
3780             }
3781         }
3782         max_offset = app0_offset + app_length + 2;
3783         /* close off the segment; a start "tag" was printed           */
3784         if(PRINT_SECTION)
3785         {
3786             print_tag_address(SECTION,app0_offset + app_length + 1,indent,"@");
3787             chpr += printf("</%s>",name);
3788             chpr = newline(chpr);
3789         }
3790     }
3791     setcharsprinted(chpr);
3792     return(max_offset);
3793 }
3794 
3795 /* Process (print) an APP1 (EXIF) section                             */
3796 
3797 unsigned long
process_app1(FILE * inptr,unsigned long app1_offset,unsigned short tag,struct image_summary * summary_entry,char * parent_name,int indent)3798 process_app1(FILE *inptr,unsigned long app1_offset,unsigned short tag,
3799                 struct image_summary *summary_entry,char *parent_name,
3800                 int indent)
3801 {
3802     unsigned long max_offset = 0UL;
3803     unsigned long ifd_offset,fileoffset_base;
3804     unsigned long dumplength = 0UL;
3805     unsigned short app_length = 0;
3806     int chpr = 0;
3807     struct fileheader *header;
3808     char *app_string,*name;
3809     char *fulldirname = CNULL;
3810 
3811     if(inptr)
3812     {
3813         if(summary_entry)
3814         {
3815             summary_entry->filesubformat |= FILESUBFMT_APPN;
3816             summary_entry->filesubformatAPPN[1] = 1;
3817         }
3818         /* display the APP1 header                                    */
3819         name = tagname(tag);    /* never null                         */
3820         if(PRINT_SECTION)
3821         {
3822             print_tag_address(SECTION,app1_offset,indent,"@");
3823             chpr += printf("<%s> %#x ",name,tag);
3824         }
3825 
3826         app_length = read_ushort(inptr,TIFF_MOTOROLA,HERE);
3827         if(ferror(inptr) || feof(inptr))
3828         {
3829             clearerr(inptr);
3830             goto appdump;
3831         }
3832         if(PRINT_SECTION)
3833             chpr += printf("length %u, ",app_length);
3834         else if((PRINT_ENTRY))
3835         {
3836             /* ###%%% pseudo-tags fpr LIST Mode here */
3837             print_tag_address(ENTRY,HERE,indent,"*");
3838             if((PRINT_TAGINFO))
3839             {
3840                 if((PRINT_LONGNAMES))
3841                     chpr += printf("%s.",parent_name);
3842                 chpr += printf("%-14.14s","APP1");
3843             }
3844             if((PRINT_VALUE))
3845                 chpr += printf(" = @%lu:%-9u",app1_offset,app_length);
3846             chpr = newline(chpr);
3847         }
3848 
3849         app_string = read_appstring(inptr,JPEG_APP1,HERE);
3850         if(ferror(inptr) || feof(inptr))
3851         {
3852             clearerr(inptr);
3853             goto appdump;
3854         }
3855 
3856         if(app_string)
3857         {
3858             if(PRINT_SECTION)
3859                 chpr += printf("\'%s\'",app_string);
3860 
3861             /* The next thing we see should be a TIFF header tag      */
3862             /* indicating byte order used in the IFD, followed by the */
3863             /* offset from the start of the header to the start of    */
3864             /* the IFD (number of entries).                           */
3865 
3866             fileoffset_base = ftell(inptr);
3867             /* If this is a valid Exif segment, skip the pad byte.    */
3868             if(strncmp(app_string,"Exif",4) == 0)
3869             {
3870                 fulldirname = splice(parent_name,".","APP1");
3871                 ++fileoffset_base;
3872                 if(PRINT_SECTION)
3873                 {
3874                     chpr = newline(chpr);
3875                     print_tag_address(SECTION,fileoffset_base,indent + SMALLINDENT,"@");
3876                 }
3877                 header = read_imageheader(inptr,fileoffset_base);
3878                 if(header && (print_header(header,SECTION) == 0) &&
3879                     (header->probe_magic == TIFF_MAGIC))
3880                 {
3881                     ifd_offset = read_ulong(inptr,header->file_marker,HERE);
3882                     if(PRINT_SECTION)
3883                     {
3884                         chpr += printf(" ifd offset = %lu (+ %lu = %#lx/%lu)",ifd_offset,
3885                                     fileoffset_base,fileoffset_base + ifd_offset,
3886                                     fileoffset_base + ifd_offset);
3887                         chpr = newline(chpr);
3888                     }
3889                     /* ###%%% maybe should unlock the summary entry,  */
3890                     /* so that the tiff processor will use it? not    */
3891                     /* sure if that's appropriate for APP1 found in   */
3892                     /* jpeg sub-images.                               */
3893                     max_offset = process_tiff_ifd(inptr,header->file_marker,ifd_offset,
3894                                             fileoffset_base,0L,summary_entry,fulldirname,
3895                                             TIFF_IFD,0,-1,indent + SMALLINDENT);
3896 
3897                     if(max_offset < app1_offset + app_length + 2)
3898                         max_offset = app1_offset + app_length +2;
3899                 }
3900                 else
3901                 {
3902                     max_offset = app1_offset + app_length + 2;
3903                     if(PRINT_SECTION)
3904                     {
3905                         extraindent(indent + ADDRWIDTH);
3906                         chpr += printf(" INVALID MAGIC %lu (%s) where TIFF header should be",
3907                                 header->probe_magic,tagname(header->probe_magic));
3908 #define PRINT_A_BIT 48
3909                         if(app_length > PRINT_A_BIT)
3910                             dumplength = PRINT_A_BIT;
3911                         else
3912                             dumplength = app_length;
3913                         goto appdump;
3914                     }
3915                 }
3916                 if(fulldirname)
3917                     free(fulldirname);
3918             }
3919             else
3920             {
3921                 max_offset = app1_offset + app_length + 2;
3922                 if(PRINT_SECTION)
3923                 {
3924                     chpr += printf(" - unknown format");
3925                     goto appdump;
3926                 }
3927             }
3928         }
3929         else if(PRINT_SECTION)
3930         {
3931             chpr += printf("  No APP1 header name string found");
3932             chpr = newline(chpr);
3933         }
3934         /* offset of last byte of segment                             */
3935         if(PRINT_SECTION)
3936         {
3937             print_tag_address(SECTION,max_offset - 1,indent,"-");
3938             chpr += printf("</%s>",name);
3939             chpr = newline(chpr);
3940         }
3941     }
3942     return(max_offset);
3943 
3944 appdump:
3945     if(app_length > 0L)
3946     {
3947         if((PRINT_APPNDUMP) || (dumplength > 0))
3948         {
3949             if((Max_appdump == DUMPALL) || (Max_appdump > (app_length + 2)))
3950                 dumplength = app_length + 2;
3951             else if(Max_appdump > 0L)
3952                 dumplength = Max_appdump;
3953             else if(dumplength == 0)
3954                 dumplength = Max_undefined;
3955             if(dumplength)
3956             {
3957                 chpr = newline(1);
3958                 hexdump(inptr,app1_offset,app_length + 2,dumplength,16,
3959                             indent + SMALLINDENT,SMALLINDENT);
3960                 chpr = newline(1);
3961             }
3962         }
3963         else
3964         {
3965             if(PRINT_SEGMENT)
3966             {
3967                 chpr += printf(" - (not dumped: use -A)");
3968                 chpr = newline(chpr);
3969             }
3970         }
3971         max_offset = app1_offset + app_length + 2;
3972         /* close off the segment; a start "tag" was printed           */
3973         print_tag_address(SECTION,app1_offset + app_length + 1,indent,"-");
3974         if(PRINT_SECTION)
3975         {
3976             chpr += printf("</%s>",name);
3977             chpr = newline(chpr);
3978         }
3979     }
3980     setcharsprinted(chpr);
3981     return(max_offset);
3982 }
3983 
3984 /* Process (print) an APP3 (Meta) section                             */
3985 
3986 unsigned long
process_app3(FILE * inptr,unsigned long app3_offset,unsigned short tag,struct image_summary * summary_entry,char * parent_name,int indent)3987 process_app3(FILE *inptr,unsigned long app3_offset,unsigned short tag,
3988                 struct image_summary *summary_entry,char *parent_name,
3989                 int indent)
3990 {
3991     unsigned long max_offset = 0UL;
3992     unsigned long ifd_offset,fileoffset_base;
3993     unsigned long dumplength = 0UL;
3994     unsigned short app_length = 0;
3995     int chpr = 0;
3996     struct fileheader *header;
3997     char *app_string,*name;
3998     char *fulldirname = CNULL;
3999 
4000     if(inptr)
4001     {
4002         if(summary_entry)
4003         {
4004             summary_entry->filesubformat |= FILESUBFMT_APPN;
4005             summary_entry->filesubformatAPPN[3] = 1;
4006         }
4007         /* display the APP3 header                                    */
4008         name = tagname(tag);    /* never null                         */
4009         if(PRINT_SECTION)
4010         {
4011             print_tag_address(SECTION,app3_offset,indent,"@");
4012             chpr += printf("<%s> %#x ",name,tag);
4013         }
4014 
4015         app_length = read_ushort(inptr,TIFF_MOTOROLA,HERE);
4016         if(ferror(inptr) || feof(inptr))
4017         {
4018             clearerr(inptr);
4019             goto appdump;
4020         }
4021         if(PRINT_SECTION)
4022             chpr += printf("length %u, ",app_length);
4023         else if((PRINT_ENTRY))
4024         {
4025             /* ###%%% pseudo-tags fpr LIST Mode here */
4026             print_tag_address(ENTRY,HERE,indent,"*");
4027             if((PRINT_TAGINFO))
4028             {
4029                 if((PRINT_LONGNAMES))
4030                     chpr += printf("%s.",parent_name);
4031                 chpr += printf("%-14.14s","APP3");
4032             }
4033             if((PRINT_VALUE))
4034                 chpr += printf(" = @%lu:%-9u",app3_offset,app_length);
4035             chpr = newline(chpr);
4036         }
4037 
4038         app_string = read_appstring(inptr,JPEG_APP3,HERE);
4039         if(ferror(inptr) || feof(inptr))
4040         {
4041             clearerr(inptr);
4042             goto appdump;
4043         }
4044 
4045         if(app_string)
4046         {
4047             if(PRINT_SECTION)
4048                 chpr += printf("\'%s\'",app_string);
4049 
4050             /* The next thing we see should be a TIFF header tag      */
4051             /* indicating byte order used in the IFD, followed by the */
4052             /* offset from the start of the header to the start of    */
4053             /* the IFD (number of entries).                           */
4054 
4055             fileoffset_base = ftell(inptr);
4056             /* If this is a valid Meta segment, skip the pad byte.    */
4057             if(strncmp(app_string,"Meta",4) == 0)
4058             {
4059                 fulldirname = splice(parent_name,".","APP3");
4060                 ++fileoffset_base;
4061                 if(PRINT_SECTION)
4062                 {
4063                     chpr = newline(chpr);
4064                     print_tag_address(SECTION,fileoffset_base,indent + SMALLINDENT,"@");
4065                 }
4066                 header = read_imageheader(inptr,fileoffset_base);
4067                 if(header && (print_header(header,SECTION) == 0) &&
4068                     (header->probe_magic == TIFF_MAGIC))
4069                 {
4070                     ifd_offset = read_ulong(inptr,header->file_marker,HERE);
4071                     if(PRINT_SECTION)
4072                     {
4073                         chpr += printf(" ifd offset = %lu (+ %lu = %#lx/%lu)",ifd_offset,
4074                                     fileoffset_base,fileoffset_base + ifd_offset,
4075                                     fileoffset_base + ifd_offset);
4076                         chpr = newline(chpr);
4077                     }
4078                     max_offset = process_tiff_ifd(inptr,header->file_marker,ifd_offset,
4079                                             fileoffset_base,0L,summary_entry,fulldirname,
4080                                             TIFF_IFD,0,-1,indent + SMALLINDENT);
4081 
4082                     if(max_offset < app3_offset + app_length + 2)
4083                         max_offset = app3_offset + app_length +2;
4084                 }
4085                 else
4086                 {
4087                     max_offset = app3_offset + app_length + 2;
4088                     if(PRINT_SECTION)
4089                     {
4090                         extraindent(indent + ADDRWIDTH);
4091                         chpr += printf(" INVALID MAGIC %lu (%s) where TIFF header should be",
4092                                 header->probe_magic,tagname(header->probe_magic));
4093 #define PRINT_A_BIT 48
4094                         if(app_length > PRINT_A_BIT)
4095                             dumplength = PRINT_A_BIT;
4096                         else
4097                             dumplength = app_length;
4098                         goto appdump;
4099                     }
4100                 }
4101                 if(fulldirname)
4102                     free(fulldirname);
4103             }
4104             else
4105             {
4106                 max_offset = app3_offset + app_length + 2;
4107                 if(PRINT_SECTION)
4108                 {
4109                     chpr += printf(" - unknown format");
4110                     goto appdump;
4111                 }
4112             }
4113         }
4114         else if(PRINT_SECTION)
4115         {
4116             chpr += printf("  No APP3 header name string found");
4117             chpr = newline(chpr);
4118         }
4119         /* offset of last byte of segment                             */
4120         if(PRINT_SECTION)
4121         {
4122             print_tag_address(SECTION,max_offset - 1,indent,"-");
4123             chpr += printf("</%s>",name);
4124             chpr = newline(chpr);
4125         }
4126     }
4127     return(max_offset);
4128 
4129 appdump:
4130     if(app_length > 0L)
4131     {
4132         if((PRINT_APPNDUMP) || (dumplength > 0))
4133         {
4134             if((Max_appdump == DUMPALL) || (Max_appdump > (app_length + 2)))
4135                 dumplength = app_length + 2;
4136             else if(Max_appdump > 0L)
4137                 dumplength = Max_appdump;
4138             else if(dumplength == 0)
4139                 dumplength = Max_undefined;
4140             if(dumplength)
4141             {
4142                 chpr = newline(1);
4143                 hexdump(inptr,app3_offset,app_length + 2,dumplength,16,
4144                             indent + SMALLINDENT,SMALLINDENT);
4145                 chpr = newline(1);
4146             }
4147         }
4148         else
4149         {
4150             if(PRINT_SEGMENT)
4151             {
4152                 chpr += printf(" - (not dumped: use -A)");
4153                 chpr = newline(chpr);
4154             }
4155         }
4156         max_offset = app3_offset + app_length + 2;
4157         /* close off the segment; a start "tag" was printed           */
4158         print_tag_address(SECTION,app3_offset + app_length + 1,indent,"-");
4159         if(PRINT_SECTION)
4160         {
4161             chpr += printf("</%s>",name);
4162             chpr = newline(chpr);
4163         }
4164     }
4165     setcharsprinted(chpr);
4166     return(max_offset);
4167 }
4168 #undef PRINT_A_BIT
4169 
4170 
4171 /* Unknown APPn markers; hex dump them and move on.                   */
4172 
4173 unsigned long
process_appn(FILE * inptr,unsigned long appn_offset,unsigned short tag,struct image_summary * summary_entry,char * parent_name,int indent)4174 process_appn(FILE *inptr,unsigned long appn_offset,unsigned short tag,
4175                 struct image_summary *summary_entry,char *parent_name,
4176                 int indent)
4177 {
4178     char *app_string,*name;
4179     unsigned short app_length = 0;
4180     unsigned long dumplength = 0L;
4181     int chpr = 0;
4182     int tagwidth = 13;
4183 
4184     if(inptr)
4185     {
4186         if(summary_entry)
4187         {
4188             summary_entry->filesubformat |= FILESUBFMT_APPN;
4189             summary_entry->filesubformatAPPN[tag & 0xf] = 1;
4190         }
4191         name = tagname(tag);    /* never null                         */
4192         app_length = read_ushort(inptr,TIFF_MOTOROLA,appn_offset + 2);
4193         print_tag_address(SECTION,appn_offset,indent,"@");
4194         if(PRINT_SECTION)
4195             chpr += printf("<%s> %#x length %u, ",name,tag,app_length);
4196         app_string = read_appstring(inptr,tag,HERE);
4197         if(PRINT_SECTION)
4198             chpr += printf("%s",app_string ? app_string : "NULL ID");
4199         else if((PRINT_ENTRY))
4200         {
4201             /* ###%%% pseudo-tags fpr LIST Mode here */
4202             print_tag_address(ENTRY,HERE,indent,"*");
4203             if((PRINT_TAGINFO))
4204             {
4205                 if((PRINT_LONGNAMES))
4206                     chpr += printf("%s.",parent_name);
4207                 tagwidth = 13;
4208                 if((tag & 0xf) > 9)
4209                     --tagwidth;
4210                 chpr += printf("%-*.*s%d",tagwidth,tagwidth,"APP",tag & 0xf);
4211             }
4212             if((PRINT_VALUE))
4213                 chpr += printf(" = @%lu:%-9u",appn_offset,app_length);
4214             chpr = newline(chpr);
4215         }
4216 
4217         if(PRINT_APPNDUMP)
4218         {
4219             if((Max_appdump == DUMPALL) || (Max_appdump > (app_length + 2)))
4220                 dumplength = app_length + 2;
4221             else if(Max_appdump > 0L)
4222                 dumplength = Max_appdump;
4223             else
4224                 dumplength = Max_undefined;
4225             if(dumplength)
4226             {
4227                 chpr = newline(1);
4228                 hexdump(inptr,appn_offset,app_length + 2,dumplength,16,
4229                             indent,SMALLINDENT);
4230                 chpr = newline(1);
4231             }
4232         }
4233         else if(PRINT_SECTION)
4234         {
4235             chpr += printf(" - unknown format (not dumped: use -A)");
4236             chpr = newline(chpr);
4237         }
4238 
4239         print_tag_address(SECTION,appn_offset + app_length + 1,indent,"-");
4240         if(PRINT_SECTION)
4241         {
4242             chpr += printf("</%s>",name);
4243             chpr = newline(chpr);
4244         }
4245         fseek(inptr,appn_offset + app_length,0);
4246     }
4247     setcharsprinted(chpr);
4248     return(appn_offset + app_length + 2);
4249 }
4250 
4251 /* Print the string data from an APP12 segment, if hexdump hasn't     */
4252 /* been asked. The "[fileinfo]" stuff is unknown format, but this     */
4253 /* part should be useful.                                             */
4254 
4255 unsigned long
process_app12(FILE * inptr,unsigned long app12_offset,unsigned short tag,struct image_summary * summary_entry,char * parent_name,int indent)4256 process_app12(FILE *inptr,unsigned long app12_offset,unsigned short tag,
4257                 struct image_summary *summary_entry,char *parent_name,
4258                 int indent)
4259 {
4260     char *app_string,*name;
4261     unsigned short app_length = 0;
4262     unsigned long dumplength = 0UL;
4263     unsigned long offset = 0UL;
4264     unsigned long end_offset = 0UL;
4265     unsigned long size = 0UL;
4266     int chpr = 0;
4267     int nextch;
4268 
4269     if(inptr)
4270     {
4271         if(summary_entry)
4272         {
4273             summary_entry->filesubformat |= FILESUBFMT_APPN;
4274             summary_entry->filesubformatAPPN[12] = 1;
4275         }
4276         name = tagname(tag);    /* never null                         */
4277         app_length = read_ushort(inptr,TIFF_MOTOROLA,app12_offset + 2);
4278         print_tag_address(SECTION,app12_offset,indent,"@");
4279         if(PRINT_SECTION)
4280             chpr += printf("<%s> %#x length %u, ",name,tag,app_length);
4281         else if((PRINT_ENTRY))
4282         {
4283             /* ###%%% pseudo-tags fpr LIST Mode here */
4284             print_tag_address(ENTRY,HERE,indent,"*");
4285             if((PRINT_TAGINFO))
4286             {
4287                 if((PRINT_LONGNAMES))
4288                     chpr += printf("%s.",parent_name);
4289                 chpr += printf("%-14.14s","APP12");
4290             }
4291             if((PRINT_VALUE))
4292                 chpr += printf(" = @%lu:%-9u",app12_offset,app_length);
4293             chpr = newline(chpr);
4294         }
4295         app_string = read_appstring(inptr,tag,HERE);
4296         if(PRINT_SECTION)
4297             chpr += printf("\'%s\'",app_string ? app_string : "NULL ID");
4298 
4299         if(PRINT_APPNDUMP)
4300         {
4301             if((Max_appdump == DUMPALL) || (Max_appdump > (app_length + 2)))
4302                 dumplength = app_length + 2;
4303             else if(Max_appdump > 0L)
4304                 dumplength = Max_appdump;
4305             else
4306                 dumplength = Max_undefined;
4307             if(dumplength)
4308             {
4309                 if(PRINT_SECTION)
4310                     chpr = newline(chpr);
4311                 hexdump(inptr,app12_offset,app_length + 2,dumplength,16,
4312                             indent + SMALLINDENT,SMALLINDENT);
4313                 chpr = newline(1);
4314             }
4315         }
4316         else if((PRINT_APPENTRY) && (PRINT_ENTRY))
4317         {
4318             /* ###%%% in LIST mode, these should get an "APP12." prefix */
4319             end_offset = app12_offset + app_length + 1;
4320             offset = ftell(inptr);
4321             nextch = skip_past_newline(inptr,end_offset);
4322             offset = ftell(inptr);
4323             if(PRINT_SECTION)
4324                 chpr = newline(chpr);
4325             if(offset < end_offset);
4326                 nextch = putword(inptr,nextch,end_offset,indent);
4327             chpr = newline(chpr);
4328             offset = ftell(inptr);
4329             while(nextch && (offset < end_offset))
4330             {
4331                 nextch = putword(inptr,nextch,end_offset,indent);
4332                 if(nextch)
4333                     chpr = newline(chpr);
4334                 offset = ftell(inptr);
4335             }
4336             while(offset < end_offset)
4337             {
4338                 nextch = skip_to_bracket(inptr,end_offset);
4339                 size = ftell(inptr) - offset;
4340                 if(nextch == '[')
4341                     --size;
4342                 if(size > 1)
4343                 {
4344                     chpr += printf(" length %lu",size);
4345                     if(Max_undefined)
4346                     {
4347                         chpr = newline(chpr);
4348                         hexdump(inptr,offset,size, Max_undefined,16,
4349                                     indent + SMALLINDENT,
4350                                     SMALLINDENT);
4351                         chpr = newline(1);
4352                         nextch = fgetc(inptr);
4353                         if(ftell(inptr) >= end_offset)
4354                             break;
4355                     }
4356                     else
4357                     {
4358                         printred(" (not dumped; use -U)");
4359                         chpr = newline(chpr);
4360                     }
4361                 }
4362                 else
4363                     chpr = newline(chpr);
4364                 if(nextch)
4365                     nextch = putword(inptr,nextch,end_offset,indent);
4366                 offset = ftell(inptr);
4367             }
4368         }
4369 
4370         print_tag_address(SECTION,app12_offset + app_length + 1,indent,"-");
4371         if(PRINT_SECTION)
4372         {
4373             chpr += printf("</%s>",name);
4374             chpr = newline(chpr);
4375         }
4376     }
4377     setcharsprinted(chpr);
4378     return(app12_offset + app_length + 2);
4379 }
4380 
4381 /* Read and discard until the next newline in the input stream, or    */
4382 /* until 'max_offset' is reached. Return the last character read.     */
4383 
4384 int
skip_past_newline(FILE * inptr,unsigned long max_offset)4385 skip_past_newline(FILE *inptr,unsigned long max_offset)
4386 {
4387     while(((unsigned long)ftell(inptr) < max_offset) && (fgetc(inptr) != '\n'))
4388         continue;
4389     return(fgetc(inptr));
4390 }
4391 
4392 /* Read and discard until the next '[' in the input stream, or until  */
4393 /* 'max_offset' is reached. Return the last character read.           */
4394 
4395 int
skip_to_bracket(FILE * inptr,unsigned long max_offset)4396 skip_to_bracket(FILE *inptr,unsigned long max_offset)
4397 {
4398     int ch = EOF;
4399 
4400     while(((unsigned long)ftell(inptr) < max_offset) && ((ch = fgetc(inptr)) != '['))
4401         continue;
4402     if(ftell(inptr) >= max_offset)
4403         ch = 0;
4404     return(ch);
4405 }
4406 
4407 /* Print a word from an APP12 segment. The first character of the     */
4408 /* word is passed in by the caller; if it's a left square bracket, it */
4409 /* is assumed to start a "section" and is indented a little less.     */
4410 /* This can print a lone open-bracket, but what the heck.             */
4411 
4412 /* CRs are stripped out and nulls end a word. Newlines are stripped   */
4413 /* as well, but cause the next character to be read and passed back   */
4414 /* to the caller, to be used as the start of a new word. Otherwise    */
4415 /* the last character read is returned.                               */
4416 
4417 /* The routine is not allowed to read past 'max_offset', which should */
4418 /* be the end of the segment.                                         */
4419 
4420 int
putword(FILE * inptr,int firstch,unsigned long max_offset,int indent)4421 putword(FILE *inptr,int firstch,unsigned long max_offset,int indent)
4422 {
4423     int eol = 0;
4424     int chpr = 0;
4425     int ch = firstch;
4426 
4427     if(firstch)
4428         print_tag_address(APP_ENTRY,ftell(inptr),indent + SMALLINDENT,"@");
4429     if(firstch)
4430     {
4431         if(firstch != '[')
4432             extraindent(SMALLINDENT);
4433         putchar(firstch);
4434         ++chpr;
4435     }
4436     else
4437         ++eol;
4438     while(((unsigned long)ftell(inptr) < max_offset) && !eol)
4439     {
4440         ch = fgetc(inptr);
4441         switch(ch)
4442         {
4443         case '\r':
4444             break;
4445         case 0:
4446             ++eol;
4447             break;
4448         case '\n':
4449             ++eol;
4450             ch = fgetc(inptr);
4451             break;
4452         case EOF:
4453             ++eol;
4454             break;
4455         default:
4456             if(isprint(ch))
4457                 putchar(ch);
4458             ++chpr;
4459             break;
4460         }
4461     }
4462     setcharsprinted(chpr);
4463     return(ch);
4464 }
4465 
4466 
4467 
4468 /* Determine if the values for an IFD entry are recorded at an        */
4469 /* offset. Returns 0 if the value is recorded directly in the entry,  */
4470 /* 1 if the value is offset.                                          */
4471 
4472 int
is_offset(struct ifd_entry * entry_ptr)4473 is_offset(struct ifd_entry *entry_ptr)
4474 {
4475     if((value_type_size(entry_ptr->value_type) * entry_ptr->count) > 4)
4476         return(1);
4477     return(0);
4478 }
4479 
4480 /* Process an Epson Print Image Matching section, included in many    */
4481 /* cameras for the purpose of adjusting image parameters when         */
4482 /* printing the image, according to values pre-determined by the      */
4483 /* device manufacturer. According to Epson, parametes which may be    */
4484 /* adjusted include:                                                  */
4485 
4486 /* Gamma Level                                                        */
4487 /* Color Space                                                        */
4488 /* Color Balance                                                      */
4489 /* Contrast                                                           */
4490 /* Brightness                                                         */
4491 /* Sharpness                                                          */
4492 /* Saturation                                                         */
4493 /* Shadow                                                             */
4494 /* Highlight                                                          */
4495 
4496 /* Pim version 2 also handles:                                        */
4497 
4498 /* Noise Reduction                                                    */
4499 /* Custom Scene setting                                               */
4500 
4501 /* This routine knows just enough about the structure of PIM to print */
4502 /* tag numbers and values, but interpretation of tags is not known.   */
4503 /* Values are printed in decimal and hex.                             */
4504 
4505 unsigned long
process_pim(FILE * inptr,unsigned short byteorder,unsigned long pim_offset,unsigned long fileoffset_base,unsigned long count,char * tagname,char * dirname,char * prefix,int indent)4506 process_pim(FILE *inptr,unsigned short byteorder,unsigned long pim_offset,
4507                     unsigned long fileoffset_base, unsigned long count,
4508                     char *tagname,char *dirname,char *prefix,
4509                     int indent)
4510 {
4511     unsigned long entry_offset,extra,value;
4512     unsigned long max_offset = 0L;
4513     unsigned long max_value_offset = 0L;
4514     unsigned char *pim_id,*pim_version,*valueptr;
4515     unsigned short tag;
4516     int tagwidth = PIMTAGWIDTH;
4517     int chpr = 0;
4518     int entry_num,num_entries;
4519 
4520     if(inptr == (FILE *)0)
4521     {
4522         fprintf(stderr,"%s: no open file pointer to read Print Image data\n",
4523                 Progname);
4524         max_offset = 0L;
4525         return(0L);
4526     }
4527 
4528     entry_offset = pim_offset + fileoffset_base;
4529     max_offset = entry_offset + count;
4530 
4531     /* Always starts with "PrintIM\0"; read it as a sanity check      */
4532     pim_id = read_bytes(inptr,8,entry_offset);
4533     if((pim_id == (unsigned char *)0) || strncasecmp((char *)pim_id,"PrintIM",8) != 0)
4534     {
4535         /* Print the value as a comment here, since we are processing */
4536         /* no further.                                                */
4537         if(PRINT_SECTION)
4538         {
4539             print_tag_address(SECTION,entry_offset,indent,prefix);
4540             chpr += printf("%s",tagname);
4541             if((PRINT_VALUE))
4542                 chpr += printf(": length %lu",count);
4543         }
4544         if(!(PRINT_SECTION))
4545         {
4546             chpr = newline(chpr);
4547             printred("# WARNING:");
4548         }
4549         printred(" INVALID PrintImage data...");
4550         return(0L);
4551     }
4552     chpr = newline(0);
4553 
4554     pim_version = read_bytes(inptr,6,HERE);
4555     num_entries = read_ushort(inptr,byteorder,HERE);
4556 
4557     if(PRINT_SECTION)
4558     {
4559         print_tag_address(SECTION,entry_offset,indent,prefix);
4560         chpr += printf("<%s> Version %s, size %lu, %d entries",tagname,pim_version,
4561                                                                 count,num_entries);
4562         if((num_entries * 6) > (count - 16))
4563         {
4564             chpr = newline(chpr);
4565             num_entries = (count - 16) / 6;
4566             PUSHCOLOR(HI_RED);
4567             chpr += printf("# WARNING: PIM claims too many entries for section size, printing %d",num_entries);
4568             POPCOLOR();
4569         }
4570     }
4571     else
4572     {
4573 
4574         /* Make pseudo-tags for these                                 */
4575         if((PRINT_TAGINFO) || (PRINT_VALUE))
4576             print_tag_address(ENTRY,HERE,indent+SMALLINDENT,"*");
4577         if(PRINT_TAGINFO)
4578         {
4579             if((PRINT_LONGNAMES))
4580                 chpr += printf("%s.",dirname);
4581             chpr += printf("%s.",tagname);
4582             chpr += printf("%-*.*s",tagwidth,tagwidth,"Offset");
4583         }
4584         if((PRINT_VALUE))
4585             chpr += printf(" = @%lu",entry_offset);
4586         chpr = newline(chpr);
4587         if((PRINT_TAGINFO) || (PRINT_VALUE))
4588             print_tag_address(ENTRY,HERE,indent+SMALLINDENT,"*");
4589         if(PRINT_TAGINFO)
4590         {
4591             if((PRINT_LONGNAMES))
4592                 chpr += printf("%s.",dirname);
4593             chpr += printf("%s.",tagname);
4594             chpr += printf("%-*.*s",tagwidth,tagwidth,"Length");
4595         }
4596         if((PRINT_VALUE))
4597             chpr += printf(" = %lu",count);
4598         chpr = newline(chpr);
4599         if((PRINT_TAGINFO) || (PRINT_VALUE))
4600             print_tag_address(ENTRY,HERE,indent+SMALLINDENT,"*");
4601         if(PRINT_TAGINFO)
4602         {
4603             if((PRINT_LONGNAMES))
4604                 chpr += printf("%s.",dirname);
4605             chpr += printf("%s.",tagname);
4606             chpr += printf("%-*.*s",tagwidth,tagwidth,"Version");
4607         }
4608         if((PRINT_VALUE))
4609             chpr += printf(" = %s",pim_version);
4610         chpr = newline(chpr);
4611         if((num_entries * 6) > (count - 16))
4612         {
4613             chpr = newline(chpr);
4614             chpr += printf("# WARNING: PIM claims too many entries (%d) for section size; ",num_entries);
4615             num_entries = (count - 16) / 6;
4616             PUSHCOLOR(HI_RED);
4617             chpr += printf("printing %d",num_entries);
4618             POPCOLOR();
4619         }
4620     }
4621 
4622     max_value_offset = entry_offset = ftell(inptr);
4623 
4624     indent += SMALLINDENT;
4625     for(entry_num = 0; entry_num < num_entries; ++entry_num)
4626     {
4627         int i;
4628 
4629         chpr = newline(chpr);
4630         tag = read_ushort(inptr,byteorder,HERE);
4631         if(ferror(inptr) || feof(inptr))
4632             goto blewit;
4633         if((PRINT_ENTRY))
4634         {
4635             print_tag_address(ENTRY,entry_offset,indent,prefix);
4636             if((PRINT_TAGINFO))
4637             {
4638                 if((PRINT_LONGNAMES))
4639                     chpr += printf("%s.%s.",dirname,tagname);
4640                 else if((LIST_MODE))
4641                     chpr += printf("%s.",tagname);
4642                 chpr += printf("PIM_%#06X",(int)tag);
4643                 if((PRINT_VALUE))
4644                 {
4645                     putindent(tagwidth - 10);
4646                     chpr += printf(" = ");
4647                 }
4648             }
4649         }
4650         valueptr = read_bytes(inptr,4,HERE);
4651         value = read_ulong(inptr,byteorder,entry_offset + 2);
4652 
4653         if(PRINT_SECTION)
4654         {
4655             if((PRINT_VALUE))
4656             {
4657                 for(i = 0; i < 4; ++i)
4658                     chpr += printf("%02x ",(unsigned int)(valueptr[i] & 0xff));
4659                 chpr += printf(" |");
4660                 for(i = 0; i < 4; ++i)
4661                 {
4662                     if(isprint(valueptr[i]))
4663                         putchar(valueptr[i]);
4664                     else
4665                         putchar('.');  /* can't win 'em all  */
4666                 }
4667                 chpr += printf("| = %#lx/%lu",value,value);
4668             }
4669         }
4670         else if((PRINT_VALUE))
4671             chpr += printf("%#lx/%lu",value,value);
4672 
4673         max_value_offset = entry_offset = ftell(inptr);
4674     }
4675 
4676     if(PRINT_SECTION)
4677     {
4678         chpr = newline(chpr);
4679         if((max_value_offset < max_offset) && PRINT_VALUE_AT_OFFSET)
4680         {
4681             int printlength = 0;
4682 
4683             print_tag_address(SECTION,max_value_offset,indent,"*");
4684             PUSHCOLOR(RED);
4685             chpr += printf("---- End of values before end of %s section",tagname);
4686             POPCOLOR();
4687             chpr = newline(chpr);
4688             extra = max_offset - max_value_offset;
4689             /* dump the extra as UNDEFINED                            */
4690             if(Max_undefined)
4691             {
4692                 if((Max_undefined == DUMPALL) || (Max_undefined > extra))
4693                     printlength = extra;
4694                 else if(Max_undefined > 0L)
4695                     printlength = Max_undefined;
4696                 hexdump(inptr,max_value_offset,extra,printlength,6,indent,
4697                                                     SMALLINDENT+8);
4698             }
4699             chpr = newline(chpr);
4700         }
4701         indent -= SMALLINDENT;
4702         print_tag_address(SECTION,max_offset - 1,indent,"-");
4703         chpr += printf("</%s>",tagname);
4704     }
4705 
4706     setcharsprinted(chpr);
4707     return(max_value_offset - 1);
4708 blewit:
4709     clearerr(inptr);
4710     return(0L);
4711 }
4712