1 /* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- */
2 /* EXIFPROBE - TIFF/JPEG/EXIF image file probe */
3 /* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- */
4 /* Copyright (C) 2005 by Duane H. Hesser. All rights reserved. */
5 /* */
6 /* See the file LICENSE.EXIFPROBE for terms of use. */
7 /* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- */
8
9 #ifndef lint
10 static char *ModuleId = "@(#) $Id: ciff.c,v 1.8 2005/07/24 17:03:18 alex Exp $";
11 #endif
12
13 /* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- */
14 /* Canon CIFF/CRW routines */
15 /* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- */
16 /* The information coded here is derived from the CIFF specification */
17 /* found at */
18 /* http://xyrion.org/ciff/CIFFspecV1R04.pdf */
19
20 /* with additional information from Phil Harvey's website at: */
21 /* http://www.sno.phy.queensu.ca/~phil/exiftool/canon_raw.html */
22 /* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- */
23
24 #include <stdio.h>
25 #include <string.h>
26 #include <stdlib.h>
27 #include <time.h>
28
29 #include "defs.h"
30 #include "datadefs.h"
31 #include "summary.h"
32 #include "maker.h"
33 #include "misc.h"
34 #include "tags.h"
35 #include "extern.h"
36 #include "ciff.h"
37 #include "canon_extern.h"
38 #include "maker_extern.h"
39
40
41 unsigned long
process_ciff(FILE * inptr,struct fileheader * header,unsigned long fileoffset_base,unsigned long heaplength,struct image_summary * summary_entry,char * parent_name,int level,int indent)42 process_ciff(FILE *inptr,struct fileheader *header,unsigned long fileoffset_base,
43 unsigned long heaplength,struct image_summary *summary_entry,
44 char *parent_name,int level,int indent)
45 {
46 struct ciff_header *ciffheader;
47 unsigned long max_offset = 0UL;
48 unsigned short byteorder = 0;
49 unsigned long heap_start = 0UL;
50 unsigned long offset_table_end = 0UL;
51
52 if(inptr)
53 {
54 if(header)
55 {
56 if(header->ciff_header)
57 {
58 ciffheader = header->ciff_header;
59 byteorder = ciffheader->byteorder;
60 heap_start = fileoffset_base + ciffheader->headerlength;
61 if(heaplength)
62 offset_table_end = fileoffset_base + heaplength;
63 else if(fseek(inptr,0L,2) == 0)
64 offset_table_end = ftell(inptr);
65 if(ferror(inptr) == 0)
66 {
67 max_offset = process_ciff_dir(inptr,heap_start,offset_table_end,
68 ciffheader->subtype,parent_name,
69 summary_entry,byteorder,
70 level,indent);
71 if(max_offset > 0L)
72 max_offset += 4;
73 }
74 else
75 fprintf(stderr,"%s: cannot read offset table\n",Progname);
76 }
77 else
78 fprintf(stderr,"%s: null ciffheader to process_ciff()\n",Progname);
79 }
80 else
81 fprintf(stderr,"%s: null fileheader to process_ciff()\n",Progname);
82 }
83 else
84 fprintf(stderr,"%s: no open file pointer to read Print Image data\n",
85 Progname);
86
87 return(max_offset);
88 }
89
90 unsigned long
process_ciff_dir(FILE * inptr,unsigned long start_offset,unsigned long end_offset,char * subtype,char * dirname,struct image_summary * summary_entry,unsigned short byteorder,int level,int indent)91 process_ciff_dir(FILE *inptr,unsigned long start_offset,unsigned long end_offset,
92 char *subtype,char *dirname,struct image_summary * summary_entry,
93 unsigned short byteorder,int level,int indent)
94 {
95 struct ciff_direntry *entry;
96 unsigned long dircount_loc;
97 unsigned long max_dir_offset = 0L;
98 unsigned long entry_offset,entry_offset_start;
99 unsigned long next_entry_offset,dir_offset;
100 unsigned short num_entries;
101 char *tablename = CNULL;
102 int i;
103 int chpr = 0;
104
105 dircount_loc = read_ulong(inptr,byteorder,end_offset - 4) + start_offset;
106 num_entries = read_ushort(inptr,byteorder,dircount_loc);
107 entry_offset = entry_offset_start = dircount_loc + 2;
108 entry = NULL;
109
110 max_dir_offset = start_offset;
111
112 /* Show where this directory is in the heap */
113 print_tag_address(SECTION|ENTRY,start_offset,indent,"@");
114 if((PRINT_SECTION && dirname))
115 {
116 chpr += printf("<%s> HEAP, length %lu",dirname,end_offset - start_offset);
117 chpr = newline(chpr);
118 }
119 else
120 {
121 if((PRINT_TAGINFO))
122 {
123 /* Always want to know WHICH heap offset */
124 chpr += printf("%s.",dirname);
125 chpr += printf("%-*.*s",CIFFTAGWIDTH,CIFFTAGWIDTH,"HeapOffset");
126 }
127 if((PRINT_VALUE))
128 {
129 if(PRINT_BOTH_OFFSET)
130 chpr += printf(" = @%#lx=%lu",start_offset,start_offset);
131 else if(PRINT_HEX_OFFSET)
132 chpr += printf(" = @%#lx",start_offset);
133 else
134 chpr += printf(" = @%lu",start_offset);
135 }
136 chpr = newline(chpr);
137 }
138
139 /* Now burrow down to the bottom, recursively. This will show the */
140 /* lower level directories and entries first. */
141 for(i = 0; i < num_entries; ++i)
142 {
143 entry = read_ciff_direntry(inptr,entry,byteorder,entry_offset);
144 if(ferror(inptr))
145 {
146 fprintf(stderr,"%s: error reading directory entry at %lu\n",
147 Progname,entry_offset);
148 break;
149 }
150 if(entry == NULL)
151 {
152 fprintf(stderr,"%s: null entry %d\n",Progname,i);
153 break;
154 }
155 next_entry_offset = ftell(inptr);
156 dir_offset =
157 process_ciff_direntry(inptr,CIFF_INHEAP,byteorder,entry,start_offset,
158 dirname,summary_entry,level,indent);
159 entry_offset = next_entry_offset;
160 }
161
162 /* Next show the directory info; this will display higher level */
163 /* directories and their direct entry values as the recursive */
164 /* calls unwind back to the top. */
165 if(PRINT_SECTION)
166 {
167 if(level == 0)
168 {
169 if(subtype && (strncmp(subtype,"JPGM",4) == 0))
170 tablename = splice(dirname,".","ImageProperties");
171 else
172 tablename = splice(dirname," ","offset table");
173 print_tag_address(SECTION,dircount_loc,indent,"@");
174 chpr += printf("<%s> %u entries",tablename,num_entries);
175 }
176 else
177 {
178 dirname = dirname ? dirname : QSTRING;
179 print_tag_address(SECTION,dircount_loc,indent+MEDIUMINDENT,"@");
180 chpr += printf("<%s DIRECTORY>, %u entries",dirname,num_entries);
181 indent += MEDIUMINDENT;
182 }
183 chpr = newline(chpr);
184 }
185
186 entry_offset = entry_offset_start;
187 max_dir_offset = start_offset;
188 for(i = 0; i < num_entries; ++i)
189 {
190 entry = read_ciff_direntry(inptr,entry,byteorder,entry_offset);
191 next_entry_offset = ftell(inptr);
192
193 if((PRINT_SECTION))
194 {
195 print_tag_address(ENTRY,entry_offset,indent + MEDIUMINDENT,"@");
196 print_ciff_taginfo(entry,start_offset);
197 }
198 if(PRINT_VALUE)
199 {
200 print_ciff_value(inptr,entry,byteorder,start_offset,entry_offset,
201 dirname,summary_entry
202 ,level,indent);
203 }
204 entry_offset = next_entry_offset;
205 if(entry_offset > max_dir_offset)
206 max_dir_offset = entry_offset;
207 }
208 /* Close off the directory; at the top, report the location of */
209 /* the offset table (or top level directory if JPGM) and loction */
210 /* where its location was found (at the end of the file). */
211 if(PRINT_SECTION)
212 {
213 if(level > 0)
214 {
215 print_tag_address(SECTION|ENTRY,max_dir_offset - 1,indent,"-");
216 dirname = dirname ? dirname : QSTRING;
217 chpr += printf("</%s DIRECTORY>\n",dirname);
218 print_tag_address(SECTION|ENTRY,end_offset - 4,indent,"-");
219 chpr += printf("%s DIRECTORY offset = %lu\n",dirname,dircount_loc);
220 print_tag_address(SECTION|ENTRY,end_offset - 1,indent-MEDIUMINDENT,"-");
221 chpr += printf("</%s>",dirname);
222 }
223 else
224 {
225 print_tag_address(SECTION|ENTRY,max_dir_offset - 1,indent,"-");
226 tablename = tablename ? tablename : QSTRING;
227 chpr += printf("</%s>\n",tablename);
228 print_tag_address(SECTION|ENTRY,end_offset - 4,indent,"-");
229 chpr += printf("%s location = @%lu",tablename,dircount_loc);
230 }
231 }
232 else if(level == 0)
233 {
234 print_tag_address(SECTION|ENTRY,end_offset - 1,indent,"-");
235 if((PRINT_TAGINFO))
236 {
237 if((PRINT_LONGNAMES))
238 chpr += printf("%s.",dirname);
239 chpr += printf("OffsetTableOffset");
240 }
241 if((PRINT_VALUE))
242 chpr += printf(" = @%lu",dircount_loc);
243 }
244 chpr = newline(chpr);
245 if(entry)
246 free(entry);
247 if(tablename)
248 free(tablename);
249 return(max_dir_offset);
250 }
251
252
253 /* Print the part of a CIFF entry describing the entry tag, including */
254 /* it's tag number, name and type. Only the items enabled in */
255 /* "Print_options" are printed. */
256
257 void
print_ciff_taginfo(struct ciff_direntry * entry,unsigned long fileoffset_base)258 print_ciff_taginfo(struct ciff_direntry *entry,unsigned long fileoffset_base)
259 {
260 char *nameoftag = NULL;
261 int tagwidth = CIFFTAGWIDTH;
262 unsigned short tag,format,location;
263 int chpr = 0;
264
265 if(entry && (PRINT_ENTRY))
266 {
267 tag = entry->type & CIFF_TYPEMASK;
268 format = entry->type & CIFF_FORMATMASK;
269 location = entry->type & CIFF_LOCATIONMASK;
270 if(PRINT_BOTH_TAGNO)
271 chpr += printf("<%#06x=%5u> ",tag,tag);
272 else if(PRINT_DEC_TAGNO)
273 chpr += printf("<%5u> ",tag);
274 else if(PRINT_HEX_TAGNO)
275 chpr += printf("<%#06x> ",tag);
276 if((PRINT_TAGNAME))
277 {
278 nameoftag = cifftagname(tag);
279 if(nameoftag)
280 {
281 chpr += printf("%-*.*s",tagwidth,tagwidth,nameoftag);
282 free(nameoftag);
283 }
284 }
285 if(PRINT_TYPE)
286 {
287 chpr += printf(" [%#06x ",format);
288 switch(format)
289 {
290 case 0x0000: chpr += printf("BYTE "); break;
291 case 0x0800: chpr += printf("ASCII "); break;
292 case 0x1000: chpr += printf("SHORT "); break;
293 case 0x1800: chpr += printf("LONG "); break;
294 case 0x2000: chpr += printf("STRUCT"); break;
295 case 0x2800: chpr += printf("SUBDIR"); break;
296 case 0x3000: chpr += printf("SUBDIR"); break;
297 case 0x3800:
298 default:
299 chpr += printf("UNDEFINED");
300 break;
301 }
302 switch(location)
303 {
304 case 0x0000: chpr += printf(" INHEAP %10lu %10lu",entry->length,entry->offset); break;
305 case 0x4000: chpr += printf(" INREC %10lu %10lu",entry->length,entry->offset); break;
306 case 0x8000: chpr += printf(" X8000 %10lu %10lu",entry->length,entry->offset); break;
307 case 0xc000: chpr += printf(" XC000 %10lu %10lu",entry->length,entry->offset); break;
308 default:
309 chpr += printf(" UNKNOWNLOC");
310 break;
311 }
312 chpr += printf("] ");
313 }
314 /* ###%%% should be done immediately before value is printed; */
315 /* not here */
316 if(PRINT_VALUE)
317 chpr += printf(" = ");
318 }
319 setcharsprinted(chpr);
320 }
321
322 /* Print the "value" portion of a directory entry. If the value is */
323 /* contained fully within the entry, the direntry processor is needed */
324 /* to decode the tag value, otherwise, just print the address in the */
325 /* heap where things have already been handled. */
326
327 void
print_ciff_value(FILE * inptr,struct ciff_direntry * entry,unsigned short byteorder,unsigned long fileoffset_base,unsigned long entry_offset,char * dirname,struct image_summary * summary_entry,int level,int indent)328 print_ciff_value(FILE *inptr,struct ciff_direntry *entry, unsigned short byteorder,
329 unsigned long fileoffset_base,unsigned long entry_offset,
330 char *dirname,struct image_summary *summary_entry,
331 int level,int indent)
332 {
333 unsigned short location;
334 unsigned long max_dir_offset = 0;
335 int chpr = 0;
336
337 location = entry->type & CIFF_LOCATIONMASK;
338 if(location == CIFF_INREC)
339 {
340 /* chpr += printf("INREC"); */
341 max_dir_offset = process_ciff_direntry(inptr,CIFF_INREC,byteorder,entry,
342 entry_offset,dirname,summary_entry,level,
343 indent);
344 }
345 else if(PRINT_SECTION)
346 {
347 if(PRINT_BOTH_OFFSET)
348 chpr += printf("@%#lx=%lu",entry->offset + fileoffset_base,
349 entry->offset + fileoffset_base);
350 else if(PRINT_HEX_OFFSET)
351 chpr += printf("@%#lx",entry->offset + fileoffset_base);
352 else /* default to decimal offset if nothing is selected */
353 chpr += printf("@%lu",entry->offset + fileoffset_base);
354
355 if(fileoffset_base && (PRINT_ENTRY_RELOFFSET))
356 chpr += printf(" (%lu) ",entry->offset);
357 chpr = newline(chpr);
358 }
359 setcharsprinted(chpr);
360 }
361
362 unsigned long
canon_colorspace(FILE * inptr,unsigned short byteorder,char * tagprefix,unsigned long offset,unsigned long dirlength,int indent)363 canon_colorspace(FILE *inptr,unsigned short byteorder,char *tagprefix,
364 unsigned long offset,unsigned long dirlength,int indent)
365 {
366 unsigned long count,value;
367 unsigned long end_offset;
368 int i;
369 int chpr = 0;
370
371 if(PRINT_SECTION)
372 {
373 chpr += printf(", length %lu",dirlength);
374 chpr = newline(chpr);
375 }
376
377 end_offset = offset + dirlength;
378 count = (dirlength / sizeof(unsigned short));
379
380 /* There should be just one (no idea why they didn't do it */
381 /* INRECORD), and there is no 2-byte count */
382 for(i = 0; i < count; ++i)
383 {
384 value = read_ushort(inptr,byteorder,offset);
385 print_tag_address(ENTRY,offset,indent,"@");
386 if((PRINT_TAGINFO))
387 {
388 if(tagprefix && (PRINT_LONGNAMES))
389 chpr = printf("%s.",tagprefix);
390 chpr = printf("%-*.*s",CIFFTAGWIDTH,CIFFTAGWIDTH,"type");
391 }
392 if((PRINT_VALUE))
393 {
394 chpr += printf(" = %lu ",value);
395 if(value == 1)
396 chpr += printf(" = \"real-world\"");
397 else if(value == 2)
398 chpr += printf(" = \"document\"");
399 else if(value == 0xfff)
400 chpr += printf(" = \"uncalibrated\"");
401 else
402 chpr += printf(" = \"undefined\"");
403 }
404 chpr = newline(chpr);
405 offset += 2;
406 }
407 setcharsprinted(chpr);
408 return(end_offset);
409 }
410
411 /* Decode the "capture time"; print in the Exif "DateTimeOriginal" */
412 /* format. */
413 unsigned long
canon_ct_to_datetime(FILE * inptr,unsigned short byteorder,char * tagname,unsigned long offset,unsigned long dirlength,int indent)414 canon_ct_to_datetime(FILE *inptr,unsigned short byteorder,char *tagname,unsigned long offset,
415 unsigned long dirlength,int indent)
416 {
417 unsigned long end_offset = 0UL;
418 unsigned long count;
419 unsigned long timezone;
420 unsigned long zoneinfo;
421 struct tm *ts_time;
422 long timestamp;
423 int chpr = 0;
424
425 if(PRINT_SECTION)
426 {
427 chpr += printf(", length %lu",dirlength);
428 chpr = newline(chpr);
429 }
430
431 count = dirlength / sizeof(unsigned long);
432 end_offset = offset + dirlength;
433 print_tag_address(ENTRY,offset,indent+MEDIUMINDENT,"@");
434 tagname = tagname ? tagname : QSTRING;
435 if(PRINT_TAGNAME)
436 chpr += printf("%s",tagname);
437 if(PRINT_VALUE)
438 {
439 chpr += printf(" = ");
440 print_ulong(inptr,count,byteorder,offset);
441 }
442 timestamp = read_ulong(inptr,byteorder,offset);
443 timezone = read_ulong(inptr,byteorder,HERE);
444 zoneinfo = read_ulong(inptr,byteorder,HERE);
445 if(PRINT_VALUE)
446 {
447 ts_time = gmtime(×tamp);
448 chpr += printf(" = %02d:%02d:%02d %02d:%02d:%02d GMT",ts_time->tm_year+1900,ts_time->tm_mon+1,
449 ts_time->tm_mday,ts_time->tm_hour,ts_time->tm_min,ts_time->tm_sec);
450 if((zoneinfo & 0x80000000) && timezone)
451 chpr += printf(" + %lu",timezone);
452 }
453 chpr = newline(chpr);
454
455 return(end_offset);
456 }
457
458 /* Print a "value" from a CIFF structure entry, according to the CIFF */
459 /* type recorded in the entry. Print in hex or decimal (or both) */
460 /* according to the global Print_options variable. */
461
462 /* This is generally undefined data, usually with unknown tagname or */
463 /* data interpretation. It may be large, so line-by-line output is */
464 /* avoided in favor of the abbreviated 'print_TYPE()' routines, and */
465 /* an opportunity is provided to hex/ascii dump the section . */
466
467 unsigned long
print_ciffinheapdata(FILE * inptr,unsigned short byteorder,char * dirname,char * tagname,unsigned long offset,unsigned long dirlength,unsigned short data_format,int indent)468 print_ciffinheapdata(FILE *inptr,unsigned short byteorder,char *dirname,
469 char *tagname,unsigned long offset,unsigned long dirlength,
470 unsigned short data_format,int indent)
471 {
472 unsigned long end_offset = 0UL;
473 unsigned long dumplength;
474 unsigned short count;
475 int chpr = 0;
476
477 if(inptr)
478 {
479 end_offset = offset + dirlength;
480 switch(data_format)
481 {
482 case 0x0000: count = dirlength; break;
483 case 0x0800: count = dirlength; break;
484 case 0x1000: count = dirlength/2; break;
485 case 0x1800: count = dirlength/4; break;
486 default: count = dirlength; break; /* handle as bytes? */
487 }
488 dirname = dirname ? dirname : QSTRING;
489 tagname = tagname ? tagname : QSTRING;
490 if((PRINT_SECTION))
491 {
492 print_tag_address(SECTION|ENTRY,offset, indent,"@");
493 chpr += printf("<%s.%s> data, %u entries, length %lu",dirname,tagname,count,dirlength);
494 chpr = newline(chpr);
495 }
496 if((PRINT_TAGINFO))
497 {
498 print_tag_address(ENTRY,offset,indent+MEDIUMINDENT,"@");
499 if((PRINT_LONGNAMES))
500 chpr += printf("%s.",dirname);
501 chpr += printf("%-*.*s",CIFFTAGWIDTH,CIFFTAGWIDTH,tagname);
502 }
503 if(PRINT_VALUE)
504 {
505 chpr += printf(" = ");
506 switch(data_format)
507 {
508 case 0x1000: /* DC_USHORT */
509 print_ushort(inptr,count,byteorder,offset);
510 break;
511 case 0x1800: /* DC_UINT32: */
512 print_ulong(inptr,count,byteorder,offset);
513 break;
514 case 0x0800: /* DC_ASCII: */
515 print_ascii(inptr,count,offset);
516 break;
517 case 0x0000: /* DC_BYTE: */
518 print_ubytes(inptr,count,offset);
519 break;
520 default:
521 chpr += printf("(data format %#x)",data_format);
522 break;
523 }
524 if(Max_undefined > 0L)
525 {
526 if((Max_undefined == DUMPALL) ||
527 (Max_undefined > dirlength))
528 dumplength = dirlength;
529 else
530 dumplength = Max_undefined;
531 chpr = newline(chpr);
532 hexdump(inptr,offset,dirlength,dumplength,16,indent+MEDIUMINDENT,
533 MEDIUMINDENT);
534 chpr = newline(chpr);
535 }
536 }
537 if(PRINT_SECTION)
538 {
539 chpr = newline(chpr);
540 print_tag_address(SECTION|ENTRY,end_offset - 1, indent,"-");
541 dirname = dirname ? dirname : QSTRING;
542 chpr += printf("</%s.%s>",dirname,tagname);
543 }
544 setcharsprinted(chpr);
545 }
546 return(end_offset);
547 }
548
549 /* Print a "value" from a CIFF directory entry when the value is */
550 /* contained within the record, rather than INHEAP. The data is */
551 /* printed according to the CIFF type recorded in the entry, in hex */
552 /* or decimal (or both) according to the global Print_options */
553 /* variable. */
554
555 /* This is generally undefined data, usually with unknown tagname or */
556 /* data interpretation. */
557
558 unsigned long
print_ciffinrecdata(FILE * inptr,unsigned short byteorder,char * tagname,unsigned long offset,unsigned long dirlength,unsigned short data_format,int indent)559 print_ciffinrecdata(FILE *inptr,unsigned short byteorder,char *tagname,
560 unsigned long offset,unsigned long dirlength,
561 unsigned short data_format,int indent)
562 {
563 unsigned long end_offset = 0UL;
564 unsigned short count;
565 int chpr = 0;
566
567 if(inptr)
568 {
569 end_offset = offset + dirlength;
570 if((PRINT_VALUE))
571 {
572 count = dirlength;
573 chpr = count;
574 switch(data_format)
575 {
576 case 0x1000: /* DC_USHORT */
577 print_ushort(inptr,count/2,byteorder,offset);
578 break;
579 case 0x1800: /* DC_UINT32: */
580 print_ulong(inptr,count/4,byteorder,offset);
581 break;
582 case 0x0800: /* DC_ASCII: */
583 print_ascii(inptr,count,offset);
584 break;
585 case 0x0000: /* DC_BYTE: */
586 print_ubytes(inptr,count,offset);
587 break;
588 default:
589 chpr += printf("(data format %#x)",data_format);
590 break;
591 }
592 setcharsprinted(chpr);
593 }
594 }
595 return(end_offset);
596 }
597
598 unsigned long
process_ciff_direntry(FILE * inptr,unsigned short location,unsigned short byteorder,struct ciff_direntry * entry,unsigned long fileoffset_base,char * dirname,struct image_summary * summary_entry,int level,int indent)599 process_ciff_direntry(FILE *inptr,unsigned short location,unsigned short byteorder,
600 struct ciff_direntry *entry, unsigned long fileoffset_base,
601 char *dirname,struct image_summary *summary_entry,int level,
602 int indent)
603 {
604 unsigned long max_offset = 0;
605 unsigned long endofdir;
606 unsigned short tag,marker,shvalue;
607 char *nameoftag = NULL;
608 char *fullnameoftag = NULL;
609 char *tagname,*makename;
610 int entrywidth = CIFFTAGWIDTH;
611 int status = 0;
612 int chpr = 0;
613 int parindent = 0;
614 int make,model,tagwidth;
615 int makelen;
616 float fvalue;
617
618 if(entry)
619 {
620 if((entry->type & CIFF_LOCATIONMASK) == location)
621 {
622 chpr = 0;
623 max_offset = fileoffset_base;
624 /* ###%%%
625 if((entry->type & CIFF_LOCATIONMASK) == CIFF_INHEAP)
626 chpr += printf("INHEAP");
627 */
628 tag = entry->type & CIFF_TYPEMASK;
629 nameoftag = cifftagname(tag);
630 fullnameoftag = splice(dirname,".",nameoftag);
631 if(PRINT_LONGNAMES)
632 {
633 tagname = fullnameoftag;
634 if(dirname)
635 entrywidth += strlen(dirname) + 1;
636 }
637 else
638 tagname = nameoftag;
639
640 switch(tag)
641 {
642 case CIFFTAG_COLORINFO2: /* fall through */
643 case CIFFTAG_COLORINFO1: /* INHEAPDATA */
644 if((PRINT_SECTION))
645 indent += MEDIUMINDENT;
646 max_offset = print_ciffinheapdata(inptr,byteorder,dirname,
647 nameoftag,entry->offset + fileoffset_base,entry->length,
648 entry->type&CIFF_FORMATMASK,indent/* +MEDIUMINDENT*/);
649 break;
650 case CIFFTAG_ROMOPERATIONMODE: /* ASCII INREC */
651 if(!(PRINT_SECTION) && (PRINT_TAGINFO))
652 {
653 print_tag_address(ENTRY,fileoffset_base + 2,indent+MEDIUMINDENT,"@");
654 chpr = printf("%-*.*s",entrywidth,entrywidth,tagname);
655 }
656 if(PRINT_VALUE)
657 {
658 print_ascii(inptr,8,fileoffset_base + 2);
659 max_offset = fileoffset_base + 2 + 8;
660 }
661 break;
662 case CIFFTAG_RAWMAKEMODEL: /* ###%%% ASCII SPECIAL */
663 print_tag_address(ENTRY,entry->offset + fileoffset_base,indent+MEDIUMINDENT,
664 "@");
665 makename = (char *)read_bytes(inptr, entry->length,
666 entry->offset + fileoffset_base);
667 max_offset = ftell(inptr);
668 Make_name = strdup(makename);
669 makelen = strlen(makename);
670 Model_name = strdup(makename + makelen + 1);
671 dirname = dirname ? dirname : QSTRING;
672 if((LIST_MODE))
673 {
674 /* Make pseudo-tags and separate Make and */
675 /* Model */
676 if(PRINT_TAGNAME)
677 chpr += printf("%s.%-*.*s",dirname,CIFFTAGWIDTH,CIFFTAGWIDTH,"Make");
678 if(PRINT_VALUE)
679 {
680 chpr += printf(" = \"%s\"",Make_name);
681 if(Use_Make_name)
682 chpr += printf(" (Using: Make=%s)",Use_Make_name);
683 }
684 chpr = newline(chpr);
685 print_tag_address(ENTRY,entry->offset + fileoffset_base + strlen(Make_name) + 1,
686 indent+MEDIUMINDENT,"@");
687 if(PRINT_TAGNAME)
688 chpr += printf("%s.%-*.*s",dirname,CIFFTAGWIDTH,CIFFTAGWIDTH,"Model");
689 if(PRINT_VALUE)
690 {
691 chpr += printf(" = \"%s\"",Model_name);
692 if(Use_Make_name)
693 chpr += printf(" (Using: Model=%s)",Use_Model_name);
694 }
695 }
696 else
697 {
698 if(PRINT_TAGNAME)
699 {
700 if((PRINT_SECTION))
701 chpr += printf("%s.%-*.*s",dirname,CIFFTAGWIDTH,CIFFTAGWIDTH,nameoftag);
702 else
703 chpr += printf("%-*.*s",CIFFTAGWIDTH,CIFFTAGWIDTH,nameoftag);
704 }
705 if(PRINT_VALUE)
706 {
707 chpr += printf(" = ");
708 if((PRINT_ASCII_IGNORE_LENGTH))
709 chpr += printf("%s\\0%s",Make_name,Model_name);
710 else
711 print_ascii(inptr,entry->length,entry->offset + fileoffset_base);
712 if(Use_Make_name)
713 chpr += printf(" Using: Make=%s",Use_Make_name);
714 if(Use_Model_name)
715 chpr += printf(" Using: Model=%s",Use_Model_name);
716 }
717 }
718 break;
719 case CIFFTAG_FILEDESCRIPTION: /* ASCII INHEAP */
720 case CIFFTAG_FIRMWAREVERSION: /* ASCII INHEAP */
721 case CIFFTAG_OWNERNAME: /* ASCII INHEAP */
722 case CIFFTAG_IMAGETYPE: /* ASCII INHEAP */
723 case CIFFTAG_ORIGINALFILENAME: /* ASCII INHEAP */
724 case CIFFTAG_THUMBNAILFILENAME: /* ASCII INHEAP */
725 print_tag_address(ENTRY,entry->offset + fileoffset_base,indent+MEDIUMINDENT,"@");
726 if((PRINT_TAGINFO))
727 chpr = printf("%-*.*s",entrywidth,entrywidth,tagname);
728 if(PRINT_VALUE)
729 {
730 chpr += printf(" = ");
731 print_ascii(inptr,entry->length,entry->offset + fileoffset_base);
732 max_offset = ftell(inptr);
733 }
734 break;
735 case CIFFTAG_BASEISO: /* INREC */
736 if(!(PRINT_SECTION) && (PRINT_TAGINFO))
737 {
738 print_tag_address(ENTRY,fileoffset_base + 2,indent+MEDIUMINDENT,"@");
739 chpr = printf("%-*.*s",entrywidth,entrywidth,tagname);
740 }
741 if(PRINT_VALUE)
742 chpr += printf("%lu",entry->length);
743 max_offset = ftell(inptr);
744 break;
745 case CIFFTAG_FOCALLENGTH: /* INREC */
746 /* length mm, xy size in .001 inch ###%%% ??? */
747 if((PRINT_VALUE) && (PRINT_SECTION))
748 {
749 indent += 19;
750 chpr = printf("{");
751 chpr = newline(chpr);
752 parindent = charsprinted() - LARGEINDENT;
753 indent += MEDIUMINDENT;
754 }
755 if(PRINT_ENTRY)
756 {
757 entrywidth = strlen("TargetCompressionRatio");
758 print_tag_address(ENTRY,fileoffset_base + 2,indent + MEDIUMINDENT,"@");
759 parindent = charsprinted() - LARGEINDENT;
760 if((PRINT_TAGINFO))
761 {
762 if((PRINT_LONGNAMES))
763 chpr += printf("%s.",fullnameoftag);
764 chpr += printf("%-*.*s",entrywidth,entrywidth,"Undefined");
765 }
766 if((PRINT_VALUE))
767 {
768 shvalue = read_ushort(inptr,byteorder,fileoffset_base + 2);
769 printf(" = %u",shvalue);
770 chpr = newline(chpr);
771 }
772 print_tag_address(ENTRY,fileoffset_base + 4,indent + MEDIUMINDENT,"@");
773 if((PRINT_TAGINFO))
774 {
775 if((PRINT_LONGNAMES))
776 chpr += printf("%s.",fullnameoftag);
777 chpr += printf("%-*.*s",entrywidth,entrywidth,
778 "FocalLength");
779 }
780 if((PRINT_VALUE))
781 {
782 shvalue = read_ushort(inptr,byteorder,fileoffset_base + 4);
783 chpr += printf(" = %u mm",shvalue);
784 chpr = newline(chpr);
785 }
786 print_tag_address(ENTRY,fileoffset_base + 6,indent + MEDIUMINDENT,"@");
787 if((PRINT_TAGINFO))
788 {
789 if((PRINT_LONGNAMES))
790 chpr += printf("%s.",fullnameoftag);
791 chpr += printf("%-*.*s",entrywidth,entrywidth,
792 "FocalPlaneXDim");
793 }
794 if((PRINT_VALUE))
795 {
796 shvalue = read_ushort(inptr,byteorder,fileoffset_base + 6);
797 chpr += printf(" = %u inches/1000",shvalue);
798 chpr = newline(chpr);
799 }
800 print_tag_address(ENTRY,fileoffset_base + 8,indent + MEDIUMINDENT,"@");
801 if((PRINT_TAGINFO))
802 {
803 if((PRINT_LONGNAMES))
804 chpr += printf("%s.",fullnameoftag);
805 chpr += printf("%-*.*s",entrywidth,entrywidth,
806 "FocalPlaneYDim");
807 }
808 if((PRINT_VALUE))
809 {
810 shvalue = read_ushort(inptr,byteorder,fileoffset_base + 8);
811 chpr += printf(" = %u inches/1000",shvalue);
812 if(PRINT_SECTION)
813 {
814 chpr = newline(chpr);
815 print_tag_address(ENTRY,fileoffset_base + 9,0,"@");
816 parindent -= charsprinted();
817 putindent(parindent);
818 chpr = printf("}");
819 indent -= MEDIUMINDENT;
820 }
821 }
822 }
823 break;
824 case CIFFTAG_SHOTINFO: /* INHEAP subroutine */
825 if((PRINT_SECTION))
826 {
827 PUSHCOLOR(MAKER_COLOR);
828 print_tag_address(SECTION|ENTRY,entry->offset + fileoffset_base,
829 indent+MEDIUMINDENT,"@");
830 chpr += printf("<%s> data, %lu entries",fullnameoftag,(entry->length/sizeof(short)) - 1);
831 indent += MEDIUMINDENT;
832 }
833 max_offset = canon_shotinfo(inptr,byteorder,tagname,
834 entry->offset + fileoffset_base,
835 entry->length,indent+MEDIUMINDENT);
836 if((PRINT_SECTION))
837 {
838 indent -= MEDIUMINDENT;
839 print_tag_address(SECTION|ENTRY,entry->offset + fileoffset_base + entry->length - 1,
840 indent+MEDIUMINDENT,"-");
841 chpr += printf("</%s>",fullnameoftag);
842 POPCOLOR();
843 }
844 break;
845 case CIFFTAG_CAMERASETTINGS: /* INHEAP subroutine */
846 if((PRINT_SECTION))
847 {
848 PUSHCOLOR(MAKER_COLOR);
849 print_tag_address(SECTION|ENTRY,entry->offset + fileoffset_base,
850 indent+MEDIUMINDENT,"@");
851 chpr += printf("<%s> data, %lu entries",fullnameoftag,
852 (entry->length/sizeof(short)) - 1);
853 indent += MEDIUMINDENT;
854 }
855 max_offset = canon_camera_settings(inptr,byteorder,
856 tagname,entry->offset + fileoffset_base,
857 entry->length,indent+MEDIUMINDENT);
858 if((PRINT_SECTION))
859 {
860 indent -= MEDIUMINDENT;
861 print_tag_address(SECTION|ENTRY,entry->offset + fileoffset_base + entry->length - 1,
862 indent+MEDIUMINDENT,"-");
863 chpr += printf("</%s>",fullnameoftag);
864 POPCOLOR();
865 }
866 break;
867 case CIFFTAG_SENSORINFO: /* INHEAP subroutine */
868 if((PRINT_SECTION))
869 {
870 PUSHCOLOR(MAKER_COLOR);
871 print_tag_address(SECTION|ENTRY,entry->offset + fileoffset_base,
872 indent+MEDIUMINDENT,"@");
873 chpr += printf("<%s> data, %lu entries",fullnameoftag,(entry->length/sizeof(short)) - 1);
874 indent += MEDIUMINDENT;
875 }
876 max_offset = canon_sensorinfo(inptr,byteorder,tagname,entry->offset + fileoffset_base,
877 entry->length,indent+MEDIUMINDENT);
878 if((PRINT_SECTION))
879 {
880 indent -= MEDIUMINDENT;
881 print_tag_address(SECTION|ENTRY,entry->offset + fileoffset_base + entry->length - 1,
882 indent+MEDIUMINDENT,"-");
883 chpr += printf("</%s>",fullnameoftag);
884 POPCOLOR();
885 }
886 break;
887 case CIFFTAG_CUSTOMFUNCTIONS: /* INHEAP subroutine */
888 if(Use_Make_name)
889 make = maker_number(Use_Make_name);
890 else
891 make = maker_number(Make_name);
892 if(Use_Model_name)
893 model = model_number(make,Use_Model_name,NULLSTRING);
894 else
895 model = model_number(make,Model_name,NULLSTRING);
896 if((PRINT_SECTION))
897 {
898 PUSHCOLOR(MAKER_COLOR);
899 print_tag_address(SECTION|ENTRY,entry->offset + fileoffset_base,
900 indent+MEDIUMINDENT,"@");
901 chpr += printf("<%s> data, %lu entries",fullnameoftag,
902 (entry->length/sizeof(short)) - 1);
903 indent += MEDIUMINDENT;
904 }
905 max_offset = canon_customfunctions(inptr,byteorder,
906 tagname,entry->offset + fileoffset_base,
907 entry->length,model,indent+MEDIUMINDENT);
908 if((PRINT_SECTION))
909 {
910 indent -= MEDIUMINDENT;
911 print_tag_address(SECTION|ENTRY,entry->offset + fileoffset_base + entry->length - 1,
912 indent+MEDIUMINDENT,"-");
913 chpr += printf("</%s>",fullnameoftag);
914 POPCOLOR();
915 }
916 break;
917 case CIFFTAG_PICTUREINFO: /* INHEAP subroutine */
918 if((PRINT_SECTION))
919 {
920 PUSHCOLOR(MAKER_COLOR);
921 print_tag_address(SECTION|ENTRY,entry->offset + fileoffset_base,
922 indent+MEDIUMINDENT,"@");
923 chpr += printf("<%s> data, %lu entries",fullnameoftag,(entry->length/sizeof(short)) - 1);
924 indent += MEDIUMINDENT;
925 }
926 max_offset = canon_pictureinfo(inptr,byteorder,
927 tagname,entry->offset + fileoffset_base,
928 entry->length,indent+MEDIUMINDENT);
929 if((PRINT_SECTION))
930 {
931 indent -= MEDIUMINDENT;
932 print_tag_address(SECTION|ENTRY,entry->offset + fileoffset_base + entry->length - 1,
933 indent+MEDIUMINDENT,"-");
934 chpr += printf("</%s>",fullnameoftag);
935 POPCOLOR();
936 }
937 break;
938 case CIFFTAG_WHITEBALANCETABLE: /* INHEAP subroutine */
939 if((PRINT_SECTION))
940 {
941 PUSHCOLOR(MAKER_COLOR);
942 print_tag_address(SECTION|ENTRY,entry->offset + fileoffset_base,
943 indent+MEDIUMINDENT,"@");
944 chpr += printf("<%s> data, %lu entries",fullnameoftag,
945 (entry->length - sizeof(unsigned short))/sizeof(float));
946 indent += MEDIUMINDENT;
947 }
948 max_offset = canon_whitebalancetable(inptr,byteorder,tagname,
949 entry->offset + fileoffset_base,entry->length,indent+MEDIUMINDENT);
950 if((PRINT_SECTION))
951 {
952 indent -= MEDIUMINDENT;
953 print_tag_address(SECTION|ENTRY,entry->offset + fileoffset_base + entry->length - 1,
954 indent+MEDIUMINDENT,"-");
955 chpr += printf("</%s>",fullnameoftag);
956 POPCOLOR();
957 }
958 break;
959 case CIFFTAG_IMAGESPEC: /* INREC */
960 if((PRINT_VALUE) && (PRINT_SECTION))
961 {
962 indent += 19;
963 chpr = printf("{");
964 chpr = newline(chpr);
965 parindent = charsprinted();
966 }
967 if(PRINT_ENTRY)
968 {
969 entrywidth = strlen("TargetCompressionRatio");
970 dirname = dirname ? dirname : QSTRING;
971 print_tag_address(ENTRY,fileoffset_base + 2,indent + LARGEINDENT,"@");
972 parindent = charsprinted() - LARGEINDENT;
973 if((PRINT_TAGINFO))
974 {
975 if((PRINT_LONGNAMES))
976 chpr += printf("%s.",fullnameoftag);
977 chpr += printf("%-*.*s",entrywidth,entrywidth,"FileFormat");
978 }
979 if((PRINT_VALUE))
980 {
981 chpr += printf(" = ");
982 switch(entry->length)
983 {
984 case 0x10000: chpr += printf("JPEG quantized\n"); break;
985 case 0x10002: chpr += printf("JPEG non-quantized\n"); break;
986 case 0x10003: chpr += printf("JPEG nq picture/q text\n"); break;
987 case 0x20001: chpr += printf("CRW\n"); break;
988 default: chpr += printf("unknown\n"); break;
989 }
990 }
991 print_tag_address(ENTRY,fileoffset_base + 6,indent + LARGEINDENT,"@");
992 if((PRINT_TAGINFO))
993 {
994 if((PRINT_LONGNAMES))
995 chpr += printf("%s.",fullnameoftag);
996 chpr += printf("%-*.*s",entrywidth,entrywidth,"TargetCompressionRatio");
997 }
998 if((PRINT_VALUE))
999 {
1000 fvalue = to_float(entry->offset);
1001 chpr += printf(" = %f",fvalue);
1002 if(PRINT_SECTION)
1003 {
1004 chpr = newline(chpr);
1005 print_tag_address(ENTRY,fileoffset_base + 9,0,"@");
1006 parindent -= charsprinted();
1007 putindent(parindent);
1008 chpr = printf("}");
1009 }
1010 }
1011 }
1012 break;
1013 case CIFFTAG_SHUTTERRELEASEMETHOD: /* INREC */
1014 if(!(PRINT_SECTION) && (PRINT_TAGINFO))
1015 {
1016 print_tag_address(ENTRY,fileoffset_base + 2,indent + MEDIUMINDENT,"@");
1017 chpr = printf("%-*.*s",entrywidth,entrywidth,tagname);
1018 if(PRINT_VALUE)
1019 chpr += printf(" = ");
1020 }
1021 if(PRINT_VALUE)
1022 {
1023 print_ushort(inptr,4,byteorder,fileoffset_base + 2);
1024 chpr += printf("%lu = ",entry->length & 0xffff);
1025 if((entry->length & 0xffff) == 0)
1026 chpr += printf("single-shot");
1027 else if((entry->length & 0xffff) == 1)
1028 chpr += printf("continuous");
1029 else
1030 chpr += printf("undefined");
1031 }
1032 break;
1033 case CIFFTAG_SHUTTERRELEASETIMING: /* INREC */
1034 if(!(PRINT_SECTION) && (PRINT_TAGINFO))
1035 {
1036 print_tag_address(ENTRY,fileoffset_base + 2,indent + MEDIUMINDENT,"@");
1037 chpr = printf("%-*.*s",entrywidth,entrywidth,tagname);
1038 if(PRINT_VALUE)
1039 chpr += printf(" = ");
1040 }
1041 if(PRINT_VALUE)
1042 {
1043 print_ushort(inptr,4,byteorder,fileoffset_base + 2);
1044 chpr += printf(" = %lu = ",entry->length & 0xffff);
1045 if((entry->length & 0xffff) == 0)
1046 chpr += printf("shutter-priority");
1047 else if((entry->length & 0xffff) == 1)
1048 chpr += printf("aperture-priority");
1049 else
1050 chpr += printf("undefined");
1051 }
1052 break;
1053 case CIFFTAG_SELFTIMERTIME: /* INREC */
1054 if(!(PRINT_SECTION) && (PRINT_TAGINFO))
1055 {
1056 print_tag_address(ENTRY,fileoffset_base + 2,indent + MEDIUMINDENT,"@");
1057 chpr = printf("%-*.*s",entrywidth,entrywidth,tagname);
1058 }
1059 if(PRINT_VALUE)
1060 chpr += printf(" = %lu msec ",entry->length & 0xffff);
1061 break;
1062 case CIFFTAG_TARGETDISTANCESETTING: /* INREC */
1063 if(!(PRINT_SECTION) && (PRINT_TAGINFO))
1064 {
1065 print_tag_address(ENTRY,fileoffset_base + 2,indent + MEDIUMINDENT,"@");
1066 chpr = printf("%-*.*s",entrywidth,entrywidth,tagname);
1067 }
1068 if(PRINT_VALUE)
1069 {
1070 float fvalue;
1071
1072 fvalue = to_float(entry->length);
1073 chpr += printf("%f mm",fvalue);
1074 }
1075 break;
1076 case CIFFTAG_COLORSPACE: /* INHEAP subroutine */
1077 if((PRINT_SECTION))
1078 {
1079 PUSHCOLOR(MAKER_COLOR);
1080 print_tag_address(SECTION|ENTRY,entry->offset + fileoffset_base,
1081 indent+MEDIUMINDENT,"@");
1082 chpr += printf("<%s> data, %lu entries",fullnameoftag,(entry->length/sizeof(unsigned short)));
1083 indent += MEDIUMINDENT;
1084 }
1085 max_offset = canon_colorspace(inptr,byteorder,
1086 tagname,entry->offset + fileoffset_base,
1087 entry->length,indent+MEDIUMINDENT);
1088 if((PRINT_SECTION))
1089 {
1090 indent -= MEDIUMINDENT;
1091 print_tag_address(SECTION|ENTRY,entry->offset + fileoffset_base + entry->length - 1,
1092 indent+MEDIUMINDENT,"-");
1093 chpr += printf("</%s>",fullnameoftag);
1094 POPCOLOR();
1095 }
1096 break;
1097 case CIFFTAG_TARGETIMAGETYPE: /* INREC */
1098 if(!(PRINT_SECTION) && (PRINT_TAGINFO))
1099 {
1100 print_tag_address(ENTRY,fileoffset_base + 2,indent + MEDIUMINDENT,"@");
1101 chpr = printf("%-*.*s",entrywidth,entrywidth,tagname);
1102 if(PRINT_VALUE)
1103 chpr += printf(" = ");
1104 }
1105 if(PRINT_VALUE)
1106 {
1107 print_ushort(inptr,4,byteorder,fileoffset_base + 2);
1108 chpr += printf(" = %lu = ",entry->length & 0xffff);
1109 if((entry->length & 0xffff) == 0)
1110 chpr += printf("real-world");
1111 else if((entry->length & 0xffff) == 1)
1112 chpr += printf("document");
1113 else
1114 chpr += printf("undefined");
1115 }
1116 break;
1117 case CIFFTAG_SERIALNUMBER: /* INREC */
1118 if(!(PRINT_SECTION) && (PRINT_TAGINFO))
1119 {
1120 print_tag_address(ENTRY,fileoffset_base + 2,indent + MEDIUMINDENT,"@");
1121 chpr = printf("%-*.*s",entrywidth,entrywidth,tagname);
1122 if(PRINT_VALUE)
1123 chpr += printf(" = ");
1124 }
1125 if(PRINT_VALUE)
1126 {
1127 chpr += printf("%lu",entry->length);
1128 print_canon_serialno(entry->length);
1129 }
1130 break;
1131 case CIFFTAG_CAPTUREDTIME: /* INHEAP subroutine */
1132 if((PRINT_SECTION))
1133 {
1134 print_tag_address(SECTION|ENTRY,entry->offset + fileoffset_base,indent+MEDIUMINDENT,
1135 "@");
1136 chpr += printf("<%s> data, %lu entries",fullnameoftag,(entry->length/sizeof(unsigned long)));
1137 }
1138 max_offset = canon_ct_to_datetime(inptr,byteorder,
1139 tagname,entry->offset + fileoffset_base,
1140 entry->length,indent+MEDIUMINDENT);
1141 if((PRINT_SECTION))
1142 {
1143 print_tag_address(SECTION|ENTRY,entry->offset + fileoffset_base + entry->length - 1,
1144 indent+MEDIUMINDENT,"-");
1145 chpr += printf("</%s>",fullnameoftag);
1146 POPCOLOR();
1147 }
1148 break;
1149 case CIFFTAG_EXPOSUREINFO: /* INHEAP, 3 floats; EC, Tv, Av */
1150 if((PRINT_SECTION))
1151 {
1152 print_tag_address(SECTION,entry->offset + fileoffset_base,indent+MEDIUMINDENT,
1153 "@");
1154 chpr = printf("<%s> data, %lu entries",fullnameoftag,(entry->length/sizeof(unsigned long)));
1155 indent += MEDIUMINDENT;
1156 }
1157 max_offset = canon_exposureinfo(inptr,byteorder,tagname,
1158 entry->offset + fileoffset_base,
1159 entry->length,indent+MEDIUMINDENT,
1160 summary_entry);
1161 indent -= MEDIUMINDENT;
1162 if((PRINT_SECTION))
1163 {
1164 print_tag_address(SECTION,entry->offset + fileoffset_base + entry->length - 1,
1165 indent+MEDIUMINDENT,"-");
1166 chpr += printf("</%s>",fullnameoftag);
1167 POPCOLOR();
1168 }
1169 break;
1170 case CIFFTAG_IMAGEINFO: /* INHEAP subroutine */
1171 if((PRINT_SECTION))
1172 {
1173 print_tag_address(SECTION,entry->offset + fileoffset_base,indent+MEDIUMINDENT,
1174 "@");
1175 chpr = printf("<%s> data, %lu entries",fullnameoftag,(entry->length/sizeof(unsigned long)));
1176 }
1177 max_offset = canon_imageinfo(inptr,byteorder,tagname,
1178 entry->offset + fileoffset_base,
1179 entry->length,indent+MEDIUMINDENT,
1180 summary_entry);
1181 if((PRINT_SECTION))
1182 {
1183 print_tag_address(SECTION,entry->offset + fileoffset_base + entry->length - 1,
1184 indent+MEDIUMINDENT,"-");
1185 chpr += printf("</%s>",fullnameoftag);
1186 POPCOLOR();
1187 }
1188 break;
1189 case CIFFTAG_FLASHINFO: /* INREC two floats, flash Guidenumber & Threshold */
1190 if((PRINT_VALUE) && (PRINT_SECTION))
1191 {
1192 indent += 19;
1193 chpr = printf("{");
1194 chpr = newline(chpr);
1195 parindent = charsprinted();
1196 }
1197 if(PRINT_ENTRY)
1198 {
1199 float fvalue;
1200
1201 entrywidth = strlen("FlashGuideNumber");
1202 dirname = dirname ? dirname : QSTRING;
1203 print_tag_address(ENTRY,fileoffset_base + 2,indent+MEDIUMINDENT,"@");
1204 parindent = charsprinted() - MEDIUMINDENT;
1205 if((PRINT_TAGINFO))
1206 {
1207 if((PRINT_LONGNAMES))
1208 chpr += printf("%s.",fullnameoftag);
1209 chpr += printf("%-*.*s",entrywidth,entrywidth,"FlashGuideNumber");
1210 }
1211 if((PRINT_VALUE))
1212 {
1213 fvalue = to_float(entry->length);
1214 chpr += printf(" = %f",fvalue);
1215 }
1216
1217 chpr = newline(chpr);
1218 print_tag_address(ENTRY,fileoffset_base + 6,indent+MEDIUMINDENT,"@");
1219 if((PRINT_TAGINFO))
1220 {
1221 if((PRINT_LONGNAMES))
1222 chpr += printf("%s.",fullnameoftag);
1223 chpr += printf("%-*.*s",entrywidth,entrywidth,
1224 "FlashThreshold");
1225 }
1226 if((PRINT_VALUE))
1227 {
1228 fvalue = to_float(entry->offset);
1229 chpr += printf(" = %f",fvalue);
1230 }
1231 }
1232 if(PRINT_SECTION)
1233 {
1234 chpr = newline(chpr);
1235 print_tag_address(ENTRY,fileoffset_base + 9,0,"@");
1236 parindent -= charsprinted();
1237 putindent(parindent);
1238 chpr = printf("}");
1239 }
1240 break;
1241 case CIFFTAG_MEASUREDEV: /* INREC */
1242 if(!(PRINT_SECTION) && (PRINT_TAGINFO))
1243 {
1244 print_tag_address(ENTRY,fileoffset_base + 2,indent+MEDIUMINDENT,"@");
1245 chpr = printf("%-*.*s",entrywidth,entrywidth,tagname);
1246 }
1247 if(PRINT_VALUE)
1248 {
1249 float fvalue;
1250
1251 fvalue = to_float(entry->length);
1252 chpr += printf("%f",fvalue);
1253 }
1254 break;
1255 case CIFFTAG_RAWIMAGEDATA: /* INHEAP */
1256 if(PRINT_SECTION)
1257 {
1258 print_tag_address(SECTION|ENTRY,entry->offset + fileoffset_base,
1259 indent,"@");
1260 chpr += printf("Start of %s, length %lu\n",nameoftag,entry->length);
1261 if((PRINT_VALUE))
1262 dumpsection(inptr,entry->offset + fileoffset_base,entry->length,indent + SMALLINDENT);
1263 print_tag_address(SECTION|ENTRY,entry->offset + fileoffset_base + entry->length - 1,
1264 indent,"@");
1265 chpr += printf("End of %s",nameoftag);
1266 }
1267 else
1268 {
1269 print_tag_address(ENTRY,entry->offset + fileoffset_base,
1270 indent+MEDIUMINDENT,"@");
1271 /* pseudo-tags */
1272 if(PRINT_TAGINFO)
1273 chpr += printf("%s.%-*.*s",dirname,CIFFTAGWIDTH,CIFFTAGWIDTH,nameoftag);
1274 if((PRINT_ENTRY))
1275 {
1276 if((PRINT_VALUE))
1277 {
1278 if(PRINT_BOTH_OFFSET)
1279 chpr += printf(" = @%#lx=%lu",entry->offset + fileoffset_base,
1280 entry->offset + fileoffset_base);
1281 else if(PRINT_HEX_OFFSET)
1282 chpr += printf(" = @%#lx",entry->offset + fileoffset_base);
1283 else
1284 chpr += printf(" = @%lu",entry->offset + fileoffset_base);
1285
1286 if(fileoffset_base && (PRINT_ENTRY_RELOFFSET))
1287 chpr += printf(" (%lu)",entry->offset);
1288 }
1289 chpr = newline(chpr);
1290 print_tag_address(ENTRY,0,indent+MEDIUMINDENT,"@");
1291 if((PRINT_TAGINFO))
1292 {
1293 tagwidth = CIFFTAGWIDTH - strlen(nameoftag) - 1;
1294 chpr += printf("%s.%s.%-*.*s",dirname,nameoftag,tagwidth,
1295 tagwidth,"length");
1296 }
1297 if((PRINT_VALUE))
1298 chpr += printf(" = %lu",entry->length);
1299 }
1300 }
1301 max_offset = entry->offset + fileoffset_base + entry->length;
1302 summary_entry->offset = entry->offset + fileoffset_base;
1303 summary_entry->length = entry->length;
1304 summary_entry->subfiletype = PRIMARY_TYPE;
1305 summary_entry->imageformat = IMGFMT_CRW;
1306 summary_entry->compression = is_compressed_crw(inptr,
1307 entry->offset + fileoffset_base,
1308 entry->length);
1309 summary_entry->entry_lock = lock_number(summary_entry);
1310
1311 break;
1312 case CIFFTAG_JPEGIMAGE: /* INHEAP */
1313 if((PRINT_SECTION))
1314 {
1315 print_tag_address(SECTION|ENTRY,entry->offset + fileoffset_base,
1316 indent,"@");
1317 chpr += printf("Start of %s length %lu\n",nameoftag,entry->length);
1318 }
1319 summary_entry = new_summary_entry(summary_entry,JPEG_SOI,JPEG_SOI);
1320 if(summary_entry)
1321 summary_entry->subfiletype = REDUCED_RES_TYPE;
1322 marker = read_ushort(inptr,TIFF_MOTOROLA,entry->offset + fileoffset_base);
1323 max_offset = process_jpeg_segments(inptr,entry->offset + fileoffset_base,
1324 marker, entry->length,summary_entry,fullnameoftag,
1325 "@",indent+MEDIUMINDENT);
1326 if((PRINT_SECTION))
1327 {
1328 if((status = jpeg_status(0) == JPEG_EARLY_EOI))
1329 chpr = newline(chpr);
1330 jpeg_status(status);
1331 print_tag_address(SECTION|ENTRY,entry->offset + fileoffset_base + entry->length - 1,
1332 indent,"@");
1333 chpr += printf("End of %s",nameoftag);
1334 }
1335 else
1336 {
1337 print_tag_address(ENTRY,entry->offset + fileoffset_base,
1338 indent+MEDIUMINDENT,"@");
1339 /* pseudo-tags */
1340 if((PRINT_TAGINFO))
1341 chpr += printf("%s.%-*.*s",dirname,CIFFTAGWIDTH,CIFFTAGWIDTH,nameoftag);
1342 if((PRINT_ENTRY))
1343 {
1344 if((PRINT_VALUE))
1345 {
1346 if(PRINT_BOTH_OFFSET)
1347 chpr += printf(" = @%#lx/%lu",entry->offset + fileoffset_base,
1348 entry->offset + fileoffset_base);
1349 else if(PRINT_HEX_OFFSET)
1350 chpr += printf(" = @%#lx",entry->offset + fileoffset_base);
1351 else
1352 chpr += printf(" = @%lu",entry->offset + fileoffset_base);
1353
1354 if(fileoffset_base && (PRINT_ENTRY_RELOFFSET))
1355 chpr += printf(" (%lu)",entry->offset);
1356 }
1357 chpr = newline(chpr);
1358 print_tag_address(ENTRY,0,indent+MEDIUMINDENT,"@");
1359 if((PRINT_TAGINFO))
1360 {
1361 tagwidth = CIFFTAGWIDTH - strlen(nameoftag) - 1;
1362 chpr += printf("%s.%s.%-*.*s",dirname,nameoftag,tagwidth,
1363 tagwidth,"length");
1364 }
1365 if((PRINT_VALUE))
1366 chpr += printf(" = %lu",entry->length);
1367 }
1368 }
1369 print_jpeg_status();
1370 break;
1371 case CIFFTAG_JPEGTHUMBNAIL: /* INHEAP */
1372 if((PRINT_SECTION))
1373 {
1374 print_tag_address(SECTION|ENTRY,entry->offset + fileoffset_base,
1375 indent,"-");
1376 chpr += printf("Start of %s length %lu\n",nameoftag,entry->length);
1377 }
1378 summary_entry = new_summary_entry(summary_entry,FILEFMT_CIFF,IMGFMT_JPEG);
1379 if(summary_entry)
1380 summary_entry->subfiletype = THUMBNAIL_TYPE;
1381 marker = read_ushort(inptr,TIFF_MOTOROLA,entry->offset + fileoffset_base);
1382 max_offset = process_jpeg_segments(inptr,entry->offset + fileoffset_base,marker,
1383 entry->length,summary_entry,fullnameoftag,
1384 "@",indent+MEDIUMINDENT);
1385 if((PRINT_SECTION))
1386 {
1387 if((status = jpeg_status(0) == JPEG_EARLY_EOI))
1388 chpr = newline(chpr);
1389 jpeg_status(status);
1390 print_tag_address(SECTION|ENTRY,entry->offset + fileoffset_base + entry->length - 1,
1391 indent,"-");
1392 chpr += printf("End of %s",nameoftag);
1393 }
1394 else
1395 {
1396 print_tag_address(ENTRY,entry->offset + fileoffset_base,
1397 indent+MEDIUMINDENT,"@");
1398 /* pseudo-tags */
1399 if((PRINT_TAGINFO))
1400 chpr += printf("%s.%-*.*s",dirname,CIFFTAGWIDTH,CIFFTAGWIDTH,nameoftag);
1401 if((PRINT_ENTRY))
1402 {
1403 if((PRINT_VALUE))
1404 {
1405 if(PRINT_BOTH_OFFSET)
1406 chpr += printf(" = @%#lx/%lu",entry->offset + fileoffset_base,
1407 entry->offset + fileoffset_base);
1408 else if(PRINT_HEX_OFFSET)
1409 chpr += printf(" = @%#lx",entry->offset + fileoffset_base);
1410 else
1411 chpr += printf(" = @%lu",entry->offset + fileoffset_base);
1412
1413 if(fileoffset_base && (PRINT_ENTRY_RELOFFSET))
1414 chpr += printf(" (%lu)",entry->offset);
1415 }
1416 chpr = newline(chpr);
1417 print_tag_address(ENTRY,0,indent+MEDIUMINDENT,"@");
1418 if((PRINT_TAGINFO))
1419 {
1420 tagwidth = CIFFTAGWIDTH - strlen(nameoftag) - 1;
1421 chpr += printf("%s.%s.%-*.*s",dirname,nameoftag,tagwidth,
1422 tagwidth,"length");
1423 }
1424 if((PRINT_VALUE))
1425 chpr += printf(" = %lu",entry->length);
1426 }
1427 }
1428 print_jpeg_status();
1429 break;
1430 case CIFFTAG_IMAGEDESCRIPTION: /* SUBDIR */
1431 endofdir = entry->offset+fileoffset_base+entry->length;
1432 if((PRINT_SECTION))
1433 tagname = fullnameoftag;
1434 max_offset = process_ciff_dir(inptr,entry->offset + fileoffset_base,
1435 endofdir,CNULL,tagname,summary_entry,
1436 byteorder,level+1,indent+MEDIUMINDENT);
1437 break;
1438 case CIFFTAG_CAMERAOBJECT: /* SUBDIR */
1439 endofdir = entry->offset+fileoffset_base+entry->length;
1440 if((PRINT_SECTION))
1441 tagname = fullnameoftag;
1442 max_offset = process_ciff_dir(inptr,entry->offset + fileoffset_base,
1443 endofdir,CNULL,tagname,summary_entry,
1444 byteorder,level+1,indent+MEDIUMINDENT);
1445 break;
1446 case CIFFTAG_SHOOTINGRECORD: /* SUBDIR */
1447 endofdir = entry->offset+fileoffset_base+entry->length;
1448 if((PRINT_SECTION))
1449 tagname = fullnameoftag;
1450 max_offset = process_ciff_dir(inptr,entry->offset + fileoffset_base,
1451 endofdir,CNULL,tagname,summary_entry,
1452 byteorder,level+1,indent+MEDIUMINDENT);
1453 break;
1454 case CIFFTAG_MEASUREDINFO: /* SUBDIR */
1455 endofdir = entry->offset+fileoffset_base+entry->length;
1456 if((PRINT_SECTION))
1457 tagname = fullnameoftag;
1458 max_offset = process_ciff_dir(inptr,entry->offset + fileoffset_base,
1459 endofdir,CNULL,tagname,summary_entry,
1460 byteorder,level+1,indent+MEDIUMINDENT);
1461 break;
1462 case CIFFTAG_CAMERASPECIFICATION: /* SUBDIR */
1463 endofdir = entry->offset+fileoffset_base+entry->length;
1464 if((PRINT_SECTION))
1465 tagname = fullnameoftag;
1466 max_offset = process_ciff_dir(inptr,entry->offset + fileoffset_base,
1467 endofdir,CNULL,tagname,summary_entry,
1468 byteorder,level+1,indent+MEDIUMINDENT);
1469 break;
1470 case CIFFTAG_IMAGEPROPS: /* SUBDIR */
1471 endofdir = entry->offset+fileoffset_base+entry->length;
1472 if((PRINT_SECTION))
1473 tagname = fullnameoftag;
1474 max_offset = process_ciff_dir(inptr,entry->offset + fileoffset_base,
1475 endofdir,CNULL,tagname,summary_entry,
1476 byteorder,level+1,indent);
1477 break;
1478 case CIFFTAG_EXIFINFORMATION: /* SUBDIR */
1479 endofdir = entry->offset+fileoffset_base+entry->length;
1480 if((PRINT_SECTION))
1481 tagname = fullnameoftag;
1482 PUSHCOLOR(EXIF_COLOR);
1483 max_offset = process_ciff_dir(inptr,entry->offset + fileoffset_base,
1484 endofdir,CNULL,tagname,summary_entry,
1485 byteorder,level+1,indent+MEDIUMINDENT);
1486 POPCOLOR();
1487 break;
1488 #if 0
1489 case CIFFTAG_FILENUMBER: break; /* no interp reqd, use default */
1490 case CIFFTAG_DECODERTABLE: break; /* 4 values; unknown, use default */
1491 case CIFFTAG_COMPONENTVERSION: break; /* unknown, use default */
1492 case CIFFTAG_RELEASESETTING: break; /* spec lists but doesn't define */
1493 case CIFFTAG_0X1834: break; /* seen in ExifInformation; unknown, use default */
1494 case CIFFTAG_0x183B: break; /* seen in ExifInformation; unknown, use default */
1495 case CIFFTAG_RECORDID: break; /* no conversion reqd */
1496 #endif
1497 case CIFFTAG_NULLRECORD: /* fall thru to default */
1498 case CIFFTAG_FREEBYTES: /* fall thru to default */
1499 default:
1500 if(location == CIFF_INHEAP)
1501 {
1502 if((PRINT_SECTION))
1503 indent += MEDIUMINDENT;
1504 max_offset = print_ciffinheapdata(inptr,byteorder,dirname,
1505 nameoftag,entry->offset + fileoffset_base,entry->length,
1506 entry->type&CIFF_FORMATMASK,indent);
1507 }
1508 else if(location == CIFF_INREC)
1509 {
1510 if(!(PRINT_SECTION) && (PRINT_TAGINFO))
1511 {
1512 print_tag_address(ENTRY,fileoffset_base + 2,indent+MEDIUMINDENT,"@");
1513 chpr += printf("%-*.*s",entrywidth,entrywidth,tagname);
1514 if(PRINT_VALUE)
1515 chpr += printf(" = ");
1516 }
1517 max_offset = print_ciffinrecdata(inptr,byteorder,tagname,
1518 fileoffset_base + 2,8,entry->type&CIFF_FORMATMASK,
1519 indent+MEDIUMINDENT);
1520 }
1521 else
1522 max_offset = 0;
1523 break;
1524 }
1525 chpr = newline(chpr);
1526 if(fullnameoftag)
1527 free(fullnameoftag);
1528 if(nameoftag)
1529 free(nameoftag);
1530 fullnameoftag = nameoftag = CNULL;
1531 }
1532 }
1533 return(max_offset);
1534 }
1535
1536 /* This checks for compression in "raw" CRW files in the manner */
1537 /* suggested by Dave Coffin's "dcraw" program. The ImageInfo data */
1538 /* doesn't seem to say. */
1539 /* A return value of 0 indicates uncompressed data. A return value of */
1540 /* 1 indicates compressed. */
1541
1542 int
is_compressed_crw(FILE * inptr,unsigned long start_offset,unsigned long imagelength)1543 is_compressed_crw(FILE *inptr,unsigned long start_offset,unsigned long imagelength)
1544 {
1545 int is_compressed = 0;
1546 int maxcheck = 16384; /* 0x4000 */
1547 int count = 0;
1548 int ch,lastch;
1549
1550 if((inptr) && (fseek(inptr,start_offset + 512,0) != -1))
1551 {
1552 if(imagelength < maxcheck)
1553 maxcheck = imagelength;
1554 lastch = 0;
1555 while(((ch = fgetc(inptr)) != EOF) && (count++ < maxcheck))
1556 {
1557 if(lastch == 0xff)
1558 {
1559 is_compressed = 1;
1560 if(ch)
1561 {
1562 is_compressed = 0;
1563 break;
1564 }
1565 }
1566 lastch = ch;
1567 }
1568 }
1569 return(is_compressed);
1570 }
1571
1572 /* Print CIFF header information if options permit. Return 0 if */
1573 /* information is valid to print, or -1 if the header is invalid */
1574
1575 int
print_ciff_header(struct fileheader * header,unsigned long section_id)1576 print_ciff_header(struct fileheader *header,unsigned long section_id)
1577 {
1578 struct ciff_header *ciffheader = NULL;
1579 unsigned short byteorder = 0;
1580 int status = -1;
1581 int chpr = 0;
1582
1583 if(header)
1584 {
1585 byteorder = header->file_marker;
1586 if(header->ciff_header)
1587 {
1588 ciffheader = header->ciff_header;
1589 if(header->probe_magic == PROBE_CIFFMAGIC)
1590 {
1591 if(Print_options & section_id)
1592 chpr += printf("CIFF");
1593 switch(byteorder)
1594 {
1595 case TIFF_INTEL:
1596 case TIFF_MOTOROLA:
1597 if(Print_options & section_id)
1598 {
1599 print_byteorder(byteorder,1);
1600 chpr += printf(" \"%s%s\", version %#lx, heap offset = %#lx/%lu",
1601 ciffheader->type,ciffheader->subtype,
1602 ciffheader->version,ciffheader->headerlength,
1603 ciffheader->headerlength);
1604 }
1605 status = 0;
1606 break;
1607 default:
1608 if(Print_options & section_id)
1609 chpr += printf("INVALID CIFF BYTEORDER ");
1610 print_byteorder(byteorder,1);
1611 chpr += printf(" (CIFF type \"%s%s\")",ciffheader->type,
1612 ciffheader->subtype);
1613 break;
1614 }
1615 }
1616 else if(Print_options & section_id)
1617 {
1618 chpr += printf("INVALID CIFF IDENTIFIER ");
1619 print_magic(header->probe_magic,4);
1620 chpr += printf(" byteorder ");
1621 print_byteorder(byteorder,1);
1622 }
1623 }
1624 else
1625 fprintf(stderr,"%s: null ciffheader to print_ciff_header()\n",Progname);
1626 }
1627 else
1628 fprintf(stderr,"%s: null fileheader to print_ciff_header()\n",Progname);
1629 chpr = newline(chpr);
1630 return(status);
1631 }
1632
1633 struct ciff_header *
read_ciffheader(FILE * inptr,unsigned short byteorder,unsigned long offset)1634 read_ciffheader(FILE *inptr,unsigned short byteorder,unsigned long offset)
1635 {
1636 static struct ciff_header header;
1637 struct ciff_header *headerptr = NULL;
1638 unsigned char *string;
1639
1640 memset(&header,0,sizeof(struct ciff_header));
1641 if(inptr)
1642 {
1643 header.byteorder = read_ushort(inptr,byteorder,offset);
1644 header.headerlength = read_ulong(inptr,byteorder,HERE);
1645 string = read_bytes(inptr,4,HERE);
1646 if(string)
1647 {
1648 strncpy(header.type,(char *)string,4);
1649 string = read_bytes(inptr,4,HERE);
1650 if(string)
1651 strncpy(header.subtype,(char *)string,4);
1652 }
1653 header.version = read_ulong(inptr,byteorder,HERE);
1654 header.reserved1 = read_ulong(inptr,byteorder,HERE);
1655 header.reserved2 = read_ulong(inptr,byteorder,HERE);
1656 if((header.byteorder == byteorder) &&
1657 (strncmp(header.type,"HEAP",4) == 0) &&
1658 (header.headerlength > 0))
1659 {
1660 headerptr = &header;
1661 }
1662 }
1663 return(headerptr);
1664 }
1665
1666
1667 struct ciff_direntry *
read_ciff_direntry(FILE * inptr,struct ciff_direntry * entry,unsigned short byteorder,unsigned long offset)1668 read_ciff_direntry(FILE *inptr,struct ciff_direntry *entry,unsigned short byteorder,unsigned long offset)
1669 {
1670 if(inptr)
1671 {
1672 if(entry == NULL)
1673 entry = (struct ciff_direntry *)malloc(sizeof(struct ciff_direntry));
1674 if(entry)
1675 {
1676 memset(entry,0,sizeof(struct ciff_direntry));
1677 entry->type = read_ushort(inptr,byteorder,offset);
1678 entry->length = read_ulong(inptr,byteorder,offset + 2);
1679 entry->offset = read_ulong(inptr,byteorder,offset + 6);
1680 }
1681 }
1682 return(entry);
1683 }
1684