/src/libexif/libexif/fuji/exif-mnote-data-fuji.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* exif-mnote-data-fuji.c |
2 | | * |
3 | | * Copyright (c) 2002 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., 51 Franklin Street, Fifth Floor, |
18 | | * Boston, MA 02110-1301 USA. |
19 | | * |
20 | | * SPDX-License-Identifier: LGPL-2.0-or-later |
21 | | */ |
22 | | |
23 | | #include <stdlib.h> |
24 | | #include <string.h> |
25 | | |
26 | | |
27 | | #include <config.h> |
28 | | #include <libexif/exif-byte-order.h> |
29 | | #include <libexif/exif-utils.h> |
30 | | |
31 | | #include "exif-mnote-data-fuji.h" |
32 | | |
33 | 23.3k | #define CHECKOVERFLOW(offset,datasize,structsize) (( (offset) >= (datasize)) || ((structsize) > (datasize)) || ((offset) > (datasize) - (structsize) )) |
34 | | |
35 | | struct _MNoteFujiDataPrivate { |
36 | | ExifByteOrder order; |
37 | | }; |
38 | | |
39 | | static void |
40 | | exif_mnote_data_fuji_clear (ExifMnoteDataFuji *n) |
41 | 1.28k | { |
42 | 1.28k | ExifMnoteData *d = (ExifMnoteData *) n; |
43 | 1.28k | unsigned int i; |
44 | | |
45 | 1.28k | if (!n) return; |
46 | | |
47 | 1.28k | if (n->entries) { |
48 | 15.9k | for (i = 0; i < n->count; i++) |
49 | 15.3k | if (n->entries[i].data) { |
50 | 3.69k | exif_mem_free (d->mem, n->entries[i].data); |
51 | 3.69k | n->entries[i].data = NULL; |
52 | 3.69k | } |
53 | 620 | exif_mem_free (d->mem, n->entries); |
54 | 620 | n->entries = NULL; |
55 | 620 | n->count = 0; |
56 | 620 | } |
57 | 1.28k | } |
58 | | |
59 | | static void |
60 | | exif_mnote_data_fuji_free (ExifMnoteData *n) |
61 | 661 | { |
62 | 661 | if (!n) return; |
63 | | |
64 | 661 | exif_mnote_data_fuji_clear ((ExifMnoteDataFuji *) n); |
65 | 661 | } |
66 | | |
67 | | static char * |
68 | | exif_mnote_data_fuji_get_value (ExifMnoteData *d, unsigned int i, char *val, unsigned int maxlen) |
69 | 7.12k | { |
70 | 7.12k | ExifMnoteDataFuji *n = (ExifMnoteDataFuji *) d; |
71 | | |
72 | 7.12k | if (!d || !val) return NULL; |
73 | 7.12k | if (i > n->count -1) return NULL; |
74 | | /* |
75 | | exif_log (d->log, EXIF_LOG_CODE_DEBUG, "ExifMnoteDataFuji", |
76 | | "Querying value for tag '%s'...", |
77 | | mnote_fuji_tag_get_name (n->entries[i].tag)); |
78 | | */ |
79 | 7.12k | return mnote_fuji_entry_get_value (&n->entries[i], val, maxlen); |
80 | 7.12k | } |
81 | | |
82 | | static void |
83 | | exif_mnote_data_fuji_save (ExifMnoteData *ne, unsigned char **buf, |
84 | | unsigned int *buf_size) |
85 | 0 | { |
86 | 0 | ExifMnoteDataFuji *n = (ExifMnoteDataFuji *) ne; |
87 | 0 | size_t i, o, s, doff; |
88 | 0 | unsigned char *t; |
89 | 0 | size_t ts; |
90 | |
|
91 | 0 | if (!n || !buf || !buf_size) return; |
92 | | |
93 | | /* |
94 | | * Allocate enough memory for all entries and the number |
95 | | * of entries. |
96 | | */ |
97 | 0 | *buf_size = 8 + 4 + 2 + n->count * 12 + 4; |
98 | 0 | *buf = exif_mem_alloc (ne->mem, *buf_size); |
99 | 0 | if (!*buf) { |
100 | 0 | *buf_size = 0; |
101 | 0 | return; |
102 | 0 | } |
103 | | |
104 | | /* |
105 | | * Header: "FUJIFILM" and 4 bytes offset to the first entry. |
106 | | * As the first entry will start right thereafter, the offset is 12. |
107 | | */ |
108 | 0 | memcpy (*buf, "FUJIFILM", 8); |
109 | 0 | exif_set_long (*buf + 8, n->order, 12); |
110 | | |
111 | | /* Save the number of entries */ |
112 | 0 | exif_set_short (*buf + 8 + 4, n->order, (ExifShort) n->count); |
113 | | |
114 | | /* Save each entry */ |
115 | 0 | for (i = 0; i < n->count; i++) { |
116 | 0 | o = 8 + 4 + 2 + i * 12; |
117 | 0 | exif_set_short (*buf + o + 0, n->order, (ExifShort) n->entries[i].tag); |
118 | 0 | exif_set_short (*buf + o + 2, n->order, (ExifShort) n->entries[i].format); |
119 | 0 | exif_set_long (*buf + o + 4, n->order, n->entries[i].components); |
120 | 0 | o += 8; |
121 | 0 | s = exif_format_get_size (n->entries[i].format) * |
122 | 0 | n->entries[i].components; |
123 | 0 | if (s > 65536) { |
124 | | /* Corrupt data: EXIF data size is limited to the |
125 | | * maximum size of a JPEG segment (64 kb). |
126 | | */ |
127 | 0 | continue; |
128 | 0 | } |
129 | 0 | if (s > 4) { |
130 | 0 | ts = *buf_size + s; |
131 | | |
132 | | /* Ensure even offsets. Set padding bytes to 0. */ |
133 | 0 | if (s & 1) ts += 1; |
134 | 0 | t = exif_mem_realloc (ne->mem, *buf, ts); |
135 | 0 | if (!t) { |
136 | 0 | return; |
137 | 0 | } |
138 | 0 | *buf = t; |
139 | 0 | *buf_size = ts; |
140 | 0 | doff = *buf_size - s; |
141 | 0 | if (s & 1) { doff--; *(*buf + *buf_size - 1) = '\0'; } |
142 | 0 | exif_set_long (*buf + o, n->order, doff); |
143 | 0 | } else |
144 | 0 | doff = o; |
145 | | |
146 | | /* |
147 | | * Write the data. Fill unneeded bytes with 0. Do not |
148 | | * crash if data is NULL. |
149 | | */ |
150 | 0 | if (!n->entries[i].data) memset (*buf + doff, 0, s); |
151 | 0 | else memcpy (*buf + doff, n->entries[i].data, s); |
152 | 0 | } |
153 | 0 | } |
154 | | |
155 | | static void |
156 | | exif_mnote_data_fuji_load (ExifMnoteData *en, |
157 | | const unsigned char *buf, unsigned int buf_size) |
158 | 661 | { |
159 | 661 | ExifMnoteDataFuji *n = (ExifMnoteDataFuji*) en; |
160 | 661 | ExifLong c; |
161 | 661 | size_t i, tcount, o, datao; |
162 | | |
163 | 661 | if (!n) return; |
164 | | |
165 | 661 | if (!buf || !buf_size) { |
166 | 0 | exif_log (en->log, EXIF_LOG_CODE_CORRUPT_DATA, |
167 | 0 | "ExifMnoteDataFuji", "Short MakerNote"); |
168 | 0 | return; |
169 | 0 | } |
170 | 661 | if (CHECKOVERFLOW(n->offset, buf_size, 6+8+4)) { |
171 | 4 | exif_log (en->log, EXIF_LOG_CODE_CORRUPT_DATA, |
172 | 4 | "ExifMnoteDataFuji", "Short MakerNote"); |
173 | 4 | return; |
174 | 4 | } |
175 | 657 | datao = 6 + n->offset; |
176 | | |
177 | 657 | n->order = EXIF_BYTE_ORDER_INTEL; |
178 | | |
179 | 657 | datao += exif_get_long (buf + datao + 8, EXIF_BYTE_ORDER_INTEL); |
180 | 657 | if (CHECKOVERFLOW(datao, buf_size, 2)) { |
181 | 28 | exif_log (en->log, EXIF_LOG_CODE_CORRUPT_DATA, |
182 | 28 | "ExifMnoteDataFuji", "Short MakerNote"); |
183 | 28 | return; |
184 | 28 | } |
185 | | |
186 | | /* Read the number of tags */ |
187 | 629 | c = exif_get_short (buf + datao, EXIF_BYTE_ORDER_INTEL); |
188 | 629 | datao += 2; |
189 | | |
190 | | /* Just use an arbitrary max tag limit here to avoid needing to much memory or time. There are 50 named tags currently. |
191 | | * Fuji XT2 had 56 entries or so, GFX500 has 68. 150 seems a safe upper bound currently. |
192 | | * The format allows specifying the same range of memory as often as it can, so this multiplies quickly. */ |
193 | 629 | if (c > 150) { |
194 | 9 | exif_log (en->log, EXIF_LOG_CODE_CORRUPT_DATA, "ExifMnoteDataFuji", "Too much tags (%d) in Fuji MakerNote", c); |
195 | 9 | return; |
196 | 9 | } |
197 | | |
198 | | /* Remove any old entries */ |
199 | 620 | exif_mnote_data_fuji_clear (n); |
200 | | |
201 | | /* Reserve enough space for all the possible MakerNote tags */ |
202 | 620 | n->entries = exif_mem_alloc (en->mem, sizeof (MnoteFujiEntry) * c); |
203 | 620 | if (!n->entries) { |
204 | 0 | EXIF_LOG_NO_MEMORY(en->log, "ExifMnoteDataFuji", sizeof (MnoteFujiEntry) * c); |
205 | 0 | return; |
206 | 0 | } |
207 | | |
208 | | /* Parse all c entries, storing ones that are successfully parsed */ |
209 | 620 | tcount = 0; |
210 | 17.8k | for (i = c, o = datao; i; --i, o += 12) { |
211 | 17.7k | size_t s; |
212 | | |
213 | 17.7k | memset(&n->entries[tcount], 0, sizeof(MnoteFujiEntry)); |
214 | 17.7k | if (CHECKOVERFLOW(o, buf_size, 12)) { |
215 | 550 | exif_log (en->log, EXIF_LOG_CODE_CORRUPT_DATA, |
216 | 550 | "ExifMnoteDataFuji", "Short MakerNote"); |
217 | 550 | break; |
218 | 550 | } |
219 | | |
220 | 17.2k | n->entries[tcount].tag = exif_get_short (buf + o, n->order); |
221 | 17.2k | n->entries[tcount].format = exif_get_short (buf + o + 2, n->order); |
222 | 17.2k | n->entries[tcount].components = exif_get_long (buf + o + 4, n->order); |
223 | 17.2k | n->entries[tcount].order = n->order; |
224 | | |
225 | 17.2k | exif_log (en->log, EXIF_LOG_CODE_DEBUG, "ExifMnoteDataFuji", |
226 | 17.2k | "Loading entry 0x%x ('%s')...", n->entries[tcount].tag, |
227 | 17.2k | mnote_fuji_tag_get_name (n->entries[tcount].tag)); |
228 | | |
229 | | /* Check if we overflow the multiplication. Use buf_size as the max size for integer overflow detection, |
230 | | * we will check the buffer sizes closer later. */ |
231 | 17.2k | if ( exif_format_get_size (n->entries[tcount].format) && |
232 | 17.2k | buf_size / exif_format_get_size (n->entries[tcount].format) < n->entries[tcount].components |
233 | 17.2k | ) { |
234 | 1.32k | exif_log (en->log, EXIF_LOG_CODE_CORRUPT_DATA, |
235 | 1.32k | "ExifMnoteDataFuji", "Tag size overflow detected (%u * %lu)", exif_format_get_size (n->entries[tcount].format), n->entries[tcount].components); |
236 | 1.32k | continue; |
237 | 1.32k | } |
238 | | /* |
239 | | * Size? If bigger than 4 bytes, the actual data is not |
240 | | * in the entry but somewhere else (offset). |
241 | | */ |
242 | 15.8k | s = exif_format_get_size (n->entries[tcount].format) * n->entries[tcount].components; |
243 | 15.8k | n->entries[tcount].size = s; |
244 | 15.8k | if (s) { |
245 | 4.24k | size_t dataofs = o + 8; |
246 | 4.24k | if (s > 4) |
247 | | /* The data in this case is merely a pointer */ |
248 | 1.96k | dataofs = exif_get_long (buf + dataofs, n->order) + 6 + n->offset; |
249 | | |
250 | 4.24k | if (CHECKOVERFLOW(dataofs, buf_size, s)) { |
251 | 551 | exif_log (en->log, EXIF_LOG_CODE_CORRUPT_DATA, |
252 | 551 | "ExifMnoteDataFuji", "Tag data past end of " |
253 | 551 | "buffer (%u >= %u)", (unsigned)(dataofs + s), buf_size); |
254 | 551 | continue; |
255 | 551 | } |
256 | | |
257 | 3.69k | n->entries[tcount].data = exif_mem_alloc (en->mem, s); |
258 | 3.69k | if (!n->entries[tcount].data) { |
259 | 0 | EXIF_LOG_NO_MEMORY(en->log, "ExifMnoteDataFuji", s); |
260 | 0 | continue; |
261 | 0 | } |
262 | 3.69k | memcpy (n->entries[tcount].data, buf + dataofs, s); |
263 | 3.69k | } |
264 | | |
265 | | /* Tag was successfully parsed */ |
266 | 15.3k | ++tcount; |
267 | 15.3k | } |
268 | | /* Store the count of successfully parsed tags */ |
269 | 620 | n->count = tcount; |
270 | 620 | } |
271 | | |
272 | | static unsigned int |
273 | | exif_mnote_data_fuji_count (ExifMnoteData *n) |
274 | 661 | { |
275 | 661 | return n ? ((ExifMnoteDataFuji *) n)->count : 0; |
276 | 661 | } |
277 | | |
278 | | static unsigned int |
279 | | exif_mnote_data_fuji_get_id (ExifMnoteData *d, unsigned int n) |
280 | 0 | { |
281 | 0 | ExifMnoteDataFuji *note = (ExifMnoteDataFuji *) d; |
282 | |
|
283 | 0 | if (!note) return 0; |
284 | 0 | if (note->count <= n) return 0; |
285 | 0 | return note->entries[n].tag; |
286 | 0 | } |
287 | | |
288 | | static const char * |
289 | | exif_mnote_data_fuji_get_name (ExifMnoteData *d, unsigned int i) |
290 | 7.39k | { |
291 | 7.39k | ExifMnoteDataFuji *n = (ExifMnoteDataFuji *) d; |
292 | | |
293 | 7.39k | if (!n) return NULL; |
294 | 7.39k | if (i >= n->count) return NULL; |
295 | 7.39k | return mnote_fuji_tag_get_name (n->entries[i].tag); |
296 | 7.39k | } |
297 | | |
298 | | static const char * |
299 | | exif_mnote_data_fuji_get_title (ExifMnoteData *d, unsigned int i) |
300 | 7.12k | { |
301 | 7.12k | ExifMnoteDataFuji *n = (ExifMnoteDataFuji *) d; |
302 | | |
303 | 7.12k | if (!n) return NULL; |
304 | 7.12k | if (i >= n->count) return NULL; |
305 | 7.12k | return mnote_fuji_tag_get_title (n->entries[i].tag); |
306 | 7.12k | } |
307 | | |
308 | | static const char * |
309 | | exif_mnote_data_fuji_get_description (ExifMnoteData *d, unsigned int i) |
310 | 7.12k | { |
311 | 7.12k | ExifMnoteDataFuji *n = (ExifMnoteDataFuji *) d; |
312 | | |
313 | 7.12k | if (!n) return NULL; |
314 | 7.12k | if (i >= n->count) return NULL; |
315 | 7.12k | return mnote_fuji_tag_get_description (n->entries[i].tag); |
316 | 7.12k | } |
317 | | |
318 | | static void |
319 | | exif_mnote_data_fuji_set_byte_order (ExifMnoteData *d, ExifByteOrder o) |
320 | 661 | { |
321 | 661 | ExifByteOrder o_orig; |
322 | 661 | ExifMnoteDataFuji *n = (ExifMnoteDataFuji *) d; |
323 | 661 | unsigned int i; |
324 | | |
325 | 661 | if (!n) return; |
326 | | |
327 | 661 | o_orig = n->order; |
328 | 661 | n->order = o; |
329 | 661 | for (i = 0; i < n->count; i++) { |
330 | 0 | if (n->entries[i].components && (n->entries[i].size/n->entries[i].components < exif_format_get_size (n->entries[i].format))) |
331 | 0 | continue; |
332 | 0 | n->entries[i].order = o; |
333 | 0 | exif_array_set_byte_order (n->entries[i].format, n->entries[i].data, |
334 | 0 | n->entries[i].components, o_orig, o); |
335 | 0 | } |
336 | 661 | } |
337 | | |
338 | | static void |
339 | | exif_mnote_data_fuji_set_offset (ExifMnoteData *n, unsigned int o) |
340 | 661 | { |
341 | 661 | if (n) ((ExifMnoteDataFuji *) n)->offset = o; |
342 | 661 | } |
343 | | |
344 | | int |
345 | | exif_mnote_data_fuji_identify (const ExifData *ed, const ExifEntry *e) |
346 | 1.55k | { |
347 | 1.55k | (void) ed; /* unused */ |
348 | 1.55k | return ((e->size >= 12) && !memcmp (e->data, "FUJIFILM", 8)); |
349 | 1.55k | } |
350 | | |
351 | | ExifMnoteData * |
352 | | exif_mnote_data_fuji_new (ExifMem *mem) |
353 | 661 | { |
354 | 661 | ExifMnoteData *d; |
355 | | |
356 | 661 | if (!mem) return NULL; |
357 | | |
358 | 661 | d = exif_mem_alloc (mem, sizeof (ExifMnoteDataFuji)); |
359 | 661 | if (!d) return NULL; |
360 | | |
361 | 661 | exif_mnote_data_construct (d, mem); |
362 | | |
363 | | /* Set up function pointers */ |
364 | 661 | d->methods.free = exif_mnote_data_fuji_free; |
365 | 661 | d->methods.set_byte_order = exif_mnote_data_fuji_set_byte_order; |
366 | 661 | d->methods.set_offset = exif_mnote_data_fuji_set_offset; |
367 | 661 | d->methods.load = exif_mnote_data_fuji_load; |
368 | 661 | d->methods.save = exif_mnote_data_fuji_save; |
369 | 661 | d->methods.count = exif_mnote_data_fuji_count; |
370 | 661 | d->methods.get_id = exif_mnote_data_fuji_get_id; |
371 | 661 | d->methods.get_name = exif_mnote_data_fuji_get_name; |
372 | 661 | d->methods.get_title = exif_mnote_data_fuji_get_title; |
373 | 661 | d->methods.get_description = exif_mnote_data_fuji_get_description; |
374 | 661 | d->methods.get_value = exif_mnote_data_fuji_get_value; |
375 | | |
376 | 661 | return d; |
377 | 661 | } |