2004-11-10 Lutz Mueller <lutz@users.sourceforge.net>
[platform/upstream/libexif.git] / libexif / exif-loader.c
1 #include <config.h>
2
3 #include <libexif/exif-loader.h>
4 #include <libexif/i18n.h>
5
6 #include <stdlib.h>
7 #include <string.h>
8 #include <stdio.h>
9
10 #include <libjpeg/jpeg-marker.h>
11
12 typedef enum {
13         EL_READ = 0,
14         EL_READ_SIZE_HIGH_BYTE,
15         EL_READ_SIZE_LOW_BYTE,
16         EL_SKIP_BYTES,
17         EL_EXIF_FOUND,
18         EL_FAILED
19 } ExifLoaderState;
20
21 struct _ExifLoader {
22         ExifLoaderState state;
23
24         unsigned int size;
25         int last_marker;
26         unsigned char *buf;
27         unsigned int bytes_read;
28
29         unsigned int ref_count;
30
31         ExifLog *log;
32         ExifMem *mem;
33 };
34
35 static void *
36 exif_loader_alloc (ExifLoader *l, unsigned int i)
37 {
38         void *d;
39
40         if (!l || !i) return NULL;
41
42         d = exif_mem_alloc (l->mem, i);
43         if (d) return d;
44
45         EXIF_LOG_NO_MEMORY (l->log, "ExifLog", i);
46         return NULL;
47 }
48
49 #undef  MIN
50 #define MIN(a, b)  (((a) < (b)) ? (a) : (b))
51
52 void
53 exif_loader_write_file (ExifLoader *l, const char *path)
54 {
55         FILE *f;
56         int size;
57         unsigned char data[1024];
58
59         if (!l) return;
60
61         f = fopen (path, "rb");
62         if (!f) {
63                 exif_log (l->log, EXIF_LOG_CODE_NONE, "ExifLoader",
64                           _("The file '%s' could not be opened."), path);
65                 return;
66         }
67         while (1) {
68                 size = fread (data, 1, sizeof (data), f);
69                 if (size <= 0) break;
70                 if (!exif_loader_write (l, data, size)) break;
71         }
72         fclose (f);
73 }
74
75 unsigned char
76 exif_loader_write (ExifLoader *eld, unsigned char *buf, unsigned int len)
77 {
78         unsigned int i, len_remain;
79
80         if (!eld || !buf || !len) return 0;
81         if (eld->state == EL_FAILED) return 0;
82         if (eld->size && eld->bytes_read == eld->size) return 0;
83
84         exif_log (eld->log, EXIF_LOG_CODE_DEBUG, "ExifLoader",
85                   "Scanning %i byte(s) of data...", len);
86
87         for (i = 0; (i < len) && (eld->state != EL_EXIF_FOUND) &&
88                                  (eld->state != EL_FAILED); i++) 
89                 switch (eld->state) {
90                 case EL_SKIP_BYTES:
91                         eld->size--;
92                         if (eld->size == 0) {
93                                 eld->state = EL_READ;
94                         }
95                         break;
96                         
97                 case EL_READ_SIZE_HIGH_BYTE:
98                         eld->size = buf [i] << 8;
99                         eld->state = EL_READ_SIZE_LOW_BYTE;
100                         break;
101                         
102                 case EL_READ_SIZE_LOW_BYTE:
103                         eld->size |= buf [i];
104
105                         switch (eld->last_marker) {
106                         case JPEG_MARKER_APP0:
107                         case JPEG_MARKER_APP13:
108                         case JPEG_MARKER_COM:
109                                 eld->state = EL_SKIP_BYTES;
110                                 eld->size -= 2;
111                                 break;
112
113                         case JPEG_MARKER_APP1:
114                                 eld->state = EL_EXIF_FOUND;
115                                 break;
116
117                         case 0:
118                                 /*
119                                  * Assume that we are reading EXIF data. 
120                                  * This should probably be verified by reading
121                                  * some bytes ahead.
122                                  */
123                                 eld->state = EL_EXIF_FOUND;
124                                 break;
125                         default:
126                                 return 0;
127                         }
128
129                         eld->last_marker = 0;
130                         break;
131
132                 default:
133                         if (buf[i] != 0xff) {
134                                 if (buf[i] == JPEG_MARKER_APP0 ||
135                                     buf[i] == JPEG_MARKER_APP1 ||
136                                     buf[i] == JPEG_MARKER_APP13 ||
137                                     buf[i] == JPEG_MARKER_COM) {
138                                         eld->state = EL_READ_SIZE_HIGH_BYTE;
139                                         eld->last_marker = buf [i];
140
141                                 } else if (buf [i] == JPEG_MARKER_SOI) {
142                                         /* Nothing */
143                                 } else {
144                                         /* Assume that we are reading EXIF
145                                          * data. This should probably be
146                                          * verified by reading some bytes
147                                          * ahead.
148                                          */
149                                         eld->last_marker = JPEG_MARKER_APP1;
150                                         eld->state = EL_READ_SIZE_HIGH_BYTE;
151                                         i--;
152                                 }
153                         }
154                 }
155
156         len_remain = len - i;
157         if (!len_remain) return 1;
158
159         if (eld->state == EL_EXIF_FOUND) {
160                 if (eld->buf == NULL) {
161                         eld->buf = exif_loader_alloc (eld, eld->size);
162                         if (!eld->buf) return 0;
163                         eld->bytes_read = 0;
164                 }
165
166                 if (eld->bytes_read < eld->size) {
167                         int cp_len;
168
169                         /* the number of bytes we need to copy */
170                         cp_len = MIN (eld->size - eld->bytes_read, len_remain);
171                         
172                         if ((cp_len + eld->bytes_read) > eld->size) return 1;
173
174                         /* Copy memory */
175                         memcpy (eld->buf + eld->bytes_read, &buf[i], cp_len);
176                         eld->bytes_read += cp_len;
177                 }
178         }
179
180         return 1;
181 }
182
183 ExifLoader *
184 exif_loader_new (void)
185 {
186         ExifMem *mem = exif_mem_new_default ();
187         ExifLoader *l = exif_loader_new_mem (mem);
188
189         exif_mem_unref (mem);
190
191         return l;
192 }
193
194 ExifLoader *
195 exif_loader_new_mem (ExifMem *mem)
196 {
197         ExifLoader *loader;
198
199         if (!mem) return NULL;
200         
201         loader = exif_mem_alloc (mem, sizeof (ExifLoader));
202         if (!loader) return NULL;
203         loader->ref_count = 1;
204
205         loader->mem = mem;
206         exif_mem_ref (mem);
207
208         return loader;
209 }
210
211 void
212 exif_loader_ref (ExifLoader *loader)
213 {
214         if (loader) loader->ref_count++;
215 }
216
217 static void
218 exif_loader_free (ExifLoader *loader)
219 {
220         ExifMem *mem;
221
222         if (!loader) return;
223
224         mem = loader->mem;
225         exif_loader_reset (loader);
226         exif_mem_free (mem, loader);
227         exif_mem_unref (mem);
228 }
229         
230 void
231 exif_loader_unref (ExifLoader *loader)
232 {
233         if (!loader) return;
234         if (!--loader->ref_count)
235                 exif_loader_free (loader);
236 }
237
238 void
239 exif_loader_reset (ExifLoader *loader)
240 {
241         if (!loader) return;
242         exif_mem_free (loader->mem, loader->buf); loader->buf = NULL;
243         loader->size = 0;
244         loader->bytes_read = 0;
245         loader->last_marker = 0;
246         loader->state = 0;
247 }
248
249 ExifData *
250 exif_loader_get_data (ExifLoader *loader)
251 {
252         ExifData *ed;
253
254         if (!loader) return NULL;
255
256         ed = exif_data_new_mem (loader->mem);
257         exif_data_log (ed, loader->log);
258         exif_data_load_data (ed, loader->buf, loader->bytes_read);
259
260         return ed;
261 }
262
263 void
264 exif_loader_log (ExifLoader *loader, ExifLog *log)
265 {
266         if (!loader) return;
267         exif_log_unref (loader->log);
268         loader->log = log;
269         exif_log_ref (log);
270 }