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: x3f.c,v 1.7 2005/07/24 20:31:30 alex Exp $";
11 #endif
12 
13 /* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- */
14 /* Sigma/FOVEON x3f routines                                          */
15 /* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- */
16 /* See http://www.sd9.org.uk/X3F_Format.pdf                           */
17 /* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- */
18 
19 #include <stdio.h>
20 #include <string.h>
21 #include <stdlib.h>
22 #include <time.h>
23 
24 #include "defs.h"
25 #include "datadefs.h"
26 #include "summary.h"
27 #include "maker.h"
28 #include "misc.h"
29 #include "tags.h"
30 #include "extern.h"
31 #include "x3f.h"
32 #include "maker_extern.h"
33 
34 /* Read and record the X3F file header                                */
35 
36 struct x3f_header *
read_x3fheader(FILE * inptr,unsigned long offset)37 read_x3fheader(FILE *inptr,unsigned long offset)
38 {
39     static struct x3f_header header;
40     struct x3f_header *headerptr = NULL;
41     unsigned long xmagic;
42     unsigned char *bytearray;
43 
44     memset(&header,0,sizeof(struct x3f_header));
45     if(inptr)
46     {
47         xmagic = read_ulong(inptr,TIFF_INTEL,offset);
48         if(xmagic == PROBE_X3FMAGIC)
49         {
50             header.magic = xmagic;
51             header.version_major = read_ushort(inptr,TIFF_INTEL,HERE);
52             header.version_minor = read_ushort(inptr,TIFF_INTEL,HERE);
53             bytearray = read_bytes(inptr,16,HERE);
54             if(bytearray)
55                 memcpy(header.unique_id,bytearray,16);
56             header.mark_bits = read_ulong(inptr,TIFF_INTEL,HERE);
57             header.image_width = read_ulong(inptr,TIFF_INTEL,HERE);
58             header.image_height = read_ulong(inptr,TIFF_INTEL,HERE);
59             header.image_rotation = read_ulong(inptr,TIFF_INTEL,HERE);
60             if(header.version_minor >= 1)
61             {
62                 /* this is a string, e.g. "AUTO\0"                    */
63                 bytearray = read_bytes(inptr,32,HERE);
64                 if(bytearray)
65                     memcpy(header.white_balance,bytearray,32);
66                 bytearray = read_bytes(inptr,32,HERE);
67                 if(bytearray)
68                     memcpy(header.extended_data_types,bytearray,32);
69                 bytearray = read_bytes(inptr,128,HERE);
70                 if(bytearray)
71                     memcpy(header.extended_data_values,bytearray,128);
72             }
73             headerptr = &header;
74         }
75     }
76     return(headerptr);
77 }
78 
79 
80 /* Print X3f header information if options permit. Return 0 if       */
81 /* information is valid to print, or -1 if the header is invalid      */
82 
83 int
print_x3f_header(FILE * inptr,struct fileheader * header,unsigned long section_id)84 print_x3f_header(FILE *inptr,struct fileheader *header,unsigned long section_id)
85 {
86     struct x3f_header *x3fheader = NULL;
87     int status = -1;
88     int chpr = 0;
89     int i;
90 
91     if(header)
92     {
93         if(header->x3f_header)
94         {
95             x3fheader = header->x3f_header;
96             if(header->probe_magic == PROBE_X3FMAGIC)
97             {
98                 if(Print_options & section_id)
99                 {
100                     chpr += printf("%4.4s (%#06lx) version %2u.%-2u, id ",
101                                             (char *)&(x3fheader->magic),
102                                                     x3fheader->magic,
103                                                     x3fheader->version_major,
104                                                     x3fheader->version_minor);
105                     chpr += printf("%#02x ",x3fheader->unique_id[0] & 0xff);
106                     for(i = 0; i < 16; ++i)
107                         chpr += printf("%02x ",x3fheader->unique_id[i] & 0xff);
108                     chpr = newline(chpr);
109                     if(x3fheader->version_minor >= 1)
110                     {
111                         print_tag_address(ENTRY,24,MEDIUMINDENT,"@");
112                         if((PRINT_TAGINFO))
113                         {
114                             if((PRINT_LONGNAMES))
115                                 chpr += printf("X3f.Header.");
116                             chpr += printf("MarkBits");
117                             if((PRINT_VALUE))
118                             {
119                                 putindent(X3FTAGWIDTH - 8);
120                                 chpr += printf(" = ");
121                             }
122                         }
123                         if((PRINT_VALUE))
124                             chpr += printf("%#06lx",x3fheader->mark_bits);
125                         chpr = newline(chpr);
126                     }
127                     print_tag_address(ENTRY,28,MEDIUMINDENT,"@");
128                     if((PRINT_TAGINFO))
129                     {
130                         if((PRINT_LONGNAMES))
131                             chpr += printf("X3f.Header.");
132                         chpr += printf("ImageWidth");
133                         if((PRINT_VALUE))
134                         {
135                             putindent(X3FTAGWIDTH - 10);
136                             chpr += printf(" = ");
137                         }
138                     }
139                     if((PRINT_VALUE))
140                         chpr += printf("%lu",x3fheader->image_width);
141                     chpr = newline(chpr);
142                     print_tag_address(ENTRY,32,MEDIUMINDENT,"@");
143                     if((PRINT_TAGINFO))
144                     {
145                         if((PRINT_LONGNAMES))
146                             chpr += printf("X3f.Header.");
147                         chpr += printf("ImageHeight");
148                         if((PRINT_VALUE))
149                         {
150                             putindent(X3FTAGWIDTH - 11);
151                             chpr += printf(" = ");
152                         }
153                     }
154                     if((PRINT_VALUE))
155                         chpr += printf("%lu",x3fheader->image_height);
156                     chpr = newline(chpr);
157                     print_tag_address(ENTRY,36,MEDIUMINDENT,"@");
158                     if((PRINT_TAGINFO))
159                     {
160                         if((PRINT_LONGNAMES))
161                             chpr += printf("X3f.Header.");
162                         chpr += printf("ImageRotation");
163                         if((PRINT_VALUE))
164                         {
165                             putindent(X3FTAGWIDTH - 13);
166                             chpr += printf(" = ");
167                         }
168                     }
169                     if((PRINT_VALUE))
170                         chpr += printf("%lu",x3fheader->image_rotation);
171                     chpr = newline(chpr);
172                     if(x3fheader->version_minor >= 1)
173                     {
174                         print_tag_address(ENTRY,40,MEDIUMINDENT,"@");
175                         if((PRINT_TAGINFO))
176                         {
177                             if((PRINT_LONGNAMES))
178                                 chpr += printf("X3f.Header.");
179                             chpr += printf("WhiteBalance");
180                             if((PRINT_VALUE))
181                             {
182                                 putindent(X3FTAGWIDTH - 12);
183                                 chpr += printf(" = ");
184                             }
185                         }
186                         if((PRINT_VALUE))
187                             show_string(x3fheader->white_balance,32,0);
188                         chpr = newline(chpr);
189                         print_tag_address(ENTRY,72,MEDIUMINDENT,"@");
190                         if((PRINT_TAGINFO))
191                         {
192                             if((PRINT_LONGNAMES))
193                                 chpr += printf("X3f.Header.");
194                             chpr += printf("ExtendedDataTypes");
195                             if((PRINT_VALUE))
196                             {
197                                 putindent(X3FTAGWIDTH - 17);
198                                 chpr += printf(" = ");
199                             }
200                         }
201                         if((PRINT_VALUE))
202                             print_ubytes(inptr,32,72);
203                         chpr = newline(chpr);
204                         print_tag_address(ENTRY,104,MEDIUMINDENT,"@");
205                         if((PRINT_TAGINFO))
206                         {
207                             if((PRINT_LONGNAMES))
208                                 chpr += printf("X3f.Header.");
209                             chpr += printf("ExtendedDataValues");
210                             if((PRINT_VALUE))
211                             {
212                                 putindent(X3FTAGWIDTH - 19);
213                                 chpr += printf(" = ");
214                             }
215                         }
216                         if((PRINT_VALUE))
217                             print_ulong(inptr,32,TIFF_INTEL,104);
218                         chpr = newline(chpr);
219                     }
220                     print_tag_address(SECTION,104 + 128 - 1,0,"@");
221                     chpr += printf("</END OF HEADER>");
222                     chpr = newline(chpr);
223                 }
224                 status = 0;
225             }
226             else if(Print_options & section_id)
227             {
228                     chpr += printf("INVALID X3F IDENTIFIER ");
229                     print_magic(header->probe_magic,4);
230             }
231         }
232         else
233             fprintf(stderr,"%s: null x3fheader to print_x3f_header()\n",Progname);
234     }
235     else
236         fprintf(stderr,"%s: null fileheader to print_x3f_header()\n",Progname);
237     chpr = newline(chpr);
238     return(status);
239 }
240 
241 /* Process the remainder of an X3F file, after the header has been    */
242 /* read and validated. Returns the maximum offset reached in          */
243 /* processing, which is normally end of file.                         */
244 
245 unsigned long
process_x3f(FILE * inptr,struct fileheader * header,unsigned long fileoffset_base,struct image_summary * summary_entry,char * parent_name,int level,int indent)246 process_x3f(FILE *inptr,struct fileheader *header,unsigned long fileoffset_base,
247                                         struct image_summary *summary_entry,
248                                         char *parent_name,int level,int indent)
249 {
250     struct x3f_header *x3fheader;
251     unsigned long max_offset = 0UL;
252     unsigned short byteorder = 0;
253     unsigned long directory_pointer = 0UL;
254 
255     if(inptr)
256     {
257         if(header)
258         {
259             if(header->x3f_header)
260             {
261                 x3fheader = header->x3f_header;
262                 /* X3F is always little-endian; nonetheless, pass it  */
263                 /* as an argument to lower-level functions. Just set  */
264                 /* it here.                                           */
265                 byteorder = TIFF_INTEL;
266                 if(fseek(inptr,-4L,2) == 0)
267                     directory_pointer = ftell(inptr);
268                 if(ferror(inptr) == 0)
269                 {
270                     max_offset = process_x3f_dir(inptr,byteorder,x3fheader,
271                                                     directory_pointer,summary_entry,
272                                                     parent_name,level,indent);
273                     if(max_offset > 0L)
274                         max_offset += 4;
275                 }
276                 else
277                     fprintf(stderr,"%s: cannot read directory offset\n",Progname);
278             }
279             else
280                 fprintf(stderr,"%s: null x3fheader to process_x3f()\n",Progname);
281         }
282         else
283             fprintf(stderr,"%s: null fileheader to process_x3f()\n",Progname);
284     }
285     else
286         fprintf(stderr,"%s: no open file pointer to read Print Image data\n",
287                                                                         Progname);
288 
289     return(max_offset);
290 }
291 
292 /* Find the directory at the end of the file and process it. Report   */
293 /* the detail data first, then show the directory itself.             */
294 
295 unsigned long
process_x3f_dir(FILE * inptr,unsigned short byteorder,struct x3f_header * x3fheader,unsigned long directory_pointer,struct image_summary * summary_entry,char * parent_name,int level,int indent)296 process_x3f_dir(FILE *inptr,unsigned short byteorder,struct x3f_header *x3fheader,
297                                                 unsigned long directory_pointer,
298                                                 struct image_summary *summary_entry,
299                                                 char *parent_name,int level,int indent)
300 {
301     struct x3f_direntry *entry;
302     unsigned long directory_offset = 0UL;
303     unsigned long section_id;
304     unsigned long max_dir_offset = 0L;
305     unsigned long entry_offset,next_entry_offset;
306     unsigned long num_entries;
307     unsigned short version_major;
308     unsigned short version_minor;
309     int i;
310     int chpr = 0;
311 
312     directory_offset = read_ulong(inptr,byteorder,directory_pointer);
313 
314     section_id = read_ulong(inptr,byteorder,directory_offset);
315     version_minor = read_ushort(inptr,byteorder,HERE);
316     version_major = read_ushort(inptr,byteorder,HERE);
317     num_entries = read_ulong(inptr,byteorder,HERE);
318     entry = NULL;
319 
320     entry_offset = ftell(inptr);
321 
322     /* Print the entries first, in order                              */
323     for(i = 0; i < num_entries; ++i)
324     {
325         entry = read_x3f_direntry(inptr,byteorder,entry,entry_offset);
326         if(ferror(inptr))
327         {
328             fprintf(stderr,"%s: error reading directory entry at %lu\n",
329                                                 Progname,entry_offset);
330             break;
331         }
332         if(entry == NULL)
333         {
334             fprintf(stderr,"%s: null entry %d\n",Progname,i);
335             break;
336         }
337         next_entry_offset = ftell(inptr);
338         process_x3f_direntry(inptr,byteorder,entry,entry_offset,
339                                             summary_entry,parent_name,i,indent);
340         entry_offset = next_entry_offset;
341     }
342     chpr = newline(chpr);
343 
344     /* Now show the directory itself                                  */
345 
346     if((PRINT_SECTION))
347     {
348         print_tag_address(SECTION,directory_offset,indent,"@");
349         chpr += printf("<DIRECTORY> version %d.%d id \"%4.4s\", %lu entries",
350                                             version_major,version_minor,
351                                             (char *)&section_id,num_entries);
352     }
353     chpr = newline(chpr);
354     entry_offset = directory_offset + 12;
355     for(i = 0; i < num_entries; ++i)
356     {
357         entry = read_x3f_direntry(inptr,byteorder,entry,entry_offset);
358         if(ferror(inptr))
359         {
360             fprintf(stderr,"%s: error reading directory entry at %lu\n",
361                                                 Progname,entry_offset);
362             break;
363         }
364         if(entry == NULL)
365         {
366             fprintf(stderr,"%s: null entry %d\n",Progname,i);
367             break;
368         }
369         next_entry_offset = ftell(inptr);
370         print_x3f_direntry(inptr,entry,entry_offset,
371                                     parent_name,i,indent);
372         entry_offset = next_entry_offset;
373     }
374     max_dir_offset = ftell(inptr);
375     if((PRINT_SECTION))
376     {
377         print_tag_address(SECTION,max_dir_offset - 1,indent,"@");
378         chpr += printf("</DIRECTORY>");
379         chpr = newline(chpr);
380     }
381 
382     print_tag_address(ENTRY,directory_pointer,indent,"@");
383     if((PRINT_TAGINFO))
384     {
385         if((PRINT_LONGNAMES))
386             chpr += printf("%s.",parent_name);
387         chpr += printf("%s","DirectoryOffset");
388         if((PRINT_VALUE))
389         {
390             putindent(X3FTAGWIDTH - 15);
391             chpr += printf(" = ");
392         }
393     }
394     if((PRINT_VALUE))
395     {
396         if(PRINT_BOTH_OFFSET)
397             chpr += printf("@%#lx=%lu",directory_offset,directory_offset);
398         else if(PRINT_HEX_OFFSET)
399             chpr += printf("@%#lx",directory_offset);
400         else
401             chpr += printf("@%lu",directory_offset);
402     }
403     chpr = newline(chpr);
404 
405     if(entry)
406         free(entry);
407     return(max_dir_offset);
408 }
409 
410 /* Process a directory entry, representing one section of the file.   */
411 /* An entry number is added to the section id, so that sections with  */
412 /* the same name (e.g. IMGA) can be identified, especially in LIST    */
413 /* mode.                                                              */
414 
415 void
process_x3f_direntry(FILE * inptr,unsigned short byteorder,struct x3f_direntry * entry,unsigned long offset,struct image_summary * summary_entry,char * parent_name,int entry_num,int indent)416 process_x3f_direntry(FILE *inptr,unsigned short byteorder,struct x3f_direntry *entry,
417                             unsigned long offset,struct image_summary *summary_entry,
418                             char *parent_name,int entry_num,int indent)
419 {
420     struct x3f_imag_header *imag_header;
421     struct x3f_prop_header *prop_header;
422     struct x3f_camf_header *camf_header;
423     unsigned long data_offset = 0UL;
424     unsigned long data_length = 0UL;
425     char *dirname = CNULL;
426     int chpr = 0;
427 
428     if(entry)
429     {
430         if((PRINT_SECTION))
431         {
432             print_tag_address(SECTION,entry->data_offset,indent,"@");
433             chpr += printf("<%4.4s:%d> (%#06lx)",(char *)&entry->data_type,entry_num,entry->data_type);
434             chpr += printf(" length %lu",entry->data_length);
435             chpr = newline(chpr);
436         }
437         switch(entry->data_type)
438         {
439             case X3F_IMAG:
440                 dirname = splice(parent_name,".","IMAG");
441                 imag_header = read_x3f_imag_header(inptr,byteorder,entry->data_offset);
442                 data_offset = display_x3f_imag_header(entry,imag_header,dirname,entry_num,
443                                                                     indent + MEDIUMINDENT);
444                 data_length = entry->data_length - (data_offset - entry->data_offset);
445                 if((summary_entry == NULL) || summary_entry->entry_lock)
446                     summary_entry = new_summary_entry(summary_entry,FILEFMT_X3F,IMGFMT_X3F);
447                 if(summary_entry)
448                 {
449                     switch(imag_header->image_type)
450                     {
451                         case 2:
452                             summary_entry->subfiletype = REDUCED_RES_TYPE;
453                             break;
454                         case 3:
455                             /* observed; spec doesn't say             */
456                             summary_entry->subfiletype = PRIMARY_TYPE;
457                             break;
458                         default:
459                             /* assume this; spec doesn't say          */
460                             summary_entry->subfiletype = REDUCED_RES_TYPE;
461                             break;
462                     }
463                     switch(imag_header->image_format)
464                     {
465                         case 3:
466                             summary_entry->imagesubformat = IMGSUBFMT_RGB;
467                             break;
468                         case 11:
469                             summary_entry->imagesubformat = IMGSUBFMT_HUFF_COMPRESSED_RGB;
470                             break;
471                         case 18:
472                             summary_entry->imagesubformat = IMGSUBFMT_JPEG_COMPRESSED_RGB;
473                             break;
474                         case 6:
475                             summary_entry->imagesubformat = IMGSUBFMT_X3F_COMPRESSED;
476                             break;
477                         default:
478                             summary_entry->imagesubformat = IMGSUBFMT_X3F_UNSPECIFIED;
479                             break;
480                     }
481                     summary_entry->imageformat = IMGFMT_X3F;
482                     summary_entry->pixel_width = imag_header->image_width;
483                     summary_entry->pixel_height = imag_header->image_height;
484                     summary_entry->offset = data_offset;
485                     summary_entry->length = data_length;
486                     summary_entry->entry_lock = lock_number(summary_entry);
487 
488                 }
489                 if((PRINT_SECTION))
490                 {
491                     print_tag_address(SECTION,data_offset,indent + MEDIUMINDENT,"@");
492                     chpr += printf("<IMAG.Data> length %lu",data_length);
493                     chpr = newline(chpr);
494                     dumpsection(inptr,data_offset,data_length,indent + LARGEINDENT);
495                     print_tag_address(SECTION,entry->data_offset + entry->data_length - 1,
496                                                                 indent + MEDIUMINDENT,"@");
497                     chpr += printf("</IMAG.Data>");
498                 }
499                 else if((LIST_MODE))
500                 {
501                     print_tag_address(ENTRY,data_offset,indent + MEDIUMINDENT,"@");
502                     if((PRINT_TAGINFO))
503                     {
504                         if((PRINT_LONGNAMES))
505                             chpr += printf("%s:%d.",dirname,entry_num);
506                         else
507                             chpr += printf("IMAG:%d.",entry_num);
508                         chpr += printf("Data");
509                         if((PRINT_VALUE))
510                         {
511                             putindent(X3FTAGWIDTH - 7);
512                             chpr += printf(" = ");
513                         }
514                     }
515                     if((PRINT_VALUE))
516                         chpr += printf("@%lu:%lu",data_offset,data_length);
517                 }
518                 chpr = newline(chpr);
519                 break;
520             case X3F_IMA2:
521                 dirname = splice(parent_name,".","IMA2");
522                 imag_header = read_x3f_imag_header(inptr,byteorder,entry->data_offset);
523                 data_offset = display_x3f_imag_header(entry,imag_header,dirname,entry_num,
524                                                                     indent + MEDIUMINDENT);
525                 data_length = entry->data_length - (data_offset - entry->data_offset);
526                 if((summary_entry == NULL) || summary_entry->entry_lock)
527                     summary_entry = new_summary_entry(summary_entry,FILEFMT_X3F,IMGFMT_X3F);
528                 if(summary_entry)
529                 {
530                     switch(imag_header->image_type)
531                     {
532                         case 2:
533                             summary_entry->subfiletype = REDUCED_RES_TYPE;
534                             break;
535                         case 3:
536                             /* observed; spec doesn't say             */
537                             summary_entry->subfiletype = PRIMARY_TYPE;
538                             break;
539                         default:
540                             /* assume this; spec doesn't say          */
541                             summary_entry->subfiletype = REDUCED_RES_TYPE;
542                             break;
543                     }
544                     switch(imag_header->image_format)
545                     {
546                         case 3:
547                             summary_entry->imagesubformat = IMGSUBFMT_RGB;
548                             break;
549                         case 11:
550                             summary_entry->imagesubformat = IMGSUBFMT_HUFF_COMPRESSED_RGB;
551                             break;
552                         case 18:
553                             summary_entry->imagesubformat = IMGSUBFMT_JPEG_COMPRESSED_RGB;
554                             break;
555                         case 6:
556                             /* No idea how "raw" this is, or how it's */
557                             /* compressed/encoded                     */
558                             summary_entry->imagesubformat = IMGSUBFMT_X3F_COMPRESSED;
559                             break;
560                         default:
561                             summary_entry->imagesubformat = IMGSUBFMT_X3F_UNSPECIFIED;
562                             break;
563                     }
564                     summary_entry->imageformat = IMGFMT_X3F;
565                     summary_entry->pixel_width = imag_header->image_width;
566                     summary_entry->pixel_height = imag_header->image_height;
567                     summary_entry->offset = data_offset;
568                     summary_entry->length = data_length;
569                     summary_entry->entry_lock = lock_number(summary_entry);
570 
571                 }
572                 if((PRINT_SECTION))
573                 {
574                     print_tag_address(SECTION,data_offset,indent + MEDIUMINDENT,"@");
575                     chpr += printf("<IMA2.Data> length %lu",data_length);
576                     chpr = newline(chpr);
577                     dumpsection(inptr,data_offset,data_length,indent + LARGEINDENT);
578                     print_tag_address(SECTION,entry->data_offset + entry->data_length - 1,
579                                                                 indent + MEDIUMINDENT,"@");
580                     chpr += printf("</IMA2.Data>");
581                 }
582                 else if((LIST_MODE))
583                 {
584                     print_tag_address(ENTRY,data_offset,indent + MEDIUMINDENT,"@");
585                     if((PRINT_TAGINFO))
586                     {
587                         if((PRINT_LONGNAMES))
588                             chpr += printf("%s:%d.",dirname,entry_num);
589                         else
590                             chpr += printf("IMA2:%d.",entry_num);
591                         chpr += printf("Data");
592                         if((PRINT_VALUE))
593                         {
594                             putindent(X3FTAGWIDTH - 7);
595                             chpr += printf(" = ");
596                         }
597                     }
598                     if((PRINT_VALUE))
599                         chpr += printf("@%lu:%lu",data_offset,data_length);
600                 }
601                 chpr = newline(chpr);
602                 break;
603             case X3F_PROP:
604                 dirname = splice(parent_name,".","PROP");
605                 prop_header = read_x3f_prop_header(inptr,byteorder,entry->data_offset);
606                 data_offset = display_x3f_prop_header(entry,prop_header,dirname,entry_num,
607                                                                     indent + MEDIUMINDENT);
608                 data_length = entry->data_length - (data_offset - entry->data_offset);
609                 process_x3f_props(inptr,byteorder,data_offset,data_length,
610                                                 prop_header->char_format,dirname,
611                                                 prop_header->num_entries,
612                                                 indent + MEDIUMINDENT);
613                 break;
614             case X3F_CAMF:
615                 dirname = splice(parent_name,".","CAMF");
616                 camf_header = read_x3f_camf_header(inptr,byteorder,entry->data_offset);
617                 data_offset = display_x3f_camf_header(entry,camf_header,dirname,entry_num,
618                                                                     indent + MEDIUMINDENT);
619                 data_length = entry->data_length - (data_offset - entry->data_offset);
620                 if((PRINT_SECTION))
621                 {
622                     print_tag_address(SECTION,data_offset,indent + MEDIUMINDENT,"@");
623                     chpr += printf("<CAMF.Data> length %lu",data_length);
624                     chpr = newline(chpr);
625                     dumpsection(inptr,data_offset,data_length,indent + LARGEINDENT);
626                     print_tag_address(SECTION,entry->data_offset + entry->data_length - 1,
627                                                                 indent + MEDIUMINDENT,"@");
628                     chpr += printf("</CAMF.Data>");
629                 }
630                 else if((LIST_MODE))
631                 {
632                     print_tag_address(ENTRY,data_offset,indent + MEDIUMINDENT,"@");
633                     if((PRINT_TAGINFO))
634                     {
635                         if((PRINT_LONGNAMES))
636                             chpr += printf("%s:%d.",dirname,entry_num);
637                         else
638                             chpr += printf("CAMF:%d.",entry_num);
639                         chpr += printf("Data");
640                         if((PRINT_VALUE))
641                         {
642                             putindent(X3FTAGWIDTH - 7);
643                             chpr += printf(" = ");
644                         }
645                     }
646                     if((PRINT_VALUE))
647                         chpr += printf("@%lu:%lu",data_offset,data_length);
648                 }
649                 chpr = newline(chpr);
650                 break;
651             default:
652                 if((PRINT_SECTION))
653                 {
654                     print_tag_address(SECTION,entry->data_offset,indent + MEDIUMINDENT,"@");
655                     chpr += printf("<%4.4s> length %lu",(char *)&entry->section_id,entry->data_length);
656                     chpr = newline(chpr);
657                     dumpsection(inptr,data_offset,data_length,indent + LARGEINDENT);
658                     print_tag_address(SECTION,entry->data_offset + entry->data_length - 1,
659                                                                 indent + MEDIUMINDENT,"@");
660                     chpr += printf("</%4.4s>",(char *)&entry->section_id);
661                 }
662                 else if((LIST_MODE))
663                 {
664                     print_tag_address(ENTRY,data_offset,indent,"@");
665                     if((PRINT_TAGINFO))
666                     {
667                         if((PRINT_LONGNAMES))
668                             chpr += printf("%s:%d.",dirname,entry_num);
669                         else
670                             chpr += printf("%4.4s:%d.",(char *)&entry->section_id,entry_num);
671                         if((PRINT_VALUE))
672                         {
673                             putindent(X3FTAGWIDTH - 7);
674                             chpr += printf(" = ");
675                         }
676                     }
677                     if((PRINT_VALUE))
678                         chpr += printf("@%lu:%lu",entry->data_offset,entry->data_length);
679                 }
680                 chpr = newline(chpr);
681                 break;
682         }
683         if((PRINT_SECTION))
684         {
685             print_tag_address(SECTION,entry->data_offset + entry->data_length - 1,indent,"@");
686             chpr += printf("</%4.4s:%d>",(char *)&entry->data_type,entry_num);
687             chpr += newline(chpr);
688         }
689         if(dirname)
690             free(dirname);
691     }
692 }
693 
694 void
print_x3f_direntry(FILE * inptr,struct x3f_direntry * entry,unsigned long offset,char * parent_name,int entry_num,int indent)695 print_x3f_direntry(FILE *inptr,struct x3f_direntry *entry,unsigned long offset,
696                                         char *parent_name,int entry_num,int indent)
697 {
698     int chpr = 0;
699 
700     if(entry)
701     {
702         print_tag_address(ENTRY,offset,indent + MEDIUMINDENT,"@");
703         if((PRINT_TAGINFO))
704         {
705             if((PRINT_LONGNAMES))
706                 chpr += printf("%s.",parent_name);
707             chpr += printf("%4.4s:%-2d",(char *)&entry->data_type,entry_num);
708             if((PRINT_VALUE))
709                 putindent(X3FTAGWIDTH - 7);
710         }
711         if((PRINT_VALUE))
712         {
713             chpr += printf(" = ");
714             chpr += printf("@%lu:%lu",entry->data_offset,entry->data_length);
715         }
716         chpr += newline(chpr);
717     }
718 }
719 
720 
721 struct x3f_direntry *
read_x3f_direntry(FILE * inptr,unsigned short byteorder,struct x3f_direntry * entry,unsigned long offset)722 read_x3f_direntry(FILE *inptr,unsigned short byteorder,struct x3f_direntry *entry,
723                                                             unsigned long offset)
724 {
725     if(inptr)
726     {
727         if(entry == NULL)
728             entry = (struct x3f_direntry *)malloc(sizeof(struct x3f_direntry));
729         if(entry)
730         {
731             memset(entry,0,sizeof(struct x3f_direntry));
732             entry->data_offset = read_ulong(inptr,byteorder,offset);
733             entry->data_length = read_ulong(inptr,byteorder,HERE);
734             entry->data_type = read_ulong(inptr,byteorder,HERE);
735         }
736     }
737     else
738         entry = (struct x3f_direntry *)0;
739     return(entry);
740 }
741 
742 struct x3f_imag_header *
read_x3f_imag_header(FILE * inptr,unsigned short byteorder,unsigned long offset)743 read_x3f_imag_header(FILE *inptr,unsigned short byteorder,unsigned long offset)
744 {
745     static struct x3f_imag_header header;
746     struct x3f_imag_header *headerptr= (struct x3f_imag_header *)0;
747 
748     if(!feof(inptr) && !ferror(inptr))
749     {
750         header.section_id = read_ulong(inptr,byteorder,offset);
751         header.version_minor = read_ushort(inptr,byteorder,HERE);
752         header.version_major = read_ushort(inptr,byteorder,HERE);
753         header.image_type = read_ulong(inptr,byteorder,HERE);
754         header.image_format = read_ulong(inptr,byteorder,HERE);
755         header.image_width = read_ulong(inptr,byteorder,HERE);
756         header.image_height = read_ulong(inptr,byteorder,HERE);
757         header.image_rowsize = read_ulong(inptr,byteorder,HERE);
758             if(!feof(inptr) && !ferror(inptr))
759                 headerptr = &header;
760     }
761     return(headerptr);
762 }
763 
764 struct x3f_camf_header *
read_x3f_camf_header(FILE * inptr,unsigned short byteorder,unsigned long offset)765 read_x3f_camf_header(FILE *inptr,unsigned short byteorder,unsigned long offset)
766 {
767     static struct x3f_camf_header header;
768     struct x3f_camf_header *headerptr = (struct x3f_camf_header *)0;
769 
770     if(!feof(inptr) && !ferror(inptr))
771     {
772         header.section_id = read_ulong(inptr,byteorder,offset);
773         header.version_minor = read_ushort(inptr,byteorder,HERE);
774         header.version_major = read_ushort(inptr,byteorder,HERE);
775         header.item1 = read_ulong(inptr,byteorder,HERE);
776         header.item2 = read_ulong(inptr,byteorder,HERE);
777         header.item3 = read_ulong(inptr,byteorder,HERE);
778         header.item4 = read_ulong(inptr,byteorder,HERE);
779         header.item5 = read_ulong(inptr,byteorder,HERE);
780         if(!feof(inptr) && !ferror(inptr))
781             headerptr = &header;
782     }
783     return(headerptr);
784 }
785 
786 struct x3f_prop_header *
read_x3f_prop_header(FILE * inptr,unsigned short byteorder,unsigned long offset)787 read_x3f_prop_header(FILE *inptr,unsigned short byteorder,unsigned long offset)
788 {
789     static struct x3f_prop_header header;
790     struct x3f_prop_header *headerptr = (struct x3f_prop_header *)0;
791 
792     if(!feof(inptr) && !ferror(inptr))
793     {
794         header.section_id = read_ulong(inptr,byteorder,offset);
795         header.version_minor = read_ushort(inptr,byteorder,HERE);
796         header.version_major = read_ushort(inptr,byteorder,HERE);
797         header.num_entries = read_ulong(inptr,byteorder,HERE);
798         header.char_format = read_ulong(inptr,byteorder,HERE);
799         header.reserved = read_ulong(inptr,byteorder,HERE);
800         header.entry_length = read_ulong(inptr,byteorder,HERE);
801         if(!feof(inptr) && !ferror(inptr))
802             headerptr = &header;
803     }
804     return(headerptr);
805 }
806 
807 unsigned long
display_x3f_imag_header(struct x3f_direntry * direntry,struct x3f_imag_header * header,char * dirname,int entry_num,int indent)808 display_x3f_imag_header(struct x3f_direntry *direntry,struct x3f_imag_header *header,
809                                                 char *dirname,int entry_num,int indent)
810 {
811     int chpr = 0;
812 
813     print_tag_address(ENTRY,direntry->data_offset,indent,"@");
814     if((PRINT_TAGINFO))
815     {
816         if((PRINT_LONGNAMES))
817             chpr += printf("%s:%d.Header.",dirname,entry_num);
818         chpr += printf("%s","SectionId");
819         if((PRINT_VALUE))
820         {
821             putindent(X3FTAGWIDTH - 9);
822             chpr += printf(" = ");
823         }
824     }
825     if((PRINT_VALUE))
826         chpr += printf("%4.4s",(char *)&header->section_id);
827     chpr = newline(chpr);
828 
829     print_tag_address(ENTRY,direntry->data_offset + 4,indent,"@");
830     if((PRINT_TAGINFO))
831     {
832         if((PRINT_LONGNAMES))
833             chpr += printf("%s:%d.Header.",dirname,entry_num);
834         chpr += printf("%s","Version");
835         if((PRINT_VALUE))
836         {
837             putindent(X3FTAGWIDTH - 7);
838             chpr += printf(" = ");
839         }
840     }
841     if((PRINT_VALUE))
842         chpr += printf("%u.%u",header->version_major,header->version_minor);
843     chpr = newline(chpr);
844 
845     print_tag_address(ENTRY,direntry->data_offset + 8,indent,"@");
846     if((PRINT_TAGINFO))
847     {
848         if((PRINT_LONGNAMES))
849             chpr += printf("%s:%d.Header.",dirname,entry_num);
850         chpr += printf("%s","ImageType");
851         if((PRINT_VALUE))
852         {
853             putindent(X3FTAGWIDTH - 9);
854             chpr += printf(" = ");
855         }
856     }
857     if((PRINT_VALUE))
858     {
859         chpr += printf("%-2lu",header->image_type);
860         switch(header->image_type)
861         {
862             case 2: chpr += printf(" = \"Preview\""); break;
863             case 3: chpr += printf(" = \"Primary\""); break;
864             default: break;
865         }
866     }
867     chpr = newline(chpr);
868 
869     print_tag_address(ENTRY,direntry->data_offset + 12,indent,"@");
870     if((PRINT_TAGINFO))
871     {
872         if((PRINT_LONGNAMES))
873             chpr += printf("%s:%d.Header.",dirname,entry_num);
874         chpr += printf("%s","ImageFormat");
875         if((PRINT_VALUE))
876         {
877             putindent(X3FTAGWIDTH - 11);
878             chpr += printf(" = ");
879         }
880     }
881     if((PRINT_VALUE))
882     {
883         chpr += printf("%-2lu",header->image_format);
884         switch(header->image_format)
885         {
886             case 3: chpr += printf(" = \"uncompressed RGB\""); break;
887             case 6: chpr += printf(" = \"compressed RAW\""); break;
888             case 11: chpr += printf(" = \"Huffman compressed RGB\""); break;
889             case 18: chpr += printf(" = \"JPEG compressed RGB\""); break;
890             default: break;
891         }
892     }
893     chpr = newline(chpr);
894 
895     print_tag_address(ENTRY,direntry->data_offset + 16,indent,"@");
896     if((PRINT_TAGINFO))
897     {
898         if((PRINT_LONGNAMES))
899             chpr += printf("%s:%d.Header.",dirname,entry_num);
900         chpr += printf("%s","ImageWidth");
901         if((PRINT_VALUE))
902         {
903             putindent(X3FTAGWIDTH - 10);
904             chpr += printf(" = ");
905         }
906     }
907     if((PRINT_VALUE))
908         chpr += printf("%lu",header->image_width);
909     chpr = newline(chpr);
910 
911     print_tag_address(ENTRY,direntry->data_offset + 20,indent,"@");
912     if((PRINT_TAGINFO))
913     {
914         if((PRINT_LONGNAMES))
915             chpr += printf("%s:%d.Header.",dirname,entry_num);
916         chpr += printf("%s","ImageHeight");
917         if((PRINT_VALUE))
918         {
919             putindent(X3FTAGWIDTH - 11);
920             chpr += printf(" = ");
921         }
922     }
923     if((PRINT_VALUE))
924         chpr += printf("%lu",header->image_height);
925     chpr = newline(chpr);
926 
927     print_tag_address(ENTRY,direntry->data_offset + 24,indent,"@");
928     if((PRINT_TAGINFO))
929     {
930         if((PRINT_LONGNAMES))
931             chpr += printf("%s:%d.Header.",dirname,entry_num);
932         chpr += printf("%s","RowSize");
933         if((PRINT_VALUE))
934         {
935             putindent(X3FTAGWIDTH - 7);
936             chpr += printf(" = ");
937         }
938     }
939     if((PRINT_VALUE))
940     {
941         chpr += printf("%lu",header->image_rowsize);
942         if(header->image_rowsize == 0)
943             chpr += printf(" = \"variable length\"");
944     }
945     chpr = newline(chpr);
946 
947     return(direntry->data_offset + 28);
948 }
949 
950 unsigned long
display_x3f_prop_header(struct x3f_direntry * direntry,struct x3f_prop_header * header,char * dirname,int entry_num,int indent)951 display_x3f_prop_header(struct x3f_direntry *direntry,struct x3f_prop_header *header,
952                                                 char *dirname,int entry_num,int indent)
953 {
954     int chpr = 0;
955 
956     print_tag_address(ENTRY,direntry->data_offset,indent,"@");
957     if((PRINT_TAGINFO))
958     {
959         if((PRINT_LONGNAMES))
960             chpr += printf("%s:%d.Header.",dirname,entry_num);
961         chpr += printf("%s","SectionId");
962         if((PRINT_VALUE))
963         {
964             putindent(X3FTAGWIDTH - 9);
965             chpr += printf(" = ");
966         }
967     }
968     if((PRINT_VALUE))
969         chpr += printf("%4.4s",(char *)&header->section_id);
970     chpr = newline(chpr);
971 
972     print_tag_address(ENTRY,direntry->data_offset + 4,indent,"@");
973     if((PRINT_TAGINFO))
974     {
975         if((PRINT_LONGNAMES))
976             chpr += printf("%s:%d.Header.",dirname,entry_num);
977         chpr += printf("%s","Version");
978         if((PRINT_VALUE))
979         {
980             putindent(X3FTAGWIDTH - 7);
981             chpr += printf(" = ");
982         }
983     }
984     if((PRINT_VALUE))
985         chpr += printf("%u.%u",header->version_major,header->version_minor);
986     chpr = newline(chpr);
987 
988     print_tag_address(ENTRY,direntry->data_offset + 8,indent,"@");
989     if((PRINT_TAGINFO))
990     {
991         if((PRINT_LONGNAMES))
992             chpr += printf("%s:%d.Header.",dirname,entry_num);
993         chpr += printf("%s","Entries");
994         if((PRINT_VALUE))
995         {
996             putindent(X3FTAGWIDTH - 7);
997             chpr += printf(" = ");
998         }
999     }
1000     if((PRINT_VALUE))
1001         chpr += printf("%lu",header->num_entries);
1002     chpr = newline(chpr);
1003 
1004     print_tag_address(ENTRY,direntry->data_offset + 12,indent,"@");
1005     if((PRINT_TAGINFO))
1006     {
1007         if((PRINT_LONGNAMES))
1008             chpr += printf("%s:%d.Header.",dirname,entry_num);
1009         chpr += printf("%s","CharFormat");
1010         if((PRINT_VALUE))
1011         {
1012             putindent(X3FTAGWIDTH - 10);
1013             chpr += printf(" = ");
1014         }
1015     }
1016     if((PRINT_VALUE))
1017         chpr += printf("%lu",header->char_format);
1018     chpr = newline(chpr);
1019 
1020     print_tag_address(ENTRY,direntry->data_offset + 16,indent,"@");
1021     if((PRINT_TAGINFO))
1022     {
1023         if((PRINT_LONGNAMES))
1024             chpr += printf("%s:%d.Header.",dirname,entry_num);
1025         chpr += printf("%s","RESERVED");
1026         if((PRINT_VALUE))
1027         {
1028             putindent(X3FTAGWIDTH - 8);
1029             chpr += printf(" = ");
1030         }
1031     }
1032     if((PRINT_VALUE))
1033         chpr += printf("%lu",header->reserved);
1034     chpr = newline(chpr);
1035 
1036     print_tag_address(ENTRY,direntry->data_offset + 20,indent,"@");
1037     if((PRINT_TAGINFO))
1038     {
1039         if((PRINT_LONGNAMES))
1040             chpr += printf("%s:%d.Header.",dirname,entry_num);
1041         chpr += printf("%s","SectionLength");
1042         if((PRINT_VALUE))
1043         {
1044             putindent(X3FTAGWIDTH - 13);
1045             chpr += printf(" = ");
1046         }
1047     }
1048     if((PRINT_VALUE))
1049         chpr += printf("%lu",header->entry_length);
1050     chpr = newline(chpr);
1051 
1052     return(direntry->data_offset + 24);
1053 }
1054 
1055 unsigned long
display_x3f_camf_header(struct x3f_direntry * direntry,struct x3f_camf_header * header,char * dirname,int entry_num,int indent)1056 display_x3f_camf_header(struct x3f_direntry *direntry,struct x3f_camf_header *header,
1057                                                 char *dirname,int entry_num,int indent)
1058 {
1059     int chpr = 0;
1060 
1061     print_tag_address(ENTRY,direntry->data_offset,indent,"@");
1062     if((PRINT_TAGINFO))
1063     {
1064         if((PRINT_LONGNAMES))
1065             chpr += printf("%s:%d.Header.",dirname,entry_num);
1066         chpr += printf("%s","SectionId");
1067         if((PRINT_VALUE))
1068         {
1069             putindent(X3FTAGWIDTH - 9);
1070             chpr += printf(" = ");
1071         }
1072     }
1073     if((PRINT_VALUE))
1074         chpr += printf("%4.4s",(char *)&header->section_id);
1075     chpr = newline(chpr);
1076 
1077     print_tag_address(ENTRY,direntry->data_offset + 4,indent,"@");
1078     if((PRINT_TAGINFO))
1079     {
1080         if((PRINT_LONGNAMES))
1081             chpr += printf("%s:%d.Header.",dirname,entry_num);
1082         chpr += printf("%s","Version");
1083         if((PRINT_VALUE))
1084         {
1085             putindent(X3FTAGWIDTH - 7);
1086             chpr += printf(" = ");
1087         }
1088     }
1089     if((PRINT_VALUE))
1090         chpr += printf("%u.%u",header->version_major,header->version_minor);
1091     chpr = newline(chpr);
1092 
1093     print_tag_address(ENTRY,direntry->data_offset + 8,indent,"@");
1094     if((PRINT_TAGINFO))
1095     {
1096         if((PRINT_LONGNAMES))
1097             chpr += printf("%s:%d.Header.",dirname,entry_num);
1098         chpr += printf("%s","Item1");
1099         if((PRINT_VALUE))
1100         {
1101             putindent(X3FTAGWIDTH - 5);
1102             chpr += printf(" = ");
1103         }
1104     }
1105     if((PRINT_VALUE))
1106         chpr += printf("%lu",header->item1);
1107     chpr = newline(chpr);
1108 
1109     print_tag_address(ENTRY,direntry->data_offset + 12,indent,"@");
1110     if((PRINT_TAGINFO))
1111     {
1112         if((PRINT_LONGNAMES))
1113             chpr += printf("%s:%d.Header.",dirname,entry_num);
1114         chpr += printf("%s","Item2");
1115         if((PRINT_VALUE))
1116         {
1117             putindent(X3FTAGWIDTH - 5);
1118             chpr += printf(" = ");
1119         }
1120     }
1121     if((PRINT_VALUE))
1122         chpr += printf("%lu",header->item2);
1123     chpr = newline(chpr);
1124 
1125     print_tag_address(ENTRY,direntry->data_offset + 16,indent,"@");
1126     if((PRINT_TAGINFO))
1127     {
1128         if((PRINT_LONGNAMES))
1129             chpr += printf("%s:%d.Header.",dirname,entry_num);
1130         chpr += printf("%s","Item3");
1131         if((PRINT_VALUE))
1132         {
1133             putindent(X3FTAGWIDTH - 5);
1134             chpr += printf(" = ");
1135         }
1136     }
1137     if((PRINT_VALUE))
1138         chpr += printf("%4.4s",(char *)&header->item3);
1139     chpr = newline(chpr);
1140 
1141     print_tag_address(ENTRY,direntry->data_offset + 20,indent,"@");
1142     if((PRINT_TAGINFO))
1143     {
1144         if((PRINT_LONGNAMES))
1145             chpr += printf("%s:%d.Header.",dirname,entry_num);
1146         chpr += printf("%s","Item4");
1147         if((PRINT_VALUE))
1148         {
1149             putindent(X3FTAGWIDTH - 5);
1150             chpr += printf(" = ");
1151         }
1152     }
1153     if((PRINT_VALUE))
1154         chpr += printf("%lu",header->item4);
1155     chpr = newline(chpr);
1156 
1157     /* Not sure how long the header is... CAMF is not described in    */
1158     /* the public X3F spec.                                           */
1159 
1160     /* Assume the header is same length as PROP for the purposes of   */
1161     /* dumping the data section                                       */
1162     return(direntry->data_offset + 24);
1163 }
1164 
1165 /* Process the property section. After the header, the section starts */
1166 /* with an index of offsets to each name and value. The actual names  */
1167 /* and values follow.                                                 */
1168 
1169 
1170 unsigned long
process_x3f_props(FILE * inptr,unsigned short byteorder,unsigned long data_offset,unsigned long data_length,unsigned long char_format,char * dirname,unsigned long num_entries,int indent)1171 process_x3f_props(FILE *inptr,unsigned short byteorder,unsigned long data_offset,
1172                            unsigned long data_length,unsigned long char_format,
1173                            char *dirname,unsigned long num_entries,int indent)
1174 {
1175     unsigned long max_offset = 0UL;
1176     unsigned long name_offset = 0UL;
1177     unsigned long value_offset = 0UL;
1178     unsigned long offset = 0UL;
1179     unsigned long property_offset = 0UL;
1180     unsigned long index_length = 0UL;
1181     unsigned long list_data_length = 0UL;
1182     int chpr = 0;
1183     int i;
1184 
1185     if(inptr)
1186     {
1187         clearerr(inptr);
1188         offset = data_offset;
1189         property_offset = data_offset + (num_entries * 8);
1190         index_length = num_entries * 8;
1191         list_data_length = data_length - index_length;
1192 
1193         if((PRINT_SECTION))
1194         {
1195             print_tag_address(SECTION,data_offset,indent,"@");
1196             chpr += printf("<Property List> %ld entries, length %lu",num_entries,data_length);
1197             chpr = newline(chpr);
1198             print_tag_address(SECTION,data_offset,indent + SMALLINDENT,"@");
1199             chpr += printf("<Property List Index> %ld entries, length %lu",num_entries,index_length);
1200             chpr = newline(chpr);
1201         }
1202         /* Print the index of name/value offsets first                */
1203         for(i = 0; i < num_entries; ++i)
1204         {
1205             if(fseek(inptr,offset,0) == 0)
1206             {
1207                 name_offset = read_ulong(inptr,byteorder,HERE);
1208                 name_offset *= 2;
1209                 if(feof(inptr) || ferror(inptr))
1210                 {
1211                     PUSHCOLOR(RED);
1212                     chpr += printf(" FAILED to read Property List name %d at offset %lu",i,offset);
1213                     POPCOLOR();
1214                     break;
1215                 }
1216                 value_offset = read_ulong(inptr,byteorder,HERE);
1217                 value_offset *= 2;
1218                 if(feof(inptr) || ferror(inptr))
1219                 {
1220                     PUSHCOLOR(RED);
1221                     chpr += printf(" FAILED to read Property List value %d at offset %lu",i,offset + 4);
1222                     POPCOLOR();
1223                     break;
1224                 }
1225 
1226                 /* Show the name/value offsets, even in LIST mode     */
1227                 print_tag_address(ENTRY,offset,indent + MEDIUMINDENT,"@");
1228                 if((PRINT_TAGINFO))
1229                 {
1230                     if((PRINT_LONGNAMES))
1231                         chpr += printf("%s.Index.",dirname);
1232                     chpr += printf("NameOffset.%-2d",i);
1233                     if((PRINT_VALUE))
1234                     {
1235                         putindent(X3FTAGWIDTH - 15);
1236                         chpr += printf(" = ");
1237                     }
1238                 }
1239                 if((PRINT_VALUE))
1240                 {
1241                     chpr += printf("@%lu",name_offset + property_offset);
1242                     if((PRINT_RAW_VALUES))
1243                         chpr += printf(" (%lu)",name_offset);
1244                 }
1245                 chpr = newline(chpr);
1246 
1247                 print_tag_address(ENTRY,offset + 4,indent + MEDIUMINDENT,"@");
1248                 if((PRINT_TAGINFO))
1249                 {
1250                     if((PRINT_LONGNAMES))
1251                         chpr += printf("%s.Index.",dirname);
1252                     chpr += printf("ValueOffset.%-2d",i);
1253                     if((PRINT_VALUE))
1254                     {
1255                         putindent(X3FTAGWIDTH - 16);
1256                         chpr += printf(" = ");
1257                     }
1258                 }
1259                 if((PRINT_VALUE))
1260                 {
1261                     chpr += printf("@%lu",value_offset + property_offset);
1262                     if((PRINT_RAW_VALUES))
1263                         chpr += printf(" (%lu)",value_offset);
1264                 }
1265                 chpr = newline(chpr);
1266 
1267             }
1268             else
1269             {
1270                 PUSHCOLOR(RED);
1271                 chpr += printf(" SEEK FAILED reading Property List item %d at offset %lu",i,offset);
1272                 POPCOLOR();
1273                 break;
1274             }
1275 
1276             offset += 8;
1277             max_offset = ftell(inptr);
1278         }
1279         if((PRINT_SECTION))
1280         {
1281             print_tag_address(SECTION,max_offset - 1,indent + SMALLINDENT,"@");
1282             chpr += printf("</Property List iIndex>");
1283             chpr = newline(chpr);
1284             print_tag_address(SECTION,property_offset,indent + SMALLINDENT,"@");
1285             chpr += printf("<Property List Data> length %lu",list_data_length);
1286             chpr = newline(chpr);
1287         }
1288         offset = data_offset;
1289 
1290         /* Read 'em again, and this time show the names and values    */
1291         for(i = 0; i < num_entries; ++i)
1292         {
1293             if(fseek(inptr,offset,0) == 0)
1294             {
1295                 name_offset = read_ulong(inptr,byteorder,HERE);
1296                 name_offset *= 2;
1297                 if(feof(inptr) || ferror(inptr))
1298                 {
1299                     PUSHCOLOR(RED);
1300                     chpr += printf(" FAILED to read Property List name %d at offset %lu",i,offset);
1301                     POPCOLOR();
1302                     break;
1303                 }
1304                 value_offset = read_ulong(inptr,byteorder,HERE);
1305                 value_offset *= 2;
1306                 if(feof(inptr) || ferror(inptr))
1307                 {
1308                     PUSHCOLOR(RED);
1309                     chpr += printf(" FAILED to read Property List value %d at offset %lu",i,offset + 4);
1310                     POPCOLOR();
1311                     break;
1312                 }
1313                 name_offset += property_offset;
1314                 value_offset += property_offset;
1315                 print_property(inptr,byteorder,name_offset,value_offset,char_format,
1316                                                     dirname,i,indent + MEDIUMINDENT);
1317             }
1318             else
1319             {
1320                 PUSHCOLOR(RED);
1321                 chpr += printf(" SEEK FAILED reading Property List item %d at offset %lu",i,offset);
1322                 POPCOLOR();
1323                 break;
1324             }
1325 
1326             offset += 8;
1327             max_offset = ftell(inptr);
1328         }
1329         if((PRINT_SECTION))
1330         {
1331             print_tag_address(SECTION,max_offset - 1,indent + SMALLINDENT,"@");
1332             chpr += printf("</Property List Data>");
1333             chpr = newline(chpr);
1334         }
1335         if((PRINT_SECTION))
1336         {
1337             print_tag_address(SECTION,property_offset + list_data_length - 1,indent,"@");
1338             chpr += printf("</Property List>");
1339             chpr = newline(chpr);
1340         }
1341     }
1342     else
1343     {
1344         PUSHCOLOR(RED);
1345         fprintf(stderr,"%s: no file pointer to read X3F Properties List\n",Progname);
1346         POPCOLOR();
1347     }
1348     setcharsprinted(chpr);
1349     return(max_offset);
1350 }
1351 
1352 /* Displays property names and values, given their offsets. The       */
1353 /* characters are encoded as 16 bit 'unicode'. This routine reads     */
1354 /* each character as an unsigned short and echos it via putchar().    */
1355 
1356 void
print_property(FILE * inptr,unsigned short byteorder,unsigned long name_offset,unsigned long value_offset,unsigned long char_format,char * dirname,int index,int indent)1357 print_property(FILE *inptr,unsigned short byteorder,unsigned long name_offset,
1358                         unsigned long value_offset,unsigned long char_format,
1359                         char *dirname,int index,int indent)
1360 {
1361     int chpr = 0;
1362     int i = 0;
1363     int ch;
1364 
1365     if(inptr)
1366     {
1367         clearerr(inptr);
1368         if(fseek(inptr,name_offset,0) == 0)
1369         {
1370             if((PRINT_SECTION) && (PRINT_VALUE_AT_OFFSET))
1371             {
1372                 print_tag_address(ENTRY,name_offset,indent + SMALLINDENT,"@");
1373                 if((PRINT_TAGINFO))
1374                 {
1375                     if((PRINT_LONGNAMES))
1376                         chpr += printf("%s.Data.",dirname);
1377                     chpr += printf("Name.%-2d",index);
1378                     if((PRINT_VALUE))
1379                     {
1380                         putindent(X3FTAGWIDTH - 17);
1381                         chpr += printf(" = ");
1382                     }
1383                 }
1384                 if((PRINT_VALUE))
1385                 {
1386                     while((ch = read_ushort(inptr,byteorder,HERE)))
1387                     {
1388                         if((PRINT_UNICODE))
1389                             fwrite((char *)&ch,2,1,stdout);
1390                         else
1391                             putchar(ch);
1392                         ++chpr;
1393                     }
1394                 }
1395             }
1396             else
1397             {
1398                 print_tag_address(ENTRY,name_offset,indent + SMALLINDENT,"@");
1399                 if((PRINT_TAGINFO))
1400                 {
1401                     if((PRINT_LONGNAMES))
1402                         chpr += printf("%s.Data.",dirname);
1403                     i = 0;
1404                     while((ch = read_ushort(inptr,byteorder,HERE)))
1405                     {
1406                         if((PRINT_UNICODE))
1407                             fwrite((char *)&ch,2,1,stdout);
1408                         else
1409                             putchar(ch);
1410                         ++chpr;
1411                         ++i;
1412                     }
1413                     if((PRINT_VALUE))
1414                     {
1415                         putindent(X3FTAGWIDTH - i - 6);
1416                         chpr += printf(" = ");
1417                     }
1418                 }
1419             }
1420         }
1421         if((PRINT_SECTION) && (PRINT_VALUE_AT_OFFSET))
1422             chpr = newline(chpr);
1423         if(fseek(inptr,value_offset,0) == 0)
1424         {
1425             if((PRINT_SECTION) && (PRINT_VALUE_AT_OFFSET))
1426             {
1427                 print_tag_address(ENTRY,value_offset,indent + SMALLINDENT,"@");
1428                 if((PRINT_TAGINFO))
1429                 {
1430                     if((PRINT_LONGNAMES))
1431                         chpr += printf("%s.",dirname);
1432                     chpr += printf("Value.%-2d",index);
1433                     if((PRINT_VALUE))
1434                     {
1435                         putindent(X3FTAGWIDTH - 18);
1436                         chpr += printf(" = ");
1437                     }
1438                 }
1439                 if((PRINT_VALUE))
1440                 {
1441                     while((ch = read_ushort(inptr,byteorder,HERE)))
1442                     {
1443                         if((PRINT_UNICODE))
1444                             fwrite((char *)&ch,2,1,stdout);
1445                         else
1446                             putchar(ch & 0xff);
1447                         ++chpr;
1448                     }
1449                 }
1450             }
1451             else if((PRINT_VALUE))
1452             {
1453                 while((ch = read_ushort(inptr,byteorder,HERE)))
1454                 {
1455                     if((PRINT_UNICODE))
1456                         fwrite((char *)&ch,2,1,stdout);
1457                     else
1458                         putchar(ch & 0xff);
1459                     ++chpr;
1460                 }
1461             }
1462         }
1463         chpr = newline(chpr);
1464     }
1465 }
1466