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