Extrenal srt problem gst-1 solved.
[openblackhole/openblackhole-enigma2.git] / lib / gdi / picexif.cpp
1 #include "picexif.h"
2 #include <lib/base/eerror.h>
3 #include <lib/base/cfile.h>
4
5 #define M_SOF0  0xC0
6 #define M_SOF1  0xC1
7 #define M_SOF2  0xC2
8 #define M_SOF3  0xC3
9 #define M_SOF5  0xC5
10 #define M_SOF6  0xC6
11 #define M_SOF7  0xC7
12 #define M_SOF9  0xC9
13 #define M_SOF10 0xCA
14 #define M_SOF11 0xCB
15 #define M_SOF13 0xCD
16 #define M_SOF14 0xCE
17 #define M_SOF15 0xCF
18 #define M_SOI   0xD8
19 #define M_EOI   0xD9
20 #define M_SOS   0xDA
21 #define M_JFIF  0xE0
22 #define M_EXIF  0xE1
23 #define M_COM   0xFE
24
25 #define NUM_FORMATS   12
26 #define FMT_BYTE       1
27 #define FMT_STRING     2
28 #define FMT_USHORT     3
29 #define FMT_ULONG      4
30 #define FMT_URATIONAL  5
31 #define FMT_SBYTE      6
32 #define FMT_UNDEFINED  7
33 #define FMT_SSHORT     8
34 #define FMT_SLONG      9
35 #define FMT_SRATIONAL 10
36 #define FMT_SINGLE    11
37 #define FMT_DOUBLE    12
38
39 #define TAG_EXIF_VERSION      0x9000
40 #define TAG_EXIF_OFFSET       0x8769
41 #define TAG_INTEROP_OFFSET    0xa005
42 #define TAG_MAKE              0x010F
43 #define TAG_MODEL             0x0110
44 #define TAG_ORIENTATION       0x0112
45 #define TAG_XRESOLUTION       0x011A
46 #define TAG_YRESOLUTION       0x011B
47 #define TAG_RESOLUTIONUNIT    0x0128
48 #define TAG_EXPOSURETIME      0x829A
49 #define TAG_FNUMBER           0x829D
50 #define TAG_SHUTTERSPEED      0x9201
51 #define TAG_APERTURE          0x9202
52 #define TAG_BRIGHTNESS        0x9203
53 #define TAG_MAXAPERTURE       0x9205
54 #define TAG_FOCALLENGTH       0x920A
55 #define TAG_DATETIME_ORIGINAL 0x9003
56 #define TAG_USERCOMMENT       0x9286
57 #define TAG_SUBJECT_DISTANCE  0x9206
58 #define TAG_FLASH             0x9209
59 #define TAG_FOCALPLANEXRES    0xa20E
60 #define TAG_FOCALPLANEYRES    0xa20F
61 #define TAG_FOCALPLANEUNITS   0xa210
62 #define TAG_EXIF_IMAGEWIDTH   0xA002
63 #define TAG_EXIF_IMAGELENGTH  0xA003
64 #define TAG_EXPOSURE_BIAS     0x9204
65 #define TAG_WHITEBALANCE      0x9208
66 #define TAG_METERING_MODE     0x9207
67 #define TAG_EXPOSURE_PROGRAM  0x8822
68 #define TAG_ISO_EQUIVALENT    0x8827
69 #define TAG_COMPRESSION_LEVEL 0x9102
70 #define TAG_THUMBNAIL_OFFSET  0x0201
71 #define TAG_THUMBNAIL_LENGTH  0x0202
72
73
74 Cexif::Cexif()
75 {
76 }
77
78 Cexif::~Cexif()
79 {
80 }
81
82 void Cexif::ClearExif()
83 {
84         if(freeinfo)
85         {
86                 for(int i=0;i<MAX_SECTIONS;i++)
87                         if(Sections[i].Data) free(Sections[i].Data);
88                                 delete m_exifinfo;
89                 freeinfo = false;
90         }
91 }
92
93 bool Cexif::DecodeExif(const char *filename, int Thumb)
94 {
95         CFile hFile(filename, "rb");
96         if (!hFile)
97                 return false;
98
99         m_exifinfo = new EXIFINFO;
100         memset(m_exifinfo,0,sizeof(EXIFINFO));
101         freeinfo = true;
102         m_exifinfo->Thumnailstate = Thumb;
103
104         m_szLastError[0]='\0';
105         ExifImageWidth = MotorolaOrder = SectionsRead=0;
106         memset(&Sections, 0, MAX_SECTIONS * sizeof(Section_t));
107
108         int HaveCom = 0;
109         int a = fgetc(hFile);
110         strcpy(m_szLastError,"EXIF-Data not found");
111
112         if (a != 0xff || fgetc(hFile) != M_SOI) return false;
113
114         for(;;)
115         {
116                 int marker = 0;
117                 int ll,lh, got, itemlen;
118                 unsigned char * Data;
119
120                 if (SectionsRead >= MAX_SECTIONS)
121                 {
122                         strcpy(m_szLastError,"Too many sections in jpg file"); return false;
123                 }
124
125                 for (a=0;a<7;a++)
126                 {
127                         marker = fgetc(hFile);
128                         if (marker != 0xff) break;
129
130                         if (a >= 6)
131                         {
132                                 strcpy(m_szLastError,"too many padding unsigned chars\n"); return false;
133                         }
134                 }
135
136                 if (marker == 0xff)
137                 {
138                         strcpy(m_szLastError,"too many padding unsigned chars!"); return false;
139                 }
140
141                 Sections[SectionsRead].Type = marker;
142
143                 lh = fgetc(hFile);
144                 ll = fgetc(hFile);
145
146                 itemlen = (lh << 8) | ll;
147
148                 if (itemlen < 2)
149                 {
150                         strcpy(m_szLastError,"invalid marker"); return false;
151                 }
152                 Sections[SectionsRead].Size = itemlen;
153
154                 Data = (unsigned char *)malloc(itemlen);
155                 if (Data == NULL)
156                 {
157                         strcpy(m_szLastError,"Could not allocate memory"); return false;
158                 }
159                 Sections[SectionsRead].Data = Data;
160
161
162                 Data[0] = (unsigned char)lh;
163                 Data[1] = (unsigned char)ll;
164
165                 got = fread(Data+2, 1, itemlen-2,hFile);
166                 if (got != itemlen-2)
167                 {
168                         strcpy(m_szLastError,"Premature end of file?"); return false;
169                 }
170                 SectionsRead += 1;
171
172                 switch(marker)
173                 {
174                 case M_SOS:
175                         return true;
176                 case M_EOI:
177                         eDebug("[Cexif] No image in jpeg!\n");
178                         return false;
179                 case M_COM:
180                         if (HaveCom)
181                         {
182                                 free(Sections[--SectionsRead].Data);
183                                 Sections[SectionsRead].Data=0;
184                         }
185                         else
186                         {
187                                 process_COM(Data, itemlen);
188                                 HaveCom = 1;
189                         }
190                         break;
191                 case M_JFIF:
192                         free(Sections[--SectionsRead].Data);
193                         Sections[SectionsRead].Data=0;
194                         break;
195                 case M_EXIF:
196                         if (memcmp(Data+2, "Exif", 4) == 0)
197                         {
198                                 m_exifinfo->IsExif = process_EXIF((unsigned char *)Data+2, itemlen);
199                         }
200                         else
201                         {
202                                 free(Sections[--SectionsRead].Data);
203                                 Sections[SectionsRead].Data=0;
204                         }
205                         break;
206                 case M_SOF0:
207                 case M_SOF1:
208                 case M_SOF2:
209                 case M_SOF3:
210                 case M_SOF5:
211                 case M_SOF6:
212                 case M_SOF7:
213                 case M_SOF9:
214                 case M_SOF10:
215                 case M_SOF11:
216                 case M_SOF13:
217                 case M_SOF14:
218                 case M_SOF15:
219                         process_SOFn(Data, marker);
220                         break;
221                 default:
222                         break;
223                 }
224         }
225
226         return true;
227 }
228
229 bool Cexif::process_EXIF(unsigned char * CharBuf, unsigned int length)
230 {
231         m_exifinfo->Comments[0] = '\0';
232         ExifImageWidth = 0;
233
234         static const unsigned char ExifHeader[] = "Exif\0\0";
235         if(memcmp(CharBuf+0, ExifHeader,6))
236         {
237                 strcpy(m_szLastError,"Incorrect Exif header"); return false;
238         }
239
240         if (memcmp(CharBuf+6,"II",2) == 0) MotorolaOrder = 0;
241         else
242         {
243                 if (memcmp(CharBuf+6,"MM",2) == 0) MotorolaOrder = 1;
244                 else
245                 {
246                         strcpy(m_szLastError,"Invalid Exif alignment marker."); return false;
247                 }
248         }
249
250         if (Get16u(CharBuf+8) != 0x2a)
251         {
252                 strcpy(m_szLastError,"Invalid Exif start (1)"); return false;
253         }
254         int FirstOffset = Get32u(CharBuf+10);
255         if (FirstOffset < 8 || FirstOffset > 16)
256         {
257                 strcpy(m_szLastError,"Suspicious offset of first IFD value"); return 0;
258         }
259         unsigned char * LastExifRefd = CharBuf;
260
261         if (!ProcessExifDir(CharBuf+14, CharBuf+6, length-6, m_exifinfo, &LastExifRefd)) return false;
262
263         if (m_exifinfo->FocalplaneXRes != 0)
264                 m_exifinfo->CCDWidth = (float)(ExifImageWidth * m_exifinfo->FocalplaneUnits / m_exifinfo->FocalplaneXRes);
265
266         return true;
267 }
268
269 int Cexif::Get16m(void * Short)
270 {
271         return (((unsigned char *)Short)[0] << 8) | ((unsigned char *)Short)[1];
272 }
273
274 int Cexif::Get16u(void * Short)
275 {
276         if (MotorolaOrder)
277         {
278                 return (((unsigned char *)Short)[0] << 8) | ((unsigned char *)Short)[1];
279         }
280         else
281         {
282                 return (((unsigned char *)Short)[1] << 8) | ((unsigned char *)Short)[0];
283         }
284 }
285
286 long Cexif::Get32s(void * Long)
287 {
288         if (MotorolaOrder)
289         {
290                 return  ((( char *)Long)[0] << 24) | (((unsigned char *)Long)[1] << 16) | (((unsigned char *)Long)[2] << 8 ) | (((unsigned char *)Long)[3] << 0 );
291         }
292         else
293         {
294                 return  ((( char *)Long)[3] << 24) | (((unsigned char *)Long)[2] << 16) | (((unsigned char *)Long)[1] << 8 ) | (((unsigned char *)Long)[0] << 0 );
295         }
296 }
297
298 unsigned long Cexif::Get32u(void * Long)
299 {
300         return (unsigned long)Get32s(Long) & 0xffffffff;
301 }
302
303 bool Cexif::ProcessExifDir(unsigned char * DirStart, unsigned char * OffsetBase, unsigned ExifLength, EXIFINFO * const m_exifinfo, unsigned char ** const LastExifRefdP )
304 {
305         int de, a, NumDirEntries;
306         unsigned ThumbnailOffset = 0;
307         unsigned ThumbnailSize = 0;
308
309         NumDirEntries = Get16u(DirStart);
310
311         if ((DirStart+2+NumDirEntries*12) > (OffsetBase+ExifLength))
312         {
313                 strcpy(m_szLastError,"Illegally sized directory"); return 0;
314         }
315
316         for (de=0;de<NumDirEntries;de++)
317         {
318                 int Tag, Format, Components;
319                 unsigned char * ValuePtr;
320                 int BytesCount;
321                 unsigned char * DirEntry;
322                 DirEntry = DirStart+2+12*de;
323                 Tag = Get16u(DirEntry);
324                 Format = Get16u(DirEntry+2);
325                 Components = Get32u(DirEntry+4);
326
327                 if ((Format-1) >= NUM_FORMATS)
328                 {
329                         strcpy(m_szLastError,"Illegal format code in EXIF dir"); return 0;
330                 }
331
332                 BytesCount = Components * BytesPerFormat[Format];
333
334                 if (BytesCount > 4)
335                 {
336                         unsigned OffsetVal;
337                         OffsetVal = Get32u(DirEntry+8);
338                         if (OffsetVal+BytesCount > ExifLength)
339                         {
340                                 strcpy(m_szLastError,"Illegal pointer offset value in EXIF."); return 0;
341                         }
342                         ValuePtr = OffsetBase+OffsetVal;
343                 }
344                 else ValuePtr = DirEntry+8;
345
346                 if (*LastExifRefdP < ValuePtr+BytesCount) *LastExifRefdP = ValuePtr+BytesCount;
347
348                 switch(Tag)
349                 {
350                 case TAG_MAKE:
351                         strncpy(m_exifinfo->CameraMake, (char*)ValuePtr, 31);
352                         break;
353                 case TAG_MODEL:
354                         strncpy(m_exifinfo->CameraModel, (char*)ValuePtr, 39);
355                         break;
356                 case TAG_EXIF_VERSION:
357                         strncpy(m_exifinfo->Version,(char*)ValuePtr, 4);
358                         break;
359                 case TAG_DATETIME_ORIGINAL:
360                         strncpy(m_exifinfo->DateTime, (char*)ValuePtr, 19);
361                         break;
362                 case TAG_USERCOMMENT:
363                         for (a=BytesCount;;)
364                         {
365                                 a--;
366                                 if (((char*)ValuePtr)[a] == ' ') ((char*)ValuePtr)[a] = '\0';
367                                 else break;
368
369                                 if (a == 0) break;
370                         }
371
372                         if (memcmp(ValuePtr, "ASCII",5) == 0)
373                         {
374                                 for (a=5;a<10;a++)
375                                 {
376                                         char c;
377                                         c = ((char*)ValuePtr)[a];
378                                         if (c != '\0' && c != ' ')
379                                         {
380                                                 strncpy(m_exifinfo->Comments, (char*)ValuePtr+a, 199);
381                                                 break;
382                                         }
383                                 }
384
385                         }
386                         else strncpy(m_exifinfo->Comments, (char*)ValuePtr, 199);
387                         break;
388                 case TAG_FNUMBER:
389                         m_exifinfo->ApertureFNumber = (float)ConvertAnyFormat(ValuePtr, Format);
390                         break;
391                 case TAG_APERTURE:
392                 case TAG_MAXAPERTURE:
393                         if (m_exifinfo->ApertureFNumber == 0)
394                         {
395                                 //m_exifinfo->ApertureFNumber = (float)exp(ConvertAnyFormat(ValuePtr, Format)*log(2)*0.5);
396                         }
397                         break;
398                 case TAG_BRIGHTNESS:
399                         m_exifinfo->Brightness = (float)ConvertAnyFormat(ValuePtr, Format);
400                         break;
401                 case TAG_FOCALLENGTH:
402                         m_exifinfo->FocalLength = (float)ConvertAnyFormat(ValuePtr, Format);
403                         break;
404                 case TAG_SUBJECT_DISTANCE:
405                         m_exifinfo->Distance = (float)ConvertAnyFormat(ValuePtr, Format);
406                         break;
407                 case TAG_EXPOSURETIME:
408                         m_exifinfo->ExposureTime = (float)ConvertAnyFormat(ValuePtr, Format);
409                         break;
410                 case TAG_SHUTTERSPEED:
411                         if (m_exifinfo->ExposureTime == 0)
412                         {
413                                 //m_exifinfo->ExposureTime = (float) (1/exp(ConvertAnyFormat(ValuePtr, Format)*log(2)));
414                         }
415                         break;
416                 case TAG_FLASH:
417                         if ((int)ConvertAnyFormat(ValuePtr, Format) & 7) strcpy(m_exifinfo->FlashUsed,"fire");
418                         else strcpy(m_exifinfo->FlashUsed,"not fired");
419                         break;
420                 case TAG_ORIENTATION:
421                         m_exifinfo->Orient = (int)ConvertAnyFormat(ValuePtr, Format);
422                         switch((int)ConvertAnyFormat(ValuePtr, Format))
423                         {
424                         case 1:         strcpy(m_exifinfo->Orientation,"Top-Left"); break;
425                         case 2:         strcpy(m_exifinfo->Orientation,"Top-Right"); break;
426                         case 3:         strcpy(m_exifinfo->Orientation,"Bottom-Right"); break;
427                         case 4:         strcpy(m_exifinfo->Orientation,"Bottom-Left"); break;
428                         case 5:         strcpy(m_exifinfo->Orientation,"Left-Top"); break;
429                         case 6:         strcpy(m_exifinfo->Orientation,"Right-Top"); break;
430                         case 7:         strcpy(m_exifinfo->Orientation,"Right-Bottom"); break;
431                         case 8:         strcpy(m_exifinfo->Orientation,"Left-Bottom"); break;
432                         default:        strcpy(m_exifinfo->Orientation,"Undefined"); break;
433                         }
434                         break;
435                 case TAG_EXIF_IMAGELENGTH:
436                 case TAG_EXIF_IMAGEWIDTH:
437                         a = (int)ConvertAnyFormat(ValuePtr, Format);
438                         if (ExifImageWidth < a) ExifImageWidth = a;
439                         break;
440                 case TAG_FOCALPLANEXRES:
441                         m_exifinfo->FocalplaneXRes = (float)ConvertAnyFormat(ValuePtr, Format);
442                         break;
443                 case TAG_FOCALPLANEYRES:
444                         m_exifinfo->FocalplaneYRes = (float)ConvertAnyFormat(ValuePtr, Format);
445                         break;
446                 case TAG_RESOLUTIONUNIT:
447                         switch((int)ConvertAnyFormat(ValuePtr, Format))
448                         {
449                                 case 2: strcpy(m_exifinfo->ResolutionUnit,"inches"); break;
450                                 case 3: strcpy(m_exifinfo->ResolutionUnit,"centimeters"); break;
451                                 default: strcpy(m_exifinfo->ResolutionUnit,"reserved");
452                         }
453                         break;
454                 case TAG_FOCALPLANEUNITS:
455                         switch((int)ConvertAnyFormat(ValuePtr, Format))
456                         {
457                                 case 1: m_exifinfo->FocalplaneUnits = 1.0f; break;
458                                 case 2: m_exifinfo->FocalplaneUnits = 1.0f; break;
459                                 case 3: m_exifinfo->FocalplaneUnits = 0.3937007874f; break;
460                                 case 4: m_exifinfo->FocalplaneUnits = 0.03937007874f; break;
461                                 case 5: m_exifinfo->FocalplaneUnits = 0.00003937007874f;
462                         }
463                         break;
464                 case TAG_EXPOSURE_BIAS:
465                         m_exifinfo->ExposureBias = (float) ConvertAnyFormat(ValuePtr, Format);
466                         break;
467                 case TAG_WHITEBALANCE:
468                         switch((int)ConvertAnyFormat(ValuePtr, Format))
469                         {
470                                 case 0: strcpy(m_exifinfo->LightSource,"unknown"); break;
471                                 case 1: strcpy(m_exifinfo->LightSource,"Daylight"); break;
472                                 case 2: strcpy(m_exifinfo->LightSource,"Fluorescent"); break;
473                                 case 3: strcpy(m_exifinfo->LightSource,"Tungsten"); break;
474                                 case 17: strcpy(m_exifinfo->LightSource,"Standard light A"); break;
475                                 case 18: strcpy(m_exifinfo->LightSource,"Standard light B"); break;
476                                 case 19: strcpy(m_exifinfo->LightSource,"Standard light C"); break;
477                                 case 20: strcpy(m_exifinfo->LightSource,"D55"); break;
478                                 case 21: strcpy(m_exifinfo->LightSource,"D65"); break;
479                                 case 22: strcpy(m_exifinfo->LightSource,"D75"); break;
480                                 default: strcpy(m_exifinfo->LightSource,"other"); break;
481                         }
482                         break;
483                 case TAG_METERING_MODE:
484                         switch((int)ConvertAnyFormat(ValuePtr, Format))
485                         {
486                                 case 0: strcpy(m_exifinfo->MeteringMode,"unknown"); break;
487                                 case 1: strcpy(m_exifinfo->MeteringMode,"Average"); break;
488                                 case 2: strcpy(m_exifinfo->MeteringMode,"Center-Weighted-Average"); break;
489                                 case 3: strcpy(m_exifinfo->MeteringMode,"Spot"); break;
490                                 case 4: strcpy(m_exifinfo->MeteringMode,"MultiSpot"); break;
491                                 case 5: strcpy(m_exifinfo->MeteringMode,"Pattern"); break;
492                                 case 6: strcpy(m_exifinfo->MeteringMode,"Partial"); break;
493                                 default: strcpy(m_exifinfo->MeteringMode,"other"); break;
494                         }
495                         break;
496                 case TAG_EXPOSURE_PROGRAM:
497                         switch((int)ConvertAnyFormat(ValuePtr, Format))
498                         {
499                                 case 0: strcpy(m_exifinfo->ExposureProgram,"not defined"); break;
500                                 case 1: strcpy(m_exifinfo->ExposureProgram,"Manual"); break;
501                                 case 2: strcpy(m_exifinfo->ExposureProgram,"Normal program"); break;
502                                 case 3: strcpy(m_exifinfo->ExposureProgram,"Aperture priority"); break;
503                                 case 4: strcpy(m_exifinfo->ExposureProgram,"Shutter priority"); break;
504                                 case 5: strcpy(m_exifinfo->ExposureProgram,"Creative program"); break;
505                                 case 6: strcpy(m_exifinfo->ExposureProgram,"Action program"); break;
506                                 case 7: strcpy(m_exifinfo->ExposureProgram,"Portrait mode"); break;
507                                 case 8: strcpy(m_exifinfo->ExposureProgram,"Landscape mode"); break;
508                                 default: strcpy(m_exifinfo->ExposureProgram,"reserved"); break;
509                         }
510                         break;
511                 case TAG_ISO_EQUIVALENT:
512                         m_exifinfo->ISOequivalent = (int)ConvertAnyFormat(ValuePtr, Format);
513                         if ( m_exifinfo->ISOequivalent < 50 ) m_exifinfo->ISOequivalent *= 200;
514                         break;
515                 case TAG_COMPRESSION_LEVEL:
516                         m_exifinfo->CompressionLevel = (int)ConvertAnyFormat(ValuePtr, Format);
517                         break;
518                 case TAG_XRESOLUTION:
519                         m_exifinfo->Xresolution = (float)ConvertAnyFormat(ValuePtr, Format);
520                         break;
521                 case TAG_YRESOLUTION:
522                         m_exifinfo->Yresolution = (float)ConvertAnyFormat(ValuePtr, Format);
523                         break;
524                 case TAG_THUMBNAIL_OFFSET:
525                         ThumbnailOffset = (unsigned)ConvertAnyFormat(ValuePtr, Format);
526                         break;
527                 case TAG_THUMBNAIL_LENGTH:
528                         ThumbnailSize = (unsigned)ConvertAnyFormat(ValuePtr, Format);
529                         break;
530                 }
531
532                 if (Tag == TAG_EXIF_OFFSET || Tag == TAG_INTEROP_OFFSET)
533                 {
534                         unsigned char * SubdirStart;
535                         SubdirStart = OffsetBase + Get32u(ValuePtr);
536                         if (SubdirStart < OffsetBase || SubdirStart > OffsetBase+ExifLength)
537                         {
538                                 strcpy(m_szLastError,"Illegal subdirectory link"); return 0;
539                         }
540                         ProcessExifDir(SubdirStart, OffsetBase, ExifLength, m_exifinfo, LastExifRefdP);
541                         continue;
542                 }
543         }
544
545
546         unsigned char * SubdirStart;
547         unsigned Offset;
548         Offset = Get16u(DirStart+2+12*NumDirEntries);
549         if (Offset)
550         {
551                 SubdirStart = OffsetBase + Offset;
552                 if (SubdirStart < OffsetBase || SubdirStart > OffsetBase+ExifLength)
553                 {
554                         strcpy(m_szLastError,"Illegal subdirectory link"); return 0;
555                 }
556                 ProcessExifDir(SubdirStart, OffsetBase, ExifLength, m_exifinfo, LastExifRefdP);
557         }
558
559         if (ThumbnailSize && ThumbnailOffset && m_exifinfo->Thumnailstate)
560         {
561                 if (ThumbnailSize + ThumbnailOffset <= ExifLength)
562                 {
563                         if(FILE *tf = fopen(THUMBNAILTMPFILE, "w"))
564                         {
565                                 fwrite( OffsetBase + ThumbnailOffset, ThumbnailSize, 1, tf);
566                                 fclose(tf);
567                                 m_exifinfo->Thumnailstate = 2;
568                         }
569                 }
570         }
571
572         return 1;
573 }
574
575 double Cexif::ConvertAnyFormat(void * ValuePtr, int Format)
576 {
577         double Value = 0;
578
579         switch(Format)
580         {
581                 case FMT_SBYTE:         Value = *(signed char *)ValuePtr;       break;
582                 case FMT_BYTE:          Value = *(unsigned char *)ValuePtr;     break;
583                 case FMT_USHORT:        Value = Get16u(ValuePtr);               break;
584                 case FMT_ULONG:         Value = Get32u(ValuePtr);               break;
585                 case FMT_URATIONAL:
586                 case FMT_SRATIONAL:
587                 {
588                         int Num = Get32s(ValuePtr);
589                         int Den = Get32s(4+(char *)ValuePtr);
590                         if (Den == 0) Value = 0;
591                         else Value = (double)Num/Den;
592                         break;
593                 }
594                 case FMT_SSHORT:        Value = (signed short)Get16u(ValuePtr); break;
595                 case FMT_SLONG:         Value = Get32s(ValuePtr);               break;
596                 case FMT_SINGLE:        Value = (double)*(float *)ValuePtr;     break;
597                 case FMT_DOUBLE:        Value = *(double *)ValuePtr;            break;
598         }
599         return Value;
600 }
601
602 void Cexif::process_COM (const unsigned char * Data, int length)
603 {
604         int ch,a;
605         char Comment[MAX_COMMENT+1];
606         int nch=0;
607
608         if (length > MAX_COMMENT) length = MAX_COMMENT;
609
610         for (a=2;a<length;a++)
611         {
612                 ch = Data[a];
613                 if (ch == '\r' && Data[a+1] == '\n') continue;
614                 if ((ch>=0x20) || ch == '\n' || ch == '\t') Comment[nch++] = (char)ch;
615                 else Comment[nch++] = '?';
616         }
617         Comment[nch] = '\0';
618         strcpy(m_exifinfo->Comments,Comment);
619 }
620
621 void Cexif::process_SOFn (const unsigned char * Data, int marker)
622 {
623         m_exifinfo->Height = Get16m((void*)(Data+3));
624         m_exifinfo->Width = Get16m((void*)(Data+5));
625         unsigned char num_components = Data[7];
626
627         if (num_components == 3) strcpy(m_exifinfo->IsColor,"yes");
628         else strcpy(m_exifinfo->IsColor,"no");
629
630         m_exifinfo->Process = marker;
631 }
632