Tue Jun 7 03:47:03 2005 John Ellis <johne@verizon.net>
[geeqie.git] / src / format_raw.c
1 /*
2  *  GQView
3  *  (C) 2005 John Ellis
4  *
5  *  Authors:
6  *    Original version 2005 Lars Ellenberg, base on dcraw by David coffin.
7  *
8  * This software is released under the GNU General Public License (GNU GPL).
9  * Please read the included file COPYING for more information.
10  * This software comes with no warranty of any kind, use at your own risk!
11  */
12
13 #ifdef HAVE_CONFIG_H
14 #  include "config.h"
15 #endif
16
17
18 #include <stdio.h>
19 #include <string.h>
20 #include <unistd.h>
21 #include <sys/types.h>
22 #include <sys/stat.h>
23 #include <sys/mman.h>
24
25 #include <glib.h>
26
27 #include "intl.h"
28
29 #include "format_raw.h"
30
31 #include "format_canon.h"
32 #include "format_fuji.h"
33 #include "format_nikon.h"
34
35
36 /* so that debugging is honored */
37 extern gint debug;
38
39
40 typedef struct _FormatRawEntry FormatRawEntry;
41 struct _FormatRawEntry {
42         const void *header_pattern;
43         const guint header_length;
44         const gchar *description;
45         FormatRawParseFunc func_parse;
46 };
47
48 static FormatRawEntry format_raw_list[] = {
49         FORMAT_RAW_CANON,
50         FORMAT_RAW_FUJI,
51         FORMAT_RAW_NIKON,
52         { NULL, 0, NULL, NULL }
53 };
54
55
56 typedef struct _FormatExifEntry FormatExifEntry;
57 struct _FormatExifEntry {
58         FormatExifMatchType header_type;
59         const void *header_pattern;
60         const guint header_length;
61         const gchar *description;
62         FormatExifParseFunc func_parse;
63 };
64
65 static FormatExifEntry format_exif_list[] = {
66         FORMAT_EXIF_CANON,
67         FORMAT_EXIF_FUJI,
68         FORMAT_EXIF_NIKON,
69         { 0, NULL, 0, NULL }
70 };
71
72
73 static FormatRawEntry *format_raw_find(const void *data, const guint len)
74 {
75         gint n;
76
77         n = 0;
78         while (format_raw_list[n].header_pattern)
79                 {
80                 if (format_raw_list[n].header_length <= len &&
81                     memcmp(data, format_raw_list[n].header_pattern, format_raw_list[n].header_length) == 0)
82                         {
83                         return &format_raw_list[n];
84                         }
85                 n++;
86                 }
87
88         return NULL;
89 }
90
91 static gint format_raw_parse(FormatRawEntry *entry,
92                              const void *data, const guint len,
93                              guint *image_offset, guint *exif_offset)
94 {
95         guint io = 0;
96         guint eo = 0;
97         gint found;
98
99         if (!entry || !entry->func_parse) return FALSE;
100
101         if (debug) printf("RAW using file parser for %s\n", entry->description);
102
103         found = entry->func_parse(data, len, &io, &eo);
104
105         if (!found ||
106             io >= len - 4 ||
107             eo >= len)
108                 {
109                 return FALSE;
110                 }
111
112         if (image_offset) *image_offset = io;
113         if (exif_offset) *exif_offset = eo;
114
115         return TRUE;
116 }
117
118 gint format_raw_img_exif_offsets(const void *data, const guint len,
119                                  guint *image_offset, guint *exif_offset)
120 {
121         FormatRawEntry *entry;
122
123         if (!data || len < 1) return FALSE;
124
125         entry = format_raw_find(data, len);
126
127         if (!entry || !entry->func_parse) return FALSE;
128
129         return format_raw_parse(entry, data, len, image_offset, exif_offset);
130 }
131
132
133 gint format_raw_img_exif_offsets_fd(int fd, const void *header_data, const guint header_len,
134                                     guint *image_offset, guint *exif_offset)
135 {
136         FormatRawEntry *entry;
137         void *map_data = NULL;
138         size_t map_len = 0;
139         struct stat st;
140         gint success;
141
142         if (!header_data || fd < 0) return FALSE;
143
144         entry = format_raw_find(header_data, header_len);
145
146         if (!entry || !entry->func_parse) return FALSE;
147
148         if (fstat(fd, &st) == -1)
149                 {
150                 printf("Failed to stat file %d\n", fd);
151                 return FALSE;
152                 }
153         map_len = st.st_size;
154         map_data = mmap(0, map_len, PROT_READ, MAP_PRIVATE, fd, 0);
155         if (map_data == MAP_FAILED)
156                 {
157                 printf("Failed to mmap file %d\n", fd);
158                 return FALSE;
159                 }
160
161         success = format_raw_parse(entry, map_data, map_len, image_offset, exif_offset);
162
163         if (munmap(map_data, map_len) == -1)
164                 {
165                 printf("Failed to unmap file %d\n", fd);
166                 }
167
168         if (success && image_offset)
169                 {
170                 if (lseek(fd, *image_offset, SEEK_SET) != *image_offset)
171                         {
172                         printf("Failed to seek to embedded image\n");
173
174                         *image_offset = 0;
175                         if (*exif_offset) *exif_offset = 0;
176                         success = FALSE;
177                         }
178                 }
179
180         return success;
181 }
182
183
184 static FormatExifEntry *format_exif_makernote_find(ExifData *exif, unsigned char *tiff,
185                                                    guint offset, guint size)
186 {
187         ExifItem *make;
188         gint n;
189
190         make = exif_get_item(exif, "Make");
191
192         n = 0;
193         while (format_exif_list[n].header_pattern)
194                 {
195                 switch (format_exif_list[n].header_type)
196                         {
197                         case FORMAT_EXIF_MATCH_MAKERNOTE:
198                                 if (format_exif_list[n].header_length + offset < size &&
199                                     memcmp(tiff + offset, format_exif_list[n].header_pattern,
200                                                           format_exif_list[n].header_length) == 0)
201                                         {
202                                         return &format_exif_list[n];
203                                         }
204                                 break;
205                         case FORMAT_EXIF_MATCH_MAKE:
206                                 if (make &&
207                                     make->data_len >= format_exif_list[n].header_length &&
208                                     memcmp(make->data, format_exif_list[n].header_pattern,
209                                                        format_exif_list[n].header_length) == 0)
210                                         {
211                                         return &format_exif_list[n];
212                                         }
213                                 break;
214                         }
215                 n++;
216                 }
217
218         return FALSE;
219 }
220
221 gint format_exif_makernote_parse(ExifData *exif, unsigned char *tiff, guint offset,
222                                  guint size, ExifByteOrder byte_order)
223 {
224         FormatExifEntry *entry;
225
226         entry = format_exif_makernote_find(exif, tiff, offset, size);
227
228         if (!entry || !entry->func_parse) return FALSE;
229
230         if (debug) printf("EXIF using makernote parser for %s\n", entry->description);
231
232         return entry->func_parse(exif, tiff, offset, size, byte_order);
233 }
234
235