1 /* test-value.c
2 *
3 * Creates all the types of tags supported in exif_entry_initialize() and
4 * ensures that exif_entry_get_value() properly truncates the output of each
5 * one according to the buffer size available.
6 *
7 * Copyright 2002 Lutz Mueller <lutz@users.sourceforge.net>
8 *
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2 of the License, or (at your option) any later version.
13 *
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
18 *
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the
21 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
22 * Boston, MA 02110-1301 USA.
23 *
24 * SPDX-License-Identifier: LGPL-2.0-or-later
25 */
26
27 #include <libexif/exif-utils.h>
28 #include <libexif/exif-data.h>
29
30 #include <assert.h>
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <string.h>
34
35 /*
36 * List of tags to test, one per default initialized type.
37 * There should be one for every block in exif_entry_initialize() and
38 * exif_entry_get_value().
39 */
40 static const ExifTag trunc_test_tags[] = {
41 EXIF_TAG_PIXEL_X_DIMENSION,
42 EXIF_TAG_SUBJECT_LOCATION,
43 EXIF_TAG_IMAGE_WIDTH,
44 EXIF_TAG_ORIENTATION,
45 EXIF_TAG_SAMPLES_PER_PIXEL,
46 EXIF_TAG_BITS_PER_SAMPLE,
47 EXIF_TAG_X_RESOLUTION,
48 EXIF_TAG_WHITE_POINT,
49 EXIF_TAG_REFERENCE_BLACK_WHITE,
50 EXIF_TAG_DATE_TIME,
51 EXIF_TAG_IMAGE_DESCRIPTION,
52 EXIF_TAG_EXIF_VERSION,
53 EXIF_TAG_FLASH_PIX_VERSION,
54 EXIF_TAG_COPYRIGHT,
55 EXIF_TAG_FILE_SOURCE,
56 EXIF_TAG_COMPONENTS_CONFIGURATION,
57 EXIF_TAG_SCENE_TYPE,
58 EXIF_TAG_YCBCR_SUB_SAMPLING,
59 EXIF_TAG_PLANAR_CONFIGURATION,
60 };
61
62 /*
63 * These tags produce different outputs depending on the amount of buffer space
64 * available.
65 */
66 static const ExifTag nonuniform_test_tags[] = {
67 EXIF_TAG_RESOLUTION_UNIT,
68 EXIF_TAG_COLOR_SPACE,
69 EXIF_TAG_METERING_MODE,
70 };
71
72 /*
73 * These tags need a nonzero rational number to be interesting.
74 * They must have space for a rational or srational created automatically by
75 * exif_entry_initialize().
76 */
77 static const ExifTag rational_test_tags[] = {
78 EXIF_TAG_FNUMBER,
79 EXIF_TAG_APERTURE_VALUE,
80 EXIF_TAG_MAX_APERTURE_VALUE,
81 EXIF_TAG_FOCAL_LENGTH,
82 EXIF_TAG_SUBJECT_DISTANCE,
83 EXIF_TAG_EXPOSURE_TIME,
84 EXIF_TAG_SHUTTER_SPEED_VALUE,
85 EXIF_TAG_BRIGHTNESS_VALUE,
86 EXIF_TAG_EXPOSURE_BIAS_VALUE,
87 };
88
89 /*
90 * Verify that the entry is properly truncated to the buffer length within
91 * exif_entry_get_value(). If uniform is zero, then only check that the
92 * resulting string fits within the buffer and don't check its content.
93 */
check_entry_trunc(ExifEntry * e,int uniform)94 static void check_entry_trunc(ExifEntry *e, int uniform)
95 {
96 unsigned int i;
97 char v[1024], full[1024]; /* Large enough to never truncate output */
98
99 printf ("Tag 0x%x\n", (int) e->tag);
100
101 /* Get the full, untruncated string to use as the expected value */
102 exif_entry_get_value (e, full, sizeof(full));
103 printf ("Full: '%s'\n", full);
104
105 for (i = strlen(full); i > 0; i--) {
106 /* Make sure the buffer isn't NUL-terminated to begin with */
107 memset(v, '*', sizeof(v));
108 exif_entry_get_value (e, v, i);
109 /* Truncate the full string by one on each iteration */
110 full[i-1] = '\0';
111 if ((strlen(v) >= i) || (uniform && strcmp(full, v))) {
112 printf("Bad truncation!\n");
113 printf("Length %2i: '%s'\n", i, v);
114 exit(1);
115 }
116 }
117 }
118
119 int
main(void)120 main (void)
121 {
122 ExifData *data;
123 ExifEntry *e;
124 ExifMem *mem;
125 unsigned i;
126 static const ExifSRational r = {1., 20.}; /* a nonzero number */
127 static const char user_comment[] = "ASCII\0\0\0A Long User Comment";
128 static const char xp_comment[] = "U\0C\0S\0-\0002\0 \0C\0o\0m\0m\0e\0n\0t\0";
129 static const char interop[] = "R98";
130 static const char subsec[] = "130 ";
131 static const ExifRational gpsh = {12., 1.};
132 static const ExifRational gpsm = {34., 1.};
133 static const ExifRational gpss = {56780., 1000.};
134
135 data = exif_data_new ();
136 if (!data) {
137 fprintf (stderr, "Error running exif_data_new()\n");
138 exit(13);
139 }
140
141 /* Full initialization/truncation tests */
142 for (i=0; i < sizeof(trunc_test_tags)/sizeof(trunc_test_tags[0]); ++i) {
143 e = exif_entry_new ();
144 if (!e) {
145 fprintf (stderr, "Error running exif_entry_new()\n");
146 exit(13);
147 }
148 exif_content_add_entry (data->ifd[EXIF_IFD_0], e);
149 exif_entry_initialize (e, trunc_test_tags[i]);
150 check_entry_trunc(e, 1);
151 exif_content_remove_entry (data->ifd[EXIF_IFD_0], e);
152 exif_entry_unref (e);
153 }
154
155 /* Nonuniform initialization/truncation tests */
156 for (i=0; i < sizeof(nonuniform_test_tags)/sizeof(nonuniform_test_tags[0]);
157 ++i) {
158 e = exif_entry_new ();
159 if (!e) {
160 fprintf (stderr, "Error running exif_entry_new()\n");
161 exit(13);
162 }
163 exif_content_add_entry (data->ifd[EXIF_IFD_0], e);
164 exif_entry_initialize (e, nonuniform_test_tags[i]);
165 check_entry_trunc(e, 0);
166 exif_content_remove_entry (data->ifd[EXIF_IFD_0], e);
167 exif_entry_unref (e);
168 }
169
170 /* Rational number initialization/truncation tests */
171 for (i=0; i < sizeof(rational_test_tags)/sizeof(rational_test_tags[0]);
172 ++i) {
173 e = exif_entry_new ();
174 if (!e) {
175 fprintf (stderr, "Error running exif_entry_new()\n");
176 exit(13);
177 }
178 exif_content_add_entry (data->ifd[EXIF_IFD_0], e);
179 exif_entry_initialize (e, rational_test_tags[i]);
180 exif_set_srational (e->data, exif_data_get_byte_order (data), r);
181 /* In case this tag needs an unsigned rational instead,
182 * fix the type automatically */
183 exif_entry_fix (e);
184 check_entry_trunc(e, 1);
185 exif_content_remove_entry (data->ifd[EXIF_IFD_0], e);
186 exif_entry_unref (e);
187 }
188
189 /* Create a memory allocator to manage the remaining ExifEntry structs */
190 mem = exif_mem_new_default();
191 if (!mem) {
192 fprintf (stderr, "Out of memory\n");
193 exit(13);
194 }
195
196 /* EXIF_TAG_SUB_SEC_TIME initialization/truncation tests */
197 e = exif_entry_new_mem (mem);
198 if (!e) {
199 fprintf (stderr, "Out of memory\n");
200 exit(13);
201 }
202 exif_content_add_entry (data->ifd[EXIF_IFD_0], e);
203 exif_entry_initialize (e, EXIF_TAG_SUB_SEC_TIME);
204 e->size = sizeof(subsec); /* include NUL */
205 e->components = e->size;
206 /* Allocate memory to use for holding the tag data */
207 e->data = exif_mem_alloc(mem, e->size);
208 if (!e->data) {
209 fprintf (stderr, "Out of memory\n");
210 exit(13);
211 }
212 memcpy(e->data, subsec, e->size);
213 check_entry_trunc(e, 1);
214 exif_content_remove_entry (data->ifd[EXIF_IFD_0], e);
215 exif_entry_unref (e);
216
217 /* EXIF_TAG_USER_COMMENT initialization/truncation tests */
218 e = exif_entry_new_mem (mem);
219 if (!e) {
220 fprintf (stderr, "Out of memory\n");
221 exit(13);
222 }
223 exif_content_add_entry (data->ifd[EXIF_IFD_0], e);
224 exif_entry_initialize (e, EXIF_TAG_USER_COMMENT);
225 e->size = sizeof(user_comment) - 1;
226 e->components = e->size;
227 /* Allocate memory to use for holding the tag data */
228 e->data = exif_mem_alloc(mem, e->size);
229 if (!e->data) {
230 fprintf (stderr, "Out of memory\n");
231 exit(13);
232 }
233 memcpy(e->data, user_comment, e->size);
234 check_entry_trunc(e, 1);
235 exif_content_remove_entry (data->ifd[EXIF_IFD_0], e);
236 exif_entry_unref (e);
237
238 /* EXIF_TAG_XP_COMMENT truncation tests */
239 e = exif_entry_new_mem (mem);
240 if (!e) {
241 fprintf (stderr, "Out of memory\n");
242 exit(13);
243 }
244 exif_content_add_entry (data->ifd[EXIF_IFD_0], e);
245 exif_entry_initialize (e, EXIF_TAG_XP_COMMENT);
246 e->format = EXIF_FORMAT_BYTE;
247 e->size = sizeof(xp_comment) - 1;
248 e->components = e->size;
249 /* Allocate memory to use for holding the tag data */
250 e->data = exif_mem_alloc(mem, e->size);
251 if (!e->data) {
252 fprintf (stderr, "Out of memory\n");
253 exit(13);
254 }
255 memcpy(e->data, xp_comment, e->size);
256 check_entry_trunc(e, 1);
257 exif_content_remove_entry (data->ifd[EXIF_IFD_0], e);
258 exif_entry_unref (e);
259
260 /* EXIF_TAG_INTEROPERABILITY_VERSION truncation tests */
261 e = exif_entry_new_mem (mem);
262 if (!e) {
263 fprintf (stderr, "Out of memory\n");
264 exit(13);
265 }
266 exif_content_add_entry (data->ifd[EXIF_IFD_INTEROPERABILITY], e);
267 exif_entry_initialize (e, EXIF_TAG_INTEROPERABILITY_VERSION);
268 e->format = EXIF_FORMAT_UNDEFINED; /* The spec says ASCII, but libexif
269 allows UNDEFINED */
270 e->size = sizeof(interop); /* include NUL */
271 e->components = e->size;
272 /* Allocate memory to use for holding the tag data */
273 e->data = exif_mem_alloc(mem, e->size);
274 if (!e->data) {
275 fprintf (stderr, "Out of memory\n");
276 exit(13);
277 }
278 memcpy(e->data, interop, e->size);
279 check_entry_trunc(e, 1);
280 exif_content_remove_entry (data->ifd[EXIF_IFD_INTEROPERABILITY], e);
281 exif_entry_unref (e);
282
283 /* EXIF_TAG_GPS_VERSION_ID truncation tests */
284 e = exif_entry_new_mem (mem);
285 if (!e) {
286 fprintf (stderr, "Out of memory\n");
287 exit(13);
288 }
289 exif_content_add_entry (data->ifd[EXIF_IFD_GPS], e);
290 exif_entry_initialize (e, EXIF_TAG_GPS_VERSION_ID);
291 assert(e->format == EXIF_FORMAT_BYTE);
292 assert(e->size == 4);
293 assert(e->components == e->size);
294 e->data[0] = 2;
295 e->data[1] = 2;
296 e->data[2] = 0;
297 e->data[3] = 0;
298 check_entry_trunc(e, 1);
299 exif_content_remove_entry (data->ifd[EXIF_IFD_GPS], e);
300 exif_entry_unref (e);
301
302 /* EXIF_TAG_GPS_ALTITUDE_REF truncation tests */
303 e = exif_entry_new_mem (mem);
304 if (!e) {
305 fprintf (stderr, "Out of memory\n");
306 exit(13);
307 }
308 exif_content_add_entry (data->ifd[EXIF_IFD_GPS], e);
309 exif_entry_initialize (e, EXIF_TAG_GPS_ALTITUDE_REF);
310 assert(e->format == EXIF_FORMAT_BYTE);
311 assert(e->size == 1);
312 assert(e->components == e->size);
313 e->data[0] = 1;
314 check_entry_trunc(e, 1);
315 exif_content_remove_entry (data->ifd[EXIF_IFD_GPS], e);
316 exif_entry_unref (e);
317
318 /* EXIF_TAG_GPS_TIME_STAMP truncation tests */
319 e = exif_entry_new_mem (mem);
320 if (!e) {
321 fprintf (stderr, "Out of memory\n");
322 exit(13);
323 }
324 exif_content_add_entry (data->ifd[EXIF_IFD_GPS], e);
325 exif_entry_initialize (e, EXIF_TAG_GPS_TIME_STAMP);
326 assert(e->format == EXIF_FORMAT_RATIONAL);
327 assert(e->components == 3);
328 assert(e->size == e->components * exif_format_get_size(EXIF_FORMAT_RATIONAL));
329 exif_set_rational(e->data, exif_data_get_byte_order (data), gpsh);
330 exif_set_rational(e->data+8, exif_data_get_byte_order (data), gpsm);
331 exif_set_rational(e->data+16, exif_data_get_byte_order (data), gpss);
332 check_entry_trunc(e, 1);
333 exif_content_remove_entry (data->ifd[EXIF_IFD_GPS], e);
334 exif_entry_unref (e);
335
336 /* EXIF_TAG_SUBJECT_AREA truncation tests */
337 e = exif_entry_new_mem (mem);
338 if (!e) {
339 fprintf (stderr, "Out of memory\n");
340 exit(13);
341 }
342 exif_content_add_entry (data->ifd[EXIF_IFD_0], e);
343 exif_entry_initialize (e, EXIF_TAG_SUBJECT_AREA);
344 e->format = EXIF_FORMAT_SHORT;
345 /* This tag is interpreted differently depending on # components */
346 /* Rectangle */
347 e->components = 4;
348 e->size = e->components * exif_format_get_size(EXIF_FORMAT_SHORT);
349 /* Allocate memory to use for holding the tag data */
350 e->data = exif_mem_alloc(mem, e->size);
351 if (!e->data) {
352 fprintf (stderr, "Out of memory\n");
353 exit(13);
354 }
355 exif_set_short(e->data, exif_data_get_byte_order (data), 123);
356 exif_set_short(e->data+2, exif_data_get_byte_order (data), 456);
357 exif_set_short(e->data+4, exif_data_get_byte_order (data), 78);
358 exif_set_short(e->data+6, exif_data_get_byte_order (data), 90);
359 check_entry_trunc(e, 1);
360 /* Circle */
361 e->components = 3;
362 e->size = e->components * exif_format_get_size(EXIF_FORMAT_SHORT);
363 check_entry_trunc(e, 1);
364 /* Centre */
365 e->components = 2;
366 e->size = e->components * exif_format_get_size(EXIF_FORMAT_SHORT);
367 check_entry_trunc(e, 1);
368 /* Invalid */
369 e->components = 1;
370 e->size = e->components * exif_format_get_size(EXIF_FORMAT_SHORT);
371 check_entry_trunc(e, 1);
372 exif_content_remove_entry (data->ifd[EXIF_IFD_0], e);
373 exif_entry_unref (e);
374
375 exif_mem_unref(mem);
376 exif_data_unref (data);
377
378 return 0;
379 }
380