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(&timestamp);
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