Please don't crash whenever calling memset
[platform/upstream/libexif.git] / libexif / olympus / exif-mnote-data-olympus.c
1 /* exif-mnote-data-olympus.c
2  *
3  * Copyright © 2002, 2003 Lutz Mueller <lutz@users.sourceforge.net>
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library; if not, write to the
17  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18  * Boston, MA 02111-1307, USA.
19  */
20
21 #include <config.h>
22 #include "exif-mnote-data-olympus.h"
23
24 #include <stdlib.h>
25 #include <string.h>
26 #include <stdio.h>
27
28 #include <libexif/exif-utils.h>
29 #include <libexif/exif-data.h>
30
31 #define DEBUG
32
33 static void
34 exif_mnote_data_olympus_clear (ExifMnoteDataOlympus *n)
35 {
36         unsigned int i;
37
38         if (!n) return;
39
40         if (n->entries) {
41                 for (i = 0; i < n->count; i++)
42                         if (n->entries[i].data) {
43                                 free (n->entries[i].data);
44                                 n->entries[i].data = NULL;
45                         }
46                 free (n->entries);
47                 n->entries = NULL;
48                 n->count = 0;
49         }
50 }
51
52 static void
53 exif_mnote_data_olympus_free (ExifMnoteData *n)
54 {
55         if (!n) return;
56
57         exif_mnote_data_olympus_clear ((ExifMnoteDataOlympus *) n);
58 }
59
60 static char *
61 exif_mnote_data_olympus_get_value (ExifMnoteData *d, unsigned int i, char *val, unsigned int maxlen)
62 {
63         ExifMnoteDataOlympus *n = (ExifMnoteDataOlympus *) d;
64
65         if (!d) return NULL;
66         if (n->count <= i) return NULL;
67         return mnote_olympus_entry_get_value (&n->entries[i], val, maxlen);
68 }
69
70 static void
71 exif_mnote_data_olympus_save (ExifMnoteData *ne,
72                 unsigned char **buf, unsigned int *buf_size)
73 {
74         ExifMnoteDataOlympus *n = (ExifMnoteDataOlympus *) ne;
75         unsigned int i, o, s, doff;
76
77         if (!n || !buf || !buf_size) return;
78
79         /*
80          * Allocate enough memory for all entries and the number of entries.
81          */
82         *buf_size = 6 + 2 + 2 + n->count * 12;
83         *buf = malloc (*buf_size);
84         if (!*buf) return;
85         memset (*buf, 0, *buf_size);
86
87         /* Write the header and the number of entries. */
88         strcpy (*buf, "OLYMP");
89         exif_set_short (*buf + 8, n->order, (ExifShort) n->count);
90
91         /* Save each entry */
92         for (i = 0; i < n->count; i++) {
93                 o = 6 + 2 + 2 + i * 12;
94                 exif_set_short (*buf + o + 0, n->order,
95                                 (ExifShort) n->entries[i].tag);
96                 exif_set_short (*buf + o + 2, n->order,
97                                 (ExifShort) n->entries[i].format);
98                 exif_set_long  (*buf + o + 4, n->order,
99                                 n->entries[i].components);
100                 o += 8;
101                 s = exif_format_get_size (n->entries[i].format) *
102                                                 n->entries[i].components;
103                 if (s > 4) {
104                         *buf_size += s;
105                         *buf = realloc (*buf, *buf_size);
106                         if (!*buf) return;
107                         doff = *buf_size - s;
108                         exif_set_long (*buf + o, n->order, n->offset + doff);
109                 } else
110                         doff = o;
111
112                 /* Write the data. */
113                 memcpy (*buf + doff, n->entries[i].data, s);
114         }
115 }
116
117 static void
118 exif_mnote_data_olympus_load (ExifMnoteData *en,
119                               const unsigned char *buf, unsigned int buf_size)
120 {
121         ExifMnoteDataOlympus *n = (ExifMnoteDataOlympus *) en;
122         ExifShort c;
123         unsigned int i, s, o;
124
125         if (!n || !buf) return;
126
127         /*
128          * Olympus headers start with "OLYMP" and need to have at least
129          * a size of 22 bytes (6 for 'OLYMP', 2 other bytes, 2 for the
130          * number of entries, and 12 for one entry.
131          */
132         if (buf_size - n->offset < 22) return;
133         if (memcmp (buf + 6 + n->offset, "OLYMP", 5)) return;
134
135         /* Read the number of entries and remove old ones. */
136         c = exif_get_short (buf + 6 + n->offset + 8, n->order);
137         exif_mnote_data_olympus_clear (n);
138
139         n->entries = malloc (sizeof (MnoteOlympusEntry) * c);
140         memset (n->entries, 0, sizeof (MnoteOlympusEntry) * c);
141
142         /* Parse the entries */
143         for (i = 0; i < c; i++) {
144             o = 6 + n->offset + 8 + 2 + 12 * i;
145             if (o + 12 > buf_size) return;
146
147             n->count = i + 1;
148             n->entries[i].tag        = exif_get_short (buf + o, n->order);
149             n->entries[i].format     = exif_get_short (buf + o + 2, n->order);
150             n->entries[i].components = exif_get_long (buf + o + 4, n->order);
151             n->entries[i].order      = n->order;
152
153             /*
154              * Size? If bigger than 4 bytes, the actual data is not
155              * in the entry but somewhere else (offset).
156              */
157             s = exif_format_get_size (n->entries[i].format) *
158                                          n->entries[i].components;
159             if (!s) return;
160             o += 8;
161             if (s > 4) o = exif_get_long (buf + o, n->order) + 6;
162             if (o + s > buf_size) return;
163
164             /* Sanity check */
165             n->entries[i].data = malloc (s);
166             if (!n->entries[i].data) return;
167             n->entries[i].size = s;
168             memcpy (n->entries[i].data, buf + o, s);
169         }
170 }
171
172 static unsigned int
173 exif_mnote_data_olympus_count (ExifMnoteData *n)
174 {
175         return n ? ((ExifMnoteDataOlympus *) n)->count : 0;
176 }
177
178 static const char *
179 exif_mnote_data_olympus_get_name (ExifMnoteData *d, unsigned int i)
180 {
181         ExifMnoteDataOlympus *n = (ExifMnoteDataOlympus *) d;
182
183         if (!n) return NULL;
184         if (i >= n->count) return NULL;
185         return mnote_olympus_tag_get_title (n->entries[i].tag);
186 }
187
188 static const char *
189 exif_mnote_data_olympus_get_title (ExifMnoteData *d, unsigned int i)
190 {
191         ExifMnoteDataOlympus *n = (ExifMnoteDataOlympus *) d;
192         
193         if (!n) return NULL;
194         if (i >= n->count) return NULL;
195         return mnote_olympus_tag_get_title (n->entries[i].tag);
196 }
197
198 static const char *
199 exif_mnote_data_olympus_get_description (ExifMnoteData *d, unsigned int i)
200 {
201         ExifMnoteDataOlympus *n = (ExifMnoteDataOlympus *) d;
202         
203         if (!n) return NULL;
204         if (i >= n->count) return NULL;
205         return mnote_olympus_tag_get_title (n->entries[i].tag);
206 }
207
208 static void
209 exif_mnote_data_olympus_set_byte_order (ExifMnoteData *d, ExifByteOrder o)
210 {
211         ExifByteOrder o_orig;
212         ExifMnoteDataOlympus *n = (ExifMnoteDataOlympus *) d;
213         unsigned int i, fs;
214         ExifShort s;
215         ExifLong l;
216         ExifSLong sl;
217         ExifRational r;
218         ExifSRational sr;
219
220         if (!n) return;
221
222         o_orig = n->order;
223         n->order = o;
224         for (i = 0; i < n->count; i++) {
225                 n->entries[i].order = o;
226                 fs = exif_format_get_size (n->entries[i].format);
227                 switch (n->entries[i].format) {
228                 case EXIF_FORMAT_SHORT:
229                         for (i = 0; i < n->entries[i].components; i++) {
230                                 s = exif_get_short (n->entries[i].data + (i*fs),
231                                                 o_orig);
232                                 exif_set_short (n->entries[i].data + (i * fs),
233                                                 o, s);
234                         }
235                         break;
236                 case EXIF_FORMAT_LONG:
237                         for (i = 0; i < n->entries[i].components; i++) {
238                                 l = exif_get_long (n->entries[i].data + (i*fs),
239                                                 o_orig);
240                                 exif_set_long (n->entries[i].data + (i * fs),
241                                                 o, l);
242                         }
243                         break;
244                 case EXIF_FORMAT_RATIONAL:
245                         for (i = 0; i < n->entries[i].components; i++) {
246                                 r = exif_get_rational (n->entries[i].data +
247                                                 (i * fs), o_orig);
248                                 exif_set_rational (n->entries[i].data +
249                                                 (i * fs), o, r);
250                         }
251                         break;
252                 case EXIF_FORMAT_SLONG:
253                         for (i = 0; i < n->entries[i].components; i++) {
254                                 sl = exif_get_slong (n->entries[i].data +
255                                                 (i * fs), o_orig);
256                                 exif_set_slong (n->entries[i].data +
257                                                 (i * fs), o, sl);
258                         }
259                         break;
260                 case EXIF_FORMAT_SRATIONAL:
261                         for (i = 0; i < n->entries[i].components; i++) {
262                                 sr = exif_get_srational (n->entries[i].data +
263                                                 (i * fs), o_orig);
264                                 exif_set_srational (n->entries[i].data +
265                                                 (i * fs), o, sr);
266                         }
267                         break;
268                 case EXIF_FORMAT_UNDEFINED:
269                 case EXIF_FORMAT_BYTE:
270                 case EXIF_FORMAT_ASCII:
271                 default:
272                         /* Nothing here. */
273                         break;
274                 }
275         }
276 }
277
278 static void
279 exif_mnote_data_olympus_set_offset (ExifMnoteData *n, unsigned int o)
280 {
281         if (n) ((ExifMnoteDataOlympus *) n)->offset = o;
282 }
283
284 ExifMnoteData *
285 exif_mnote_data_olympus_new (void)
286 {
287         ExifMnoteData *n;
288
289         n = malloc (sizeof (ExifMnoteDataOlympus));
290         if (!n) return NULL;
291         memset (n, 0, sizeof (ExifMnoteDataOlympus));
292
293         exif_mnote_data_construct (n);
294
295         /* Set up the function pointers */
296         n->methods.free            = exif_mnote_data_olympus_free;
297         n->methods.set_byte_order  = exif_mnote_data_olympus_set_byte_order;
298         n->methods.set_offset      = exif_mnote_data_olympus_set_offset;
299         n->methods.load            = exif_mnote_data_olympus_load;
300         n->methods.save            = exif_mnote_data_olympus_save;
301         n->methods.count           = exif_mnote_data_olympus_count;
302         n->methods.get_name        = exif_mnote_data_olympus_get_name;
303         n->methods.get_title       = exif_mnote_data_olympus_get_title;
304         n->methods.get_description = exif_mnote_data_olympus_get_description;
305         n->methods.get_value       = exif_mnote_data_olympus_get_value;
306
307         return n;
308 }