Sat Jun 4 22:24:00 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 typedef struct _FormatRawEntry FormatRawEntry;
37 struct _FormatRawEntry {
38         const void *header_pattern;
39         const guint header_length;
40         const gchar *description;
41         FormatRawParseFunc func_parse;
42 };
43
44 static FormatRawEntry format_raw_list[] = {
45         FORMAT_RAW_CANON,
46         FORMAT_RAW_FUJI,
47         { NULL, 0, NULL, NULL }
48 };
49
50
51 typedef struct _FormatExifEntry FormatExifEntry;
52 struct _FormatExifEntry {
53         FormatExifMatchType header_type;
54         const void *header_pattern;
55         const guint header_length;
56         FormatExifParseFunc func_parse;
57 };
58
59 static FormatExifEntry format_exif_list[] = {
60         FORMAT_EXIF_CANON,
61         FORMAT_EXIF_FUJI,
62         FORMAT_EXIF_NIKON,
63         { 0, NULL, 0, NULL }
64 };
65
66
67 static FormatRawEntry *format_raw_find(const void *data, const guint len)
68 {
69         gint n;
70
71         n = 0;
72         while (format_raw_list[n].header_pattern)
73                 {
74                 if (format_raw_list[n].header_length <= len &&
75                     memcmp(data, format_raw_list[n].header_pattern, format_raw_list[n].header_length) == 0)
76                         {
77                         return &format_raw_list[n];
78                         }
79                 n++;
80                 }
81
82         return NULL;
83 }
84
85 static gint format_raw_parse(FormatRawEntry *entry,
86                              const void *data, const guint len,
87                              guint *image_offset, guint *exif_offset)
88 {
89         guint io = 0;
90         guint eo = 0;
91         gint found;
92
93         if (!entry || !entry->func_parse) return FALSE;
94
95         found = entry->func_parse(data, len, &io, &eo);
96
97         if (!found ||
98             io >= len - 4 ||
99             eo >= len)
100                 {
101                 return FALSE;
102                 }
103
104         if (image_offset) *image_offset = io;
105         if (exif_offset) *exif_offset = eo;
106
107         return TRUE;
108 }
109
110 gint format_raw_img_exif_offsets(const void *data, const guint len,
111                                  guint *image_offset, guint *exif_offset)
112 {
113         FormatRawEntry *entry;
114
115         if (!data || len < 1) return FALSE;
116
117         entry = format_raw_find(data, len);
118
119         if (!entry || !entry->func_parse) return FALSE;
120
121         return format_raw_parse(entry, data, len, image_offset, exif_offset);
122 }
123
124
125 gint format_raw_img_exif_offsets_fd(int fd, const void *header_data, const guint header_len,
126                                     guint *image_offset, guint *exif_offset)
127 {
128         FormatRawEntry *entry;
129         void *map_data = NULL;
130         size_t map_len = 0;
131         struct stat st;
132         gint success;
133
134         if (!header_data || fd < 0) return FALSE;
135
136         entry = format_raw_find(header_data, header_len);
137
138         if (!entry || !entry->func_parse) return FALSE;
139
140         if (fstat(fd, &st) == -1)
141                 {
142                 printf("Failed to stat file %d\n", fd);
143                 return FALSE;
144                 }
145         map_len = st.st_size;
146         map_data = mmap(0, map_len, PROT_READ, MAP_PRIVATE, fd, 0);
147         if (map_data == MAP_FAILED)
148                 {
149                 printf("Failed to mmap file %d\n", fd);
150                 return FALSE;
151                 }
152
153         success = format_raw_parse(entry, map_data, map_len, image_offset, exif_offset);
154
155         if (munmap(map_data, map_len) == -1)
156                 {
157                 printf("Failed to unmap file %d\n", fd);
158                 }
159
160         if (success && image_offset)
161                 {
162                 if (lseek(fd, *image_offset, SEEK_SET) != *image_offset)
163                         {
164                         printf("Failed to seek to embedded image\n");
165
166                         *image_offset = 0;
167                         if (*exif_offset) *exif_offset = 0;
168                         success = FALSE;
169                         }
170                 }
171
172         return success;
173 }
174
175
176 static FormatExifEntry *format_exif_makernote_find(ExifData *exif, unsigned char *tiff,
177                                                    guint offset, guint size)
178 {
179         ExifItem *make;
180         gint n;
181
182         make = exif_get_item(exif, "Make");
183
184         n = 0;
185         while (format_exif_list[n].header_pattern)
186                 {
187                 switch (format_exif_list[n].header_type)
188                         {
189                         case FORMAT_EXIF_MATCH_MAKERNOTE:
190                                 if (format_exif_list[n].header_length + offset < size &&
191                                     memcmp(tiff + offset, format_exif_list[n].header_pattern,
192                                                           format_exif_list[n].header_length) == 0)
193                                         {
194                                         return &format_exif_list[n];
195                                         }
196                                 break;
197                         case FORMAT_EXIF_MATCH_MAKE:
198                                 if (make &&
199                                     make->data_len >= format_exif_list[n].header_length &&
200                                     memcmp(make->data, format_exif_list[n].header_pattern,
201                                                        format_exif_list[n].header_length) == 0)
202                                         {
203                                         return &format_exif_list[n];
204                                         }
205                                 break;
206                         }
207                 n++;
208                 }
209
210         return FALSE;
211 }
212
213 gint format_exif_makernote_parse(ExifData *exif, unsigned char *tiff, guint offset,
214                                  guint size, ExifByteOrder byte_order)
215 {
216         FormatExifEntry *entry;
217
218         entry = format_exif_makernote_find(exif, tiff, offset, size);
219
220         if (!entry || !entry->func_parse) return FALSE;
221
222         return entry->func_parse(exif, tiff, offset, size, byte_order);
223 }
224
225