1/** \file test-parse-from-data.c 2 * \brief Completely parse all files given on the command line. 3 * 4 * Copyright (C) 2007 Hans Ulrich Niedermann <gp@n-dimensional.de> 5 * 6 * This library is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU Lesser General Public 8 * License as published by the Free Software Foundation; either 9 * version 2 of the License, or (at your option) any later version. 10 * 11 * This library is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 * Lesser General Public License for more details. 15 * 16 * You should have received a copy of the GNU Lesser General Public 17 * License along with this library; if not, write to the 18 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 19 * Boston, MA 02110-1301 USA. 20 * 21 */ 22 23#include "libexif/exif-data.h" 24#include "libexif/exif-system.h" 25 26#include <string.h> 27#include <stdio.h> 28#include <stdlib.h> 29#include <unistd.h> 30#include <fcntl.h> 31#include <sys/stat.h> 32 33 34static unsigned entry_count; 35 36/** Callback function handling an ExifEntry. */ 37static void content_foreach_func(ExifEntry *entry, void *UNUSED(callback_data)) 38{ 39 char buf[2000]; 40 exif_entry_get_value(entry, buf, sizeof(buf)); 41 printf(" Entry %u: %s (%s)\n" 42 " Size, Comps: %d, %d\n" 43 " Value: %s\n", 44 entry_count, 45 exif_tag_get_name(entry->tag), 46 exif_format_get_name(entry->format), 47 entry->size, 48 (int)(entry->components), 49 exif_entry_get_value(entry, buf, sizeof(buf))); 50 ++entry_count; 51} 52 53 54/** Callback function handling an ExifContent (corresponds 1:1 to an IFD). */ 55static void data_foreach_func(ExifContent *content, void *callback_data) 56{ 57 static unsigned content_count; 58 entry_count = 0; 59 printf(" Content %u: ifd=%d\n", content_count, exif_content_get_ifd(content)); 60 exif_content_foreach_entry(content, content_foreach_func, callback_data); 61 ++content_count; 62} 63 64static void dump_makernote(ExifData *d) { 65 ExifMnoteData *mn = exif_data_get_mnote_data(d); 66 if (mn) { 67 char buf[2000]; 68 int i; 69 int num = exif_mnote_data_count(mn); 70 printf(" MakerNote\n"); 71 for (i=0; i < num; ++i) { 72 if (exif_mnote_data_get_value(mn, i, buf, sizeof(buf))) { 73 const char *name = exif_mnote_data_get_name(mn, i); 74 unsigned int id = exif_mnote_data_get_id(mn, i); 75 if (!name) 76 name = "(unknown)"; 77 printf(" Entry %u: %u, %s\n" 78 " Size: %u\n" 79 " Value: %s\n", i, id, name, (unsigned)strlen(buf), buf); 80 } 81 } 82 } 83} 84 85/** Run EXIF parsing test on the given file. */ 86static void test_parse(const char *filename, void *callback_data, int swap) 87{ 88 ExifData *d; 89 int fd; 90 unsigned char *data; 91 struct stat stbuf; 92 93 /* Skip over path to display only the file name */ 94 const char *fn = strrchr(filename, '/'); 95 if (fn) 96 ++fn; 97 else 98 fn = filename; 99 printf("File %s\n", fn); 100 101 d = exif_data_new_from_file(filename); 102 fd = open(filename,O_RDONLY); 103 if (fd == -1) { 104 perror(filename); 105 return; 106 } 107 if (-1 == fstat(fd, &stbuf)) { 108 perror(filename); 109 return; 110 } 111 data = malloc(stbuf.st_size); 112 if (!data) { 113 fprintf (stderr, "Failed to allocate %ld bytes for reading %s\n", stbuf.st_size, filename); 114 return; 115 } 116 if (-1 == read(fd, data, stbuf.st_size)) { 117 perror ("read"); 118 free(data); 119 close(fd); 120 return; 121 } 122 close(fd); 123 124 d = exif_data_new_from_data(data, stbuf.st_size); 125 if (!d) { 126 fprintf (stderr, "Could not load data from '%s'!\n", filename); 127 free(data); 128 return; 129 } 130 printf("Byte order: %s\n", 131 exif_byte_order_get_name(exif_data_get_byte_order(d))); 132 133 if (swap) { 134 ExifByteOrder order = EXIF_BYTE_ORDER_INTEL; 135 if (exif_data_get_byte_order(d) == order) { 136 order = EXIF_BYTE_ORDER_MOTOROLA; 137 } 138 /* This switches the byte order of the entire EXIF data structure, 139 * including the MakerNote */ 140 exif_data_set_byte_order(d, order); 141 printf("New byte order: %s\n", 142 exif_byte_order_get_name(exif_data_get_byte_order(d))); 143 } 144 145 exif_data_foreach_content(d, data_foreach_func, callback_data); 146 147 dump_makernote(d); 148 149 exif_data_unref(d); 150} 151 152 153/** Callback function prototype for string parsing. */ 154typedef void (*test_parse_func) (const char *filename, void *callback_data, int swap); 155 156 157/** Split string at whitespace and call callback with each substring. */ 158static void split_ws_string(const char *string, test_parse_func func, void *callback_data) 159{ 160 const char *start = string; 161 const char *p = start; 162 for (;;) { 163 if (*p == ' ' || *p == '\t' || *p == '\n' || *p == '\r' || *p == '\0' ) { 164 size_t len = p-start; 165 if (len > 0) { 166 /* emulate strndup */ 167 char *str = malloc(1+len); 168 if (str) { 169 memcpy(str, start, len); 170 str[len] = '\0'; 171 func(str, callback_data, 0); 172 free(str); 173 start = p+1; 174 } 175 } else { 176 start = p+1; 177 } 178 } 179 if (*p == '\0') { 180 break; 181 } 182 p++; 183 } 184} 185 186 187/** Main program. */ 188int main(const int argc, const char *argv[]) 189{ 190 int i; 191 void *callback_data = NULL; 192 int swap = 0; 193 int first = 1; 194 195 if (argc > 1 && !strcmp(argv[1], "--swap-byte-order")) { 196 swap = 1; 197 ++first; 198 } 199 200 if (argc > first) { 201 for (i=first; i<argc; i++) { 202 test_parse(argv[i], callback_data, swap); 203 } 204 } else { 205 /* If no command-line argument is found, get the file names from 206 the environment. */ 207 const char *envar = getenv("TEST_IMAGES"); 208 if (envar) { 209 split_ws_string(envar, test_parse, callback_data); 210 } 211 } 212 213 return 0; 214} 215