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