1 /* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- */
2 /*          EXIFPROBE - TIFF/JPEG/EXIF image file probe               */
3 /* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- */
4 /* Copyright (C) 2002,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: maker_sanyo.c,v 1.23 2005/07/24 22:56:27 alex Exp $";
11 #endif
12 
13 /* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- */
14 /* sanyo camera maker-specific routines                             */
15 /* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- */
16 /* The information coded here is largely due to John Hawkins as shown */
17 /* at:                                                                */
18 /*     http://www.exif.org/makernotes/SanyoMakerNote.html             */
19 
20 /* (John even lists the JPEG thumbnail in TIFF makernotes and the     */
21 /* Epson PrintIM tag!)                                                */
22 /* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- */
23 
24 #include <stdio.h>
25 #include <string.h>
26 #include <stdlib.h>
27 #include "defs.h"
28 #include "datadefs.h"
29 #include "maker_datadefs.h"
30 #include "summary.h"
31 #include "maker.h"
32 #include "misc.h"
33 #include "tags.h"
34 #include "maker_extern.h"
35 #include "extern.h"
36 
37 extern struct camera_id sanyo_model_id[];
38 
39 /* Find the identifying number assigned to known Sanyo camera models. */
40 /* This number is used to dispatch print and interpret routines       */
41 /* approopriate to the current image.                                 */
42 
43 int
sanyo_model_number(char * model,char * software)44 sanyo_model_number(char *model,char *software)
45 {
46     struct camera_id *model_id;
47     int number = NO_MODEL;
48 
49     for(model_id = &sanyo_model_id[0]; model_id && model_id->name; ++model_id)
50     {
51         if(strncasecmp(model,model_id->name,model_id->namelen) == 0)
52         {
53             number = model_id->id;
54             setnoteversion(model_id->noteversion);
55             setnotetagset(model_id->notetagset);    /* info only      */
56             break;
57         }
58     }
59 
60     return(number);
61 }
62 
63 /* Dispatch a print routine based upon model                          */
64 
65 void
print_sanyo_makervalue(struct ifd_entry * entry_ptr,int make,int model,char * prefix)66 print_sanyo_makervalue(struct ifd_entry *entry_ptr,int make,int model,
67                     char *prefix)
68 {
69     int noteversion = 0;
70 
71     noteversion = getnoteversion();
72 
73     if(entry_ptr && (PRINT_VALUE))
74     {
75         switch(noteversion)
76         {
77             case 1:
78                 print_sanyo1_makervalue(entry_ptr,make,model,prefix);
79                 sanyo1_interpret_value(entry_ptr);
80                 break;
81             default:
82                 print_value(entry_ptr,PREFIX);
83                 break;
84         }
85     }
86 }
87 
88 /* Model-specific print routine for sanyo cameras. This routine is      */
89 /* responsible for picking off any direct entry tags which are        */
90 /* peculiar and will not be handled properly by print_value()         */
91 /* (usually UNDEFINED values which fit in the 4-byte entry value). If */
92 /* there are no such entries, this function simply calls              */
93 /* print_value().                                                     */
94 
95 void
print_sanyo1_makervalue(struct ifd_entry * entry_ptr,int make,int model,char * prefix)96 print_sanyo1_makervalue(struct ifd_entry *entry_ptr,int make,int model,
97                     char *prefix)
98 {
99     if(entry_ptr && (PRINT_VALUE))
100     {
101         switch(entry_ptr->tag)
102         {
103             default:
104                 print_value(entry_ptr,PREFIX);
105                 break;
106         }
107     }
108 }
109 
110 
111 /* Dispatch a routine to decode and print offset values for sanyo     */
112 /* cameras.                                                           */
113 void
print_sanyo_offset_makervalue(FILE * inptr,unsigned short byteorder,struct ifd_entry * entry_ptr,unsigned long fileoffset_base,struct image_summary * summary_entry,char * parent_name,char * prefix,int indent,int make,int model,int at_offset)114 print_sanyo_offset_makervalue(FILE *inptr,unsigned short byteorder,
115     struct ifd_entry *entry_ptr,unsigned long fileoffset_base,
116     struct image_summary *summary_entry,char *parent_name,char*prefix,
117     int indent,int make,int model,int at_offset)
118 {
119     int noteversion = 0;
120 
121     noteversion = getnoteversion();
122 
123     if(entry_ptr)
124     {
125         switch(noteversion)
126         {
127             case 1:
128                 sanyo1_offset_makervalue(inptr,byteorder,entry_ptr,
129                                             fileoffset_base,summary_entry,
130                                             parent_name,prefix,indent,
131                                             make,model,at_offset);
132                 sanyo1_interpret_offset_makervalue(inptr,byteorder,entry_ptr,
133                                             fileoffset_base);
134                 break;
135             default:
136                 print_generic_offset_makervalue(inptr,byteorder,entry_ptr,
137                                         fileoffset_base,parent_name,prefix,indent,
138                                         make,model,at_offset);
139                 break;
140         }
141     }
142 }
143 
144 /* Model-specific routine to print UNDEFINED values found at offsets  */
145 /* in sanyo makernotes. One of these may be supplied for each model   */
146 /* with unique UNDEFINED tags.                                        */
147 
148 void
sanyo1_offset_makervalue(FILE * inptr,unsigned short byteorder,struct ifd_entry * entry_ptr,unsigned long fileoffset_base,struct image_summary * summary_entry,char * parent_name,char * prefix,int indent,int make,int model,int at_offset)149 sanyo1_offset_makervalue(FILE *inptr,unsigned short byteorder,
150     struct ifd_entry *entry_ptr,unsigned long fileoffset_base,
151     struct image_summary *summary_entry,char *parent_name,char*prefix,
152     int indent,int make,int model,int at_offset)
153 {
154     unsigned long value_offset;
155     unsigned long dumplength;
156     unsigned long count;
157     unsigned short marker;
158     unsigned long max_offset = 0;
159     char *nameoftag;
160     char *fulldirname = NULL;
161     int status = 0;
162     int chpr = 0;
163 
164     if(entry_ptr)
165     {
166         nameoftag = maker_tagname(entry_ptr->tag,make,model);
167         fulldirname = splice(parent_name,".",nameoftag);
168         value_offset = fileoffset_base + entry_ptr->value;
169         count = entry_ptr->count;
170         switch(entry_ptr->tag)
171         {
172             case 0x0100:    /* Jpeg Thumbnail in TIFF MakerNote       */
173                 if(at_offset && (PRINT_SECTION))
174                 {
175                     print_tag_address(VALUE_AT_OFFSET,value_offset,indent,prefix);
176                     extraindent(4);
177                     chpr += printf("# Start of JPEG Thumbnail from MakerNote");
178                     chpr += printf(" length %ld",count);
179                 }
180                 else if(!at_offset && (PRINT_VALUE))
181                 {
182                     if(!(PRINT_OFFSET))
183                         chpr += printf("@%lu:%lu",value_offset,entry_ptr->count);
184                     else
185                         chpr += printf(":%lu", entry_ptr->count);
186                     if(!(PRINT_VALUE_AT_OFFSET))
187                         chpr += printf(" # UNDEFINED");
188                 }
189                 if((PRINT_SECTION) || (PRINT_SEGMENT))
190                     chpr = newline(chpr);
191                 marker = read_ushort(inptr,TIFF_MOTOROLA,value_offset);
192                 max_offset = process_jpeg_segments(inptr,value_offset,marker,
193                                     count,summary_entry,fulldirname,
194                                     prefix,indent+(SUBINDENT * 2));
195                 if(at_offset)
196                 {
197                     if((PRINT_SECTION))
198                     {
199                         if((status = jpeg_status(0) == JPEG_EARLY_EOI))
200                             chpr = newline(chpr);
201                         jpeg_status(status);
202                         print_tag_address(VALUE_AT_OFFSET,value_offset + count - 1,
203                                                     indent,"-");
204                         extraindent(SUBINDENT);
205                         chpr += printf("# End of JPEG Thumbnail from MakerNote");
206                         if((PRINT_ENTRY) && !(PRINT_VALUE))
207                             chpr = newline(chpr);
208                     }
209                 }
210                 print_jpeg_status();
211                 if(marker && summary_entry)
212                 {
213                     /* The new one is on the end of the chain         */
214                     if((summary_entry = last_summary_entry(summary_entry)))
215                     {
216                         summary_entry->filesubformat |= FILESUBFMT_MNOTE;
217                         summary_entry->datatype = MAKER_IFD;
218                         summary_entry->subfiletype = THUMBNAIL_TYPE;
219                     }
220                 }
221                 /* make certain we're at the end                      */
222                 clearerr(inptr);
223                 fseek(inptr,value_offset + count,0);
224                 break;
225             case 0x0e00: /* PrintIM (Epson Print Image matching)      */
226                 if(!at_offset && (PRINT_VALUE))
227                 {
228                     if(!(PRINT_OFFSET))
229                     {
230                         chpr += printf("@%lu:%lu",value_offset,count);
231                         chpr = newline(chpr);
232                     }
233                 }
234                 process_pim(inptr,byteorder,entry_ptr->value,fileoffset_base,
235                     count,nameoftag,parent_name,prefix,indent);
236                 break;
237             case 0x0f00: /* Data                                      */
238                 if(at_offset && (PRINT_ENTRY))
239                 {
240                     print_tag_address(ENTRY,value_offset,indent,prefix);
241                     print_makertagid(entry_ptr,23," : ",make,model);
242                     chpr += printf("length %-9lu # UNDEFINED", count);
243                     if(Max_undefined == 0)
244                     {
245                         if(chpr)
246                             printred(" (not dumped, use -U)");
247                     }
248                     else
249                     {
250                         if((Max_undefined == DUMPALL) || (Max_undefined > count))
251                             dumplength = count;
252                         else
253                             dumplength = Max_undefined;
254                         chpr = newline(chpr);
255                         hexdump(inptr,value_offset,count,dumplength,12,
256                                     indent,SUBINDENT);
257                         chpr = newline(1);
258                     }
259                 }
260                 else if(!at_offset && (PRINT_VALUE))
261                 {
262                     if(!(PRINT_OFFSET))
263                         chpr += printf("@%lu:%lu",value_offset,entry_ptr->count);
264                     else
265                         chpr += printf(":%lu", entry_ptr->count);
266                     if(!(PRINT_VALUE_AT_OFFSET))
267                         chpr += printf(" # UNDEFINED");
268                 }
269                 /* make certain we're at the end                      */
270                 fseek(inptr,value_offset + count,0);
271                 break;
272             default:
273                 print_generic_offset_makervalue(inptr,byteorder,entry_ptr,
274                                         fileoffset_base,fulldirname,prefix,indent,
275                                         make,model,at_offset);
276                 break;
277         }
278         if(fulldirname)
279             free(fulldirname);
280     }
281     setcharsprinted(chpr);
282 }
283 
284 
285 /* sanyo-specific tagnames for makernotes.                            */
286 
287 /* The tagname routine is the first place in the code path which      */
288 /* requires knowledge of the note version. If the version is not      */
289 /* given in the model table (e.g. the model is unknown), then switch  */
290 /* code in find_maker_scheme() should have set it. This routine       */
291 /* repeats the check for non-zero noteversion and is prepared to set  */
292 /* the noteversion first time through, but should never need to do    */
293 /* so. Noteversion should always be non-zero; it should be set to -1  */
294 /* if generic processing is required.                                 */
295 
296 char *
maker_sanyo_tagname(unsigned short tag,int model)297 maker_sanyo_tagname(unsigned short tag,int model)
298 {
299     char *tagname = CNULL;
300     int noteversion = 0;
301 
302     if(((noteversion = getnoteversion()) == 0))
303     {
304         /* Need more model samples before it is safe to assume a      */
305         /* default                                                    */
306         noteversion = 1;
307         setnoteversion(1);
308     }
309 
310     switch(noteversion)
311     {
312         case 1:
313             tagname = maker_sanyo1_tagname(tag,model);
314             break;
315         default:
316             break;
317     }
318 
319     /* If no model-specific tag is found, check "generic" tags        */
320     if(tagname == NULL)
321     {
322         switch(tag)
323         {
324             case 0x0e00: tagname = "PrintIM"; break;
325             default: break;
326         }
327     }
328     return(tagname);
329 }
330 
331 char *
maker_sanyo1_tagname(unsigned short tag,int model)332 maker_sanyo1_tagname(unsigned short tag,int model)
333 {
334     char *tagname = CNULL;
335 
336     switch(tag)
337     {
338         case 0x0100: tagname = "JpegThumbnail"; break;
339         case 0x0200: tagname = "SpecialMode"; break;
340         case 0x0201: tagname = "Quality"; break;
341         case 0x0202: tagname = "Macro"; break;
342         case 0x0204: tagname = "DigiZoom"; break;
343         case 0x0207: tagname = "SoftwareRelease"; break;
344         case 0x0208: tagname = "PictureInfo"; break;
345         case 0x0209: tagname = "CameraID"; break;
346         case 0x020e: tagname = "SeqShotMethod"; break;
347         case 0x020f: tagname = "WideRange"; break;
348         case 0x0210: tagname = "ColorAdjMode"; break;
349         case 0x0213: tagname = "QuickShot"; break;
350         case 0x0214: tagname = "SelfTImer"; break;
351         case 0x0216: tagname = "VoiceMemo"; break;
352         case 0x0217: tagname = "RecordShutterRel"; break;
353         case 0x0218: tagname = "FlickerReduce"; break;
354         case 0x0219: tagname = "OpticalZoom"; break;
355         case 0x021b: tagname = "DigitalZoom"; break;
356         case 0x021d: tagname = "LightSourceSpecial"; break;
357         case 0x021e: tagname = "Resaved"; break;
358         case 0x021f: tagname = "SceneSelect"; break;
359         case 0x0223: tagname = "ManualFocalDist"; break;
360         case 0x0224: tagname = "SeqShotIntvl"; break;
361         case 0x0225: tagname = "FlashMode"; break;
362         case 0x0e00: tagname = "PrintIM"; break;
363         case 0x0f00: tagname = "Data"; break;
364         default: break;
365     }
366     setnotetagset(1);
367     return(tagname);
368 }
369 
370 
371 void
sanyo1_interpret_value(struct ifd_entry * entry_ptr)372 sanyo1_interpret_value(struct ifd_entry *entry_ptr)
373 {
374     int chpr = 0;
375 
376     if(entry_ptr && (PRINT_VALUE))
377     {
378         switch(entry_ptr->tag)
379         {
380             case 0x0201:    /* Quality */
381                 print_startvalue();
382                 /* ###%%% is this related to image size, e.g. 640x480?    */
383                 /* This tag is the same tag number as used by the         */
384                 /* Olympus, Epson, and Minolta F100, except that "super   */
385                 /* high" + "super fine" would give a (short) value of 34, */
386                 /* which is the value used for uncompressed tiff in the   */
387                 /* Epson at 2048x1536.                                    */
388                 switch(entry_ptr->value & 0xff)
389                 {
390                     case 0: chpr += printf("very low res,"); break;
391                     case 1: chpr += printf("low res,"); break;
392                     case 2: chpr += printf("medium low res,");    /* 640 x 480 */ break;
393                     case 3: chpr += printf("medium res,"); break;
394                     case 4: chpr += printf("medium high res,"); break;
395                     case 5: chpr += printf("high res,"); break;
396                     case 6: chpr += printf("very high res,"); break;
397                     case 7: chpr += printf("super high"); break;
398                     default: printred("undefined"); break;
399                 }
400                 /* ###%%% is this related to compression, e.g TIFF vs     */
401                 /* JPEG ???                                               */
402                 switch((entry_ptr->value >> 8) & 0xff)
403                 {
404                     case 0: chpr += printf(" normal"); break;
405                     case 1: chpr += printf(" fine"); break;
406                     case 2: chpr += printf(" super fine"); break;
407                 }
408                 print_endvalue();
409                 break;
410             case 0x0202:    /* Macro */
411                 print_startvalue();
412                 switch(entry_ptr->value)
413                 {
414                     case 0: chpr += printf("Normal"); break;
415                     case 1: chpr += printf("Macro"); break;
416                     case 2: chpr += printf("View"); break;
417                     case 3: chpr += printf("Manual"); break;
418                     default: printred("undefined"); break;
419                 }
420                 print_endvalue();
421                 break;
422             case 0x020e:    /* Sequential Shot Method */
423                 print_startvalue();
424                 switch(entry_ptr->value)
425                 {
426                     case 0: chpr += printf("none"); break;
427                     case 1: chpr += printf("Standard"); break;
428                     case 2: chpr += printf("Best"); break;
429                     case 3: chpr += printf("Exposure Adjust"); break;
430                     default: printred("undefined"); break;
431                 }
432                 print_endvalue();
433                 break;
434             case 0x020f:    /* Wide Range */
435                 print_startvalue();
436                 switch(entry_ptr->value)
437                 {
438                     case 0: chpr += printf("Off"); break;
439                     case 1: chpr += printf("On"); break;
440                     default: printred("undefined"); break;
441                 }
442                 print_endvalue();
443                 break;
444             case 0x0210:    /* Color Adjustment Mode */
445                 print_startvalue();
446                 switch(entry_ptr->value)
447                 {
448                     case 0: chpr += printf("Off"); break;
449                     case 1: chpr += printf("On"); break;
450                     default: printred("undefined"); break;
451                 }
452                 print_endvalue();
453                 break;
454             case 0x0213:    /* Quick Shot */
455                 print_startvalue();
456                 switch(entry_ptr->value)
457                 {
458                     case 0: chpr += printf("Off"); break;
459                     case 1: chpr += printf("On"); break;
460                     default: printred("undefined"); break;
461                 }
462                 print_endvalue();
463                 break;
464             case 0x0214:    /* Self Timer  */
465                 print_startvalue();
466                 switch(entry_ptr->value)
467                 {
468                     case 0: chpr += printf("Off"); break;
469                     case 1: chpr += printf("On"); break;
470                     default: printred("undefined"); break;
471                 }
472                 print_endvalue();
473                 break;
474             case 0x0216:    /* Voice Memo  */
475                 print_startvalue();
476                 switch(entry_ptr->value)
477                 {
478                     case 0: chpr += printf("Off"); break;
479                     case 1: chpr += printf("On"); break;
480                     default: printred("undefined"); break;
481                 }
482                 print_endvalue();
483                 break;
484             case 0x0217:    /* Record Shutter Release  */
485                 print_startvalue();
486                 switch(entry_ptr->value)
487                 {
488                     case 0: chpr += printf("Held"); break;
489                     case 1: chpr += printf("Start/Stop"); break;
490                     default: printred("undefined"); break;
491                 }
492                 print_endvalue();
493                 break;
494             case 0x0218:    /* Flicker Reduce  */
495                 print_startvalue();
496                 switch(entry_ptr->value)
497                 {
498                     case 0: chpr += printf("Off"); break;
499                     case 1: chpr += printf("On"); break;
500                     default: printred("undefined"); break;
501                 }
502                 print_endvalue();
503                 break;
504             case 0x0219:    /* Optical Zoom  */
505                 print_startvalue();
506                 switch(entry_ptr->value)
507                 {
508                     case 0: chpr += printf("Disabled"); break;
509                     case 1: chpr += printf("Enabled"); break;
510                     default: printred("undefined"); break;
511                 }
512                 print_endvalue();
513                 break;
514             case 0x021b:    /* Digital Zoom  */
515                 print_startvalue();
516                 switch(entry_ptr->value)
517                 {
518                     case 0: chpr += printf("Disabled"); break;
519                     case 1: chpr += printf("Enabled"); break;
520                     default: printred("undefined"); break;
521                 }
522                 print_endvalue();
523                 break;
524             case 0x021d:    /* Light Source Special  */
525                 print_startvalue();
526                 switch(entry_ptr->value)
527                 {
528                     case 0: chpr += printf("Off"); break;
529                     case 1: chpr += printf("On"); break;
530                     default: printred("undefined"); break;
531                 }
532                 print_endvalue();
533                 break;
534             case 0x021e:    /* Resaved  */
535                 print_startvalue();
536                 switch(entry_ptr->value)
537                 {
538                     case 0: chpr += printf("No"); break;
539                     case 1: chpr += printf("Yes"); break;
540                     default: printred("undefined"); break;
541                 }
542                 print_endvalue();
543                 break;
544             case 0x021f:    /* Scene Select  */
545                 print_startvalue();
546                 switch(entry_ptr->value)
547                 {
548                     case 0: chpr += printf("Off"); break;
549                     case 1: chpr += printf("Sport"); break;
550                     case 2: chpr += printf("TV?"); break;
551                     case 3: chpr += printf("Night"); break;
552                     case 4: chpr += printf("User 1"); break;
553                     case 5: chpr += printf("User 2"); break;
554                     default: printred("undefined"); break;
555                 }
556                 print_endvalue();
557                 break;
558             case 0x0224:    /* Sequential Shot Interval  */
559                 print_startvalue();
560                 switch(entry_ptr->value)
561                 {
562                     case 0: chpr += printf("5 frames/sec"); break;
563                     case 1: chpr += printf("10 frames/sec"); break;
564                     case 2: chpr += printf("15 frames/sec?"); break;
565                     case 3: chpr += printf("20 frames/sec"); break;
566                     default: printred("undefined"); break;
567                 }
568                 print_endvalue();
569                 break;
570             case 0x0225:    /* Flash Mode  */
571                 print_startvalue();
572                 switch(entry_ptr->value)
573                 {
574                     case 0: chpr += printf("Auto"); break;
575                     case 1: chpr += printf("Force"); break;
576                     case 2: chpr += printf("Disabled"); break;
577                     case 3: chpr += printf("Redeye"); break;
578                     default: printred("undefined"); break;
579                 }
580                 print_endvalue();
581                 break;
582 
583             default:
584                 break;
585         }
586     }
587     setcharsprinted(chpr);
588 }
589 
590 void
sanyo1_interpret_offset_makervalue(FILE * inptr,unsigned short byteorder,struct ifd_entry * entry_ptr,unsigned long fileoffset_base)591 sanyo1_interpret_offset_makervalue(FILE *inptr,unsigned short byteorder,
592                     struct ifd_entry *entry_ptr,unsigned long fileoffset_base)
593 {
594     unsigned long offset,value;
595     int chpr = 0;
596 
597     if(entry_ptr && (PRINT_VALUE))
598     {
599         offset = entry_ptr->value + fileoffset_base;
600         switch(entry_ptr->tag)
601         {
602             case 0x0200:    /* SpecialMode                               */
603                 value = read_ulong(inptr,byteorder,offset);
604                 print_startvalue();
605                 switch(value)
606                 {
607                     case 0: chpr += printf("Normal"); break;
608                     case 1: chpr += printf("Unkown"); break;
609                     case 2: chpr += printf("Fast"); break;
610                     case 3: chpr += printf("Panorama,");
611                             value = read_ulong(inptr,byteorder,HERE);
612                             chpr += printf("#%lu,",value);
613                             value = read_ulong(inptr,byteorder,HERE);
614                             switch(value)
615                             {
616                                 case 1: chpr += printf(" Left to Right"); break;
617                                 case 2: chpr += printf(" Right to Left"); break;
618                                 case 3: chpr += printf(" Bottom to Top"); break;
619                                 case 4: chpr += printf(" Top to Bottom"); break;
620                                 default: printred(" undefined"); break;
621                             }
622                             break;
623                     default: printred("undefined"); break;
624                 }
625                 print_endvalue();
626                 break;
627             default:
628                 break;
629         }
630     }
631     setcharsprinted(chpr);
632 }
633