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