• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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