2003-10-30 Lutz Mueller <lutz@users.sourceforge.net>
[platform/upstream/libexif.git] / libexif / exif-loader.c
1 #include <config.h>
2 #include "exif-loader.h"
3
4 #include <stdlib.h>
5 #include <string.h>
6
7 #include <libjpeg/jpeg-marker.h>
8
9 typedef enum {
10         EL_READ = 0,
11         EL_READ_SIZE_HIGH_BYTE,
12         EL_READ_SIZE_LOW_BYTE,
13         EL_SKIP_BYTES,
14         EL_EXIF_FOUND,
15         EL_FAILED
16 } ExifLoaderState;
17
18 struct _ExifLoader {
19         ExifLoaderState state;
20
21         unsigned int size;
22         int last_marker;
23         unsigned char *buf;
24         unsigned int bytes_read;
25
26         unsigned int ref_count;
27 };
28
29 #undef  MIN
30 #define MIN(a, b)  (((a) < (b)) ? (a) : (b))
31
32 /*
33  * This function imitates code from libexif, written by Lutz
34  * Müller. See libexif/exif-data.c:exif_data_new_from_file. Here, it
35  * can cope with a sequence of data chunks.
36  */
37 unsigned char
38 exif_loader_write (ExifLoader *eld, unsigned char *buf, unsigned int len)
39 {
40         int i, len_remain;
41
42         if (!eld) return 0;
43         if (eld->state == EL_FAILED) return 0;
44         if (eld->size && eld->bytes_read == eld->size) return 0;
45
46         for (i = 0; (i < len) && (eld->state != EL_EXIF_FOUND) &&
47                                  (eld->state != EL_FAILED); i++) 
48                 switch (eld->state) {
49                 case EL_SKIP_BYTES:
50                         eld->size--;
51                         if (eld->size == 0) {
52                                 eld->state = EL_READ;
53                         }
54                         break;
55                         
56                 case EL_READ_SIZE_HIGH_BYTE:
57                         eld->size = buf [i] << 8;
58                         eld->state = EL_READ_SIZE_LOW_BYTE;
59                         break;
60                         
61                 case EL_READ_SIZE_LOW_BYTE:
62                         eld->size |= buf [i];
63
64                         switch (eld->last_marker) {
65                         case JPEG_MARKER_APP0:
66                         case JPEG_MARKER_APP13:
67                                 eld->state = EL_SKIP_BYTES;
68                                 eld->size -= 2;
69                                 break;
70
71                         case JPEG_MARKER_APP1:
72                                 eld->state = EL_EXIF_FOUND;
73                                 break;
74
75                         case 0:
76                                 /*
77                                  * Assume that we are reading EXIF data. 
78                                  * This should probably be verified by reading
79                                  * some bytes ahead.
80                                  */
81                                 eld->state = EL_EXIF_FOUND;
82                                 break;
83                         default:
84                                 return 0;
85                         }
86
87                         eld->last_marker = 0;
88                         break;
89
90                 default:
91                         if (buf[i] != 0xff) {
92                                 if (buf[i] == JPEG_MARKER_APP0 ||
93                                     buf[i] == JPEG_MARKER_APP1 ||
94                                     buf[i] == JPEG_MARKER_APP13) {
95                                         eld->state = EL_READ_SIZE_HIGH_BYTE;
96                                         eld->last_marker = buf [i];
97
98                                 } else if (buf [i] == JPEG_MARKER_SOI) {
99                                         /* Nothing */
100                                 } else {
101                                         /* Assume that we are reading EXIF
102                                          * data. This should probably be
103                                          * verified by reading some bytes
104                                          * ahead.
105                                          */
106                                         eld->last_marker = JPEG_MARKER_APP1;
107                                         eld->state = EL_READ_SIZE_HIGH_BYTE;
108                                         i--;
109                                 }
110                         }
111                 }
112
113         len_remain = len - i;
114         if (!len_remain) return 1;
115
116         if (eld->state == EL_EXIF_FOUND && len_remain > 0) {
117                 if (eld->buf == NULL) {
118                         eld->buf = malloc (sizeof (unsigned char) * eld->size);
119                         eld->bytes_read = 0;
120                 }
121
122                 if (eld->bytes_read < eld->size) {
123                         int cp_len;
124
125                         /* the number of bytes we need to copy */
126                         cp_len = MIN (eld->size - eld->bytes_read, len_remain);
127                         
128                         if ((cp_len + eld->bytes_read) > eld->size) return 1;
129
130                         /* Copy memory */
131                         memcpy (eld->buf + eld->bytes_read, &buf[i], cp_len);
132                         eld->bytes_read += cp_len;
133                 }
134         }
135
136         return 1;
137 }
138
139 ExifLoader *
140 exif_loader_new (void)
141 {
142         ExifLoader *loader = malloc (sizeof (ExifLoader));
143
144         memset (loader, 0, sizeof (ExifLoader));
145         loader->ref_count = 1;
146         
147         return loader;
148 }
149
150 void
151 exif_loader_ref (ExifLoader *loader)
152 {
153         if (loader) loader->ref_count++;
154 }
155
156 void
157 exif_loader_unref (ExifLoader *loader)
158 {
159         if (!loader) return;
160         if (!--loader->ref_count) {
161                 exif_loader_reset (loader);
162                 free (loader);
163         }
164 }
165
166 void
167 exif_loader_reset (ExifLoader *loader)
168 {
169         if (!loader) return;
170         free (loader->buf); loader->buf = NULL;
171         loader->size = 0;
172         loader->bytes_read = 0;
173         loader->last_marker = 0;
174         loader->state = 0;
175 }
176
177 ExifData *
178 exif_loader_get_data (ExifLoader *loader)
179 {
180         return exif_data_new_from_data (loader->buf, loader->bytes_read);
181 }