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