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: raf.c,v 1.7 2005/07/24 20:33:55 alex Exp $";
11 #endif
12 
13 /* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- */
14 /* Fujifilm RAF routines                                              */
15 /* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- */
16 /* This is *experimental* and incomplete. It is based upon            */
17 /* examination of only four (count 'em' FOUR) images which I have     */
18 /* found on the web. This is sufficient to find and print the JPEG    */
19 /* image contained within the file, and even extract it with          */
20 /* something like 'extract_section'. The names and even identities of */
21 /* the items describing the CFA array are arbitrary and possibly      */
22 /* wrong; feedback is welcome.                                        */
23 /* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- */
24 
25 #include <stdio.h>
26 #include <string.h>
27 #include <stdlib.h>
28 #include <time.h>
29 #include <math.h>
30 
31 #include "defs.h"
32 #include "datadefs.h"
33 #include "summary.h"
34 #include "maker.h"
35 #include "misc.h"
36 #include "tags.h"
37 #include "extern.h"
38 #include "raf.h"
39 
40 
41 /* Print the RAF header information, even though it's hard to tell    */
42 /* exactly where the header ends and data begins.                     */
43 
44 int
print_raf_header(FILE * inptr,struct fileheader * fileheader,unsigned long section_id)45 print_raf_header(FILE *inptr,struct fileheader *fileheader,unsigned long section_id)
46 {
47     int status = -1;
48     int chpr = 0;
49 
50     if(Print_options & section_id)
51     {
52         /* ###%%% for now, the first 48 bytes are "header"            */
53         if(fileheader && (fileheader->probe_magic == PROBE_RAFMAGIC))
54         {
55             print_ascii(inptr,28,0);
56             chpr += printf(" Model = ");
57             print_ascii(inptr,16,28);
58             status = 0;
59         }
60         else
61             chpr += printf(" NOT AN RAF HEADER");
62     }
63     chpr = newline(chpr);
64     return(status);
65 }
66 
67 /* Process a Fujifilm RAF file, starting right after the RAF header.  */
68 /* At this point, I *think* the location of the jpeg image is fixed;  */
69 /* the rest is unclear, but do the best we can.                       */
70 
71 unsigned long
process_raf(FILE * inptr,unsigned long offset,struct image_summary * summary_entry,char * parent_name,int indent)72 process_raf(FILE *inptr,unsigned long offset,
73             struct image_summary *summary_entry,
74             char *parent_name,int indent)
75 {
76     unsigned long start_of_jpeg,jpeg_length,max_offset;
77     unsigned long table1_offset,table2_offset;
78     unsigned long table1_length,table2_length;
79     unsigned long CFA_offset,CFA_length;
80     unsigned long unknown2,CFA_primaryarraywidth,CFA_fullarraywidth;
81     unsigned long Secondary_offset,Secondary_length;
82     unsigned long unknown3,Secondary_arraywidth,Secondary_fullarraywidth;
83     unsigned long unused_value;
84     struct image_summary *tmp_summary_entry;
85     int unused;
86     char *fullname = CNULL;
87     int chpr = 0;
88     unsigned short tag;
89 
90 
91     CFA_primaryarraywidth = Secondary_offset = table1_offset = table2_offset =  0UL;
92 
93     /* Record the primary for the image summary                       */
94     if(((summary_entry == NULL) || summary_entry->entry_lock) ||
95                         (summary_entry->imageformat != IMGFMT_NOIMAGE))
96     {
97         summary_entry = new_summary_entry(summary_entry,FILEFMT_RAF,IMGFMT_RAF);
98     }
99     if(summary_entry)
100     {
101         summary_entry->imageformat = IMGFMT_RAF;
102         summary_entry->imagesubformat = IMGSUBFMT_CFA;
103         summary_entry->entry_lock = lock_number(summary_entry);
104     }
105     chpr = newline(chpr);
106 
107     /* A short section of zeros; why?                                 */
108     if((PRINT_SECTION))
109     {
110         print_tag_address(SECTION,offset,indent,"@");
111         chpr += printf("<Offset Directory>");
112         chpr = newline(chpr);
113         print_tag_address(ENTRY,offset,indent + SMALLINDENT,"@");
114         if((PRINT_VALUE))
115             print_ubytes(inptr,16,offset);
116         chpr = newline(chpr);
117     }
118     offset += 16;
119 
120     /* Some sort of ID or version?                                    */
121     print_tag_address(ENTRY,offset,indent + SMALLINDENT,"@");
122     if((PRINT_TAGINFO))
123     {
124         if((PRINT_LONGNAMES))
125             chpr += printf("%s.",parent_name);
126         chpr += printf("%-*.*s",TAGWIDTH,TAGWIDTH,"unknown1");
127     }
128     if((PRINT_VALUE))
129     {
130         chpr += printf(" = ");
131         print_ascii(inptr,4,60);
132     }
133     chpr = newline(chpr);
134     offset += 4;
135 
136     /* Another short section of zeros. Why again?                     */
137     if((PRINT_SECTION))
138     {
139         print_tag_address(ENTRY,offset,indent + SMALLINDENT,"@");
140         if((PRINT_VALUE))
141             print_ubytes(inptr,16,offset);
142         chpr = newline(chpr);
143     }
144 
145     /* A jpeg reduced resolution image, complete with EXIF            */
146     start_of_jpeg = read_ulong(inptr,TIFF_MOTOROLA,RAF_JPEGLOC);
147     print_tag_address(ENTRY,RAF_JPEGLOC,indent + SMALLINDENT,"@");
148     if((PRINT_TAGINFO))
149     {
150         if((PRINT_LONGNAMES))
151             chpr += printf("%s.",parent_name);
152         chpr += printf("%-*.*s",TAGWIDTH,TAGWIDTH,"JpegImageOffset");
153     }
154     if((PRINT_VALUE))
155         chpr += printf(" = @%lu",start_of_jpeg);
156     chpr = newline(chpr);
157     print_tag_address(ENTRY,RAF_JPEGLOC + 4,indent + SMALLINDENT,"@");
158     jpeg_length = read_ulong(inptr,TIFF_MOTOROLA,RAF_JPEGLOC + 4);
159     if((PRINT_TAGINFO))
160     {
161         if((PRINT_LONGNAMES))
162             chpr += printf("%s.",parent_name);
163         chpr += printf("%-*.*s",TAGWIDTH,TAGWIDTH,"JpegImageLength");
164     }
165     if((PRINT_VALUE))
166         chpr += printf(" = %lu",jpeg_length);
167     chpr = newline(chpr);
168 
169     /* An offset to what may be a white balance table                 */
170     print_tag_address(ENTRY,RAF_JPEGLOC + 8,indent + SMALLINDENT,"@");
171     table1_offset = read_ulong(inptr,TIFF_MOTOROLA,RAF_JPEGLOC + 8);
172     table1_length = read_ulong(inptr,TIFF_MOTOROLA,HERE);
173     if((PRINT_TAGINFO))
174     {
175         if((PRINT_LONGNAMES))
176             chpr += printf("%s.",parent_name);
177         chpr += printf("%-*.*s",TAGWIDTH,TAGWIDTH,"Table1Offset");
178     }
179     if((PRINT_VALUE))
180         chpr += printf(" = @%lu",table1_offset);
181     chpr = newline(chpr);
182 
183     /* The length of the table; probably also the number of rows in   */
184     /* the CFA array                                                  */
185     print_tag_address(ENTRY,RAF_JPEGLOC + 12,indent + SMALLINDENT,"@");
186     table1_length = read_ulong(inptr,TIFF_MOTOROLA,RAF_JPEGLOC + 12);
187     if((PRINT_TAGINFO))
188     {
189         if((PRINT_LONGNAMES))
190             chpr += printf("%s.",parent_name);
191         chpr += printf("%-*.*s",TAGWIDTH,TAGWIDTH,"Table1Length");
192     }
193     if((PRINT_VALUE))
194         chpr += printf(" = %lu",table1_length);
195     chpr = newline(chpr);
196 
197     /* If there is a second table, this must be an SR Super CCD with  */
198     /* a secondary CFA table containing the data for the secondary    */
199     /* photodiodes. The start offset for the secondary data is offset */
200     /* one row (2944 bytes) from the start of the primary data,       */
201     /* suggesting that the primary and secondary CFA arrays are       */
202     /* interleaved by rows (of 1472 unsigned shorts)                  */
203 
204     table2_offset = read_ulong(inptr,TIFF_MOTOROLA,RAF_JPEGLOC + 36);
205     table2_length = read_ulong(inptr,TIFF_MOTOROLA,HERE);
206     if(table2_offset == 0)
207     {
208         print_tag_address(ENTRY,RAF_JPEGLOC + 16,indent + SMALLINDENT,"@");
209         CFA_offset = read_ulong(inptr,TIFF_MOTOROLA,RAF_JPEGLOC + 16);
210         CFA_length = read_ulong(inptr,TIFF_MOTOROLA,HERE);
211         Secondary_length = 0;
212         if((PRINT_TAGINFO))
213         {
214             if((PRINT_LONGNAMES))
215                 chpr += printf("%s.",parent_name);
216             chpr += printf("%-*.*s",TAGWIDTH,TAGWIDTH,"CFAOffset");
217         }
218         if((PRINT_VALUE))
219             chpr += printf(" = @%lu",CFA_offset);
220         chpr = newline(chpr);
221         print_tag_address(ENTRY,RAF_JPEGLOC + 20,indent + SMALLINDENT,"@");
222         if((PRINT_TAGINFO))
223         {
224             if((PRINT_LONGNAMES))
225                 chpr += printf("%s.",parent_name);
226             chpr += printf("%-*.*s",TAGWIDTH,TAGWIDTH,"CFALength");
227         }
228         if((PRINT_VALUE))
229             chpr += printf(" = %lu",CFA_length);
230         chpr = newline(chpr);
231         for(unused = 24; unused < 64; unused += 4)
232         {
233             print_tag_address(ENTRY,RAF_JPEGLOC + unused,indent + SMALLINDENT,"@");
234             unused_value = read_ulong(inptr,TIFF_MOTOROLA,(unsigned long)(RAF_JPEGLOC + unused));
235             if((PRINT_TAGINFO))
236             {
237                 if((PRINT_LONGNAMES))
238                     chpr += printf("%s.",parent_name);
239                 chpr += printf("%s%-2d%*.*s","unused",(unused - 24)/4 + 1,TAGWIDTH-8,TAGWIDTH-8," ");
240             }
241             if((PRINT_VALUE))
242                 chpr += printf(" = %lu",unused_value);
243             chpr = newline(chpr);
244         }
245     }
246     else
247     {
248         /* No secondary; easy.                                        */
249         CFA_offset = read_ulong(inptr,TIFF_MOTOROLA,RAF_JPEGLOC + 16);
250         CFA_length = read_ulong(inptr,TIFF_MOTOROLA,RAF_JPEGLOC + 20);
251 
252         print_tag_address(ENTRY,RAF_JPEGLOC + 16,indent + SMALLINDENT,"@");
253         if((PRINT_TAGINFO))
254         {
255             if((PRINT_LONGNAMES))
256                 chpr += printf("%s.",parent_name);
257             chpr += printf("%-*.*s",TAGWIDTH,TAGWIDTH,"CFA_Offset");
258         }
259         if((PRINT_VALUE))
260             chpr += printf(" = @%lu",CFA_offset);
261         chpr = newline(chpr);
262 
263         print_tag_address(ENTRY,RAF_JPEGLOC + 20,indent + SMALLINDENT,"@");
264         if((PRINT_TAGINFO))
265         {
266             if((PRINT_LONGNAMES))
267                 chpr += printf("%s.",parent_name);
268             chpr += printf("%-*.*s",TAGWIDTH,TAGWIDTH,"CFA_length");
269         }
270         if((PRINT_VALUE))
271             chpr += printf(" = @%lu",CFA_length);
272         chpr = newline(chpr);
273 
274         print_tag_address(ENTRY,RAF_JPEGLOC + 24,indent + SMALLINDENT,"@");
275         unknown2 = read_ulong(inptr,TIFF_MOTOROLA,RAF_JPEGLOC + 24);
276         if((PRINT_TAGINFO))
277         {
278             if((PRINT_LONGNAMES))
279                 chpr += printf("%s.",parent_name);
280             chpr += printf("%-*.*s",TAGWIDTH,TAGWIDTH,"unknown2");
281         }
282         if((PRINT_VALUE))
283             chpr += printf(" = %lu",unknown2);
284         chpr = newline(chpr);
285 
286         CFA_primaryarraywidth = read_ulong(inptr,TIFF_MOTOROLA,RAF_JPEGLOC + 28);
287         print_tag_address(ENTRY,RAF_JPEGLOC + 28,indent + SMALLINDENT,"@");
288         if((PRINT_TAGINFO))
289         {
290             /* Array width in 16 bit unsigned shorts                  */
291             if((PRINT_LONGNAMES))
292                 chpr += printf("%s.",parent_name);
293             chpr += printf("%-*.*s",TAGWIDTH,TAGWIDTH,"CFAPrimaryArrayWidth");
294         }
295         if((PRINT_VALUE))
296             chpr += printf(" = %lu",CFA_primaryarraywidth);
297         chpr = newline(chpr);
298 
299         print_tag_address(ENTRY,RAF_JPEGLOC + 32,indent + SMALLINDENT,"@");
300         CFA_fullarraywidth = read_ulong(inptr,TIFF_MOTOROLA,RAF_JPEGLOC + 32);
301         if((PRINT_TAGINFO))
302         {
303             /* Array width in bytes                                   */
304             if((PRINT_LONGNAMES))
305                 chpr += printf("%s.",parent_name);
306             chpr += printf("%-*.*s",TAGWIDTH,TAGWIDTH,"CFAFullArrayWidth");
307         }
308         if((PRINT_VALUE))
309             chpr += printf(" = %lu",CFA_fullarraywidth);
310         chpr = newline(chpr);
311 
312         print_tag_address(ENTRY,RAF_JPEGLOC + 36,indent + SMALLINDENT,"@");
313         if((PRINT_TAGINFO))
314         {
315             if((PRINT_LONGNAMES))
316                 chpr += printf("%s.",parent_name);
317             chpr += printf("%-*.*s",TAGWIDTH,TAGWIDTH,"Table2Offset");
318         }
319         if((PRINT_VALUE))
320             chpr += printf(" = @%lu",table2_offset);
321         chpr = newline(chpr);
322         print_tag_address(ENTRY,RAF_JPEGLOC + 40,indent + SMALLINDENT,"@");
323         if((PRINT_TAGINFO))
324         {
325             if((PRINT_LONGNAMES))
326                 chpr += printf("%s.",parent_name);
327             chpr += printf("%-*.*s",TAGWIDTH,TAGWIDTH,"Table2Length");
328         }
329         if((PRINT_VALUE))
330             chpr += printf(" = %lu",table2_length);
331         chpr = newline(chpr);
332 
333         /* It appears that the secondary CFA data is interlaced by    */
334         /* row with the primary data.                                 */
335         Secondary_offset = read_ulong(inptr,TIFF_MOTOROLA,RAF_JPEGLOC + 44);
336         Secondary_length = read_ulong(inptr,TIFF_MOTOROLA,HERE);
337         print_tag_address(ENTRY,RAF_JPEGLOC + 44,indent + SMALLINDENT,"@");
338         if((PRINT_TAGINFO))
339         {
340             if((PRINT_LONGNAMES))
341                 chpr += printf("%s.",parent_name);
342             chpr += printf("%-*.*s",TAGWIDTH,TAGWIDTH,"CFASecondaryOffset**");
343         }
344         if((PRINT_VALUE))
345             chpr += printf(" = @%lu",Secondary_offset);
346         chpr = newline(chpr);
347         print_tag_address(ENTRY,RAF_JPEGLOC + 48,indent + SMALLINDENT,"@");
348         if((PRINT_TAGINFO))
349         {
350             if((PRINT_LONGNAMES))
351                 chpr += printf("%s.",parent_name);
352             chpr += printf("%-*.*s",TAGWIDTH,TAGWIDTH,"CFASecondaryLength**");
353         }
354         if((PRINT_VALUE))
355             chpr += printf(" = %lu",Secondary_length);
356         chpr = newline(chpr);
357 
358         unknown3 = read_ulong(inptr,TIFF_MOTOROLA,RAF_JPEGLOC + 52);
359         Secondary_arraywidth = read_ulong(inptr,TIFF_MOTOROLA,RAF_JPEGLOC + 56);
360         Secondary_fullarraywidth = read_ulong(inptr,TIFF_MOTOROLA,RAF_JPEGLOC + 60);
361         print_tag_address(ENTRY,RAF_JPEGLOC + 52,indent + SMALLINDENT,"@");
362         if((PRINT_TAGINFO))
363         {
364             if((PRINT_LONGNAMES))
365                 chpr += printf("%s.",parent_name);
366             chpr += printf("%-*.*s",TAGWIDTH,TAGWIDTH,"unknown3");
367         }
368         if((PRINT_VALUE))
369             chpr += printf(" = %lu",unknown3);
370         chpr = newline(chpr);
371         print_tag_address(ENTRY,RAF_JPEGLOC + 56,indent + SMALLINDENT,"@");
372         if((PRINT_TAGINFO))
373         {
374             if((PRINT_LONGNAMES))
375                 chpr += printf("%s.",parent_name);
376             chpr += printf("%-*.*s",TAGWIDTH,TAGWIDTH,"CFASecondaryArrayWidth");
377         }
378         if((PRINT_VALUE))
379             chpr += printf(" = %lu",Secondary_arraywidth);
380         chpr = newline(chpr);
381         print_tag_address(ENTRY,RAF_JPEGLOC + 60,indent + SMALLINDENT,"@");
382         if((PRINT_TAGINFO))
383         {
384             if((PRINT_LONGNAMES))
385                 chpr += printf("%s.",parent_name);
386             /* I dunno what to call this...                           */
387             chpr += printf("%-*.*s",TAGWIDTH,TAGWIDTH,"CFASecondaryFullArrayWidth");
388         }
389         if((PRINT_VALUE))
390             chpr += printf(" = %lu",Secondary_fullarraywidth);
391         chpr = newline(chpr);
392     }
393     if((PRINT_SECTION))
394     {
395         print_tag_address(SECTION,RAF_JPEGLOC + 63,indent,"@");
396         chpr += printf("</Offset Directory>");
397         chpr = newline(chpr);
398     }
399 
400     /* Finish the summary entry                                       */
401     if(summary_entry)
402     {
403         if(summary_entry->length <= 0)
404             summary_entry->length = CFA_length + Secondary_length;
405         if(summary_entry->offset <= 0)
406             summary_entry->offset = CFA_offset;
407         /* Not really compression; just record the presence of the    */
408         /* secondary                                                  */
409         if(Secondary_offset)
410             summary_entry->compression = 1;
411         else
412             summary_entry->compression = 0;
413 
414         /* These aren't really pixel sizes, since the actual number   */
415         /* of columns is half the arraywidth, and the array will have */
416         /* to be rotated 45 degrees. And then there is the secondary  */
417         /* pixel data...                                              */
418         /* It's what we know, and post-processing can do what it      */
419         /* wants.                                                     */
420         if(CFA_primaryarraywidth)
421         {
422             summary_entry->pixel_width = CFA_primaryarraywidth;
423             summary_entry->pixel_height = table1_length;
424             summary_entry->primary_width = CFA_primaryarraywidth;
425             summary_entry->primary_height = table1_length;
426         }
427         else
428         {
429             /* No size provided; this is the best we can do.          */
430             summary_entry->pixel_width = (CFA_length + Secondary_length)/table1_length;
431             summary_entry->pixel_height = table1_length;
432             summary_entry->primary_width = summary_entry->pixel_width;
433             summary_entry->primary_height = table1_length;
434         }
435         summary_entry->subfiletype = PRIMARY_TYPE;
436     }
437 
438     /* Now display the offset sections, starting with the jpeg image  */
439     /* (but only if showing sections)                                 */
440     if((PRINT_SECTION))
441     {
442         print_tag_address(SECTION,start_of_jpeg,indent,"@");
443         chpr += printf("#### Start of Jpeg Image, length %lu",jpeg_length);
444         chpr = newline(chpr);
445     }
446 
447     /* Is this really a jpeg section?                             */
448     tag = read_ushort(inptr,TIFF_MOTOROLA,start_of_jpeg);
449     if(tag == JPEG_SOI)
450     {
451         /* If so, process it regardless of output options, to pick up */
452         /* information for the image summary                          */
453         fullname = splice(parent_name,".","JPEG");
454         max_offset = process_jpeg_segments(inptr,start_of_jpeg,JPEG_SOI,jpeg_length,
455                                                 summary_entry,fullname,"@",SMALLINDENT);
456         print_jpeg_status();
457         if(summary_entry)
458         {
459             /* The jpeg summary entry should be next in the chain;    */
460             /* there may be others following; mark the jpeg entry so  */
461             /* that it will show up in the format summary.            */
462             if((tmp_summary_entry = summary_entry->next_entry))
463                 tmp_summary_entry->filesubformat |= FILESUBFMT_JPEG;
464         }
465     }
466     else
467         dumpsection(inptr,start_of_jpeg,jpeg_length,indent + SMALLINDENT);
468 
469     if((PRINT_SECTION))
470     {
471         print_tag_address(SECTION,start_of_jpeg + jpeg_length - 1,indent,"@");
472         chpr += printf("#### End of Jpeg Image, length %lu",jpeg_length);
473         chpr = newline(chpr);
474 
475         print_tag_address(SECTION,table1_offset,indent,"@");
476         chpr += printf("<Table 1> length %lu",table1_length);
477         chpr = newline(chpr);
478         if((PRINT_VALUE))
479             dumpsection(inptr,table1_offset,table1_length,indent + SMALLINDENT);
480         print_tag_address(SECTION,table1_offset + table1_length - 1,indent,"@");
481         chpr += printf("</Table 1>");
482         chpr = newline(chpr);
483 
484         if(table2_offset)
485         {
486             print_tag_address(SECTION,table2_offset,indent,"@");
487             chpr += printf("<Table 2> length %lu",table2_length);
488             chpr = newline(chpr);
489             if((PRINT_VALUE))
490                 dumpsection(inptr,table2_offset,table2_length,indent + SMALLINDENT);
491             print_tag_address(SECTION,table2_offset + table2_length - 1,indent,"@");
492             chpr += printf("</Table 2>");
493             chpr = newline(chpr);
494         }
495 
496         /* The full CFA, with secondary if present                    */
497         print_tag_address(SECTION,CFA_offset,indent,"@");
498         chpr += printf("<CFA Image> length %lu",CFA_length + Secondary_length);
499         chpr = newline(chpr);
500         if((PRINT_VALUE))
501             dumpsection(inptr,CFA_offset,CFA_length + Secondary_length,indent + SMALLINDENT);
502         print_tag_address(SECTION,CFA_offset + CFA_length + Secondary_length - 1,indent,"@");
503         chpr += printf("</CFA Image>");
504         chpr = newline(chpr);
505 
506     }
507 
508     setcharsprinted(chpr);
509     return(get_filesize(inptr));
510 }
511 
512