diff options
author | Lorry Tar Creator <lorry-tar-importer@lorry> | 2012-07-12 20:34:34 +0000 |
---|---|---|
committer | Lorry Tar Creator <lorry-tar-importer@lorry> | 2012-07-12 20:34:34 +0000 |
commit | 0c6a5fa0d9719a40748d8726b4543f02f70518c1 (patch) | |
tree | 241f9ae619069ac5861d7621ade296102ab5de5d /libexif | |
download | libexif-tarball-master.tar.gz |
libexif-0.6.21HEADlibexif-0.6.21master
Diffstat (limited to 'libexif')
61 files changed, 14725 insertions, 0 deletions
diff --git a/libexif/Makefile.am b/libexif/Makefile.am new file mode 100644 index 0000000..dde00ac --- /dev/null +++ b/libexif/Makefile.am @@ -0,0 +1,67 @@ +EXTRA_DIST = +lib_LTLIBRARIES = +noinst_LTLIBRARIES = + +include canon/Makefile-files +include fuji/Makefile-files +include olympus/Makefile-files +include pentax/Makefile-files + +# The -no-undefined makes it possible to build DLLs for Windows, +# or shared libraries for Tru64 or AIX (according to the autobook +# chapter on "Portable Library Design"). It doesn't seem to hurt +# elsewhere, so we can leave it in. +lib_LTLIBRARIES += libexif.la +libexif_la_LDFLAGS = \ + -export-symbols $(srcdir)/libexif.sym \ + -no-undefined -version-info @LIBEXIF_VERSION_INFO@ +libexif_la_SOURCES = \ + exif-byte-order.c \ + exif-content.c \ + exif-data.c \ + exif-entry.c \ + exif-format.c \ + exif-ifd.c \ + exif-loader.c \ + exif-log.c \ + exif-mem.c \ + exif-mnote-data.c \ + exif-mnote-data-priv.h \ + exif-tag.c \ + exif-utils.c \ + i18n.h +libexif_la_DEPENDENCIES = \ + $(srcdir)/libexif.sym \ + libmnote-canon.la \ + libmnote-fuji.la \ + libmnote-olympus.la \ + libmnote-pentax.la +libexif_la_LIBADD = \ + $(LTLIBINTL) \ + libmnote-canon.la \ + libmnote-fuji.la \ + libmnote-olympus.la \ + libmnote-pentax.la + +libexifincludedir = $(includedir)/libexif +libexifinclude_HEADERS = \ + exif-byte-order.h \ + exif-content.h \ + exif-data.h \ + exif-data-type.h \ + exif-entry.h \ + exif-format.h \ + exif-ifd.h \ + exif-loader.h \ + exif-log.h \ + exif-mem.h \ + exif-mnote-data.h \ + exif-tag.h \ + exif-utils.h \ + _stdint.h + +EXTRA_DIST += exif-system.h exif.h + +EXTRA_DIST += libexif.sym + +DISTCLEANFILES = _stdint.h diff --git a/libexif/Makefile.in b/libexif/Makefile.in new file mode 100644 index 0000000..1156f64 --- /dev/null +++ b/libexif/Makefile.in @@ -0,0 +1,856 @@ +# Makefile.in generated by automake 1.11.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, +# Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + + +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +DIST_COMMON = $(libexifinclude_HEADERS) $(srcdir)/Makefile.am \ + $(srcdir)/Makefile.in $(srcdir)/canon/Makefile-files \ + $(srcdir)/fuji/Makefile-files $(srcdir)/olympus/Makefile-files \ + $(srcdir)/pentax/Makefile-files +subdir = libexif +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/m4m/gp-check-shell-environment.m4 \ + $(top_srcdir)/m4m/gp-config-msg.m4 \ + $(top_srcdir)/m4m/gp-documentation.m4 \ + $(top_srcdir)/m4m/gp-gettext-hack.m4 \ + $(top_srcdir)/m4m/stdint.m4 $(top_srcdir)/auto-m4/gettext.m4 \ + $(top_srcdir)/auto-m4/iconv.m4 $(top_srcdir)/auto-m4/lib-ld.m4 \ + $(top_srcdir)/auto-m4/lib-link.m4 \ + $(top_srcdir)/auto-m4/lib-prefix.m4 \ + $(top_srcdir)/auto-m4/libtool.m4 \ + $(top_srcdir)/auto-m4/ltoptions.m4 \ + $(top_srcdir)/auto-m4/ltsugar.m4 \ + $(top_srcdir)/auto-m4/ltversion.m4 \ + $(top_srcdir)/auto-m4/lt~obsolete.m4 \ + $(top_srcdir)/auto-m4/nls.m4 $(top_srcdir)/auto-m4/po.m4 \ + $(top_srcdir)/auto-m4/progtest.m4 $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; +am__vpath_adj = case $$p in \ + $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ + *) f=$$p;; \ + esac; +am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; +am__install_max = 40 +am__nobase_strip_setup = \ + srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` +am__nobase_strip = \ + for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" +am__nobase_list = $(am__nobase_strip_setup); \ + for p in $$list; do echo "$$p $$p"; done | \ + sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ + $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ + if (++n[$$2] == $(am__install_max)) \ + { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ + END { for (dir in files) print dir, files[dir] }' +am__base_list = \ + sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ + sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' +am__installdirs = "$(DESTDIR)$(libdir)" \ + "$(DESTDIR)$(libexifincludedir)" +LTLIBRARIES = $(lib_LTLIBRARIES) $(noinst_LTLIBRARIES) +am__DEPENDENCIES_1 = +am_libexif_la_OBJECTS = exif-byte-order.lo exif-content.lo \ + exif-data.lo exif-entry.lo exif-format.lo exif-ifd.lo \ + exif-loader.lo exif-log.lo exif-mem.lo exif-mnote-data.lo \ + exif-tag.lo exif-utils.lo +libexif_la_OBJECTS = $(am_libexif_la_OBJECTS) +AM_V_lt = $(am__v_lt_$(V)) +am__v_lt_ = $(am__v_lt_$(AM_DEFAULT_VERBOSITY)) +am__v_lt_0 = --silent +libexif_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(libexif_la_LDFLAGS) $(LDFLAGS) -o $@ +libmnote_canon_la_DEPENDENCIES = $(am__DEPENDENCIES_1) +am_libmnote_canon_la_OBJECTS = exif-mnote-data-canon.lo \ + mnote-canon-entry.lo mnote-canon-tag.lo +libmnote_canon_la_OBJECTS = $(am_libmnote_canon_la_OBJECTS) +libmnote_fuji_la_DEPENDENCIES = $(am__DEPENDENCIES_1) +am_libmnote_fuji_la_OBJECTS = mnote-fuji-entry.lo \ + exif-mnote-data-fuji.lo mnote-fuji-tag.lo +libmnote_fuji_la_OBJECTS = $(am_libmnote_fuji_la_OBJECTS) +libmnote_olympus_la_DEPENDENCIES = $(am__DEPENDENCIES_1) +am_libmnote_olympus_la_OBJECTS = mnote-olympus-entry.lo \ + exif-mnote-data-olympus.lo mnote-olympus-tag.lo +libmnote_olympus_la_OBJECTS = $(am_libmnote_olympus_la_OBJECTS) +libmnote_pentax_la_DEPENDENCIES = $(am__DEPENDENCIES_1) +am_libmnote_pentax_la_OBJECTS = mnote-pentax-entry.lo \ + exif-mnote-data-pentax.lo mnote-pentax-tag.lo +libmnote_pentax_la_OBJECTS = $(am_libmnote_pentax_la_OBJECTS) +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__depfiles_maybe = depfiles +am__mv = mv -f +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ + $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ + $(AM_CFLAGS) $(CFLAGS) +AM_V_CC = $(am__v_CC_$(V)) +am__v_CC_ = $(am__v_CC_$(AM_DEFAULT_VERBOSITY)) +am__v_CC_0 = @echo " CC " $@; +AM_V_at = $(am__v_at_$(V)) +am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY)) +am__v_at_0 = @ +CCLD = $(CC) +LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(AM_LDFLAGS) $(LDFLAGS) -o $@ +AM_V_CCLD = $(am__v_CCLD_$(V)) +am__v_CCLD_ = $(am__v_CCLD_$(AM_DEFAULT_VERBOSITY)) +am__v_CCLD_0 = @echo " CCLD " $@; +AM_V_GEN = $(am__v_GEN_$(V)) +am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY)) +am__v_GEN_0 = @echo " GEN " $@; +SOURCES = $(libexif_la_SOURCES) $(libmnote_canon_la_SOURCES) \ + $(libmnote_fuji_la_SOURCES) $(libmnote_olympus_la_SOURCES) \ + $(libmnote_pentax_la_SOURCES) +DIST_SOURCES = $(libexif_la_SOURCES) $(libmnote_canon_la_SOURCES) \ + $(libmnote_fuji_la_SOURCES) $(libmnote_olympus_la_SOURCES) \ + $(libmnote_pentax_la_SOURCES) +HEADERS = $(libexifinclude_HEADERS) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AM_CPPFLAGS = @AM_CPPFLAGS@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +AM_LDFLAGS = @AM_LDFLAGS@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLTOOL = @DLLTOOL@ +DOT = @DOT@ +DOXYGEN = @DOXYGEN@ +DOXYGEN_OUTPUT_DIR = @DOXYGEN_OUTPUT_DIR@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +GETTEXT_PACKAGE = @GETTEXT_PACKAGE@ +GMSGFMT = @GMSGFMT@ +GREP = @GREP@ +HAVE_DOT = @HAVE_DOT@ +HTML_APIDOC_DIR = @HTML_APIDOC_DIR@ +HTML_APIDOC_INTERNALS_DIR = @HTML_APIDOC_INTERNALS_DIR@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +INTLLIBS = @INTLLIBS@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBEXIF_AGE = @LIBEXIF_AGE@ +LIBEXIF_CURRENT = @LIBEXIF_CURRENT@ +LIBEXIF_CURRENT_MIN = @LIBEXIF_CURRENT_MIN@ +LIBEXIF_REVISION = @LIBEXIF_REVISION@ +LIBEXIF_VERSION_INFO = @LIBEXIF_VERSION_INFO@ +LIBICONV = @LIBICONV@ +LIBINTL = @LIBINTL@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBICONV = @LTLIBICONV@ +LTLIBINTL = @LTLIBINTL@ +LTLIBOBJS = @LTLIBOBJS@ +MAINT = @MAINT@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +MKDIR_P = @MKDIR_P@ +MKINSTALLDIRS = @MKINSTALLDIRS@ +MSGFMT = @MSGFMT@ +MSGMERGE = @MSGMERGE@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +POSUB = @POSUB@ +RANLIB = @RANLIB@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +USE_NLS = @USE_NLS@ +VERSION = @VERSION@ +XGETTEXT = @XGETTEXT@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +EXTRA_DIST = exif-system.h exif.h libexif.sym + +# The -no-undefined makes it possible to build DLLs for Windows, +# or shared libraries for Tru64 or AIX (according to the autobook +# chapter on "Portable Library Design"). It doesn't seem to hurt +# elsewhere, so we can leave it in. +lib_LTLIBRARIES = libexif.la + +# -*- Makefile -*- + +# -*- Makefile -*- + +# -*- Makefile -*- + +# -*- Makefile -*- +noinst_LTLIBRARIES = libmnote-canon.la libmnote-fuji.la \ + libmnote-olympus.la libmnote-pentax.la +libmnote_canon_la_SOURCES = \ + canon/exif-mnote-data-canon.c canon/exif-mnote-data-canon.h \ + canon/mnote-canon-entry.c canon/mnote-canon-entry.h \ + canon/mnote-canon-tag.c canon/mnote-canon-tag.h + +libmnote_canon_la_LIBADD = $(LTLIBINTL) +libmnote_fuji_la_SOURCES = \ + fuji/mnote-fuji-entry.c fuji/mnote-fuji-entry.h \ + fuji/exif-mnote-data-fuji.c fuji/exif-mnote-data-fuji.h \ + fuji/mnote-fuji-tag.c fuji/mnote-fuji-tag.h + +libmnote_fuji_la_LIBADD = $(LTLIBINTL) +libmnote_olympus_la_SOURCES = \ + olympus/mnote-olympus-entry.c olympus/mnote-olympus-entry.h \ + olympus/exif-mnote-data-olympus.c olympus/exif-mnote-data-olympus.h \ + olympus/mnote-olympus-tag.c olympus/mnote-olympus-tag.h + +libmnote_olympus_la_LIBADD = $(LTLIBINTL) +libmnote_pentax_la_SOURCES = \ + pentax/mnote-pentax-entry.c pentax/mnote-pentax-entry.h \ + pentax/exif-mnote-data-pentax.c pentax/exif-mnote-data-pentax.h \ + pentax/mnote-pentax-tag.c pentax/mnote-pentax-tag.h + +libmnote_pentax_la_LIBADD = $(LTLIBINTL) +libexif_la_LDFLAGS = \ + -export-symbols $(srcdir)/libexif.sym \ + -no-undefined -version-info @LIBEXIF_VERSION_INFO@ + +libexif_la_SOURCES = \ + exif-byte-order.c \ + exif-content.c \ + exif-data.c \ + exif-entry.c \ + exif-format.c \ + exif-ifd.c \ + exif-loader.c \ + exif-log.c \ + exif-mem.c \ + exif-mnote-data.c \ + exif-mnote-data-priv.h \ + exif-tag.c \ + exif-utils.c \ + i18n.h + +libexif_la_DEPENDENCIES = \ + $(srcdir)/libexif.sym \ + libmnote-canon.la \ + libmnote-fuji.la \ + libmnote-olympus.la \ + libmnote-pentax.la + +libexif_la_LIBADD = \ + $(LTLIBINTL) \ + libmnote-canon.la \ + libmnote-fuji.la \ + libmnote-olympus.la \ + libmnote-pentax.la + +libexifincludedir = $(includedir)/libexif +libexifinclude_HEADERS = \ + exif-byte-order.h \ + exif-content.h \ + exif-data.h \ + exif-data-type.h \ + exif-entry.h \ + exif-format.h \ + exif-ifd.h \ + exif-loader.h \ + exif-log.h \ + exif-mem.h \ + exif-mnote-data.h \ + exif-tag.h \ + exif-utils.h \ + _stdint.h + +DISTCLEANFILES = _stdint.h +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .lo .o .obj +$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(srcdir)/canon/Makefile-files $(srcdir)/fuji/Makefile-files $(srcdir)/olympus/Makefile-files $(srcdir)/pentax/Makefile-files $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu libexif/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --gnu libexif/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): +install-libLTLIBRARIES: $(lib_LTLIBRARIES) + @$(NORMAL_INSTALL) + test -z "$(libdir)" || $(MKDIR_P) "$(DESTDIR)$(libdir)" + @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ + list2=; for p in $$list; do \ + if test -f $$p; then \ + list2="$$list2 $$p"; \ + else :; fi; \ + done; \ + test -z "$$list2" || { \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(libdir)'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(libdir)"; \ + } + +uninstall-libLTLIBRARIES: + @$(NORMAL_UNINSTALL) + @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ + for p in $$list; do \ + $(am__strip_dir) \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$f'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$f"; \ + done + +clean-libLTLIBRARIES: + -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES) + @list='$(lib_LTLIBRARIES)'; for p in $$list; do \ + dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ + test "$$dir" != "$$p" || dir=.; \ + echo "rm -f \"$${dir}/so_locations\""; \ + rm -f "$${dir}/so_locations"; \ + done + +clean-noinstLTLIBRARIES: + -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES) + @list='$(noinst_LTLIBRARIES)'; for p in $$list; do \ + dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ + test "$$dir" != "$$p" || dir=.; \ + echo "rm -f \"$${dir}/so_locations\""; \ + rm -f "$${dir}/so_locations"; \ + done +libexif.la: $(libexif_la_OBJECTS) $(libexif_la_DEPENDENCIES) + $(AM_V_CCLD)$(libexif_la_LINK) -rpath $(libdir) $(libexif_la_OBJECTS) $(libexif_la_LIBADD) $(LIBS) +libmnote-canon.la: $(libmnote_canon_la_OBJECTS) $(libmnote_canon_la_DEPENDENCIES) + $(AM_V_CCLD)$(LINK) $(libmnote_canon_la_OBJECTS) $(libmnote_canon_la_LIBADD) $(LIBS) +libmnote-fuji.la: $(libmnote_fuji_la_OBJECTS) $(libmnote_fuji_la_DEPENDENCIES) + $(AM_V_CCLD)$(LINK) $(libmnote_fuji_la_OBJECTS) $(libmnote_fuji_la_LIBADD) $(LIBS) +libmnote-olympus.la: $(libmnote_olympus_la_OBJECTS) $(libmnote_olympus_la_DEPENDENCIES) + $(AM_V_CCLD)$(LINK) $(libmnote_olympus_la_OBJECTS) $(libmnote_olympus_la_LIBADD) $(LIBS) +libmnote-pentax.la: $(libmnote_pentax_la_OBJECTS) $(libmnote_pentax_la_DEPENDENCIES) + $(AM_V_CCLD)$(LINK) $(libmnote_pentax_la_OBJECTS) $(libmnote_pentax_la_LIBADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/exif-byte-order.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/exif-content.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/exif-data.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/exif-entry.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/exif-format.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/exif-ifd.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/exif-loader.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/exif-log.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/exif-mem.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/exif-mnote-data-canon.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/exif-mnote-data-fuji.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/exif-mnote-data-olympus.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/exif-mnote-data-pentax.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/exif-mnote-data.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/exif-tag.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/exif-utils.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mnote-canon-entry.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mnote-canon-tag.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mnote-fuji-entry.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mnote-fuji-tag.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mnote-olympus-entry.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mnote-olympus-tag.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mnote-pentax-entry.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mnote-pentax-tag.Plo@am__quote@ + +.c.o: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c $< + +.c.obj: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` + +.c.lo: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< + +exif-mnote-data-canon.lo: canon/exif-mnote-data-canon.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT exif-mnote-data-canon.lo -MD -MP -MF $(DEPDIR)/exif-mnote-data-canon.Tpo -c -o exif-mnote-data-canon.lo `test -f 'canon/exif-mnote-data-canon.c' || echo '$(srcdir)/'`canon/exif-mnote-data-canon.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/exif-mnote-data-canon.Tpo $(DEPDIR)/exif-mnote-data-canon.Plo +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='canon/exif-mnote-data-canon.c' object='exif-mnote-data-canon.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o exif-mnote-data-canon.lo `test -f 'canon/exif-mnote-data-canon.c' || echo '$(srcdir)/'`canon/exif-mnote-data-canon.c + +mnote-canon-entry.lo: canon/mnote-canon-entry.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT mnote-canon-entry.lo -MD -MP -MF $(DEPDIR)/mnote-canon-entry.Tpo -c -o mnote-canon-entry.lo `test -f 'canon/mnote-canon-entry.c' || echo '$(srcdir)/'`canon/mnote-canon-entry.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/mnote-canon-entry.Tpo $(DEPDIR)/mnote-canon-entry.Plo +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='canon/mnote-canon-entry.c' object='mnote-canon-entry.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o mnote-canon-entry.lo `test -f 'canon/mnote-canon-entry.c' || echo '$(srcdir)/'`canon/mnote-canon-entry.c + +mnote-canon-tag.lo: canon/mnote-canon-tag.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT mnote-canon-tag.lo -MD -MP -MF $(DEPDIR)/mnote-canon-tag.Tpo -c -o mnote-canon-tag.lo `test -f 'canon/mnote-canon-tag.c' || echo '$(srcdir)/'`canon/mnote-canon-tag.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/mnote-canon-tag.Tpo $(DEPDIR)/mnote-canon-tag.Plo +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='canon/mnote-canon-tag.c' object='mnote-canon-tag.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o mnote-canon-tag.lo `test -f 'canon/mnote-canon-tag.c' || echo '$(srcdir)/'`canon/mnote-canon-tag.c + +mnote-fuji-entry.lo: fuji/mnote-fuji-entry.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT mnote-fuji-entry.lo -MD -MP -MF $(DEPDIR)/mnote-fuji-entry.Tpo -c -o mnote-fuji-entry.lo `test -f 'fuji/mnote-fuji-entry.c' || echo '$(srcdir)/'`fuji/mnote-fuji-entry.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/mnote-fuji-entry.Tpo $(DEPDIR)/mnote-fuji-entry.Plo +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='fuji/mnote-fuji-entry.c' object='mnote-fuji-entry.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o mnote-fuji-entry.lo `test -f 'fuji/mnote-fuji-entry.c' || echo '$(srcdir)/'`fuji/mnote-fuji-entry.c + +exif-mnote-data-fuji.lo: fuji/exif-mnote-data-fuji.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT exif-mnote-data-fuji.lo -MD -MP -MF $(DEPDIR)/exif-mnote-data-fuji.Tpo -c -o exif-mnote-data-fuji.lo `test -f 'fuji/exif-mnote-data-fuji.c' || echo '$(srcdir)/'`fuji/exif-mnote-data-fuji.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/exif-mnote-data-fuji.Tpo $(DEPDIR)/exif-mnote-data-fuji.Plo +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='fuji/exif-mnote-data-fuji.c' object='exif-mnote-data-fuji.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o exif-mnote-data-fuji.lo `test -f 'fuji/exif-mnote-data-fuji.c' || echo '$(srcdir)/'`fuji/exif-mnote-data-fuji.c + +mnote-fuji-tag.lo: fuji/mnote-fuji-tag.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT mnote-fuji-tag.lo -MD -MP -MF $(DEPDIR)/mnote-fuji-tag.Tpo -c -o mnote-fuji-tag.lo `test -f 'fuji/mnote-fuji-tag.c' || echo '$(srcdir)/'`fuji/mnote-fuji-tag.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/mnote-fuji-tag.Tpo $(DEPDIR)/mnote-fuji-tag.Plo +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='fuji/mnote-fuji-tag.c' object='mnote-fuji-tag.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o mnote-fuji-tag.lo `test -f 'fuji/mnote-fuji-tag.c' || echo '$(srcdir)/'`fuji/mnote-fuji-tag.c + +mnote-olympus-entry.lo: olympus/mnote-olympus-entry.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT mnote-olympus-entry.lo -MD -MP -MF $(DEPDIR)/mnote-olympus-entry.Tpo -c -o mnote-olympus-entry.lo `test -f 'olympus/mnote-olympus-entry.c' || echo '$(srcdir)/'`olympus/mnote-olympus-entry.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/mnote-olympus-entry.Tpo $(DEPDIR)/mnote-olympus-entry.Plo +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='olympus/mnote-olympus-entry.c' object='mnote-olympus-entry.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o mnote-olympus-entry.lo `test -f 'olympus/mnote-olympus-entry.c' || echo '$(srcdir)/'`olympus/mnote-olympus-entry.c + +exif-mnote-data-olympus.lo: olympus/exif-mnote-data-olympus.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT exif-mnote-data-olympus.lo -MD -MP -MF $(DEPDIR)/exif-mnote-data-olympus.Tpo -c -o exif-mnote-data-olympus.lo `test -f 'olympus/exif-mnote-data-olympus.c' || echo '$(srcdir)/'`olympus/exif-mnote-data-olympus.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/exif-mnote-data-olympus.Tpo $(DEPDIR)/exif-mnote-data-olympus.Plo +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='olympus/exif-mnote-data-olympus.c' object='exif-mnote-data-olympus.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o exif-mnote-data-olympus.lo `test -f 'olympus/exif-mnote-data-olympus.c' || echo '$(srcdir)/'`olympus/exif-mnote-data-olympus.c + +mnote-olympus-tag.lo: olympus/mnote-olympus-tag.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT mnote-olympus-tag.lo -MD -MP -MF $(DEPDIR)/mnote-olympus-tag.Tpo -c -o mnote-olympus-tag.lo `test -f 'olympus/mnote-olympus-tag.c' || echo '$(srcdir)/'`olympus/mnote-olympus-tag.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/mnote-olympus-tag.Tpo $(DEPDIR)/mnote-olympus-tag.Plo +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='olympus/mnote-olympus-tag.c' object='mnote-olympus-tag.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o mnote-olympus-tag.lo `test -f 'olympus/mnote-olympus-tag.c' || echo '$(srcdir)/'`olympus/mnote-olympus-tag.c + +mnote-pentax-entry.lo: pentax/mnote-pentax-entry.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT mnote-pentax-entry.lo -MD -MP -MF $(DEPDIR)/mnote-pentax-entry.Tpo -c -o mnote-pentax-entry.lo `test -f 'pentax/mnote-pentax-entry.c' || echo '$(srcdir)/'`pentax/mnote-pentax-entry.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/mnote-pentax-entry.Tpo $(DEPDIR)/mnote-pentax-entry.Plo +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='pentax/mnote-pentax-entry.c' object='mnote-pentax-entry.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o mnote-pentax-entry.lo `test -f 'pentax/mnote-pentax-entry.c' || echo '$(srcdir)/'`pentax/mnote-pentax-entry.c + +exif-mnote-data-pentax.lo: pentax/exif-mnote-data-pentax.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT exif-mnote-data-pentax.lo -MD -MP -MF $(DEPDIR)/exif-mnote-data-pentax.Tpo -c -o exif-mnote-data-pentax.lo `test -f 'pentax/exif-mnote-data-pentax.c' || echo '$(srcdir)/'`pentax/exif-mnote-data-pentax.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/exif-mnote-data-pentax.Tpo $(DEPDIR)/exif-mnote-data-pentax.Plo +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='pentax/exif-mnote-data-pentax.c' object='exif-mnote-data-pentax.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o exif-mnote-data-pentax.lo `test -f 'pentax/exif-mnote-data-pentax.c' || echo '$(srcdir)/'`pentax/exif-mnote-data-pentax.c + +mnote-pentax-tag.lo: pentax/mnote-pentax-tag.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT mnote-pentax-tag.lo -MD -MP -MF $(DEPDIR)/mnote-pentax-tag.Tpo -c -o mnote-pentax-tag.lo `test -f 'pentax/mnote-pentax-tag.c' || echo '$(srcdir)/'`pentax/mnote-pentax-tag.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/mnote-pentax-tag.Tpo $(DEPDIR)/mnote-pentax-tag.Plo +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='pentax/mnote-pentax-tag.c' object='mnote-pentax-tag.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o mnote-pentax-tag.lo `test -f 'pentax/mnote-pentax-tag.c' || echo '$(srcdir)/'`pentax/mnote-pentax-tag.c + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs +install-libexifincludeHEADERS: $(libexifinclude_HEADERS) + @$(NORMAL_INSTALL) + test -z "$(libexifincludedir)" || $(MKDIR_P) "$(DESTDIR)$(libexifincludedir)" + @list='$(libexifinclude_HEADERS)'; test -n "$(libexifincludedir)" || list=; \ + for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + echo "$$d$$p"; \ + done | $(am__base_list) | \ + while read files; do \ + echo " $(INSTALL_HEADER) $$files '$(DESTDIR)$(libexifincludedir)'"; \ + $(INSTALL_HEADER) $$files "$(DESTDIR)$(libexifincludedir)" || exit $$?; \ + done + +uninstall-libexifincludeHEADERS: + @$(NORMAL_UNINSTALL) + @list='$(libexifinclude_HEADERS)'; test -n "$(libexifincludedir)" || list=; \ + files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ + test -n "$$files" || exit 0; \ + echo " ( cd '$(DESTDIR)$(libexifincludedir)' && rm -f" $$files ")"; \ + cd "$(DESTDIR)$(libexifincludedir)" && rm -f $$files + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + set x; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(LTLIBRARIES) $(HEADERS) +installdirs: + for dir in "$(DESTDIR)$(libdir)" "$(DESTDIR)$(libexifincludedir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + -test -z "$(DISTCLEANFILES)" || rm -f $(DISTCLEANFILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-libLTLIBRARIES clean-libtool \ + clean-noinstLTLIBRARIES mostlyclean-am + +distclean: distclean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: install-libexifincludeHEADERS + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: install-libLTLIBRARIES + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-libLTLIBRARIES uninstall-libexifincludeHEADERS + +.MAKE: install-am install-strip + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ + clean-libLTLIBRARIES clean-libtool clean-noinstLTLIBRARIES \ + ctags distclean distclean-compile distclean-generic \ + distclean-libtool distclean-tags distdir dvi dvi-am html \ + html-am info info-am install install-am install-data \ + install-data-am install-dvi install-dvi-am install-exec \ + install-exec-am install-html install-html-am install-info \ + install-info-am install-libLTLIBRARIES \ + install-libexifincludeHEADERS install-man install-pdf \ + install-pdf-am install-ps install-ps-am install-strip \ + installcheck installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ + tags uninstall uninstall-am uninstall-libLTLIBRARIES \ + uninstall-libexifincludeHEADERS + + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/libexif/_stdint.h b/libexif/_stdint.h new file mode 100644 index 0000000..80ecf41 --- /dev/null +++ b/libexif/_stdint.h @@ -0,0 +1,2 @@ +/* This file is generated automatically by configure */ +#include <stdint.h> diff --git a/libexif/canon/Makefile-files b/libexif/canon/Makefile-files new file mode 100644 index 0000000..ef7ee2b --- /dev/null +++ b/libexif/canon/Makefile-files @@ -0,0 +1,7 @@ +# -*- Makefile -*- +noinst_LTLIBRARIES += libmnote-canon.la +libmnote_canon_la_SOURCES = \ + canon/exif-mnote-data-canon.c canon/exif-mnote-data-canon.h \ + canon/mnote-canon-entry.c canon/mnote-canon-entry.h \ + canon/mnote-canon-tag.c canon/mnote-canon-tag.h +libmnote_canon_la_LIBADD = $(LTLIBINTL) diff --git a/libexif/canon/exif-mnote-data-canon.c b/libexif/canon/exif-mnote-data-canon.c new file mode 100644 index 0000000..eb53598 --- /dev/null +++ b/libexif/canon/exif-mnote-data-canon.c @@ -0,0 +1,389 @@ +/* exif-mnote-data-canon.c + * + * Copyright (c) 2002, 2003 Lutz Mueller <lutz@users.sourceforge.net> + * Copyright (c) 2003 Matthieu Castet <mat-c@users.sourceforge.net> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA. + */ + +#include <config.h> +#include "exif-mnote-data-canon.h" + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +#include <libexif/exif-byte-order.h> +#include <libexif/exif-utils.h> +#include <libexif/exif-data.h> + +#define DEBUG + +static void +exif_mnote_data_canon_clear (ExifMnoteDataCanon *n) +{ + ExifMnoteData *d = (ExifMnoteData *) n; + unsigned int i; + + if (!n) return; + + if (n->entries) { + for (i = 0; i < n->count; i++) + if (n->entries[i].data) { + exif_mem_free (d->mem, n->entries[i].data); + n->entries[i].data = NULL; + } + exif_mem_free (d->mem, n->entries); + n->entries = NULL; + n->count = 0; + } +} + +static void +exif_mnote_data_canon_free (ExifMnoteData *n) +{ + if (!n) return; + + exif_mnote_data_canon_clear ((ExifMnoteDataCanon *) n); +} + +static void +exif_mnote_data_canon_get_tags (ExifMnoteDataCanon *dc, unsigned int n, + unsigned int *m, unsigned int *s) +{ + unsigned int from = 0, to; + + if (!dc || !m) return; + for (*m = 0; *m < dc->count; (*m)++) { + to = from + mnote_canon_entry_count_values (&dc->entries[*m]); + if (to > n) { + if (s) *s = n - from; + break; + } + from = to; + } +} + +static char * +exif_mnote_data_canon_get_value (ExifMnoteData *note, unsigned int n, char *val, unsigned int maxlen) +{ + ExifMnoteDataCanon *dc = (ExifMnoteDataCanon *) note; + unsigned int m, s; + + if (!dc) return NULL; + exif_mnote_data_canon_get_tags (dc, n, &m, &s); + if (m >= dc->count) return NULL; + return mnote_canon_entry_get_value (&dc->entries[m], s, val, maxlen); +} + +static void +exif_mnote_data_canon_set_byte_order (ExifMnoteData *d, ExifByteOrder o) +{ + ExifByteOrder o_orig; + ExifMnoteDataCanon *n = (ExifMnoteDataCanon *) d; + unsigned int i; + + if (!n) return; + + o_orig = n->order; + n->order = o; + for (i = 0; i < n->count; i++) { + n->entries[i].order = o; + exif_array_set_byte_order (n->entries[i].format, n->entries[i].data, + n->entries[i].components, o_orig, o); + } +} + +static void +exif_mnote_data_canon_set_offset (ExifMnoteData *n, unsigned int o) +{ + if (n) ((ExifMnoteDataCanon *) n)->offset = o; +} + +static void +exif_mnote_data_canon_save (ExifMnoteData *ne, + unsigned char **buf, unsigned int *buf_size) +{ + ExifMnoteDataCanon *n = (ExifMnoteDataCanon *) ne; + size_t i, o, s, doff; + unsigned char *t; + size_t ts; + + if (!n || !buf || !buf_size) return; + + /* + * Allocate enough memory for all entries and the number + * of entries. + */ + *buf_size = 2 + n->count * 12 + 4; + *buf = exif_mem_alloc (ne->mem, sizeof (char) * *buf_size); + if (!*buf) { + EXIF_LOG_NO_MEMORY(ne->log, "ExifMnoteCanon", *buf_size); + return; + } + + /* Save the number of entries */ + exif_set_short (*buf, n->order, (ExifShort) n->count); + + /* Save each entry */ + for (i = 0; i < n->count; i++) { + o = 2 + i * 12; + exif_set_short (*buf + o + 0, n->order, (ExifShort) n->entries[i].tag); + exif_set_short (*buf + o + 2, n->order, (ExifShort) n->entries[i].format); + exif_set_long (*buf + o + 4, n->order, + n->entries[i].components); + o += 8; + s = exif_format_get_size (n->entries[i].format) * + n->entries[i].components; + if (s > 65536) { + /* Corrupt data: EXIF data size is limited to the + * maximum size of a JPEG segment (64 kb). + */ + continue; + } + if (s > 4) { + ts = *buf_size + s; + + /* Ensure even offsets. Set padding bytes to 0. */ + if (s & 1) ts += 1; + t = exif_mem_realloc (ne->mem, *buf, + sizeof (char) * ts); + if (!t) { + EXIF_LOG_NO_MEMORY(ne->log, "ExifMnoteCanon", ts); + return; + } + *buf = t; + *buf_size = ts; + doff = *buf_size - s; + if (s & 1) { doff--; *(*buf + *buf_size - 1) = '\0'; } + exif_set_long (*buf + o, n->order, n->offset + doff); + } else + doff = o; + + /* + * Write the data. Fill unneeded bytes with 0. Do not + * crash if data is NULL. + */ + if (!n->entries[i].data) memset (*buf + doff, 0, s); + else memcpy (*buf + doff, n->entries[i].data, s); + if (s < 4) memset (*buf + doff + s, 0, (4 - s)); + } +} + +/* XXX + * FIXME: exif_mnote_data_canon_load() may fail and there is no + * semantics to express that. + * See bug #1054323 for details, especially the comment by liblit + * after it has supposedly been fixed: + * + * https://sourceforge.net/tracker/?func=detail&aid=1054323&group_id=12272&atid=112272 + * Unfortunately, the "return" statements aren't commented at + * all, so it isn't trivial to find out what is a normal + * return, and what is a reaction to an error condition. + */ + +static void +exif_mnote_data_canon_load (ExifMnoteData *ne, + const unsigned char *buf, unsigned int buf_size) +{ + ExifMnoteDataCanon *n = (ExifMnoteDataCanon *) ne; + ExifShort c; + size_t i, tcount, o, datao; + + if (!n || !buf || !buf_size) { + exif_log (ne->log, EXIF_LOG_CODE_CORRUPT_DATA, + "ExifMnoteCanon", "Short MakerNote"); + return; + } + datao = 6 + n->offset; + if ((datao + 2 < datao) || (datao + 2 < 2) || (datao + 2 > buf_size)) { + exif_log (ne->log, EXIF_LOG_CODE_CORRUPT_DATA, + "ExifMnoteCanon", "Short MakerNote"); + return; + } + + /* Read the number of tags */ + c = exif_get_short (buf + datao, n->order); + datao += 2; + + /* Remove any old entries */ + exif_mnote_data_canon_clear (n); + + /* Reserve enough space for all the possible MakerNote tags */ + n->entries = exif_mem_alloc (ne->mem, sizeof (MnoteCanonEntry) * c); + if (!n->entries) { + EXIF_LOG_NO_MEMORY(ne->log, "ExifMnoteCanon", sizeof (MnoteCanonEntry) * c); + return; + } + + /* Parse the entries */ + tcount = 0; + for (i = c, o = datao; i; --i, o += 12) { + size_t s; + if ((o + 12 < o) || (o + 12 < 12) || (o + 12 > buf_size)) { + exif_log (ne->log, EXIF_LOG_CODE_CORRUPT_DATA, + "ExifMnoteCanon", "Short MakerNote"); + break; + } + + n->entries[tcount].tag = exif_get_short (buf + o, n->order); + n->entries[tcount].format = exif_get_short (buf + o + 2, n->order); + n->entries[tcount].components = exif_get_long (buf + o + 4, n->order); + n->entries[tcount].order = n->order; + + exif_log (ne->log, EXIF_LOG_CODE_DEBUG, "ExifMnoteCanon", + "Loading entry 0x%x ('%s')...", n->entries[tcount].tag, + mnote_canon_tag_get_name (n->entries[tcount].tag)); + + /* + * Size? If bigger than 4 bytes, the actual data is not + * in the entry but somewhere else (offset). + */ + s = exif_format_get_size (n->entries[tcount].format) * + n->entries[tcount].components; + n->entries[tcount].size = s; + if (!s) { + exif_log (ne->log, EXIF_LOG_CODE_CORRUPT_DATA, + "ExifMnoteCanon", + "Invalid zero-length tag size"); + continue; + + } else { + size_t dataofs = o + 8; + if (s > 4) dataofs = exif_get_long (buf + dataofs, n->order) + 6; + if ((dataofs + s < s) || (dataofs + s < dataofs) || (dataofs + s > buf_size)) { + exif_log (ne->log, EXIF_LOG_CODE_DEBUG, + "ExifMnoteCanon", + "Tag data past end of buffer (%u > %u)", + dataofs + s, buf_size); + continue; + } + + n->entries[tcount].data = exif_mem_alloc (ne->mem, s); + if (!n->entries[tcount].data) { + EXIF_LOG_NO_MEMORY(ne->log, "ExifMnoteCanon", s); + continue; + } + memcpy (n->entries[tcount].data, buf + dataofs, s); + } + + /* Tag was successfully parsed */ + ++tcount; + } + /* Store the count of successfully parsed tags */ + n->count = tcount; +} + +static unsigned int +exif_mnote_data_canon_count (ExifMnoteData *n) +{ + ExifMnoteDataCanon *dc = (ExifMnoteDataCanon *) n; + unsigned int i, c; + + for (i = c = 0; dc && (i < dc->count); i++) + c += mnote_canon_entry_count_values (&dc->entries[i]); + return c; +} + +static unsigned int +exif_mnote_data_canon_get_id (ExifMnoteData *d, unsigned int i) +{ + ExifMnoteDataCanon *dc = (ExifMnoteDataCanon *) d; + unsigned int m; + + if (!dc) return 0; + exif_mnote_data_canon_get_tags (dc, i, &m, NULL); + if (m >= dc->count) return 0; + return dc->entries[m].tag; +} + +static const char * +exif_mnote_data_canon_get_name (ExifMnoteData *note, unsigned int i) +{ + ExifMnoteDataCanon *dc = (ExifMnoteDataCanon *) note; + unsigned int m, s; + + if (!dc) return NULL; + exif_mnote_data_canon_get_tags (dc, i, &m, &s); + if (m >= dc->count) return NULL; + return mnote_canon_tag_get_name_sub (dc->entries[m].tag, s, dc->options); +} + +static const char * +exif_mnote_data_canon_get_title (ExifMnoteData *note, unsigned int i) +{ + ExifMnoteDataCanon *dc = (ExifMnoteDataCanon *) note; + unsigned int m, s; + + if (!dc) return NULL; + exif_mnote_data_canon_get_tags (dc, i, &m, &s); + if (m >= dc->count) return NULL; + return mnote_canon_tag_get_title_sub (dc->entries[m].tag, s, dc->options); +} + +static const char * +exif_mnote_data_canon_get_description (ExifMnoteData *note, unsigned int i) +{ + ExifMnoteDataCanon *dc = (ExifMnoteDataCanon *) note; + unsigned int m; + + if (!dc) return NULL; + exif_mnote_data_canon_get_tags (dc, i, &m, NULL); + if (m >= dc->count) return NULL; + return mnote_canon_tag_get_description (dc->entries[m].tag); +} + +int +exif_mnote_data_canon_identify (const ExifData *ed, const ExifEntry *e) +{ + char value[8]; + ExifEntry *em = exif_data_get_entry (ed, EXIF_TAG_MAKE); + if (!em) + return 0; + return !strcmp (exif_entry_get_value (em, value, sizeof (value)), "Canon"); +} + +ExifMnoteData * +exif_mnote_data_canon_new (ExifMem *mem, ExifDataOption o) +{ + ExifMnoteData *d; + ExifMnoteDataCanon *dc; + + if (!mem) return NULL; + + d = exif_mem_alloc (mem, sizeof (ExifMnoteDataCanon)); + if (!d) + return NULL; + + exif_mnote_data_construct (d, mem); + + /* Set up function pointers */ + d->methods.free = exif_mnote_data_canon_free; + d->methods.set_byte_order = exif_mnote_data_canon_set_byte_order; + d->methods.set_offset = exif_mnote_data_canon_set_offset; + d->methods.load = exif_mnote_data_canon_load; + d->methods.save = exif_mnote_data_canon_save; + d->methods.count = exif_mnote_data_canon_count; + d->methods.get_id = exif_mnote_data_canon_get_id; + d->methods.get_name = exif_mnote_data_canon_get_name; + d->methods.get_title = exif_mnote_data_canon_get_title; + d->methods.get_description = exif_mnote_data_canon_get_description; + d->methods.get_value = exif_mnote_data_canon_get_value; + + dc = (ExifMnoteDataCanon*)d; + dc->options = o; + return d; +} diff --git a/libexif/canon/exif-mnote-data-canon.h b/libexif/canon/exif-mnote-data-canon.h new file mode 100644 index 0000000..2a1cc87 --- /dev/null +++ b/libexif/canon/exif-mnote-data-canon.h @@ -0,0 +1,58 @@ +/* exif-mnote-data-canon.h + * + * Copyright (c) 2002, 2003 Lutz Mueller <lutz@users.sourceforge.net> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA. + */ + +#ifndef __EXIF_MNOTE_DATA_CANON_H__ +#define __EXIF_MNOTE_DATA_CANON_H__ + +#include <libexif/exif-byte-order.h> +#include <libexif/exif-mnote-data.h> +#include <libexif/exif-mnote-data-priv.h> +#include <libexif/exif-mem.h> +#include <libexif/exif-data.h> + +typedef struct _ExifMnoteDataCanon ExifMnoteDataCanon; + +#include <libexif/canon/mnote-canon-entry.h> + +struct _ExifMnoteDataCanon { + ExifMnoteData parent; + + MnoteCanonEntry *entries; + unsigned int count; + + ExifByteOrder order; + unsigned int offset; + + ExifDataOption options; +}; + +/*! Detect if MakerNote is recognized as one handled by the Canon module. + * + * \param[in] ed image #ExifData to identify as as a Canon type + * \param[in] e #ExifEntry for EXIF_TAG_MAKER_NOTE, from within ed but + * duplicated here for convenience + * \return 0 if not recognized, nonzero if recognized. The specific nonzero + * value returned may identify a subtype unique within this module. + */ +int exif_mnote_data_canon_identify (const ExifData *ed, const ExifEntry *e); + +ExifMnoteData *exif_mnote_data_canon_new (ExifMem *mem, ExifDataOption o); + +#endif /* __EXIF_MNOTE_DATA_CANON_H__ */ diff --git a/libexif/canon/mnote-canon-entry.c b/libexif/canon/mnote-canon-entry.c new file mode 100644 index 0000000..b92f69c --- /dev/null +++ b/libexif/canon/mnote-canon-entry.c @@ -0,0 +1,762 @@ +/* mnote-canon-entry.c + * + * Copyright (c) 2002 Lutz Mueller <lutz@users.sourceforge.net> + * Copyright (c) 2003 Matthieu Castet <mat-c@users.sourceforge.net> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA. + */ + +#include "config.h" +#include "mnote-canon-entry.h" + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <math.h> + +#include <libexif/exif-format.h> +#include <libexif/exif-utils.h> +#include <libexif/i18n.h> + +/* #define DEBUG */ + +#define CF(format,target,v,maxlen) \ +{ \ + if (format != target) { \ + snprintf (v, maxlen, \ + _("Invalid format '%s', " \ + "expected '%s'."), \ + exif_format_get_name (format), \ + exif_format_get_name (target)); \ + break; \ + } \ +} + +#define CC(number,target,v,maxlen) \ +{ \ + if (number != target) { \ + snprintf (v, maxlen, \ + _("Invalid number of components (%i, " \ + "expected %i)."), (int) number, (int) target); \ + break; \ + } \ +} +#define CC2(number,t1,t2,v,maxlen) \ +{ \ + if ((number != t1) && (number != t2)) { \ + snprintf (v, maxlen, \ + _("Invalid number of components (%i, " \ + "expected %i or %i)."), (int) number, \ + (int) t1, (int) t2); \ + break; \ + } \ +} + +#define UNDEFINED 0xFF + +static const struct canon_entry_table_t { + unsigned int subtag; + ExifShort value; + const char *name; +} entries_settings_1 [] = { +#ifndef NO_VERBOSE_TAG_DATA + { 0, 1, N_("Macro")}, + { 0, 2, N_("Normal")}, + { 2, 1, N_("Economy")}, + { 2, 2, N_("Normal")}, + { 2, 3, N_("Fine")}, + { 2, 4, N_("RAW")}, + { 2, 5, N_("Superfine")}, + { 3, 0, N_("Off")}, + { 3, 1, N_("Auto")}, + { 3, 2, N_("On")}, + { 3, 3, N_("Red-eye reduction")}, + { 3, 4, N_("Slow synchro")}, + { 3, 5, N_("Auto, red-eye reduction")}, + { 3, 6, N_("On, red-eye reduction")}, + { 3, 16, N_("External flash")}, + { 4, 0, N_("Single")}, + { 4, 1, N_("Continuous")}, + { 4, 2, N_("Movie")}, + { 4, 3, N_("Continuous, speed priority")}, + { 4, 4, N_("Continuous, low")}, + { 4, 5, N_("Continuous, high")}, + { 6, 0, N_("One-shot AF")}, + { 6, 1, N_("AI servo AF")}, + { 6, 2, N_("AI focus AF")}, + { 6, 3, N_("Manual focus")}, + { 6, 4, N_("Single")}, + { 6, 5, N_("Continuous")}, + { 6, 6, N_("Manual focus")}, + { 6, 16, N_("Pan focus")}, + { 8, 1, N_("JPEG")}, + { 8, 2, N_("CRW+THM")}, + { 8, 3, N_("AVI+THM")}, + { 8, 4, N_("TIF")}, + { 8, 5, N_("TIF+JPEG")}, + { 8, 6, N_("CR2")}, + { 8, 7, N_("CR2+JPEG")}, + { 9, 0, N_("Large")}, + { 9, 1, N_("Medium")}, + { 9, 2, N_("Small")}, + { 9, 5, N_("Medium 1")}, + { 9, 6, N_("Medium 2")}, + { 9, 7, N_("Medium 3")}, + { 9, 8, N_("Postcard")}, + { 9, 9, N_("Widescreen")}, + {10, 0, N_("Full auto")}, + {10, 1, N_("Manual")}, + {10, 2, N_("Landscape")}, + {10, 3, N_("Fast shutter")}, + {10, 4, N_("Slow shutter")}, + {10, 5, N_("Night")}, + {10, 6, N_("Grayscale")}, + {10, 7, N_("Sepia")}, + {10, 8, N_("Portrait")}, + {10, 9, N_("Sports")}, + {10, 10, N_("Macro")}, + {10, 11, N_("Black & white")}, + {10, 12, N_("Pan focus")}, + {10, 13, N_("Vivid")}, + {10, 14, N_("Neutral")}, + {10, 15, N_("Flash off")}, + {10, 16, N_("Long shutter")}, + {10, 17, N_("Super macro")}, + {10, 18, N_("Foliage")}, + {10, 19, N_("Indoor")}, + {10, 20, N_("Fireworks")}, + {10, 21, N_("Beach")}, + {10, 22, N_("Underwater")}, + {10, 23, N_("Snow")}, + {10, 24, N_("Kids & pets")}, + {10, 25, N_("Night snapshot")}, + {10, 26, N_("Digital macro")}, + {10, 27, N_("My colors")}, + {10, 28, N_("Still image")}, + {10, 30, N_("Color accent")}, + {10, 31, N_("Color swap")}, + {10, 32, N_("Aquarium")}, + {10, 33, N_("ISO 3200")}, + {11, 0, N_("None")}, + {11, 1, N_("2x")}, + {11, 2, N_("4x")}, + {11, 3, N_("Other")}, + {12, 0x0000, N_("Normal")}, + {12, 0x0001, N_("High")}, + {12, 0xffff, N_("Low")}, + {13, 0x0000, N_("Normal")}, + {13, 0x0001, N_("High")}, + {13, 0xffff, N_("Low")}, + {14, 0x0000, N_("Normal")}, + {14, 0x0001, N_("High")}, + {14, 0xffff, N_("Low")}, + {15, 14, N_("Auto high")}, + {15, 15, N_("Auto")}, + {15, 16, N_("50")}, + {15, 17, N_("100")}, + {15, 18, N_("200")}, + {15, 19, N_("400")}, + {15, 20, N_("800")}, + {16, 0, N_("Default")}, + {16, 1, N_("Spot")}, + {16, 2, N_("Average")}, + {16, 3, N_("Evaluative")}, + {16, 4, N_("Partial")}, + {16, 5, N_("Center-weighted average")}, + {17, 0, N_("Manual")}, + {17, 1, N_("Auto")}, + {17, 2, N_("Not known")}, + {17, 3, N_("Macro")}, + {17, 4, N_("Very close")}, + {17, 5, N_("Close")}, + {17, 6, N_("Middle range")}, + {17, 7, N_("Far range")}, + {17, 8, N_("Pan focus")}, + {17, 9, N_("Super macro")}, + {17, 10, N_("Infinity")}, + {18, 0x2005, N_("Manual AF point selection")}, + {18, 0x3000, N_("None (MF)")}, + {18, 0x3001, N_("Auto-selected")}, + {18, 0x3002, N_("Right")}, + {18, 0x3003, N_("Center")}, + {18, 0x3004, N_("Left")}, + {18, 0x4001, N_("Auto AF point selection")}, + {19, 0, N_("Easy shooting")}, + {19, 1, N_("Program")}, + {19, 2, N_("Tv-priority")}, + {19, 3, N_("Av-priority")}, + {19, 4, N_("Manual")}, + {19, 5, N_("A-DEP")}, + {19, 6, N_("M-DEP")}, + {21, 1, N_("Canon EF 50mm f/1.8")}, + {21, 2, N_("Canon EF 28mm f/2.8")}, + {21, 4, N_("Sigma UC Zoom 35-135mm f/4-5.6")}, + {21, 6, N_("Tokina AF193-2 19-35mm f/3.5-4.5")}, + {21, 7, N_("Canon EF 100-300mm F5.6L")}, + {21, 10, N_("Sigma 50mm f/2.8 EX or 28mm f/1.8")}, + {21, 11, N_("Canon EF 35mm f/2")}, + {21, 13, N_("Canon EF 15mm f/2.8")}, + {21, 21, N_("Canon EF 80-200mm f/2.8L")}, + {21, 22, N_("Tokina AT-X280AF PRO 28-80mm F2.8 Aspherical")}, + {21, 26, N_("Cosina 100mm f/3.5 Macro AF")}, + {21, 28, N_("Tamron AF Aspherical 28-200mm f/3.8-5.6")}, + {21, 29, N_("Canon EF 50mm f/1.8 MkII")}, + {21, 31, N_("Tamron SP AF 300mm f/2.8 LD IF")}, + {21, 32, N_("Canon EF 24mm f/2.8 or Sigma 15mm f/2.8 EX Fisheye")}, + {21, 37, N_("Canon EF 35-80mm f/4-5.6")}, + {21, 39, N_("Canon EF 75-300mm f/4-5.6")}, + {21, 40, N_("Canon EF 28-80mm f/3.5-5.6")}, + {21, 43, N_("Canon EF 28-105mm f/4-5.6")}, + {21, 45, N_("Canon EF-S 18-55mm f/3.5-5.6")}, + {21, 52, N_("Canon EF-S 18-55mm f/3.5-5.6 IS II")}, + {21, 124, N_("Canon MP-E 65mm f/2.8 1-5x Macro Photo")}, + {21, 125, N_("Canon TS-E 24mm f/3.5L")}, + {21, 126, N_("Canon TS-E 45mm f/2.8")}, + {21, 127, N_("Canon TS-E 90mm f/2.8")}, + {21, 130, N_("Canon EF 50mm f/1.0L")}, + {21, 131, N_("Sigma 17-35mm f2.8-4 EX Aspherical HSM")}, + {21, 134, N_("Canon EF 600mm f/4L IS")}, + {21, 135, N_("Canon EF 200mm f/1.8L")}, + {21, 136, N_("Canon EF 300mm f/2.8L")}, + {21, 137, N_("Canon EF 85mm f/1.2L")}, + {21, 139, N_("Canon EF 400mm f/2.8L")}, + {21, 141, N_("Canon EF 500mm f/4.5L")}, + {21, 142, N_("Canon EF 300mm f/2.8L IS")}, + {21, 143, N_("Canon EF 500mm f/4L IS")}, + {21, 149, N_("Canon EF 100mm f/2")}, + {21, 150, N_("Sigma 20mm EX f/1.8")}, + {21, 151, N_("Canon EF 200mm f/2.8L")}, + {21, 152, N_("Sigma 10-20mm F4-5.6 or 12-24mm f/4.5-5.6 or 14mm f/2.8")}, + {21, 153, N_("Canon EF 35-350mm f/3.5-5.6L")}, + {21, 155, N_("Canon EF 85mm f/1.8 USM")}, + {21, 156, N_("Canon EF 28-105mm f/3.5-4.5 USM")}, + {21, 160, N_("Canon EF 20-35mm f/3.5-4.5 USM")}, + {21, 161, N_("Canon EF 28-70mm f/2.8L or Sigma 24-70mm EX f/2.8")}, + {21, 165, N_("Canon EF 70-200mm f/2.8 L")}, + {21, 166, N_("Canon EF 70-200mm f/2.8 L + x1.4")}, + {21, 167, N_("Canon EF 70-200mm f/2.8 L + x2")}, + {21, 168, N_("Canon EF 28mm f/1.8 USM")}, + {21, 169, N_("Sigma 15-30mm f/3.5-4.5 EX DG Aspherical")}, + {21, 170, N_("Canon EF 200mm f/2.8L II")}, + {21, 173, N_("Canon EF 180mm Macro f/3.5L or Sigma 180mm EX HSM Macro f/3.5")}, + {21, 174, N_("Canon EF 135mm f/2L")}, + {21, 176, N_("Canon EF 24-85mm f/3.5-4.5 USM")}, + {21, 177, N_("Canon EF 300mm f/4L IS")}, + {21, 178, N_("Canon EF 28-135mm f/3.5-5.6 IS")}, + {21, 180, N_("Canon EF 35mm f/1.4L")}, + {21, 181, N_("Canon EF 100-400mm f/4.5-5.6L IS + x1.4")}, + {21, 182, N_("Canon EF 100-400mm f/4.5-5.6L IS + x2")}, + {21, 183, N_("Canon EF 100-400mm f/4.5-5.6L IS")}, + {21, 184, N_("Canon EF 400mm f/2.8L + x2")}, + {21, 186, N_("Canon EF 70-200mm f/4L")}, + {21, 190, N_("Canon EF 100mm f/2.8 Macro")}, + {21, 191, N_("Canon EF 400mm f/4 DO IS")}, + {21, 197, N_("Canon EF 75-300mm f/4-5.6 IS")}, + {21, 198, N_("Canon EF 50mm f/1.4")}, + {21, 202, N_("Canon EF 28-80 f/3.5-5.6 USM IV")}, + {21, 211, N_("Canon EF 28-200mm f/3.5-5.6")}, + {21, 213, N_("Canon EF 90-300mm f/4.5-5.6")}, + {21, 214, N_("Canon EF-S 18-55mm f/3.5-4.5 USM")}, + {21, 224, N_("Canon EF 70-200mm f/2.8L IS USM")}, + {21, 225, N_("Canon EF 70-200mm f/2.8L IS USM + x1.4")}, + {21, 226, N_("Canon EF 70-200mm f/2.8L IS USM + x2")}, + {21, 229, N_("Canon EF 16-35mm f/2.8L")}, + {21, 230, N_("Canon EF 24-70mm f/2.8L")}, + {21, 231, N_("Canon EF 17-40mm f/4L")}, + {21, 232, N_("Canon EF 70-300mm f/4.5-5.6 DO IS USM")}, + {21, 234, N_("Canon EF-S 17-85mm f4-5.6 IS USM")}, + {21, 235, N_("Canon EF-S10-22mm F3.5-4.5 USM")}, + {21, 236, N_("Canon EF-S60mm F2.8 Macro USM")}, + {21, 237, N_("Canon EF 24-105mm f/4L IS")}, + {21, 238, N_("Canon EF 70-300mm F4-5.6 IS USM")}, + {21, 241, N_("Canon EF 50mm F1.2L USM")}, + {21, 242, N_("Canon EF 70-200mm f/4L IS USM")}, + {21, 251, N_("Canon EF 70-200mm f/2.8L IS II USM")}, + {28, 0, N_("Manual")}, + {28, 1, N_("TTL")}, + {28, 2, N_("A-TTL")}, + {28, 3, N_("E-TTL")}, + {28, 4, N_("FP sync enabled")}, + {28, 7, N_("2nd-curtain sync used")}, + {28, 11, N_("FP sync used")}, + {28, 13, N_("Internal")}, + {28, 14, N_("External")}, + {31, 0, N_("Single")}, + {31, 1, N_("Continuous")}, + {32, 0, N_("Normal AE")}, + {32, 1, N_("Exposure compensation")}, + {32, 2, N_("AE lock")}, + {32, 3, N_("AE lock + exposure compensation")}, + {32, 4, N_("No AE")}, + {33, 0, N_("Off")}, + {33, 1, N_("On")}, + {33, 2, N_("On, shot only")}, + {39, 0, N_("Off")}, + {39, 1, N_("Vivid")}, + {39, 2, N_("Neutral")}, + {39, 3, N_("Smooth")}, + {39, 4, N_("Sepia")}, + {39, 5, N_("Black & white")}, + {39, 6, N_("Custom")}, + {39, 100, N_("My color data")}, + {40, 0, N_("Off")}, + {40, 0x0500, N_("Full")}, + {40, 0x0502, N_("2/3")}, + {40, 0x0504, N_("1/3")}, +#endif + { 0, 0, NULL} +}, +entries_focal_length [] = { +#ifndef NO_VERBOSE_TAG_DATA + {0, 1, N_("Fixed")}, + {0, 2, N_("Zoom")}, +#endif + {0, 0, NULL} +}, +entries_settings_2 [] = { +#ifndef NO_VERBOSE_TAG_DATA + { 6, 0, N_("Auto")}, + { 6, 1, N_("Sunny")}, + { 6, 2, N_("Cloudy")}, + { 6, 3, N_("Tungsten")}, + { 6, 4, N_("Fluorescent")}, + { 6, 5, N_("Flash")}, + { 6, 6, N_("Custom")}, + { 6, 7, N_("Black & white")}, + { 6, 8, N_("Shade")}, + { 6, 9, N_("Manual temperature (Kelvin)")}, + { 6, 10, N_("PC set 1")}, + { 6, 11, N_("PC set 2")}, + { 6, 12, N_("PC set 3")}, + { 6, 14, N_("Daylight fluorescent")}, + { 6, 15, N_("Custom 1")}, + { 6, 16, N_("Custom 2")}, + { 6, 17, N_("Underwater")}, + { 7, 0, N_("Off")}, + { 7, 1, N_("Night scene")}, + { 7, 2, N_("On")}, + { 7, 3, N_("None")}, + { 13, 0x3000, N_("None (MF)")}, + { 13, 0x3001, N_("Right")}, + { 13, 0x3002, N_("Center")}, + { 13, 0x3003, N_("Center-right")}, + { 13, 0x3004, N_("Left")}, + { 13, 0x3005, N_("Left-right")}, + { 13, 0x3006, N_("Left-center")}, + { 13, 0x3007, N_("All")}, + { 15, 0, N_("Off")}, + { 15, 1, N_("On (shot 1)")}, + { 15, 2, N_("On (shot 2)")}, + { 15, 3, N_("On (shot 3)")}, + { 15, 0xffff, N_("On")}, + { 25, 248, N_("EOS high-end")}, + { 25, 250, N_("Compact")}, + { 25, 252, N_("EOS mid-range")}, + { 26, 0, N_("None")}, + { 26, 1, N_("Rotate 90 CW")}, + { 26, 2, N_("Rotate 180")}, + { 26, 3, N_("Rotate 270 CW")}, + { 26, 0xffff, N_("Rotated by software")}, + { 27, 0, N_("Off")}, + { 27, 1, N_("On")}, + { 32, 0, N_("Off")}, + { 32, 0x0014, N_("1/3")}, + { 32, 0x008c, N_("2/3")}, + { 32, 0x07d0, N_("Full")}, +#endif + {0, 0, NULL} +}, +entries_panorama [] = { +#ifndef NO_VERBOSE_TAG_DATA + {0, 0, N_("Left to right")}, + {0, 1, N_("Right to left")}, + {0, 2, N_("Bottom to top")}, + {0, 3, N_("Top to bottom")}, + {0, 4, N_("2x2 matrix (clockwise)")}, +#endif + {0, 0, NULL} +}, +color_information [] = { +#ifndef NO_VERBOSE_TAG_DATA + {0, 0, N_("Standard")}, + {0, 1, N_("Manual")}, + {0, 2, N_("Custom")}, + {2, 0, N_("N/A")}, + {2, 1, N_("Lowest")}, + {2, 2, N_("Low")}, + {2, 3, N_("Standard")}, + {2, 4, N_("High")}, + {2, 5, N_("Highest")}, + {7, 0, N_("Auto")}, + {7, 1, N_("Daylight")}, + {7, 2, N_("Cloudy")}, + {7, 3, N_("Tungsten")}, + {7, 4, N_("Fluorescent")}, + {7, 5, N_("Flash")}, + {7, 6, N_("Custom")}, + {7, 7, N_("Black & white")}, + {7, 8, N_("Shade")}, + {7, 9, N_("Manual temperature (Kelvin)")}, + {7, 10, N_("PC set 1")}, + {7, 11, N_("PC set 2")}, + {7, 12, N_("PC set 3")}, + {7, 14, N_("Daylight fluorescent")}, + {7, 15, N_("Custom 1")}, + {7, 16, N_("Custom 2")}, + {7, 17, N_("Underwater")}, + {9, 0x00, N_("None")}, + {9, 0x01, N_("Standard")}, + {9, 0x02, N_("Set 1")}, + {9, 0x03, N_("Set 2")}, + {9, 0x04, N_("Set 3")}, + {9, 0x21, N_("User def. 1")}, + {9, 0x22, N_("User def. 2")}, + {9, 0x23, N_("User def. 3")}, + {9, 0x41, N_("External 1")}, + {9, 0x42, N_("External 2")}, + {9, 0x43, N_("External 3")}, + {9, 0x81, N_("Standard")}, + {9, 0x82, N_("Portrait")}, + {9, 0x83, N_("Landscape")}, + {9, 0x84, N_("Neutral")}, + {9, 0x85, N_("Faithful")}, + {9, 0x86, N_("Monochrome")}, +#endif + {0, 0, NULL} +}; + +static void +canon_search_table_value (const struct canon_entry_table_t table[], + unsigned int t, ExifShort vs, char *val, unsigned int maxlen) +{ + unsigned int j; + + /* Search the table for the first matching subtag and value. */ + for (j = 0; table[j].name && ((table[j].subtag < t) || + ((table[j].subtag == t) && table[j].value <= vs)); j++) { + if ((table[j].subtag == t) && (table[j].value == vs)) { + break; + } + } + if ((table[j].subtag == t) && (table[j].value == vs) && table[j].name) { + /* Matching subtag and value found. */ + strncpy (val, _(table[j].name), maxlen); + } else { + /* No matching subtag and/or value found. */ + snprintf (val, maxlen, "0x%04x", vs); + } +} + +static void +canon_search_table_bitfield (const struct canon_entry_table_t table[], + unsigned int t, ExifShort vs, char *val, unsigned int maxlen) +{ + unsigned int j; + + /* Search the table for the first matching subtag. */ + for (j = 0; table[j].name && (table[j].subtag <= t); j++) { + if (table[j].subtag == t) { + break; + } + } + if ((table[j].subtag == t) && table[j].name) { + unsigned int i, bit, lastbit = 0; + + /* + * Search the table for the last matching bit, because + * that one needs no additional comma appended. + */ + for (i = j; table[i].name && (table[i].subtag == t); i++) { + bit = table[i].value; + if ((vs >> bit) & 1) { + lastbit = bit; + } + } + /* Search the table for all matching bits. */ + for (i = j; table[i].name && (table[i].subtag == t); i++) { + bit = table[i].value; + if ((vs >> bit) & 1) { + strncat(val, _(table[i].name), maxlen - strlen (val)); + if (bit != lastbit) + strncat (val, _(", "), maxlen - strlen (val)); + } + } + } else { + /* No matching subtag found. */ + snprintf (val, maxlen, "0x%04x", vs); + } +} + +unsigned int +mnote_canon_entry_count_values (const MnoteCanonEntry *entry) +{ + unsigned int val; + + if (!entry) return 0; + + switch (entry->tag) { + case MNOTE_CANON_TAG_FOCAL_LENGTH: + case MNOTE_CANON_TAG_PANORAMA: + return entry->components; + case MNOTE_CANON_TAG_SETTINGS_1: + case MNOTE_CANON_TAG_SETTINGS_2: + case MNOTE_CANON_TAG_CUSTOM_FUNCS: + case MNOTE_CANON_TAG_COLOR_INFORMATION: + if (entry->format != EXIF_FORMAT_SHORT) return 0; + + val = exif_get_short (entry->data, entry->order); + /* val is buffer size, i.e. # of values plus 1 */ + return MIN (entry->size - 2, val) / 2; + default: + return 1; + } +} + +/* + * For reference, see Exif 2.1 specification (Appendix C), + * or http://en.wikipedia.org/wiki/APEX_system + */ +static double +apex_value_to_aperture (double x) +{ + return pow (2, x / 2.); +} + +static double +apex_value_to_shutter_speed(double x) +{ + return 1.0 / pow (2, x); +} + +static double +apex_value_to_iso_speed (double x) +{ + return 3.125 * pow (2, x); +} + +char * +mnote_canon_entry_get_value (const MnoteCanonEntry *entry, unsigned int t, char *val, unsigned int maxlen) +{ + char buf[128]; + ExifLong vl; + ExifShort vs, n; + unsigned char *data; + double d; + + if (!entry) + return NULL; + + data = entry->data; + + memset (val, 0, maxlen); + maxlen--; + + switch (entry->tag) { + case MNOTE_CANON_TAG_SETTINGS_1: + CF (entry->format, EXIF_FORMAT_SHORT, val, maxlen); + n = exif_get_short (data, entry->order) / 2; + if (t >= n) return NULL; + CC (entry->components, n, val, maxlen); + vs = exif_get_short (data + 2 + t * 2, entry->order); + switch (t) { + case 1: + if (!vs) { + strncpy(val, _("Off"), maxlen); + break; + } + snprintf (val, maxlen, _("%i (ms)"), vs * 100); + break; + case 15: + if (((vs & 0xC000) == 0x4000) && (vs != 0x7FFF)) { + /* Canon S3 IS - directly specified value */ + snprintf (val, maxlen, "%i", vs & ~0x4000); + } else { + /* Standard Canon - index into lookup table */ + canon_search_table_value (entries_settings_1, t, vs, val, maxlen); + } + break; + case 22: + case 23: + case 24: + snprintf (val, maxlen, "%u", vs); + break; + case 25: + case 26: + snprintf (val, maxlen, "%.2f", apex_value_to_aperture (vs / 32.0)); + break; + case 28: + canon_search_table_bitfield(entries_settings_1, t, vs, val, maxlen); + break; + case 34: + snprintf (val, maxlen, "%.2f", vs / 10.0); + break; + case 35: + case 36: + snprintf (val, maxlen, "%u", vs); + break; + default: + canon_search_table_value (entries_settings_1, t, vs, val, maxlen); + } + break; + + case MNOTE_CANON_TAG_FOCAL_LENGTH: + CF (entry->format, EXIF_FORMAT_SHORT, val, maxlen); + vs = exif_get_short (data + t * 2, entry->order); + switch (t) { + case 1: + snprintf (val, maxlen, "%u", vs); + break; + case 2: + case 3: + snprintf (val, maxlen, _("%.2f mm"), vs * 25.4 / 1000); + break; + default: + canon_search_table_value (entries_focal_length, t, vs, val, maxlen); + } + break; + + case MNOTE_CANON_TAG_SETTINGS_2: + CF (entry->format, EXIF_FORMAT_SHORT, val, maxlen); + n = exif_get_short (data, entry->order) / 2; + if (t >= n) return NULL; + CC (entry->components, n, val, maxlen); + vs = exif_get_short (data + 2 + t * 2, entry->order); + switch (t) { + case 0: + snprintf (val, maxlen, "%.3f", pow (2, (ExifSShort)vs / 32.0)); + break; + case 1: + snprintf (val, maxlen, "%.0f", apex_value_to_iso_speed ((ExifSShort)vs / 32.0)); + break; + case 2: + case 5: + case 14: + case 16: + snprintf (val, maxlen, _("%.2f EV"), (ExifSShort)vs / 32.0); + break; + case 3: + case 20: + snprintf (val, maxlen, "%.2f", apex_value_to_aperture (vs / 32.0)); + break; + case 4: + case 21: + d = apex_value_to_shutter_speed ((ExifSShort)vs / 32.0); + if (d < 1) + snprintf (val, maxlen, _("1/%i"),(int)(1.0 / d)); + else + snprintf (val, maxlen, "%i", (int) d); + break; + case 8: + snprintf (val, maxlen, "%u", vs); + break; + case 12: + snprintf (val, maxlen, "%.2f", vs / 32.0); + break; + case 18: + case 19: + snprintf (val, maxlen, _("%u mm"), vs); + break; + case 28: + if ((ExifSShort)vs <= 0) { + strncpy(val, _("Off"), maxlen); + break; + } + snprintf (val, maxlen, _("%i (ms)"), vs * 100); + break; + default: + canon_search_table_value (entries_settings_2, t, vs, val, maxlen); + } + break; + + case MNOTE_CANON_TAG_PANORAMA: + CF (entry->format, EXIF_FORMAT_SHORT, val, maxlen); + vs = exif_get_short (data + t * 2, entry->order); + canon_search_table_value (entries_panorama, t, vs, val, maxlen); + break; + + case MNOTE_CANON_TAG_OWNER: + CC (entry->components, 32, val, maxlen); + /* Fall through; ImageType can have many sizes */ + case MNOTE_CANON_TAG_IMAGE_TYPE: + CF (entry->format, EXIF_FORMAT_ASCII, val, maxlen); + strncpy (val, (char *)data, MIN (entry->size, maxlen)); + break; + + case MNOTE_CANON_TAG_FIRMWARE: + CF (entry->format, EXIF_FORMAT_ASCII, val, maxlen); +/* CC2 (entry->components, 24, 32, val, maxlen); Can also be 22 */ + strncpy (val, (char *)data, MIN (entry->size, maxlen)); + break; + + case MNOTE_CANON_TAG_IMAGE_NUMBER: + CF (entry->format, EXIF_FORMAT_LONG, val, maxlen); + CC (entry->components, 1, val, maxlen); + vl = exif_get_long (data, entry->order); + snprintf (val, maxlen, "%03lu-%04lu", + (unsigned long) vl/10000, + (unsigned long) vl%10000); + break; + + case MNOTE_CANON_TAG_SERIAL_NUMBER: + CF (entry->format, EXIF_FORMAT_LONG, val, maxlen); + CC (entry->components, 1, val, maxlen); + vl = exif_get_long (data, entry->order); + snprintf (val, maxlen, "%04X-%05d", (int)vl>>16,(int)vl&0xffff); + break; + + case MNOTE_CANON_TAG_CUSTOM_FUNCS: + CF (entry->format, EXIF_FORMAT_SHORT, val, maxlen); + n = exif_get_short (data, entry->order) / 2; + if (t >= n) return NULL; + CC (entry->components, n, val, maxlen); + vs = exif_get_short (data + 2 + t * 2, entry->order); + snprintf (buf, sizeof (buf), "%u", vs); + strncat (val, buf, maxlen - strlen (val)); + break; + + case MNOTE_CANON_TAG_COLOR_INFORMATION: + CF (entry->format, EXIF_FORMAT_SHORT, val, maxlen); + n = exif_get_short (data, entry->order) / 2; + if (t >= n) return NULL; + CC (entry->components, n, val, maxlen); + vs = exif_get_short (data + 2 + t * 2, entry->order); + canon_search_table_value (color_information, t, vs, val, maxlen); + break; + + default: +#ifdef DEBUG + { + int i; + if (entry->format == EXIF_FORMAT_SHORT) + for(i=0;i<entry->components;i++) { + vs = exif_get_short (data, entry->order); + data+=2; + printf ("Value%d=%d\n", i, vs); + } + else if (entry->format == EXIF_FORMAT_LONG) + for(i=0;i<entry->components;i++) { + vl = exif_get_long (data, entry->order); + data+=4; + printf ("Value%d=%d\n", i, vs); + } + else if (entry->format == EXIF_FORMAT_ASCII) + strncpy (val, data, MIN (entry->size, maxlen)); + } +#endif + break; + } + return val; +} diff --git a/libexif/canon/mnote-canon-entry.h b/libexif/canon/mnote-canon-entry.h new file mode 100644 index 0000000..a4d4499 --- /dev/null +++ b/libexif/canon/mnote-canon-entry.h @@ -0,0 +1,44 @@ +/* mnote-canon-entry.h + * + * Copyright (c) 2002 Lutz Mueller <lutz@users.sourceforge.net> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA. + */ + +#ifndef __MNOTE_CANON_ENTRY_H__ +#define __MNOTE_CANON_ENTRY_H__ + +#include <libexif/exif-format.h> +#include <libexif/exif-byte-order.h> +#include <libexif/canon/mnote-canon-tag.h> + +typedef struct _MnoteCanonEntry MnoteCanonEntry; + +struct _MnoteCanonEntry { + MnoteCanonTag tag; + ExifFormat format; + unsigned long components; + + unsigned char *data; + unsigned int size; + + ExifByteOrder order; +}; + +unsigned int mnote_canon_entry_count_values (const MnoteCanonEntry *); +char *mnote_canon_entry_get_value (const MnoteCanonEntry *, unsigned int t, char *val, unsigned int maxlen); + +#endif /* __MNOTE_CANON_ENTRY_H__ */ diff --git a/libexif/canon/mnote-canon-tag.c b/libexif/canon/mnote-canon-tag.c new file mode 100644 index 0000000..3cacfa6 --- /dev/null +++ b/libexif/canon/mnote-canon-tag.c @@ -0,0 +1,201 @@ +/* mnote-canon-tag.c + * + * Copyright (c) 2002 Lutz Mueller <lutz@users.sourceforge.net> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA. + */ + +#include <config.h> +#include "mnote-canon-tag.h" + +#include <stdlib.h> + +#include <libexif/i18n.h> + +static const struct { + MnoteCanonTag tag; + const char *name; + const char *title; + const char *description; +} table[] = { +#ifndef NO_VERBOSE_TAG_STRINGS + {MNOTE_CANON_TAG_SETTINGS_1, "Settings1", N_("Settings (First Part)"), ""}, + {MNOTE_CANON_TAG_FOCAL_LENGTH, "FocalLength", N_("Focal Length"), ""}, + {MNOTE_CANON_TAG_SETTINGS_2, "Settings2", N_("Settings (Second Part)"), ""}, + {MNOTE_CANON_TAG_PANORAMA, "Panorama", N_("Panorama"), ""}, + {MNOTE_CANON_TAG_IMAGE_TYPE, "ImageType", N_("Image Type"), ""}, + {MNOTE_CANON_TAG_FIRMWARE, "FirmwareVersion", N_("Firmware Version"), ""}, + {MNOTE_CANON_TAG_IMAGE_NUMBER, "ImageNumber", N_("Image Number"), ""}, + {MNOTE_CANON_TAG_OWNER, "OwnerName", N_("Owner Name"), ""}, + {MNOTE_CANON_TAG_COLOR_INFORMATION, "ColorInformation", N_("Color Information"), ""}, + {MNOTE_CANON_TAG_SERIAL_NUMBER, "SerialNumber", N_("Serial Number"), ""}, + {MNOTE_CANON_TAG_CUSTOM_FUNCS, "CustomFunctions", N_("Custom Functions"), ""}, +#endif + {0, NULL, NULL, NULL} +}; + +static const struct { + MnoteCanonTag tag; + unsigned int subtag; + const char *name; +} table_sub[] = { +#ifndef NO_VERBOSE_TAG_STRINGS + {MNOTE_CANON_TAG_SETTINGS_1, 0, N_("Macro Mode")}, + {MNOTE_CANON_TAG_SETTINGS_1, 1, N_("Self-timer")}, + {MNOTE_CANON_TAG_SETTINGS_1, 2, N_("Quality")}, + {MNOTE_CANON_TAG_SETTINGS_1, 3, N_("Flash Mode")}, + {MNOTE_CANON_TAG_SETTINGS_1, 4, N_("Drive Mode")}, + {MNOTE_CANON_TAG_SETTINGS_1, 6, N_("Focus Mode")}, + {MNOTE_CANON_TAG_SETTINGS_1, 8, N_("Record Mode")}, + {MNOTE_CANON_TAG_SETTINGS_1, 9, N_("Image Size")}, + {MNOTE_CANON_TAG_SETTINGS_1, 10, N_("Easy Shooting Mode")}, + {MNOTE_CANON_TAG_SETTINGS_1, 11, N_("Digital Zoom")}, + {MNOTE_CANON_TAG_SETTINGS_1, 12, N_("Contrast")}, + {MNOTE_CANON_TAG_SETTINGS_1, 13, N_("Saturation")}, + {MNOTE_CANON_TAG_SETTINGS_1, 14, N_("Sharpness")}, + {MNOTE_CANON_TAG_SETTINGS_1, 15, N_("ISO")}, + {MNOTE_CANON_TAG_SETTINGS_1, 16, N_("Metering Mode")}, + {MNOTE_CANON_TAG_SETTINGS_1, 17, N_("Focus Range")}, + {MNOTE_CANON_TAG_SETTINGS_1, 18, N_("AF Point")}, + {MNOTE_CANON_TAG_SETTINGS_1, 19, N_("Exposure Mode")}, + {MNOTE_CANON_TAG_SETTINGS_1, 21, N_("Lens Type")}, + {MNOTE_CANON_TAG_SETTINGS_1, 22, N_("Long Focal Length of Lens")}, + {MNOTE_CANON_TAG_SETTINGS_1, 23, N_("Short Focal Length of Lens")}, + {MNOTE_CANON_TAG_SETTINGS_1, 24, N_("Focal Units per mm")}, + {MNOTE_CANON_TAG_SETTINGS_1, 25, N_("Maximal Aperture")}, + {MNOTE_CANON_TAG_SETTINGS_1, 26, N_("Minimal Aperture")}, + {MNOTE_CANON_TAG_SETTINGS_1, 27, N_("Flash Activity")}, + {MNOTE_CANON_TAG_SETTINGS_1, 28, N_("Flash Details")}, + {MNOTE_CANON_TAG_SETTINGS_1, 31, N_("Focus Mode")}, + {MNOTE_CANON_TAG_SETTINGS_1, 32, N_("AE Setting")}, + {MNOTE_CANON_TAG_SETTINGS_1, 33, N_("Image Stabilization")}, + {MNOTE_CANON_TAG_SETTINGS_1, 34, N_("Display Aperture")}, + {MNOTE_CANON_TAG_SETTINGS_1, 35, N_("Zoom Source Width")}, + {MNOTE_CANON_TAG_SETTINGS_1, 36, N_("Zoom Target Width")}, + {MNOTE_CANON_TAG_SETTINGS_1, 39, N_("Photo Effect")}, + {MNOTE_CANON_TAG_SETTINGS_1, 40, N_("Manual Flash Output")}, + {MNOTE_CANON_TAG_SETTINGS_1, 41, N_("Color Tone")}, + {MNOTE_CANON_TAG_FOCAL_LENGTH, 0, N_("Focal Type")}, + {MNOTE_CANON_TAG_FOCAL_LENGTH, 1, N_("Focal Length")}, + {MNOTE_CANON_TAG_FOCAL_LENGTH, 2, N_("Focal Plane X Size")}, + {MNOTE_CANON_TAG_FOCAL_LENGTH, 3, N_("Focal Plane Y Size")}, + {MNOTE_CANON_TAG_SETTINGS_2, 0, N_("Auto ISO")}, + {MNOTE_CANON_TAG_SETTINGS_2, 1, N_("Shot ISO")}, + {MNOTE_CANON_TAG_SETTINGS_2, 2, N_("Measured EV")}, + {MNOTE_CANON_TAG_SETTINGS_2, 3, N_("Target Aperture")}, + {MNOTE_CANON_TAG_SETTINGS_2, 4, N_("Target Exposure Time")}, + {MNOTE_CANON_TAG_SETTINGS_2, 5, N_("Exposure Compensation")}, + {MNOTE_CANON_TAG_SETTINGS_2, 6, N_("White Balance")}, + {MNOTE_CANON_TAG_SETTINGS_2, 7, N_("Slow Shutter")}, + {MNOTE_CANON_TAG_SETTINGS_2, 8, N_("Sequence Number")}, + {MNOTE_CANON_TAG_SETTINGS_2, 12, N_("Flash Guide Number")}, + {MNOTE_CANON_TAG_SETTINGS_2, 13, N_("AF Point")}, + {MNOTE_CANON_TAG_SETTINGS_2, 14, N_("Flash Exposure Compensation")}, + {MNOTE_CANON_TAG_SETTINGS_2, 15, N_("AE Bracketing")}, + {MNOTE_CANON_TAG_SETTINGS_2, 16, N_("AE Bracket Value")}, + {MNOTE_CANON_TAG_SETTINGS_2, 18, N_("Focus Distance Upper")}, + {MNOTE_CANON_TAG_SETTINGS_2, 19, N_("Focus Distance Lower")}, + {MNOTE_CANON_TAG_SETTINGS_2, 20, N_("FNumber")}, + {MNOTE_CANON_TAG_SETTINGS_2, 21, N_("Exposure Time")}, + {MNOTE_CANON_TAG_SETTINGS_2, 23, N_("Bulb Duration")}, + {MNOTE_CANON_TAG_SETTINGS_2, 25, N_("Camera Type")}, + {MNOTE_CANON_TAG_SETTINGS_2, 26, N_("Auto Rotate")}, + {MNOTE_CANON_TAG_SETTINGS_2, 27, N_("ND Filter")}, + {MNOTE_CANON_TAG_SETTINGS_2, 28, N_("Self-timer")}, + {MNOTE_CANON_TAG_SETTINGS_2, 32, N_("Manual Flash Output")}, + {MNOTE_CANON_TAG_PANORAMA, 2, N_("Panorama Frame")}, + {MNOTE_CANON_TAG_PANORAMA, 5, N_("Panorama Direction")}, + {MNOTE_CANON_TAG_COLOR_INFORMATION, 0, N_("Tone Curve")}, + {MNOTE_CANON_TAG_COLOR_INFORMATION, 2, N_("Sharpness Frequency")}, + {MNOTE_CANON_TAG_COLOR_INFORMATION, 7, N_("White Balance")}, + {MNOTE_CANON_TAG_COLOR_INFORMATION, 9, N_("Picture Style")}, +#endif + {0, 0, NULL} +}; + +const char * +mnote_canon_tag_get_name (MnoteCanonTag t) +{ + unsigned int i; + + for (i = 0; i < sizeof (table) / sizeof (table[0]); i++) + if (table[i].tag == t) return table[i].name; /* do not translate */ + return NULL; +} + +const char * +mnote_canon_tag_get_name_sub (MnoteCanonTag t, unsigned int s, ExifDataOption o) +{ + unsigned int i; + int tag_found = 0; + + for (i = 0; i < sizeof (table_sub) / sizeof (table_sub[0]); i++) { + if (table_sub[i].tag == t) { + if (table_sub[i].subtag == s) + return table_sub[i].name; + tag_found = 1; + } + } + if (!tag_found || !(o & EXIF_DATA_OPTION_IGNORE_UNKNOWN_TAGS)) + return mnote_canon_tag_get_name (t); + else + return NULL; +} + +const char * +mnote_canon_tag_get_title (MnoteCanonTag t) +{ + unsigned int i; + + bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR); + for (i = 0; i < sizeof (table) / sizeof (table[0]); i++) + if (table[i].tag == t) return (_(table[i].title)); + return NULL; +} + +const char * +mnote_canon_tag_get_title_sub (MnoteCanonTag t, unsigned int s, ExifDataOption o) +{ + unsigned int i; + int tag_found = 0; + + for (i = 0; i < sizeof (table_sub) / sizeof (table_sub[0]); i++) { + if (table_sub[i].tag == t) { + if (table_sub[i].subtag == s) + return _(table_sub[i].name); + tag_found = 1; + } + } + if (!tag_found || !(o & EXIF_DATA_OPTION_IGNORE_UNKNOWN_TAGS)) + return mnote_canon_tag_get_title (t); + else + return NULL; +} + +const char * +mnote_canon_tag_get_description (MnoteCanonTag t) +{ + unsigned int i; + + for (i = 0; i < sizeof (table) / sizeof (table[0]); i++) + if (table[i].tag == t) { + if (!table[i].description || !*table[i].description) + return ""; + bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR); + return _(table[i].description); + } + return NULL; +} diff --git a/libexif/canon/mnote-canon-tag.h b/libexif/canon/mnote-canon-tag.h new file mode 100644 index 0000000..0c7d9aa --- /dev/null +++ b/libexif/canon/mnote-canon-tag.h @@ -0,0 +1,59 @@ +/* mnote-canon-tag.h + * + * Copyright (c) 2002 Lutz Mueller <lutz@users.sourceforge.net> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA. + */ + +#ifndef __MNOTE_CANON_TAG_H__ +#define __MNOTE_CANON_TAG_H__ + +#include <libexif/exif-data.h> + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +enum _MnoteCanonTag { + MNOTE_CANON_TAG_UNKNOWN_0 = 0x0, + MNOTE_CANON_TAG_SETTINGS_1 = 0x1, + MNOTE_CANON_TAG_FOCAL_LENGTH = 0x2, + MNOTE_CANON_TAG_UNKNOWN_3 = 0x3, + MNOTE_CANON_TAG_SETTINGS_2 = 0x4, + MNOTE_CANON_TAG_PANORAMA = 0x5, + MNOTE_CANON_TAG_IMAGE_TYPE = 0x6, + MNOTE_CANON_TAG_FIRMWARE = 0x7, + MNOTE_CANON_TAG_IMAGE_NUMBER = 0x8, + MNOTE_CANON_TAG_OWNER = 0x9, + MNOTE_CANON_TAG_UNKNOWN_10 = 0xa, + MNOTE_CANON_TAG_SERIAL_NUMBER = 0xc, + MNOTE_CANON_TAG_UNKNOWN_13 = 0xd, + MNOTE_CANON_TAG_CUSTOM_FUNCS = 0xf, + MNOTE_CANON_TAG_COLOR_INFORMATION = 0xa0 +}; +typedef enum _MnoteCanonTag MnoteCanonTag; + +const char *mnote_canon_tag_get_name (MnoteCanonTag); +const char *mnote_canon_tag_get_name_sub (MnoteCanonTag, unsigned int, ExifDataOption); +const char *mnote_canon_tag_get_title (MnoteCanonTag); +const char *mnote_canon_tag_get_title_sub (MnoteCanonTag, unsigned int, ExifDataOption); +const char *mnote_canon_tag_get_description (MnoteCanonTag); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __MNOTE_CANON_TAG_H__ */ diff --git a/libexif/exif-byte-order.c b/libexif/exif-byte-order.c new file mode 100644 index 0000000..05164e0 --- /dev/null +++ b/libexif/exif-byte-order.c @@ -0,0 +1,39 @@ +/* exif-byte-order.c + * + * Copyright (c) 2002 Lutz Mueller <lutz@users.sourceforge.net> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA. + */ + +#include <config.h> + +#include <libexif/exif-byte-order.h> +#include <libexif/i18n.h> + +#include <stdlib.h> + +const char * +exif_byte_order_get_name (ExifByteOrder order) +{ + switch (order) { + case EXIF_BYTE_ORDER_MOTOROLA: + return (_("Motorola")); + case EXIF_BYTE_ORDER_INTEL: + return (_("Intel")); + default: + return NULL; + } +} diff --git a/libexif/exif-byte-order.h b/libexif/exif-byte-order.h new file mode 100644 index 0000000..10ded49 --- /dev/null +++ b/libexif/exif-byte-order.h @@ -0,0 +1,48 @@ +/*! \file exif-byte-order.h + * \brief Defines the ExifByteOrder enum and the associated functions. + */ +/* + * Copyright (c) 2002 Lutz Mueller <lutz@users.sourceforge.net> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA. + */ + +#ifndef __EXIF_BYTE_ORDER_H__ +#define __EXIF_BYTE_ORDER_H__ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/*! Which byte order to use */ +typedef enum { + /*! Big-endian byte order */ + EXIF_BYTE_ORDER_MOTOROLA, + /*! Little-endian byte order */ + EXIF_BYTE_ORDER_INTEL +} ExifByteOrder; + +/*! Return a short, localized, textual name for the given byte order. + * \param[in] order byte order + * \return localized textual name of the byte order + */ +const char *exif_byte_order_get_name (ExifByteOrder order); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __EXIF_BYTE_ORDER_H__ */ diff --git a/libexif/exif-content.c b/libexif/exif-content.c new file mode 100644 index 0000000..6d6c589 --- /dev/null +++ b/libexif/exif-content.c @@ -0,0 +1,327 @@ +/* exif-content.c + * + * Copyright (c) 2001 Lutz Mueller <lutz@users.sourceforge.net> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA. + */ + +#include <config.h> + +#include <libexif/exif-content.h> +#include <libexif/exif-system.h> + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +/* unused constant + * static const unsigned char ExifHeader[] = {0x45, 0x78, 0x69, 0x66, 0x00, 0x00}; + */ + +struct _ExifContentPrivate +{ + unsigned int ref_count; + + ExifMem *mem; + ExifLog *log; +}; + +ExifContent * +exif_content_new (void) +{ + ExifMem *mem = exif_mem_new_default (); + ExifContent *content = exif_content_new_mem (mem); + + exif_mem_unref (mem); + + return content; +} + +ExifContent * +exif_content_new_mem (ExifMem *mem) +{ + ExifContent *content; + + if (!mem) return NULL; + + content = exif_mem_alloc (mem, (ExifLong) sizeof (ExifContent)); + if (!content) + return NULL; + content->priv = exif_mem_alloc (mem, + (ExifLong) sizeof (ExifContentPrivate)); + if (!content->priv) { + exif_mem_free (mem, content); + return NULL; + } + + content->priv->ref_count = 1; + + content->priv->mem = mem; + exif_mem_ref (mem); + + return content; +} + +void +exif_content_ref (ExifContent *content) +{ + content->priv->ref_count++; +} + +void +exif_content_unref (ExifContent *content) +{ + content->priv->ref_count--; + if (!content->priv->ref_count) + exif_content_free (content); +} + +void +exif_content_free (ExifContent *content) +{ + ExifMem *mem = (content && content->priv) ? content->priv->mem : NULL; + unsigned int i; + + if (!content) return; + + for (i = 0; i < content->count; i++) + exif_entry_unref (content->entries[i]); + exif_mem_free (mem, content->entries); + + if (content->priv) { + exif_log_unref (content->priv->log); + } + + exif_mem_free (mem, content->priv); + exif_mem_free (mem, content); + exif_mem_unref (mem); +} + +void +exif_content_dump (ExifContent *content, unsigned int indent) +{ + char buf[1024]; + unsigned int i; + + for (i = 0; i < 2 * indent; i++) + buf[i] = ' '; + buf[i] = '\0'; + + if (!content) + return; + + printf ("%sDumping exif content (%u entries)...\n", buf, + content->count); + for (i = 0; i < content->count; i++) + exif_entry_dump (content->entries[i], indent + 1); +} + +void +exif_content_add_entry (ExifContent *c, ExifEntry *entry) +{ + ExifEntry **entries; + if (!c || !c->priv || !entry || entry->parent) return; + + /* One tag can only be added once to an IFD. */ + if (exif_content_get_entry (c, entry->tag)) { + exif_log (c->priv->log, EXIF_LOG_CODE_DEBUG, "ExifContent", + "An attempt has been made to add " + "the tag '%s' twice to an IFD. This is against " + "specification.", exif_tag_get_name (entry->tag)); + return; + } + + entries = exif_mem_realloc (c->priv->mem, + c->entries, sizeof (ExifEntry*) * (c->count + 1)); + if (!entries) return; + entry->parent = c; + entries[c->count++] = entry; + c->entries = entries; + exif_entry_ref (entry); +} + +void +exif_content_remove_entry (ExifContent *c, ExifEntry *e) +{ + unsigned int i; + ExifEntry **t, *temp; + + if (!c || !c->priv || !e || (e->parent != c)) return; + + /* Search the entry */ + for (i = 0; i < c->count; i++) + if (c->entries[i] == e) + break; + + if (i == c->count) + return; + + /* Remove the entry */ + temp = c->entries[c->count-1]; + if (c->count > 1) { + t = exif_mem_realloc (c->priv->mem, c->entries, + sizeof(ExifEntry*) * (c->count - 1)); + if (!t) { + return; + } + c->entries = t; + c->count--; + if (i != c->count) { /* we deallocated the last slot already */ + memmove (&t[i], &t[i + 1], sizeof (ExifEntry*) * (c->count - i - 1)); + t[c->count-1] = temp; + } + } else { + exif_mem_free (c->priv->mem, c->entries); + c->entries = NULL; + c->count = 0; + } + e->parent = NULL; + exif_entry_unref (e); +} + +ExifEntry * +exif_content_get_entry (ExifContent *content, ExifTag tag) +{ + unsigned int i; + + if (!content) + return (NULL); + + for (i = 0; i < content->count; i++) + if (content->entries[i]->tag == tag) + return (content->entries[i]); + return (NULL); +} + +void +exif_content_foreach_entry (ExifContent *content, + ExifContentForeachEntryFunc func, void *data) +{ + unsigned int i; + + if (!content || !func) + return; + + for (i = 0; i < content->count; i++) + func (content->entries[i], data); +} + +void +exif_content_log (ExifContent *content, ExifLog *log) +{ + if (!content || !content->priv || !log || content->priv->log == log) + return; + + if (content->priv->log) exif_log_unref (content->priv->log); + content->priv->log = log; + exif_log_ref (log); +} + +ExifIfd +exif_content_get_ifd (ExifContent *c) +{ + if (!c || !c->parent) return EXIF_IFD_COUNT; + + return + ((c)->parent->ifd[EXIF_IFD_EXIF] == (c)) ? EXIF_IFD_EXIF : + ((c)->parent->ifd[EXIF_IFD_0] == (c)) ? EXIF_IFD_0 : + ((c)->parent->ifd[EXIF_IFD_1] == (c)) ? EXIF_IFD_1 : + ((c)->parent->ifd[EXIF_IFD_GPS] == (c)) ? EXIF_IFD_GPS : + ((c)->parent->ifd[EXIF_IFD_INTEROPERABILITY] == (c)) ? EXIF_IFD_INTEROPERABILITY : + EXIF_IFD_COUNT; +} + +static void +fix_func (ExifEntry *e, void *UNUSED(data)) +{ + exif_entry_fix (e); +} + +/*! + * Check if this entry is unknown and if so, delete it. + * \note Be careful calling this function in a loop. Deleting an entry from + * an ExifContent changes the index of subsequent entries, as well as the + * total size of the entries array. + */ +static void +remove_not_recorded (ExifEntry *e, void *UNUSED(data)) +{ + ExifIfd ifd = exif_entry_get_ifd(e) ; + ExifContent *c = e->parent; + ExifDataType dt = exif_data_get_data_type (c->parent); + ExifTag t = e->tag; + + if (exif_tag_get_support_level_in_ifd (t, ifd, dt) == + EXIF_SUPPORT_LEVEL_NOT_RECORDED) { + exif_log (c->priv->log, EXIF_LOG_CODE_DEBUG, "exif-content", + "Tag 0x%04x is not recorded in IFD '%s' and has therefore been " + "removed.", t, exif_ifd_get_name (ifd)); + exif_content_remove_entry (c, e); + } + +} + +void +exif_content_fix (ExifContent *c) +{ + ExifIfd ifd = exif_content_get_ifd (c); + ExifDataType dt; + ExifEntry *e; + unsigned int i, num; + + if (!c) + return; + + dt = exif_data_get_data_type (c->parent); + + /* + * First of all, fix all existing entries. + */ + exif_content_foreach_entry (c, fix_func, NULL); + + /* + * Go through each tag and if it's not recorded, remove it. If one + * is removed, exif_content_foreach_entry() will skip the next entry, + * so if this happens do the loop again from the beginning to ensure + * they're all checked. This could be avoided if we stop relying on + * exif_content_foreach_entry but loop intelligently here. + */ + do { + num = c->count; + exif_content_foreach_entry (c, remove_not_recorded, NULL); + } while (num != c->count); + + /* + * Then check for non-existing mandatory tags and create them if needed + */ + num = exif_tag_table_count(); + for (i = 0; i < num; ++i) { + const ExifTag t = exif_tag_table_get_tag (i); + if (exif_tag_get_support_level_in_ifd (t, ifd, dt) == + EXIF_SUPPORT_LEVEL_MANDATORY) { + if (exif_content_get_entry (c, t)) + /* This tag already exists */ + continue; + exif_log (c->priv->log, EXIF_LOG_CODE_DEBUG, "exif-content", + "Tag '%s' is mandatory in IFD '%s' and has therefore been added.", + exif_tag_get_name_in_ifd (t, ifd), exif_ifd_get_name (ifd)); + e = exif_entry_new (); + exif_content_add_entry (c, e); + exif_entry_initialize (e, t); + exif_entry_unref (e); + } + } +} diff --git a/libexif/exif-content.h b/libexif/exif-content.h new file mode 100644 index 0000000..d912ccf --- /dev/null +++ b/libexif/exif-content.h @@ -0,0 +1,145 @@ +/*! \file exif-content.h + * \brief Handling EXIF IFDs + */ +/* + * Copyright (c) 2001 Lutz Mueller <lutz@users.sourceforge.net> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA. + */ + +#ifndef __EXIF_CONTENT_H__ +#define __EXIF_CONTENT_H__ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/*! Holds all EXIF tags in a single IFD */ +typedef struct _ExifContent ExifContent; +typedef struct _ExifContentPrivate ExifContentPrivate; + +#include <libexif/exif-tag.h> +#include <libexif/exif-entry.h> +#include <libexif/exif-data.h> +#include <libexif/exif-log.h> +#include <libexif/exif-mem.h> + +struct _ExifContent +{ + ExifEntry **entries; + unsigned int count; + + /*! Data containing this content */ + ExifData *parent; + + ExifContentPrivate *priv; +}; + +/* Lifecycle */ +ExifContent *exif_content_new (void); +ExifContent *exif_content_new_mem (ExifMem *); +void exif_content_ref (ExifContent *content); +void exif_content_unref (ExifContent *content); +void exif_content_free (ExifContent *content); + +/*! Add an EXIF tag to an IFD. + * If this tag already exists in the IFD, this function does nothing. + * \pre The "tag" member of the entry must be set on entry. + * + * \param[out] c IFD + * \param[in] entry EXIF entry to add + */ +void exif_content_add_entry (ExifContent *c, ExifEntry *entry); + +/*! Remove an EXIF tag from an IFD. + * If this tag does not exist in the IFD, this function does nothing. + * + * \param[out] c IFD + * \param[in] e EXIF entry to remove + */ +void exif_content_remove_entry (ExifContent *c, ExifEntry *e); + +/*! Return the #ExifEntry in this IFD corresponding to the given tag. + * This is a pointer into a member of the #ExifContent array and must NOT be + * freed or unrefed by the caller. + * + * \param[in] content EXIF content for an IFD + * \param[in] tag EXIF tag to return + * \return #ExifEntry of the tag, or NULL on error + */ +ExifEntry *exif_content_get_entry (ExifContent *content, ExifTag tag); + +/*! Fix the IFD to bring it into specification. Call #exif_entry_fix on + * each entry in this IFD to fix existing entries, create any new entries + * that are mandatory in this IFD but do not yet exist, and remove any + * entries that are not allowed in this IFD. + * + * \param[in,out] c EXIF content for an IFD + */ +void exif_content_fix (ExifContent *c); + +typedef void (* ExifContentForeachEntryFunc) (ExifEntry *, void *user_data); + +/*! Executes function on each EXIF tag in this IFD in turn. + * The tags will not necessarily be visited in numerical order. + * + * \param[in,out] content IFD over which to iterate + * \param[in] func function to call for each entry + * \param[in] user_data data to pass into func on each call + */ +void exif_content_foreach_entry (ExifContent *content, + ExifContentForeachEntryFunc func, + void *user_data); + +/*! Return the IFD number in which the given #ExifContent is found. + * + * \param[in] c an #ExifContent* + * \return IFD number, or #EXIF_IFD_COUNT on error + */ +ExifIfd exif_content_get_ifd (ExifContent *c); + +/*! Return a textual representation of the EXIF data for a tag. + * + * \param[in] c #ExifContent* for an IFD + * \param[in] t #ExifTag to return + * \param[out] v char* buffer in which to store value + * \param[in] m unsigned int length of the buffer v + * \return the v pointer, or NULL on error + */ +#define exif_content_get_value(c,t,v,m) \ + (exif_content_get_entry (c,t) ? \ + exif_entry_get_value (exif_content_get_entry (c,t),v,m) : NULL) + +/*! Dump contents of the IFD to stdout. + * This is intended for diagnostic purposes only. + * + * \param[in] content IFD data + * \param[in] indent how many levels deep to indent the data + */ +void exif_content_dump (ExifContent *content, unsigned int indent); + +/*! Set the log message object for this IFD. + * + * \param[in] content IFD + * \param[in] log #ExifLog* + */ +void exif_content_log (ExifContent *content, ExifLog *log); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __EXIF_CONTENT_H__ */ diff --git a/libexif/exif-data-type.h b/libexif/exif-data-type.h new file mode 100644 index 0000000..05d4f95 --- /dev/null +++ b/libexif/exif-data-type.h @@ -0,0 +1,46 @@ +/* exif-data-tag.h + * + * Copyright (c) 2005 Lutz Mueller <lutz@users.sourceforge.net> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA. + */ + +#ifndef __EXIF_DATA_TYPE_H__ +#define __EXIF_DATA_TYPE_H__ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/*! Represents the type of image data to which the EXIF data applies. + * The EXIF tags have different constraints depending on the type of + * image data. + */ +typedef enum { + EXIF_DATA_TYPE_UNCOMPRESSED_CHUNKY = 0, + EXIF_DATA_TYPE_UNCOMPRESSED_PLANAR, + EXIF_DATA_TYPE_UNCOMPRESSED_YCC, + EXIF_DATA_TYPE_COMPRESSED, + EXIF_DATA_TYPE_COUNT, + + EXIF_DATA_TYPE_UNKNOWN = EXIF_DATA_TYPE_COUNT +} ExifDataType; + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __EXIF_TAG_H__ */ diff --git a/libexif/exif-data.c b/libexif/exif-data.c new file mode 100644 index 0000000..67df4db --- /dev/null +++ b/libexif/exif-data.c @@ -0,0 +1,1276 @@ +/* exif-data.c + * + * Copyright (c) 2001 Lutz Mueller <lutz@users.sourceforge.net> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA. + */ + +#include <config.h> + +#include <libexif/exif-mnote-data.h> +#include <libexif/exif-data.h> +#include <libexif/exif-ifd.h> +#include <libexif/exif-mnote-data-priv.h> +#include <libexif/exif-utils.h> +#include <libexif/exif-loader.h> +#include <libexif/exif-log.h> +#include <libexif/i18n.h> +#include <libexif/exif-system.h> + +#include <libexif/canon/exif-mnote-data-canon.h> +#include <libexif/fuji/exif-mnote-data-fuji.h> +#include <libexif/olympus/exif-mnote-data-olympus.h> +#include <libexif/pentax/exif-mnote-data-pentax.h> + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +#undef JPEG_MARKER_SOI +#define JPEG_MARKER_SOI 0xd8 +#undef JPEG_MARKER_APP0 +#define JPEG_MARKER_APP0 0xe0 +#undef JPEG_MARKER_APP1 +#define JPEG_MARKER_APP1 0xe1 + +static const unsigned char ExifHeader[] = {0x45, 0x78, 0x69, 0x66, 0x00, 0x00}; + +struct _ExifDataPrivate +{ + ExifByteOrder order; + + ExifMnoteData *md; + + ExifLog *log; + ExifMem *mem; + + unsigned int ref_count; + + /* Temporarily used while loading data */ + unsigned int offset_mnote; + + ExifDataOption options; + ExifDataType data_type; +}; + +static void * +exif_data_alloc (ExifData *data, unsigned int i) +{ + void *d; + + if (!data || !i) + return NULL; + + d = exif_mem_alloc (data->priv->mem, i); + if (d) + return d; + + EXIF_LOG_NO_MEMORY (data->priv->log, "ExifData", i); + return NULL; +} + +ExifMnoteData * +exif_data_get_mnote_data (ExifData *d) +{ + return (d && d->priv) ? d->priv->md : NULL; +} + +ExifData * +exif_data_new (void) +{ + ExifMem *mem = exif_mem_new_default (); + ExifData *d = exif_data_new_mem (mem); + + exif_mem_unref (mem); + + return d; +} + +ExifData * +exif_data_new_mem (ExifMem *mem) +{ + ExifData *data; + unsigned int i; + + if (!mem) + return NULL; + + data = exif_mem_alloc (mem, sizeof (ExifData)); + if (!data) + return (NULL); + data->priv = exif_mem_alloc (mem, sizeof (ExifDataPrivate)); + if (!data->priv) { + exif_mem_free (mem, data); + return (NULL); + } + data->priv->ref_count = 1; + + data->priv->mem = mem; + exif_mem_ref (mem); + + for (i = 0; i < EXIF_IFD_COUNT; i++) { + data->ifd[i] = exif_content_new_mem (data->priv->mem); + if (!data->ifd[i]) { + exif_data_free (data); + return (NULL); + } + data->ifd[i]->parent = data; + } + + /* Default options */ +#ifndef NO_VERBOSE_TAG_STRINGS + /* + * When the tag list is compiled away, setting this option prevents + * any tags from being loaded + */ + exif_data_set_option (data, EXIF_DATA_OPTION_IGNORE_UNKNOWN_TAGS); +#endif + exif_data_set_option (data, EXIF_DATA_OPTION_FOLLOW_SPECIFICATION); + + /* Default data type: none */ + exif_data_set_data_type (data, EXIF_DATA_TYPE_COUNT); + + return (data); +} + +ExifData * +exif_data_new_from_data (const unsigned char *data, unsigned int size) +{ + ExifData *edata; + + edata = exif_data_new (); + exif_data_load_data (edata, data, size); + return (edata); +} + +static int +exif_data_load_data_entry (ExifData *data, ExifEntry *entry, + const unsigned char *d, + unsigned int size, unsigned int offset) +{ + unsigned int s, doff; + + entry->tag = exif_get_short (d + offset + 0, data->priv->order); + entry->format = exif_get_short (d + offset + 2, data->priv->order); + entry->components = exif_get_long (d + offset + 4, data->priv->order); + + /* FIXME: should use exif_tag_get_name_in_ifd here but entry->parent + * has not been set yet + */ + exif_log (data->priv->log, EXIF_LOG_CODE_DEBUG, "ExifData", + "Loading entry 0x%x ('%s')...", entry->tag, + exif_tag_get_name (entry->tag)); + + /* {0,1,2,4,8} x { 0x00000000 .. 0xffffffff } + * -> { 0x000000000 .. 0x7fffffff8 } */ + s = exif_format_get_size(entry->format) * entry->components; + if ((s < entry->components) || (s == 0)){ + return 0; + } + + /* + * Size? If bigger than 4 bytes, the actual data is not + * in the entry but somewhere else (offset). + */ + if (s > 4) + doff = exif_get_long (d + offset + 8, data->priv->order); + else + doff = offset + 8; + + /* Sanity checks */ + if ((doff + s < doff) || (doff + s < s) || (doff + s > size)) { + exif_log (data->priv->log, EXIF_LOG_CODE_DEBUG, "ExifData", + "Tag data past end of buffer (%u > %u)", doff+s, size); + return 0; + } + + entry->data = exif_data_alloc (data, s); + if (entry->data) { + entry->size = s; + memcpy (entry->data, d + doff, s); + } else { + /* FIXME: What do our callers do if (entry->data == NULL)? */ + EXIF_LOG_NO_MEMORY(data->priv->log, "ExifData", s); + } + + /* If this is the MakerNote, remember the offset */ + if (entry->tag == EXIF_TAG_MAKER_NOTE) { + if (!entry->data) { + exif_log (data->priv->log, EXIF_LOG_CODE_DEBUG, "ExifData", + "MakerNote found with empty data"); + } else if (entry->size > 6) { + exif_log (data->priv->log, + EXIF_LOG_CODE_DEBUG, "ExifData", + "MakerNote found (%02x %02x %02x %02x " + "%02x %02x %02x...).", + entry->data[0], entry->data[1], entry->data[2], + entry->data[3], entry->data[4], entry->data[5], + entry->data[6]); + } + data->priv->offset_mnote = doff; + } + return 1; +} + +static void +exif_data_save_data_entry (ExifData *data, ExifEntry *e, + unsigned char **d, unsigned int *ds, + unsigned int offset) +{ + unsigned int doff, s; + unsigned int ts; + + if (!data || !data->priv) + return; + + /* + * Each entry is 12 bytes long. The memory for the entry has + * already been allocated. + */ + exif_set_short (*d + 6 + offset + 0, + data->priv->order, (ExifShort) e->tag); + exif_set_short (*d + 6 + offset + 2, + data->priv->order, (ExifShort) e->format); + + if (!(data->priv->options & EXIF_DATA_OPTION_DONT_CHANGE_MAKER_NOTE)) { + /* If this is the maker note tag, update it. */ + if ((e->tag == EXIF_TAG_MAKER_NOTE) && data->priv->md) { + /* TODO: this is using the wrong ExifMem to free e->data */ + exif_mem_free (data->priv->mem, e->data); + e->data = NULL; + e->size = 0; + exif_mnote_data_set_offset (data->priv->md, *ds - 6); + exif_mnote_data_save (data->priv->md, &e->data, &e->size); + e->components = e->size; + } + } + + exif_set_long (*d + 6 + offset + 4, + data->priv->order, e->components); + + /* + * Size? If bigger than 4 bytes, the actual data is not in + * the entry but somewhere else. + */ + s = exif_format_get_size (e->format) * e->components; + if (s > 4) { + unsigned char *t; + doff = *ds - 6; + ts = *ds + s; + + /* + * According to the TIFF specification, + * the offset must be an even number. If we need to introduce + * a padding byte, we set it to 0. + */ + if (s & 1) + ts++; + t = exif_mem_realloc (data->priv->mem, *d, ts); + if (!t) { + EXIF_LOG_NO_MEMORY (data->priv->log, "ExifData", ts); + return; + } + *d = t; + *ds = ts; + exif_set_long (*d + 6 + offset + 8, data->priv->order, doff); + if (s & 1) + *(*d + *ds - 1) = '\0'; + + } else + doff = offset + 8; + + /* Write the data. Fill unneeded bytes with 0. Do not crash with + * e->data is NULL */ + if (e->data) { + memcpy (*d + 6 + doff, e->data, s); + } else { + memset (*d + 6 + doff, 0, s); + } + if (s < 4) + memset (*d + 6 + doff + s, 0, (4 - s)); +} + +static void +exif_data_load_data_thumbnail (ExifData *data, const unsigned char *d, + unsigned int ds, ExifLong o, ExifLong s) +{ + /* Sanity checks */ + if ((o + s < o) || (o + s < s) || (o + s > ds) || (o > ds)) { + exif_log (data->priv->log, EXIF_LOG_CODE_DEBUG, "ExifData", + "Bogus thumbnail offset (%u) or size (%u).", + o, s); + return; + } + + if (data->data) + exif_mem_free (data->priv->mem, data->data); + if (!(data->data = exif_data_alloc (data, s))) { + EXIF_LOG_NO_MEMORY (data->priv->log, "ExifData", s); + data->size = 0; + return; + } + data->size = s; + memcpy (data->data, d + o, s); +} + +#undef CHECK_REC +#define CHECK_REC(i) \ +if ((i) == ifd) { \ + exif_log (data->priv->log, EXIF_LOG_CODE_DEBUG, \ + "ExifData", "Recursive entry in IFD " \ + "'%s' detected. Skipping...", \ + exif_ifd_get_name (i)); \ + break; \ +} \ +if (data->ifd[(i)]->count) { \ + exif_log (data->priv->log, EXIF_LOG_CODE_DEBUG, \ + "ExifData", "Attempt to load IFD " \ + "'%s' multiple times detected. " \ + "Skipping...", \ + exif_ifd_get_name (i)); \ + break; \ +} + +/*! Load data for an IFD. + * + * \param[in,out] data #ExifData + * \param[in] ifd IFD to load + * \param[in] d pointer to buffer containing raw IFD data + * \param[in] ds size of raw data in buffer at \c d + * \param[in] offset offset into buffer at \c d at which IFD starts + * \param[in] recursion_depth number of times this function has been + * recursively called without returning + */ +static void +exif_data_load_data_content (ExifData *data, ExifIfd ifd, + const unsigned char *d, + unsigned int ds, unsigned int offset, unsigned int recursion_depth) +{ + ExifLong o, thumbnail_offset = 0, thumbnail_length = 0; + ExifShort n; + ExifEntry *entry; + unsigned int i; + ExifTag tag; + + if (!data || !data->priv) + return; + + /* check for valid ExifIfd enum range */ + if ((((int)ifd) < 0) || ( ((int)ifd) >= EXIF_IFD_COUNT)) + return; + + if (recursion_depth > 30) { + exif_log (data->priv->log, EXIF_LOG_CODE_CORRUPT_DATA, "ExifData", + "Deep recursion detected!"); + return; + } + + /* Read the number of entries */ + if ((offset + 2 < offset) || (offset + 2 < 2) || (offset + 2 > ds)) { + exif_log (data->priv->log, EXIF_LOG_CODE_CORRUPT_DATA, "ExifData", + "Tag data past end of buffer (%u > %u)", offset+2, ds); + return; + } + n = exif_get_short (d + offset, data->priv->order); + exif_log (data->priv->log, EXIF_LOG_CODE_DEBUG, "ExifData", + "Loading %hu entries...", n); + offset += 2; + + /* Check if we have enough data. */ + if (offset + 12 * n > ds) { + n = (ds - offset) / 12; + exif_log (data->priv->log, EXIF_LOG_CODE_DEBUG, "ExifData", + "Short data; only loading %hu entries...", n); + } + + for (i = 0; i < n; i++) { + + tag = exif_get_short (d + offset + 12 * i, data->priv->order); + switch (tag) { + case EXIF_TAG_EXIF_IFD_POINTER: + case EXIF_TAG_GPS_INFO_IFD_POINTER: + case EXIF_TAG_INTEROPERABILITY_IFD_POINTER: + case EXIF_TAG_JPEG_INTERCHANGE_FORMAT_LENGTH: + case EXIF_TAG_JPEG_INTERCHANGE_FORMAT: + o = exif_get_long (d + offset + 12 * i + 8, + data->priv->order); + /* FIXME: IFD_POINTER tags aren't marked as being in a + * specific IFD, so exif_tag_get_name_in_ifd won't work + */ + exif_log (data->priv->log, EXIF_LOG_CODE_DEBUG, "ExifData", + "Sub-IFD entry 0x%x ('%s') at %u.", tag, + exif_tag_get_name(tag), o); + switch (tag) { + case EXIF_TAG_EXIF_IFD_POINTER: + CHECK_REC (EXIF_IFD_EXIF); + exif_data_load_data_content (data, EXIF_IFD_EXIF, d, ds, o, recursion_depth + 1); + break; + case EXIF_TAG_GPS_INFO_IFD_POINTER: + CHECK_REC (EXIF_IFD_GPS); + exif_data_load_data_content (data, EXIF_IFD_GPS, d, ds, o, recursion_depth + 1); + break; + case EXIF_TAG_INTEROPERABILITY_IFD_POINTER: + CHECK_REC (EXIF_IFD_INTEROPERABILITY); + exif_data_load_data_content (data, EXIF_IFD_INTEROPERABILITY, d, ds, o, recursion_depth + 1); + break; + case EXIF_TAG_JPEG_INTERCHANGE_FORMAT: + thumbnail_offset = o; + if (thumbnail_offset && thumbnail_length) + exif_data_load_data_thumbnail (data, d, + ds, thumbnail_offset, + thumbnail_length); + break; + case EXIF_TAG_JPEG_INTERCHANGE_FORMAT_LENGTH: + thumbnail_length = o; + if (thumbnail_offset && thumbnail_length) + exif_data_load_data_thumbnail (data, d, + ds, thumbnail_offset, + thumbnail_length); + break; + default: + return; + } + break; + default: + + /* + * If we don't know the tag, don't fail. It could be that new + * versions of the standard have defined additional tags. Note that + * 0 is a valid tag in the GPS IFD. + */ + if (!exif_tag_get_name_in_ifd (tag, ifd)) { + + /* + * Special case: Tag and format 0. That's against specification + * (at least up to 2.2). But Photoshop writes it anyways. + */ + if (!memcmp (d + offset + 12 * i, "\0\0\0\0", 4)) { + exif_log (data->priv->log, EXIF_LOG_CODE_DEBUG, "ExifData", + "Skipping empty entry at position %u in '%s'.", i, + exif_ifd_get_name (ifd)); + break; + } + exif_log (data->priv->log, EXIF_LOG_CODE_DEBUG, "ExifData", + "Unknown tag 0x%04x (entry %u in '%s'). Please report this tag " + "to <libexif-devel@lists.sourceforge.net>.", tag, i, + exif_ifd_get_name (ifd)); + if (data->priv->options & EXIF_DATA_OPTION_IGNORE_UNKNOWN_TAGS) + break; + } + entry = exif_entry_new_mem (data->priv->mem); + if (exif_data_load_data_entry (data, entry, d, ds, + offset + 12 * i)) + exif_content_add_entry (data->ifd[ifd], entry); + exif_entry_unref (entry); + break; + } + } +} + +static int +cmp_func (const unsigned char *p1, const unsigned char *p2, ExifByteOrder o) +{ + ExifShort tag1 = exif_get_short (p1, o); + ExifShort tag2 = exif_get_short (p2, o); + + return (tag1 < tag2) ? -1 : (tag1 > tag2) ? 1 : 0; +} + +static int +cmp_func_intel (const void *elem1, const void *elem2) +{ + return cmp_func ((const unsigned char *) elem1, + (const unsigned char *) elem2, EXIF_BYTE_ORDER_INTEL); +} + +static int +cmp_func_motorola (const void *elem1, const void *elem2) +{ + return cmp_func ((const unsigned char *) elem1, + (const unsigned char *) elem2, EXIF_BYTE_ORDER_MOTOROLA); +} + +static void +exif_data_save_data_content (ExifData *data, ExifContent *ifd, + unsigned char **d, unsigned int *ds, + unsigned int offset) +{ + unsigned int j, n_ptr = 0, n_thumb = 0; + ExifIfd i; + unsigned char *t; + unsigned int ts; + + if (!data || !data->priv || !ifd || !d || !ds) + return; + + for (i = 0; i < EXIF_IFD_COUNT; i++) + if (ifd == data->ifd[i]) + break; + if (i == EXIF_IFD_COUNT) + return; /* error */ + + /* + * Check if we need some extra entries for pointers or the thumbnail. + */ + switch (i) { + case EXIF_IFD_0: + + /* + * The pointer to IFD_EXIF is in IFD_0. The pointer to + * IFD_INTEROPERABILITY is in IFD_EXIF. + */ + if (data->ifd[EXIF_IFD_EXIF]->count || + data->ifd[EXIF_IFD_INTEROPERABILITY]->count) + n_ptr++; + + /* The pointer to IFD_GPS is in IFD_0. */ + if (data->ifd[EXIF_IFD_GPS]->count) + n_ptr++; + + break; + case EXIF_IFD_1: + if (data->size) + n_thumb = 2; + break; + case EXIF_IFD_EXIF: + if (data->ifd[EXIF_IFD_INTEROPERABILITY]->count) + n_ptr++; + default: + break; + } + + /* + * Allocate enough memory for all entries + * and the number of entries. + */ + ts = *ds + (2 + (ifd->count + n_ptr + n_thumb) * 12 + 4); + t = exif_mem_realloc (data->priv->mem, *d, ts); + if (!t) { + EXIF_LOG_NO_MEMORY (data->priv->log, "ExifData", ts); + return; + } + *d = t; + *ds = ts; + + /* Save the number of entries */ + exif_set_short (*d + 6 + offset, data->priv->order, + (ExifShort) (ifd->count + n_ptr + n_thumb)); + offset += 2; + + /* + * Save each entry. Make sure that no memcpys from NULL pointers are + * performed + */ + exif_log (data->priv->log, EXIF_LOG_CODE_DEBUG, "ExifData", + "Saving %i entries (IFD '%s', offset: %i)...", + ifd->count, exif_ifd_get_name (i), offset); + for (j = 0; j < ifd->count; j++) { + if (ifd->entries[j]) { + exif_data_save_data_entry (data, ifd->entries[j], d, ds, + offset + 12 * j); + } + } + + offset += 12 * ifd->count; + + /* Now save special entries. */ + switch (i) { + case EXIF_IFD_0: + + /* + * The pointer to IFD_EXIF is in IFD_0. + * However, the pointer to IFD_INTEROPERABILITY is in IFD_EXIF, + * therefore, if IFD_INTEROPERABILITY is not empty, we need + * IFD_EXIF even if latter is empty. + */ + if (data->ifd[EXIF_IFD_EXIF]->count || + data->ifd[EXIF_IFD_INTEROPERABILITY]->count) { + exif_set_short (*d + 6 + offset + 0, data->priv->order, + EXIF_TAG_EXIF_IFD_POINTER); + exif_set_short (*d + 6 + offset + 2, data->priv->order, + EXIF_FORMAT_LONG); + exif_set_long (*d + 6 + offset + 4, data->priv->order, + 1); + exif_set_long (*d + 6 + offset + 8, data->priv->order, + *ds - 6); + exif_data_save_data_content (data, + data->ifd[EXIF_IFD_EXIF], d, ds, *ds - 6); + offset += 12; + } + + /* The pointer to IFD_GPS is in IFD_0, too. */ + if (data->ifd[EXIF_IFD_GPS]->count) { + exif_set_short (*d + 6 + offset + 0, data->priv->order, + EXIF_TAG_GPS_INFO_IFD_POINTER); + exif_set_short (*d + 6 + offset + 2, data->priv->order, + EXIF_FORMAT_LONG); + exif_set_long (*d + 6 + offset + 4, data->priv->order, + 1); + exif_set_long (*d + 6 + offset + 8, data->priv->order, + *ds - 6); + exif_data_save_data_content (data, + data->ifd[EXIF_IFD_GPS], d, ds, *ds - 6); + offset += 12; + } + + break; + case EXIF_IFD_EXIF: + + /* + * The pointer to IFD_INTEROPERABILITY is in IFD_EXIF. + * See note above. + */ + if (data->ifd[EXIF_IFD_INTEROPERABILITY]->count) { + exif_set_short (*d + 6 + offset + 0, data->priv->order, + EXIF_TAG_INTEROPERABILITY_IFD_POINTER); + exif_set_short (*d + 6 + offset + 2, data->priv->order, + EXIF_FORMAT_LONG); + exif_set_long (*d + 6 + offset + 4, data->priv->order, + 1); + exif_set_long (*d + 6 + offset + 8, data->priv->order, + *ds - 6); + exif_data_save_data_content (data, + data->ifd[EXIF_IFD_INTEROPERABILITY], d, ds, + *ds - 6); + offset += 12; + } + + break; + case EXIF_IFD_1: + + /* + * Information about the thumbnail (if any) is saved in + * IFD_1. + */ + if (data->size) { + + /* EXIF_TAG_JPEG_INTERCHANGE_FORMAT */ + exif_set_short (*d + 6 + offset + 0, data->priv->order, + EXIF_TAG_JPEG_INTERCHANGE_FORMAT); + exif_set_short (*d + 6 + offset + 2, data->priv->order, + EXIF_FORMAT_LONG); + exif_set_long (*d + 6 + offset + 4, data->priv->order, + 1); + exif_set_long (*d + 6 + offset + 8, data->priv->order, + *ds - 6); + ts = *ds + data->size; + t = exif_mem_realloc (data->priv->mem, *d, ts); + if (!t) { + EXIF_LOG_NO_MEMORY (data->priv->log, "ExifData", + ts); + return; + } + *d = t; + *ds = ts; + memcpy (*d + *ds - data->size, data->data, data->size); + offset += 12; + + /* EXIF_TAG_JPEG_INTERCHANGE_FORMAT_LENGTH */ + exif_set_short (*d + 6 + offset + 0, data->priv->order, + EXIF_TAG_JPEG_INTERCHANGE_FORMAT_LENGTH); + exif_set_short (*d + 6 + offset + 2, data->priv->order, + EXIF_FORMAT_LONG); + exif_set_long (*d + 6 + offset + 4, data->priv->order, + 1); + exif_set_long (*d + 6 + offset + 8, data->priv->order, + data->size); + offset += 12; + } + + break; + default: + break; + } + + /* Sort the directory according to TIFF specification */ + qsort (*d + 6 + offset - (ifd->count + n_ptr + n_thumb) * 12, + (ifd->count + n_ptr + n_thumb), 12, + (data->priv->order == EXIF_BYTE_ORDER_INTEL) ? cmp_func_intel : cmp_func_motorola); + + /* Correctly terminate the directory */ + if (i == EXIF_IFD_0 && (data->ifd[EXIF_IFD_1]->count || + data->size)) { + + /* + * We are saving IFD 0. Tell where IFD 1 starts and save + * IFD 1. + */ + exif_set_long (*d + 6 + offset, data->priv->order, *ds - 6); + exif_data_save_data_content (data, data->ifd[EXIF_IFD_1], d, ds, + *ds - 6); + } else + exif_set_long (*d + 6 + offset, data->priv->order, 0); +} + +typedef enum { + EXIF_DATA_TYPE_MAKER_NOTE_NONE = 0, + EXIF_DATA_TYPE_MAKER_NOTE_CANON = 1, + EXIF_DATA_TYPE_MAKER_NOTE_OLYMPUS = 2, + EXIF_DATA_TYPE_MAKER_NOTE_PENTAX = 3, + EXIF_DATA_TYPE_MAKER_NOTE_NIKON = 4, + EXIF_DATA_TYPE_MAKER_NOTE_CASIO = 5, + EXIF_DATA_TYPE_MAKER_NOTE_FUJI = 6 +} ExifDataTypeMakerNote; + +/*! If MakerNote is recognized, load it. + * + * \param[in,out] data #ExifData + * \param[in] d pointer to raw EXIF data + * \param[in] ds length of data at d + */ +static void +interpret_maker_note(ExifData *data, const unsigned char *d, unsigned int ds) +{ + int mnoteid; + ExifEntry* e = exif_data_get_entry (data, EXIF_TAG_MAKER_NOTE); + if (!e) + return; + + if ((mnoteid = exif_mnote_data_olympus_identify (data, e)) != 0) { + exif_log (data->priv->log, EXIF_LOG_CODE_DEBUG, + "ExifData", "Olympus MakerNote variant type %d", mnoteid); + data->priv->md = exif_mnote_data_olympus_new (data->priv->mem); + + } else if ((mnoteid = exif_mnote_data_canon_identify (data, e)) != 0) { + exif_log (data->priv->log, EXIF_LOG_CODE_DEBUG, + "ExifData", "Canon MakerNote variant type %d", mnoteid); + data->priv->md = exif_mnote_data_canon_new (data->priv->mem, data->priv->options); + + } else if ((mnoteid = exif_mnote_data_fuji_identify (data, e)) != 0) { + exif_log (data->priv->log, EXIF_LOG_CODE_DEBUG, + "ExifData", "Fuji MakerNote variant type %d", mnoteid); + data->priv->md = exif_mnote_data_fuji_new (data->priv->mem); + + /* NOTE: Must do Pentax detection last because some of the + * heuristics are pretty general. */ + } else if ((mnoteid = exif_mnote_data_pentax_identify (data, e)) != 0) { + exif_log (data->priv->log, EXIF_LOG_CODE_DEBUG, + "ExifData", "Pentax MakerNote variant type %d", mnoteid); + data->priv->md = exif_mnote_data_pentax_new (data->priv->mem); + } + + /* + * If we are able to interpret the maker note, do so. + */ + if (data->priv->md) { + exif_mnote_data_log (data->priv->md, data->priv->log); + exif_mnote_data_set_byte_order (data->priv->md, + data->priv->order); + exif_mnote_data_set_offset (data->priv->md, + data->priv->offset_mnote); + exif_mnote_data_load (data->priv->md, d, ds); + } +} + +#define LOG_TOO_SMALL \ +exif_log (data->priv->log, EXIF_LOG_CODE_CORRUPT_DATA, "ExifData", \ + _("Size of data too small to allow for EXIF data.")); + +void +exif_data_load_data (ExifData *data, const unsigned char *d_orig, + unsigned int ds) +{ + unsigned int l; + ExifLong offset; + ExifShort n; + const unsigned char *d = d_orig; + unsigned int len, fullds; + + if (!data || !data->priv || !d || !ds) + return; + + exif_log (data->priv->log, EXIF_LOG_CODE_DEBUG, "ExifData", + "Parsing %i byte(s) EXIF data...\n", ds); + + /* + * It can be that the data starts with the EXIF header. If it does + * not, search the EXIF marker. + */ + if (ds < 6) { + LOG_TOO_SMALL; + return; + } + if (!memcmp (d, ExifHeader, 6)) { + exif_log (data->priv->log, EXIF_LOG_CODE_DEBUG, "ExifData", + "Found EXIF header."); + } else { + while (ds >= 3) { + while (ds && (d[0] == 0xff)) { + d++; + ds--; + } + + /* JPEG_MARKER_SOI */ + if (ds && d[0] == JPEG_MARKER_SOI) { + d++; + ds--; + continue; + } + + /* JPEG_MARKER_APP0 */ + if (ds >= 3 && d[0] == JPEG_MARKER_APP0) { + d++; + ds--; + l = (d[0] << 8) | d[1]; + if (l > ds) + return; + d += l; + ds -= l; + continue; + } + + /* JPEG_MARKER_APP1 */ + if (ds && d[0] == JPEG_MARKER_APP1) + break; + + /* Unknown marker or data. Give up. */ + exif_log (data->priv->log, EXIF_LOG_CODE_CORRUPT_DATA, + "ExifData", _("EXIF marker not found.")); + return; + } + if (ds < 3) { + LOG_TOO_SMALL; + return; + } + d++; + ds--; + len = (d[0] << 8) | d[1]; + exif_log (data->priv->log, EXIF_LOG_CODE_DEBUG, "ExifData", + "We have to deal with %i byte(s) of EXIF data.", + len); + d += 2; + ds -= 2; + } + + /* + * Verify the exif header + * (offset 2, length 6). + */ + if (ds < 6) { + LOG_TOO_SMALL; + return; + } + if (memcmp (d, ExifHeader, 6)) { + exif_log (data->priv->log, EXIF_LOG_CODE_CORRUPT_DATA, + "ExifData", _("EXIF header not found.")); + return; + } + + exif_log (data->priv->log, EXIF_LOG_CODE_DEBUG, "ExifData", + "Found EXIF header."); + + /* Sanity check the data length */ + if (ds < 14) + return; + + /* The JPEG APP1 section can be no longer than 64 KiB (including a + 16-bit length), so cap the data length to protect against overflow + in future offset calculations */ + fullds = ds; + if (ds > 0xfffe) + ds = 0xfffe; + + /* Byte order (offset 6, length 2) */ + if (!memcmp (d + 6, "II", 2)) + data->priv->order = EXIF_BYTE_ORDER_INTEL; + else if (!memcmp (d + 6, "MM", 2)) + data->priv->order = EXIF_BYTE_ORDER_MOTOROLA; + else { + exif_log (data->priv->log, EXIF_LOG_CODE_CORRUPT_DATA, + "ExifData", _("Unknown encoding.")); + return; + } + + /* Fixed value */ + if (exif_get_short (d + 8, data->priv->order) != 0x002a) + return; + + /* IFD 0 offset */ + offset = exif_get_long (d + 10, data->priv->order); + exif_log (data->priv->log, EXIF_LOG_CODE_DEBUG, "ExifData", + "IFD 0 at %i.", (int) offset); + + /* Sanity check the offset, being careful about overflow */ + if (offset > ds || offset + 6 + 2 > ds) + return; + + /* Parse the actual exif data (usually offset 14 from start) */ + exif_data_load_data_content (data, EXIF_IFD_0, d + 6, ds - 6, offset, 0); + + /* IFD 1 offset */ + n = exif_get_short (d + 6 + offset, data->priv->order); + if (offset + 6 + 2 + 12 * n + 4 > ds) + return; + + offset = exif_get_long (d + 6 + offset + 2 + 12 * n, data->priv->order); + if (offset) { + exif_log (data->priv->log, EXIF_LOG_CODE_DEBUG, "ExifData", + "IFD 1 at %i.", (int) offset); + + /* Sanity check. */ + if (offset > ds || offset + 6 > ds) { + exif_log (data->priv->log, EXIF_LOG_CODE_CORRUPT_DATA, + "ExifData", "Bogus offset of IFD1."); + } else { + exif_data_load_data_content (data, EXIF_IFD_1, d + 6, ds - 6, offset, 0); + } + } + + /* + * If we got an EXIF_TAG_MAKER_NOTE, try to interpret it. Some + * cameras use pointers in the maker note tag that point to the + * space between IFDs. Here is the only place where we have access + * to that data. + */ + interpret_maker_note(data, d, fullds); + + /* Fixup tags if requested */ + if (data->priv->options & EXIF_DATA_OPTION_FOLLOW_SPECIFICATION) + exif_data_fix (data); +} + +void +exif_data_save_data (ExifData *data, unsigned char **d, unsigned int *ds) +{ + if (ds) + *ds = 0; /* This means something went wrong */ + + if (!data || !d || !ds) + return; + + /* Header */ + *ds = 14; + *d = exif_data_alloc (data, *ds); + if (!*d) { + *ds = 0; + return; + } + memcpy (*d, ExifHeader, 6); + + /* Order (offset 6) */ + if (data->priv->order == EXIF_BYTE_ORDER_INTEL) { + memcpy (*d + 6, "II", 2); + } else { + memcpy (*d + 6, "MM", 2); + } + + /* Fixed value (2 bytes, offset 8) */ + exif_set_short (*d + 8, data->priv->order, 0x002a); + + /* + * IFD 0 offset (4 bytes, offset 10). + * We will start 8 bytes after the + * EXIF header (2 bytes for order, another 2 for the test, and + * 4 bytes for the IFD 0 offset make 8 bytes together). + */ + exif_set_long (*d + 10, data->priv->order, 8); + + /* Now save IFD 0. IFD 1 will be saved automatically. */ + exif_log (data->priv->log, EXIF_LOG_CODE_DEBUG, "ExifData", + "Saving IFDs..."); + exif_data_save_data_content (data, data->ifd[EXIF_IFD_0], d, ds, + *ds - 6); + exif_log (data->priv->log, EXIF_LOG_CODE_DEBUG, "ExifData", + "Saved %i byte(s) EXIF data.", *ds); +} + +ExifData * +exif_data_new_from_file (const char *path) +{ + ExifData *edata; + ExifLoader *loader; + + loader = exif_loader_new (); + exif_loader_write_file (loader, path); + edata = exif_loader_get_data (loader); + exif_loader_unref (loader); + + return (edata); +} + +void +exif_data_ref (ExifData *data) +{ + if (!data) + return; + + data->priv->ref_count++; +} + +void +exif_data_unref (ExifData *data) +{ + if (!data) + return; + + data->priv->ref_count--; + if (!data->priv->ref_count) + exif_data_free (data); +} + +void +exif_data_free (ExifData *data) +{ + unsigned int i; + ExifMem *mem = (data && data->priv) ? data->priv->mem : NULL; + + if (!data) + return; + + for (i = 0; i < EXIF_IFD_COUNT; i++) { + if (data->ifd[i]) { + exif_content_unref (data->ifd[i]); + data->ifd[i] = NULL; + } + } + + if (data->data) { + exif_mem_free (mem, data->data); + data->data = NULL; + } + + if (data->priv) { + if (data->priv->log) { + exif_log_unref (data->priv->log); + data->priv->log = NULL; + } + if (data->priv->md) { + exif_mnote_data_unref (data->priv->md); + data->priv->md = NULL; + } + exif_mem_free (mem, data->priv); + exif_mem_free (mem, data); + } + + exif_mem_unref (mem); +} + +void +exif_data_dump (ExifData *data) +{ + unsigned int i; + + if (!data) + return; + + for (i = 0; i < EXIF_IFD_COUNT; i++) { + if (data->ifd[i] && data->ifd[i]->count) { + printf ("Dumping IFD '%s'...\n", + exif_ifd_get_name (i)); + exif_content_dump (data->ifd[i], 0); + } + } + + if (data->data) { + printf ("%i byte(s) thumbnail data available.", data->size); + if (data->size >= 4) { + printf ("0x%02x 0x%02x ... 0x%02x 0x%02x\n", + data->data[0], data->data[1], + data->data[data->size - 2], + data->data[data->size - 1]); + } + } +} + +ExifByteOrder +exif_data_get_byte_order (ExifData *data) +{ + if (!data) + return (0); + + return (data->priv->order); +} + +void +exif_data_foreach_content (ExifData *data, ExifDataForeachContentFunc func, + void *user_data) +{ + unsigned int i; + + if (!data || !func) + return; + + for (i = 0; i < EXIF_IFD_COUNT; i++) + func (data->ifd[i], user_data); +} + +typedef struct _ByteOrderChangeData ByteOrderChangeData; +struct _ByteOrderChangeData { + ExifByteOrder old, new; +}; + +static void +entry_set_byte_order (ExifEntry *e, void *data) +{ + ByteOrderChangeData *d = data; + + if (!e) + return; + + exif_array_set_byte_order (e->format, e->data, e->components, d->old, d->new); +} + +static void +content_set_byte_order (ExifContent *content, void *data) +{ + exif_content_foreach_entry (content, entry_set_byte_order, data); +} + +void +exif_data_set_byte_order (ExifData *data, ExifByteOrder order) +{ + ByteOrderChangeData d; + + if (!data || (order == data->priv->order)) + return; + + d.old = data->priv->order; + d.new = order; + exif_data_foreach_content (data, content_set_byte_order, &d); + data->priv->order = order; + if (data->priv->md) + exif_mnote_data_set_byte_order (data->priv->md, order); +} + +void +exif_data_log (ExifData *data, ExifLog *log) +{ + unsigned int i; + + if (!data || !data->priv) + return; + exif_log_unref (data->priv->log); + data->priv->log = log; + exif_log_ref (log); + + for (i = 0; i < EXIF_IFD_COUNT; i++) + exif_content_log (data->ifd[i], log); +} + +/* Used internally within libexif */ +ExifLog *exif_data_get_log (ExifData *); +ExifLog * +exif_data_get_log (ExifData *data) +{ + if (!data || !data->priv) + return NULL; + return data->priv->log; +} + +static const struct { + ExifDataOption option; + const char *name; + const char *description; +} exif_data_option[] = { + {EXIF_DATA_OPTION_IGNORE_UNKNOWN_TAGS, N_("Ignore unknown tags"), + N_("Ignore unknown tags when loading EXIF data.")}, + {EXIF_DATA_OPTION_FOLLOW_SPECIFICATION, N_("Follow specification"), + N_("Add, correct and remove entries to get EXIF data that follows " + "the specification.")}, + {EXIF_DATA_OPTION_DONT_CHANGE_MAKER_NOTE, N_("Do not change maker note"), + N_("When loading and resaving Exif data, save the maker note unmodified." + " Be aware that the maker note can get corrupted.")}, + {0, NULL, NULL} +}; + +const char * +exif_data_option_get_name (ExifDataOption o) +{ + unsigned int i; + + for (i = 0; exif_data_option[i].name; i++) + if (exif_data_option[i].option == o) + break; + return _(exif_data_option[i].name); +} + +const char * +exif_data_option_get_description (ExifDataOption o) +{ + unsigned int i; + + for (i = 0; exif_data_option[i].description; i++) + if (exif_data_option[i].option == o) + break; + return _(exif_data_option[i].description); +} + +void +exif_data_set_option (ExifData *d, ExifDataOption o) +{ + if (!d) + return; + + d->priv->options |= o; +} + +void +exif_data_unset_option (ExifData *d, ExifDataOption o) +{ + if (!d) + return; + + d->priv->options &= ~o; +} + +static void +fix_func (ExifContent *c, void *UNUSED(data)) +{ + switch (exif_content_get_ifd (c)) { + case EXIF_IFD_1: + if (c->parent->data) + exif_content_fix (c); + else if (c->count) { + exif_log (c->parent->priv->log, EXIF_LOG_CODE_DEBUG, "exif-data", + "No thumbnail but entries on thumbnail. These entries have been " + "removed."); + while (c->count) { + unsigned int cnt = c->count; + exif_content_remove_entry (c, c->entries[c->count - 1]); + if (cnt == c->count) { + /* safety net */ + exif_log (c->parent->priv->log, EXIF_LOG_CODE_DEBUG, "exif-data", + "failed to remove last entry from entries."); + c->count--; + } + } + } + break; + default: + exif_content_fix (c); + } +} + +void +exif_data_fix (ExifData *d) +{ + exif_data_foreach_content (d, fix_func, NULL); +} + +void +exif_data_set_data_type (ExifData *d, ExifDataType dt) +{ + if (!d || !d->priv) + return; + + d->priv->data_type = dt; +} + +ExifDataType +exif_data_get_data_type (ExifData *d) +{ + return (d && d->priv) ? d->priv->data_type : EXIF_DATA_TYPE_UNKNOWN; +} diff --git a/libexif/exif-data.h b/libexif/exif-data.h new file mode 100644 index 0000000..eeee782 --- /dev/null +++ b/libexif/exif-data.h @@ -0,0 +1,265 @@ +/*! \file exif-data.h + * \brief Defines the ExifData type and the associated functions. + */ +/* + * \author Lutz Mueller <lutz@users.sourceforge.net> + * \date 2001-2005 + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA. + */ + +#ifndef __EXIF_DATA_H__ +#define __EXIF_DATA_H__ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#include <libexif/exif-byte-order.h> +#include <libexif/exif-data-type.h> +#include <libexif/exif-ifd.h> +#include <libexif/exif-log.h> +#include <libexif/exif-tag.h> + +/*! Represents the entire EXIF data found in an image */ +typedef struct _ExifData ExifData; +typedef struct _ExifDataPrivate ExifDataPrivate; + +#include <libexif/exif-content.h> +#include <libexif/exif-mnote-data.h> +#include <libexif/exif-mem.h> + +/*! Represents the entire EXIF data found in an image */ +struct _ExifData +{ + /*! Data for each IFD */ + ExifContent *ifd[EXIF_IFD_COUNT]; + + /*! Pointer to thumbnail image, or NULL if not available */ + unsigned char *data; + + /*! Number of bytes in thumbnail image at \c data */ + unsigned int size; + + ExifDataPrivate *priv; +}; + +/*! Allocate a new #ExifData. The #ExifData contains an empty + * #ExifContent for each IFD and the default set of options, + * which has #EXIF_DATA_OPTION_IGNORE_UNKNOWN_TAGS + * and #EXIF_DATA_OPTION_FOLLOW_SPECIFICATION set. + * + * \return allocated #ExifData, or NULL on error + */ +ExifData *exif_data_new (void); + +/*! Allocate a new #ExifData using the given memory allocator. + * The #ExifData contains an empty #ExifContent for each IFD and the default + * set of options, which has #EXIF_DATA_OPTION_IGNORE_UNKNOWN_TAGS and + * #EXIF_DATA_OPTION_FOLLOW_SPECIFICATION set. + * + * \return allocated #ExifData, or NULL on error + */ +ExifData *exif_data_new_mem (ExifMem *); + +/*! Allocate a new #ExifData and load EXIF data from a JPEG file. + * Uses an #ExifLoader internally to do the loading. + * + * \param[in] path filename including path + * \return allocated #ExifData, or NULL on error + */ +ExifData *exif_data_new_from_file (const char *path); + +/*! Allocate a new #ExifData and load EXIF data from a memory buffer. + * + * \param[in] data pointer to raw JPEG or EXIF data + * \param[in] size number of bytes of data at data + * \return allocated #ExifData, or NULL on error + */ +ExifData *exif_data_new_from_data (const unsigned char *data, + unsigned int size); + +/*! Load the #ExifData structure from the raw JPEG or EXIF data in the given + * memory buffer. If the EXIF data contains a recognized MakerNote, it is + * loaded and stored as well for later retrieval by #exif_data_get_mnote_data. + * If the #EXIF_DATA_OPTION_FOLLOW_SPECIFICATION option has been set on this + * #ExifData, then the tags are automatically fixed after loading (by calling + * #exif_data_fix). + * + * \param[in,out] data EXIF data + * \param[in] d pointer to raw JPEG or EXIF data + * \param[in] size number of bytes of data at d + */ +void exif_data_load_data (ExifData *data, const unsigned char *d, + unsigned int size); + +/*! Store raw EXIF data representing the #ExifData structure into a memory + * buffer. The buffer is allocated by this function and must subsequently be + * freed by the caller using the matching free function as used by the #ExifMem + * in use by this #ExifData. + * + * \param[in] data EXIF data + * \param[out] d pointer to buffer pointer containing raw EXIF data on return + * \param[out] ds pointer to variable to hold the number of bytes of + * data at d, or set to 0 on error + */ +void exif_data_save_data (ExifData *data, unsigned char **d, + unsigned int *ds); + +void exif_data_ref (ExifData *data); +void exif_data_unref (ExifData *data); +void exif_data_free (ExifData *data); + +/*! Return the byte order in use by this EXIF structure. + * + * \param[in] data EXIF data + * \return byte order + */ +ExifByteOrder exif_data_get_byte_order (ExifData *data); + +/*! Set the byte order to use for this EXIF data. If any tags already exist + * (including MakerNote tags) they are are converted to the specified byte + * order. + * + * \param[in,out] data EXIF data + * \param[in] order byte order + */ +void exif_data_set_byte_order (ExifData *data, ExifByteOrder order); + +/*! Return the MakerNote data out of the EXIF data. Only certain + * MakerNote formats that are recognized by libexif are supported. + * The pointer references a member of the #ExifData structure and must NOT be + * freed by the caller. + * + * \param[in] d EXIF data + * \return MakerNote data, or NULL if not found or not supported + */ +ExifMnoteData *exif_data_get_mnote_data (ExifData *d); + +/*! Fix the EXIF data to bring it into specification. Call #exif_content_fix + * on each IFD to fix existing entries, create any new entries that are + * mandatory but do not yet exist, and remove any entries that are not + * allowed. + * + * \param[in,out] d EXIF data + */ +void exif_data_fix (ExifData *d); + +typedef void (* ExifDataForeachContentFunc) (ExifContent *, void *user_data); + +/*! Execute a function on each IFD in turn. + * + * \param[in] data EXIF data over which to iterate + * \param[in] func function to call for each entry + * \param[in] user_data data to pass into func on each call + */ +void exif_data_foreach_content (ExifData *data, + ExifDataForeachContentFunc func, + void *user_data); + +/*! Options to configure the behaviour of #ExifData */ +typedef enum { + /*! Act as though unknown tags are not present */ + EXIF_DATA_OPTION_IGNORE_UNKNOWN_TAGS = 1 << 0, + + /*! Fix the EXIF tags to follow the spec */ + EXIF_DATA_OPTION_FOLLOW_SPECIFICATION = 1 << 1, + + /*! Leave the MakerNote alone, which could cause it to be corrupted */ + EXIF_DATA_OPTION_DONT_CHANGE_MAKER_NOTE = 1 << 2 +} ExifDataOption; + +/*! Return a short textual description of the given #ExifDataOption. + * + * \param[in] o option + * \return localized textual description of the option + */ +const char *exif_data_option_get_name (ExifDataOption o); + +/*! Return a verbose textual description of the given #ExifDataOption. + * + * \param[in] o option + * \return verbose localized textual description of the option + */ +const char *exif_data_option_get_description (ExifDataOption o); + +/*! Set the given option on the given #ExifData. + * + * \param[in] d EXIF data + * \param[in] o option + */ +void exif_data_set_option (ExifData *d, ExifDataOption o); + +/*! Clear the given option on the given #ExifData. + * + * \param[in] d EXIF data + * \param[in] o option + */ +void exif_data_unset_option (ExifData *d, ExifDataOption o); + +/*! Set the data type for the given #ExifData. + * + * \param[in] d EXIF data + * \param[in] dt data type + */ +void exif_data_set_data_type (ExifData *d, ExifDataType dt); + +/*! Return the data type for the given #ExifData. + * + * \param[in] d EXIF data + * \return data type, or #EXIF_DATA_TYPE_UNKNOWN on error + */ +ExifDataType exif_data_get_data_type (ExifData *d); + +/*! Dump all EXIF data to stdout. + * This is intended for diagnostic purposes only. + * + * \param[in] data EXIF data + */ +void exif_data_dump (ExifData *data); + +/*! Set the log message object for all IFDs. + * + * \param[in] data EXIF data + * \param[in] log #ExifLog + */ +void exif_data_log (ExifData *data, ExifLog *log); + +/*! Return an #ExifEntry for the given tag if found in any IFD. + * Each IFD is searched in turn and the first containing a tag with + * this number is returned. + * + * \param[in] d #ExifData + * \param[in] t #ExifTag + * \return #ExifEntry* if found, else NULL if not found + */ +#define exif_data_get_entry(d,t) \ + (exif_content_get_entry(d->ifd[EXIF_IFD_0],t) ? \ + exif_content_get_entry(d->ifd[EXIF_IFD_0],t) : \ + exif_content_get_entry(d->ifd[EXIF_IFD_1],t) ? \ + exif_content_get_entry(d->ifd[EXIF_IFD_1],t) : \ + exif_content_get_entry(d->ifd[EXIF_IFD_EXIF],t) ? \ + exif_content_get_entry(d->ifd[EXIF_IFD_EXIF],t) : \ + exif_content_get_entry(d->ifd[EXIF_IFD_GPS],t) ? \ + exif_content_get_entry(d->ifd[EXIF_IFD_GPS],t) : \ + exif_content_get_entry(d->ifd[EXIF_IFD_INTEROPERABILITY],t) ? \ + exif_content_get_entry(d->ifd[EXIF_IFD_INTEROPERABILITY],t) : NULL) + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __EXIF_DATA_H__ */ diff --git a/libexif/exif-entry.c b/libexif/exif-entry.c new file mode 100644 index 0000000..54a90a2 --- /dev/null +++ b/libexif/exif-entry.c @@ -0,0 +1,1748 @@ +/* exif-entry.c + * + * Copyright (c) 2001 Lutz Mueller <lutz@users.sourceforge.net> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA. + */ + +#include <config.h> + +#include <libexif/exif-entry.h> +#include <libexif/exif-ifd.h> +#include <libexif/exif-utils.h> +#include <libexif/i18n.h> + +#include <ctype.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <time.h> +#include <math.h> + +#ifndef M_PI +#define M_PI 3.14159265358979323846 +#endif + +struct _ExifEntryPrivate +{ + unsigned int ref_count; + + ExifMem *mem; +}; + +/* This function is hidden in exif-data.c */ +ExifLog *exif_data_get_log (ExifData *); + +#ifndef NO_VERBOSE_TAG_STRINGS +static void +exif_entry_log (ExifEntry *e, ExifLogCode code, const char *format, ...) +{ + va_list args; + ExifLog *l = NULL; + + if (e && e->parent && e->parent->parent) + l = exif_data_get_log (e->parent->parent); + va_start (args, format); + exif_logv (l, code, "ExifEntry", format, args); + va_end (args); +} +#else +#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L +#define exif_entry_log(...) do { } while (0) +#elif defined(__GNUC__) +#define exif_entry_log(x...) do { } while (0) +#else +#define exif_entry_log (void) +#endif +#endif + +static void * +exif_entry_alloc (ExifEntry *e, unsigned int i) +{ + void *d; + ExifLog *l = NULL; + + if (!e || !e->priv || !i) return NULL; + + d = exif_mem_alloc (e->priv->mem, i); + if (d) return d; + + if (e->parent && e->parent->parent) + l = exif_data_get_log (e->parent->parent); + EXIF_LOG_NO_MEMORY (l, "ExifEntry", i); + return NULL; +} + +static void * +exif_entry_realloc (ExifEntry *e, void *d_orig, unsigned int i) +{ + void *d; + ExifLog *l = NULL; + + if (!e || !e->priv) return NULL; + + if (!i) { exif_mem_free (e->priv->mem, d_orig); return NULL; } + + d = exif_mem_realloc (e->priv->mem, d_orig, i); + if (d) return d; + + if (e->parent && e->parent->parent) + l = exif_data_get_log (e->parent->parent); + EXIF_LOG_NO_MEMORY (l, "ExifEntry", i); + return NULL; +} + +ExifEntry * +exif_entry_new (void) +{ + ExifMem *mem = exif_mem_new_default (); + ExifEntry *e = exif_entry_new_mem (mem); + + exif_mem_unref (mem); + + return e; +} + +ExifEntry * +exif_entry_new_mem (ExifMem *mem) +{ + ExifEntry *e = NULL; + + e = exif_mem_alloc (mem, sizeof (ExifEntry)); + if (!e) return NULL; + e->priv = exif_mem_alloc (mem, sizeof (ExifEntryPrivate)); + if (!e->priv) { exif_mem_free (mem, e); return NULL; } + e->priv->ref_count = 1; + + e->priv->mem = mem; + exif_mem_ref (mem); + + return e; +} + +void +exif_entry_ref (ExifEntry *e) +{ + if (!e) return; + + e->priv->ref_count++; +} + +void +exif_entry_unref (ExifEntry *e) +{ + if (!e) return; + + e->priv->ref_count--; + if (!e->priv->ref_count) + exif_entry_free (e); +} + +void +exif_entry_free (ExifEntry *e) +{ + if (!e) return; + + if (e->priv) { + ExifMem *mem = e->priv->mem; + if (e->data) + exif_mem_free (mem, e->data); + exif_mem_free (mem, e->priv); + exif_mem_free (mem, e); + exif_mem_unref (mem); + } +} + +/*! Get a value and convert it to an ExifShort. + * \bug Not all types are converted that could be converted and no indication + * is made when that occurs + */ +static inline ExifShort +exif_get_short_convert (const unsigned char *buf, ExifFormat format, + ExifByteOrder order) +{ + switch (format) { + case EXIF_FORMAT_LONG: + return (ExifShort) exif_get_long (buf, order); + case EXIF_FORMAT_SLONG: + return (ExifShort) exif_get_slong (buf, order); + case EXIF_FORMAT_SHORT: + return (ExifShort) exif_get_short (buf, order); + case EXIF_FORMAT_SSHORT: + return (ExifShort) exif_get_sshort (buf, order); + case EXIF_FORMAT_BYTE: + case EXIF_FORMAT_SBYTE: + return (ExifShort) buf[0]; + default: + /* Unsupported type */ + return (ExifShort) 0; + } +} + +void +exif_entry_fix (ExifEntry *e) +{ + unsigned int i, newsize; + unsigned char *newdata; + ExifByteOrder o; + ExifRational r; + ExifSRational sr; + + if (!e || !e->priv) return; + + switch (e->tag) { + + /* These tags all need to be of format SHORT. */ + case EXIF_TAG_YCBCR_SUB_SAMPLING: + case EXIF_TAG_SUBJECT_AREA: + case EXIF_TAG_COLOR_SPACE: + case EXIF_TAG_PLANAR_CONFIGURATION: + case EXIF_TAG_SENSING_METHOD: + case EXIF_TAG_ORIENTATION: + case EXIF_TAG_YCBCR_POSITIONING: + case EXIF_TAG_PHOTOMETRIC_INTERPRETATION: + case EXIF_TAG_CUSTOM_RENDERED: + case EXIF_TAG_EXPOSURE_MODE: + case EXIF_TAG_WHITE_BALANCE: + case EXIF_TAG_SCENE_CAPTURE_TYPE: + case EXIF_TAG_GAIN_CONTROL: + case EXIF_TAG_SATURATION: + case EXIF_TAG_CONTRAST: + case EXIF_TAG_SHARPNESS: + case EXIF_TAG_ISO_SPEED_RATINGS: + switch (e->format) { + case EXIF_FORMAT_LONG: + case EXIF_FORMAT_SLONG: + case EXIF_FORMAT_BYTE: + case EXIF_FORMAT_SBYTE: + case EXIF_FORMAT_SSHORT: + if (!e->parent || !e->parent->parent) break; + exif_entry_log (e, EXIF_LOG_CODE_DEBUG, + _("Tag '%s' was of format '%s' (which is " + "against specification) and has been " + "changed to format '%s'."), + exif_tag_get_name_in_ifd(e->tag, + exif_entry_get_ifd(e)), + exif_format_get_name (e->format), + exif_format_get_name (EXIF_FORMAT_SHORT)); + + o = exif_data_get_byte_order (e->parent->parent); + newsize = e->components * exif_format_get_size (EXIF_FORMAT_SHORT); + newdata = exif_entry_alloc (e, newsize); + if (!newdata) { + exif_entry_log (e, EXIF_LOG_CODE_NO_MEMORY, + "Could not allocate %lu byte(s).", (unsigned long)newsize); + break; + } + + for (i = 0; i < e->components; i++) + exif_set_short ( + newdata + i * + exif_format_get_size ( + EXIF_FORMAT_SHORT), o, + exif_get_short_convert ( + e->data + i * + exif_format_get_size (e->format), + e->format, o)); + + exif_mem_free (e->priv->mem, e->data); + e->data = newdata; + e->size = newsize; + e->format = EXIF_FORMAT_SHORT; + break; + case EXIF_FORMAT_SHORT: + /* No conversion necessary */ + break; + default: + exif_entry_log (e, EXIF_LOG_CODE_CORRUPT_DATA, + _("Tag '%s' is of format '%s' (which is " + "against specification) but cannot be changed " + "to format '%s'."), + exif_tag_get_name_in_ifd(e->tag, + exif_entry_get_ifd(e)), + exif_format_get_name (e->format), + exif_format_get_name (EXIF_FORMAT_SHORT)); + break; + } + break; + + /* All these tags need to be of format 'Rational'. */ + case EXIF_TAG_FNUMBER: + case EXIF_TAG_APERTURE_VALUE: + case EXIF_TAG_EXPOSURE_TIME: + case EXIF_TAG_FOCAL_LENGTH: + switch (e->format) { + case EXIF_FORMAT_SRATIONAL: + if (!e->parent || !e->parent->parent) break; + o = exif_data_get_byte_order (e->parent->parent); + for (i = 0; i < e->components; i++) { + sr = exif_get_srational (e->data + i * + exif_format_get_size ( + EXIF_FORMAT_SRATIONAL), o); + r.numerator = (ExifLong) sr.numerator; + r.denominator = (ExifLong) sr.denominator; + exif_set_rational (e->data + i * + exif_format_get_size ( + EXIF_FORMAT_RATIONAL), o, r); + } + e->format = EXIF_FORMAT_RATIONAL; + exif_entry_log (e, EXIF_LOG_CODE_DEBUG, + _("Tag '%s' was of format '%s' (which is " + "against specification) and has been " + "changed to format '%s'."), + exif_tag_get_name_in_ifd(e->tag, + exif_entry_get_ifd(e)), + exif_format_get_name (EXIF_FORMAT_SRATIONAL), + exif_format_get_name (EXIF_FORMAT_RATIONAL)); + break; + default: + break; + } + break; + + /* All these tags need to be of format 'SRational'. */ + case EXIF_TAG_EXPOSURE_BIAS_VALUE: + case EXIF_TAG_BRIGHTNESS_VALUE: + case EXIF_TAG_SHUTTER_SPEED_VALUE: + switch (e->format) { + case EXIF_FORMAT_RATIONAL: + if (!e->parent || !e->parent->parent) break; + o = exif_data_get_byte_order (e->parent->parent); + for (i = 0; i < e->components; i++) { + r = exif_get_rational (e->data + i * + exif_format_get_size ( + EXIF_FORMAT_RATIONAL), o); + sr.numerator = (ExifLong) r.numerator; + sr.denominator = (ExifLong) r.denominator; + exif_set_srational (e->data + i * + exif_format_get_size ( + EXIF_FORMAT_SRATIONAL), o, sr); + } + e->format = EXIF_FORMAT_SRATIONAL; + exif_entry_log (e, EXIF_LOG_CODE_DEBUG, + _("Tag '%s' was of format '%s' (which is " + "against specification) and has been " + "changed to format '%s'."), + exif_tag_get_name_in_ifd(e->tag, + exif_entry_get_ifd(e)), + exif_format_get_name (EXIF_FORMAT_RATIONAL), + exif_format_get_name (EXIF_FORMAT_SRATIONAL)); + break; + default: + break; + } + break; + + case EXIF_TAG_USER_COMMENT: + + /* Format needs to be UNDEFINED. */ + if (e->format != EXIF_FORMAT_UNDEFINED) { + exif_entry_log (e, EXIF_LOG_CODE_DEBUG, + _("Tag 'UserComment' had invalid format '%s'. " + "Format has been set to 'undefined'."), + exif_format_get_name (e->format)); + e->format = EXIF_FORMAT_UNDEFINED; + } + + /* Some packages like Canon ZoomBrowser EX 4.5 store + only one zero byte followed by 7 bytes of rubbish */ + if ((e->size >= 8) && (e->data[0] == 0)) { + memcpy(e->data, "\0\0\0\0\0\0\0\0", 8); + } + + /* There need to be at least 8 bytes. */ + if (e->size < 8) { + e->data = exif_entry_realloc (e, e->data, 8 + e->size); + if (!e->data) { + e->size = 0; + e->components = 0; + return; + } + + /* Assume ASCII */ + memmove (e->data + 8, e->data, e->size); + memcpy (e->data, "ASCII\0\0\0", 8); + e->size += 8; + e->components += 8; + exif_entry_log (e, EXIF_LOG_CODE_DEBUG, + _("Tag 'UserComment' has been expanded to at " + "least 8 bytes in order to follow the " + "specification.")); + break; + } + + /* + * If the first 8 bytes are empty and real data starts + * afterwards, let's assume ASCII and claim the 8 first + * bytes for the format specifyer. + */ + for (i = 0; (i < e->size) && !e->data[i]; i++); + if (!i) for ( ; (i < e->size) && (e->data[i] == ' '); i++); + if ((i >= 8) && (i < e->size)) { + exif_entry_log (e, EXIF_LOG_CODE_DEBUG, + _("Tag 'UserComment' is not empty but does not " + "start with a format identifier. " + "This has been fixed.")); + memcpy (e->data, "ASCII\0\0\0", 8); + break; + } + + /* + * First 8 bytes need to follow the specification. If they don't, + * assume ASCII. + */ + if (memcmp (e->data, "ASCII\0\0\0" , 8) && + memcmp (e->data, "UNICODE\0" , 8) && + memcmp (e->data, "JIS\0\0\0\0\0" , 8) && + memcmp (e->data, "\0\0\0\0\0\0\0\0", 8)) { + e->data = exif_entry_realloc (e, e->data, 8 + e->size); + if (!e->data) { + e->size = 0; + e->components = 0; + break; + } + + /* Assume ASCII */ + memmove (e->data + 8, e->data, e->size); + memcpy (e->data, "ASCII\0\0\0", 8); + e->size += 8; + e->components += 8; + exif_entry_log (e, EXIF_LOG_CODE_DEBUG, + _("Tag 'UserComment' did not start with a " + "format identifier. This has been fixed.")); + break; + } + + break; + default: + break; + } +} + +/*! Format the value of an ExifEntry for human display in a generic way. + * The output is localized. The formatting is independent of the tag number + * and is based entirely on the data type. + * \pre The ExifEntry is already a member of an ExifData. + * \param[in] e EXIF entry + * \param[out] val buffer in which to store value + * \param[in] maxlen one less than the length of the buffer val + */ +static void +exif_entry_format_value(ExifEntry *e, char *val, size_t maxlen) +{ + ExifByte v_byte; + ExifShort v_short; + ExifSShort v_sshort; + ExifLong v_long; + ExifRational v_rat; + ExifSRational v_srat; + ExifSLong v_slong; + unsigned int i; + size_t len; + const ExifByteOrder o = exif_data_get_byte_order (e->parent->parent); + + if (!e->size || !maxlen) + return; + ++maxlen; /* include the terminating NUL */ + switch (e->format) { + case EXIF_FORMAT_UNDEFINED: + snprintf (val, maxlen, _("%i bytes undefined data"), e->size); + break; + case EXIF_FORMAT_BYTE: + case EXIF_FORMAT_SBYTE: + v_byte = e->data[0]; + snprintf (val, maxlen, "0x%02x", v_byte); + len = strlen (val); + for (i = 1; i < e->components; i++) { + v_byte = e->data[i]; + snprintf (val+len, maxlen-len, ", 0x%02x", v_byte); + len += strlen (val+len); + if (len >= maxlen-1) break; + } + break; + case EXIF_FORMAT_SHORT: + v_short = exif_get_short (e->data, o); + snprintf (val, maxlen, "%u", v_short); + len = strlen (val); + for (i = 1; i < e->components; i++) { + v_short = exif_get_short (e->data + + exif_format_get_size (e->format) * i, o); + snprintf (val+len, maxlen-len, ", %u", v_short); + len += strlen (val+len); + if (len >= maxlen-1) break; + } + break; + case EXIF_FORMAT_SSHORT: + v_sshort = exif_get_sshort (e->data, o); + snprintf (val, maxlen, "%i", v_sshort); + len = strlen (val); + for (i = 1; i < e->components; i++) { + v_sshort = exif_get_short (e->data + + exif_format_get_size (e->format) * + i, o); + snprintf (val+len, maxlen-len, ", %i", v_sshort); + len += strlen (val+len); + if (len >= maxlen-1) break; + } + break; + case EXIF_FORMAT_LONG: + v_long = exif_get_long (e->data, o); + snprintf (val, maxlen, "%lu", (unsigned long) v_long); + len = strlen (val); + for (i = 1; i < e->components; i++) { + v_long = exif_get_long (e->data + + exif_format_get_size (e->format) * + i, o); + snprintf (val+len, maxlen-len, ", %lu", (unsigned long) v_long); + len += strlen (val+len); + if (len >= maxlen-1) break; + } + break; + case EXIF_FORMAT_SLONG: + v_slong = exif_get_slong (e->data, o); + snprintf (val, maxlen, "%li", (long) v_slong); + len = strlen (val); + for (i = 1; i < e->components; i++) { + v_slong = exif_get_slong (e->data + + exif_format_get_size (e->format) * i, o); + snprintf (val+len, maxlen-len, ", %li", (long) v_slong); + len += strlen (val+len); + if (len >= maxlen-1) break; + } + break; + case EXIF_FORMAT_ASCII: + strncpy (val, (char *) e->data, MIN (maxlen-1, e->size)); + val[MIN (maxlen-1, e->size)] = 0; + break; + case EXIF_FORMAT_RATIONAL: + len = 0; + for (i = 0; i < e->components; i++) { + if (i > 0) { + snprintf (val+len, maxlen-len, ", "); + len += strlen (val+len); + } + v_rat = exif_get_rational ( + e->data + 8 * i, o); + if (v_rat.denominator) { + /* + * Choose the number of significant digits to + * display based on the size of the denominator. + * It is scaled so that denominators within the + * range 13..120 will show 2 decimal points. + */ + int decimals = (int)(log10(v_rat.denominator)-0.08+1.0); + snprintf (val+len, maxlen-len, "%2.*f", + decimals, + (double) v_rat.numerator / + (double) v_rat.denominator); + } else + snprintf (val+len, maxlen-len, "%lu/%lu", + (unsigned long) v_rat.numerator, + (unsigned long) v_rat.denominator); + len += strlen (val+len); + if (len >= maxlen-1) break; + } + break; + case EXIF_FORMAT_SRATIONAL: + len = 0; + for (i = 0; i < e->components; i++) { + if (i > 0) { + snprintf (val+len, maxlen-len, ", "); + len += strlen (val+len); + } + v_srat = exif_get_srational ( + e->data + 8 * i, o); + if (v_srat.denominator) { + int decimals = (int)(log10(fabs(v_srat.denominator))-0.08+1.0); + snprintf (val+len, maxlen-len, "%2.*f", + decimals, + (double) v_srat.numerator / + (double) v_srat.denominator); + } else + snprintf (val+len, maxlen-len, "%li/%li", + (long) v_srat.numerator, + (long) v_srat.denominator); + len += strlen (val+len); + if (len >= maxlen-1) break; + } + break; + case EXIF_FORMAT_DOUBLE: + case EXIF_FORMAT_FLOAT: + default: + snprintf (val, maxlen, _("%i bytes unsupported data type"), + e->size); + break; + } +} + +void +exif_entry_dump (ExifEntry *e, unsigned int indent) +{ + char buf[1024]; + char value[1024]; + unsigned int i; + + for (i = 0; i < 2 * indent; i++) + buf[i] = ' '; + buf[i] = '\0'; + + if (!e) + return; + + printf ("%sTag: 0x%x ('%s')\n", buf, e->tag, + exif_tag_get_name_in_ifd (e->tag, exif_entry_get_ifd(e))); + printf ("%s Format: %i ('%s')\n", buf, e->format, + exif_format_get_name (e->format)); + printf ("%s Components: %i\n", buf, (int) e->components); + printf ("%s Size: %i\n", buf, e->size); + printf ("%s Value: %s\n", buf, exif_entry_get_value (e, value, sizeof(value))); +} + +/*! Check if a string consists entirely of a single, repeated character. + * Up to first n bytes are checked. + * + * \param[in] data pointer of string to check + * \param[in] ch character to match + * \param[in] n maximum number of characters to match + * + * \return 0 if the string matches or is of zero length, nonzero otherwise + */ +static int +match_repeated_char(const unsigned char *data, unsigned char ch, size_t n) +{ + int i; + for (i=n; i; --i, ++data) { + if (*data == 0) { + i = 0; /* all bytes before NUL matched */ + break; + } + if (*data != ch) + break; + } + return i; +} + +#define CF(entry,target,v,maxlen) \ +{ \ + if (entry->format != target) { \ + exif_entry_log (entry, EXIF_LOG_CODE_CORRUPT_DATA, \ + _("The tag '%s' contains data of an invalid " \ + "format ('%s', expected '%s')."), \ + exif_tag_get_name (entry->tag), \ + exif_format_get_name (entry->format), \ + exif_format_get_name (target)); \ + break; \ + } \ +} + +#define CC(entry,target,v,maxlen) \ +{ \ + if (entry->components != target) { \ + exif_entry_log (entry, EXIF_LOG_CODE_CORRUPT_DATA, \ + _("The tag '%s' contains an invalid number of " \ + "components (%i, expected %i)."), \ + exif_tag_get_name (entry->tag), \ + (int) entry->components, (int) target); \ + break; \ + } \ +} + +static const struct { + ExifTag tag; + const char *strings[10]; +} list[] = { +#ifndef NO_VERBOSE_TAG_DATA + { EXIF_TAG_PLANAR_CONFIGURATION, + { N_("Chunky format"), N_("Planar format"), NULL}}, + { EXIF_TAG_SENSING_METHOD, + { "", N_("Not defined"), N_("One-chip color area sensor"), + N_("Two-chip color area sensor"), N_("Three-chip color area sensor"), + N_("Color sequential area sensor"), "", N_("Trilinear sensor"), + N_("Color sequential linear sensor"), NULL}}, + { EXIF_TAG_ORIENTATION, + { "", N_("Top-left"), N_("Top-right"), N_("Bottom-right"), + N_("Bottom-left"), N_("Left-top"), N_("Right-top"), + N_("Right-bottom"), N_("Left-bottom"), NULL}}, + { EXIF_TAG_YCBCR_POSITIONING, + { "", N_("Centered"), N_("Co-sited"), NULL}}, + { EXIF_TAG_PHOTOMETRIC_INTERPRETATION, + { N_("Reversed mono"), N_("Normal mono"), N_("RGB"), N_("Palette"), "", + N_("CMYK"), N_("YCbCr"), "", N_("CieLAB"), NULL}}, + { EXIF_TAG_CUSTOM_RENDERED, + { N_("Normal process"), N_("Custom process"), NULL}}, + { EXIF_TAG_EXPOSURE_MODE, + { N_("Auto exposure"), N_("Manual exposure"), N_("Auto bracket"), NULL}}, + { EXIF_TAG_WHITE_BALANCE, + { N_("Auto white balance"), N_("Manual white balance"), NULL}}, + { EXIF_TAG_SCENE_CAPTURE_TYPE, + { N_("Standard"), N_("Landscape"), N_("Portrait"), + N_("Night scene"), NULL}}, + { EXIF_TAG_GAIN_CONTROL, + { N_("Normal"), N_("Low gain up"), N_("High gain up"), + N_("Low gain down"), N_("High gain down"), NULL}}, + { EXIF_TAG_SATURATION, + { N_("Normal"), N_("Low saturation"), N_("High saturation"), NULL}}, + { EXIF_TAG_CONTRAST , {N_("Normal"), N_("Soft"), N_("Hard"), NULL}}, + { EXIF_TAG_SHARPNESS, {N_("Normal"), N_("Soft"), N_("Hard"), NULL}}, +#endif + { 0, {NULL}} +}; + +static const struct { + ExifTag tag; + struct { + int index; + const char *values[4]; /*!< list of progressively shorter string + descriptions; the longest one that fits will be + selected */ + } elem[25]; +} list2[] = { +#ifndef NO_VERBOSE_TAG_DATA + { EXIF_TAG_METERING_MODE, + { { 0, {N_("Unknown"), NULL}}, + { 1, {N_("Average"), N_("Avg"), NULL}}, + { 2, {N_("Center-weighted average"), N_("Center-weight"), NULL}}, + { 3, {N_("Spot"), NULL}}, + { 4, {N_("Multi spot"), NULL}}, + { 5, {N_("Pattern"), NULL}}, + { 6, {N_("Partial"), NULL}}, + {255, {N_("Other"), NULL}}, + { 0, {NULL}}}}, + { EXIF_TAG_COMPRESSION, + { {1, {N_("Uncompressed"), NULL}}, + {5, {N_("LZW compression"), NULL}}, + {6, {N_("JPEG compression"), NULL}}, + {7, {N_("JPEG compression"), NULL}}, + {8, {N_("Deflate/ZIP compression"), NULL}}, + {32773, {N_("PackBits compression"), NULL}}, + {0, {NULL}}}}, + { EXIF_TAG_LIGHT_SOURCE, + { { 0, {N_("Unknown"), NULL}}, + { 1, {N_("Daylight"), NULL}}, + { 2, {N_("Fluorescent"), NULL}}, + { 3, {N_("Tungsten incandescent light"), N_("Tungsten"), NULL}}, + { 4, {N_("Flash"), NULL}}, + { 9, {N_("Fine weather"), NULL}}, + { 10, {N_("Cloudy weather"), N_("Cloudy"), NULL}}, + { 11, {N_("Shade"), NULL}}, + { 12, {N_("Daylight fluorescent"), NULL}}, + { 13, {N_("Day white fluorescent"), NULL}}, + { 14, {N_("Cool white fluorescent"), NULL}}, + { 15, {N_("White fluorescent"), NULL}}, + { 17, {N_("Standard light A"), NULL}}, + { 18, {N_("Standard light B"), NULL}}, + { 19, {N_("Standard light C"), NULL}}, + { 20, {N_("D55"), NULL}}, + { 21, {N_("D65"), NULL}}, + { 22, {N_("D75"), NULL}}, + { 24, {N_("ISO studio tungsten"),NULL}}, + {255, {N_("Other"), NULL}}, + { 0, {NULL}}}}, + { EXIF_TAG_FOCAL_PLANE_RESOLUTION_UNIT, + { {2, {N_("Inch"), N_("in"), NULL}}, + {3, {N_("Centimeter"), N_("cm"), NULL}}, + {0, {NULL}}}}, + { EXIF_TAG_RESOLUTION_UNIT, + { {2, {N_("Inch"), N_("in"), NULL}}, + {3, {N_("Centimeter"), N_("cm"), NULL}}, + {0, {NULL}}}}, + { EXIF_TAG_EXPOSURE_PROGRAM, + { {0, {N_("Not defined"), NULL}}, + {1, {N_("Manual"), NULL}}, + {2, {N_("Normal program"), N_("Normal"), NULL}}, + {3, {N_("Aperture priority"), N_("Aperture"), NULL}}, + {4, {N_("Shutter priority"),N_("Shutter"), NULL}}, + {5, {N_("Creative program (biased toward depth of field)"), + N_("Creative"), NULL}}, + {6, {N_("Creative program (biased toward fast shutter speed)"), + N_("Action"), NULL}}, + {7, {N_("Portrait mode (for closeup photos with the background out " + "of focus)"), N_("Portrait"), NULL}}, + {8, {N_("Landscape mode (for landscape photos with the background " + "in focus)"), N_("Landscape"), NULL}}, + {0, {NULL}}}}, + { EXIF_TAG_FLASH, + { {0x0000, {N_("Flash did not fire"), N_("No flash"), NULL}}, + {0x0001, {N_("Flash fired"), N_("Flash"), N_("Yes"), NULL}}, + {0x0005, {N_("Strobe return light not detected"), N_("Without strobe"), + NULL}}, + {0x0007, {N_("Strobe return light detected"), N_("With strobe"), NULL}}, + {0x0008, {N_("Flash did not fire"), NULL}}, /* Olympus E-330 */ + {0x0009, {N_("Flash fired, compulsory flash mode"), NULL}}, + {0x000d, {N_("Flash fired, compulsory flash mode, return light " + "not detected"), NULL}}, + {0x000f, {N_("Flash fired, compulsory flash mode, return light " + "detected"), NULL}}, + {0x0010, {N_("Flash did not fire, compulsory flash mode"), NULL}}, + {0x0018, {N_("Flash did not fire, auto mode"), NULL}}, + {0x0019, {N_("Flash fired, auto mode"), NULL}}, + {0x001d, {N_("Flash fired, auto mode, return light not detected"), + NULL}}, + {0x001f, {N_("Flash fired, auto mode, return light detected"), NULL}}, + {0x0020, {N_("No flash function"),NULL}}, + {0x0041, {N_("Flash fired, red-eye reduction mode"), NULL}}, + {0x0045, {N_("Flash fired, red-eye reduction mode, return light " + "not detected"), NULL}}, + {0x0047, {N_("Flash fired, red-eye reduction mode, return light " + "detected"), NULL}}, + {0x0049, {N_("Flash fired, compulsory flash mode, red-eye reduction " + "mode"), NULL}}, + {0x004d, {N_("Flash fired, compulsory flash mode, red-eye reduction " + "mode, return light not detected"), NULL}}, + {0x004f, {N_("Flash fired, compulsory flash mode, red-eye reduction mode, " + "return light detected"), NULL}}, + {0x0058, {N_("Flash did not fire, auto mode, red-eye reduction mode"), NULL}}, + {0x0059, {N_("Flash fired, auto mode, red-eye reduction mode"), NULL}}, + {0x005d, {N_("Flash fired, auto mode, return light not detected, " + "red-eye reduction mode"), NULL}}, + {0x005f, {N_("Flash fired, auto mode, return light detected, " + "red-eye reduction mode"), NULL}}, + {0x0000, {NULL}}}}, + { EXIF_TAG_SUBJECT_DISTANCE_RANGE, + { {0, {N_("Unknown"), N_("?"), NULL}}, + {1, {N_("Macro"), NULL}}, + {2, {N_("Close view"), N_("Close"), NULL}}, + {3, {N_("Distant view"), N_("Distant"), NULL}}, + {0, {NULL}}}}, + { EXIF_TAG_COLOR_SPACE, + { {1, {N_("sRGB"), NULL}}, + {2, {N_("Adobe RGB"), NULL}}, + {0xffff, {N_("Uncalibrated"), NULL}}, + {0x0000, {NULL}}}}, +#endif + {0, { { 0, {NULL}}} } +}; + +const char * +exif_entry_get_value (ExifEntry *e, char *val, unsigned int maxlen) +{ + unsigned int i, j, k; + ExifShort v_short, v_short2, v_short3, v_short4; + ExifByte v_byte; + ExifRational v_rat; + ExifSRational v_srat; + char b[64]; + const char *c; + ExifByteOrder o; + double d; + ExifEntry *entry; + static const struct { + char label[5]; + char major, minor; + } versions[] = { + {"0110", 1, 1}, + {"0120", 1, 2}, + {"0200", 2, 0}, + {"0210", 2, 1}, + {"0220", 2, 2}, + {"0221", 2, 21}, + {"0230", 2, 3}, + {"" , 0, 0} + }; + + /* FIXME: This belongs to somewhere else. */ + /* libexif should use the default system locale. + * If an application specifically requires UTF-8, then we + * must give the application a way to tell libexif that. + * + * bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8"); + */ + bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR); + + if (!e || !e->parent || !e->parent->parent || !maxlen) + return val; + + /* make sure the returned string is zero terminated */ + memset (val, 0, maxlen); + maxlen--; + memset (b, 0, sizeof (b)); + + /* We need the byte order */ + o = exif_data_get_byte_order (e->parent->parent); + + /* Sanity check */ + if (e->size != e->components * exif_format_get_size (e->format)) { + snprintf (val, maxlen, _("Invalid size of entry (%i, " + "expected %li x %i)."), e->size, e->components, + exif_format_get_size (e->format)); + return val; + } + + switch (e->tag) { + case EXIF_TAG_USER_COMMENT: + + /* + * The specification says UNDEFINED, but some + * manufacturers don't care and use ASCII. If this is the + * case here, only refuse to read it if there is no chance + * of finding readable data. + */ + if ((e->format != EXIF_FORMAT_ASCII) || + (e->size <= 8) || + ( memcmp (e->data, "ASCII\0\0\0" , 8) && + memcmp (e->data, "UNICODE\0" , 8) && + memcmp (e->data, "JIS\0\0\0\0\0", 8) && + memcmp (e->data, "\0\0\0\0\0\0\0\0", 8))) + CF (e, EXIF_FORMAT_UNDEFINED, val, maxlen); + + /* + * Note that, according to the specification (V2.1, p 40), + * the user comment field does not have to be + * NULL terminated. + */ + if ((e->size >= 8) && !memcmp (e->data, "ASCII\0\0\0", 8)) { + strncpy (val, (char *) e->data + 8, MIN (e->size - 8, maxlen)); + break; + } + if ((e->size >= 8) && !memcmp (e->data, "UNICODE\0", 8)) { + strncpy (val, _("Unsupported UNICODE string"), maxlen); + /* FIXME: use iconv to convert into the locale encoding. + * EXIF 2.2 implies (but does not say) that this encoding is + * UCS-2. + */ + break; + } + if ((e->size >= 8) && !memcmp (e->data, "JIS\0\0\0\0\0", 8)) { + strncpy (val, _("Unsupported JIS string"), maxlen); + /* FIXME: use iconv to convert into the locale encoding */ + break; + } + + /* Check if there is really some information in the tag. */ + for (i = 0; (i < e->size) && + (!e->data[i] || (e->data[i] == ' ')); i++); + if (i == e->size) break; + + /* + * If we reach this point, the tag does not + * comply with the standard but seems to contain data. + * Print as much as possible. + */ + exif_entry_log (e, EXIF_LOG_CODE_DEBUG, + _("Tag UserComment contains data but is " + "against specification.")); + for (j = 0; (i < e->size) && (j < maxlen); i++, j++) { + exif_entry_log (e, EXIF_LOG_CODE_DEBUG, + _("Byte at position %i: 0x%02x"), i, e->data[i]); + val[j] = isprint (e->data[i]) ? e->data[i] : '.'; + } + break; + + case EXIF_TAG_EXIF_VERSION: + CF (e, EXIF_FORMAT_UNDEFINED, val, maxlen); + CC (e, 4, val, maxlen); + strncpy (val, _("Unknown Exif Version"), maxlen); + for (i = 0; *versions[i].label; i++) { + if (!memcmp (e->data, versions[i].label, 4)) { + snprintf (val, maxlen, + _("Exif Version %d.%d"), + versions[i].major, + versions[i].minor); + break; + } + } + break; + case EXIF_TAG_FLASH_PIX_VERSION: + CF (e, EXIF_FORMAT_UNDEFINED, val, maxlen); + CC (e, 4, val, maxlen); + if (!memcmp (e->data, "0100", 4)) + strncpy (val, _("FlashPix Version 1.0"), maxlen); + else if (!memcmp (e->data, "0101", 4)) + strncpy (val, _("FlashPix Version 1.01"), maxlen); + else + strncpy (val, _("Unknown FlashPix Version"), maxlen); + break; + case EXIF_TAG_COPYRIGHT: + CF (e, EXIF_FORMAT_ASCII, val, maxlen); + + /* + * First part: Photographer. + * Some cameras store a string like " " here. Ignore it. + * Remember that a corrupted tag might not be NUL-terminated + */ + if (e->size && e->data && match_repeated_char(e->data, ' ', e->size)) + strncpy (val, (char *) e->data, MIN (maxlen, e->size)); + else + strncpy (val, _("[None]"), maxlen); + strncat (val, " ", maxlen - strlen (val)); + strncat (val, _("(Photographer)"), maxlen - strlen (val)); + + /* Second part: Editor. */ + strncat (val, " - ", maxlen - strlen (val)); + k = 0; + if (e->size && e->data) { + const unsigned char *tagdata = memchr(e->data, 0, e->size); + if (tagdata++) { + int editor_ofs = tagdata - e->data; + int remaining = e->size - editor_ofs; + if (match_repeated_char(tagdata, ' ', remaining)) { + strncat (val, (const char*)tagdata, MIN (maxlen - strlen (val), remaining)); + ++k; + } + } + } + if (!k) + strncat (val, _("[None]"), maxlen - strlen (val)); + strncat (val, " ", maxlen - strlen (val)); + strncat (val, _("(Editor)"), maxlen - strlen (val)); + + break; + case EXIF_TAG_FNUMBER: + CF (e, EXIF_FORMAT_RATIONAL, val, maxlen); + CC (e, 1, val, maxlen); + v_rat = exif_get_rational (e->data, o); + if (!v_rat.denominator) { + exif_entry_format_value(e, val, maxlen); + break; + } + d = (double) v_rat.numerator / (double) v_rat.denominator; + snprintf (val, maxlen, "f/%.01f", d); + break; + case EXIF_TAG_APERTURE_VALUE: + case EXIF_TAG_MAX_APERTURE_VALUE: + CF (e, EXIF_FORMAT_RATIONAL, val, maxlen); + CC (e, 1, val, maxlen); + v_rat = exif_get_rational (e->data, o); + if (!v_rat.denominator || (0x80000000 == v_rat.numerator)) { + exif_entry_format_value(e, val, maxlen); + break; + } + d = (double) v_rat.numerator / (double) v_rat.denominator; + snprintf (val, maxlen, _("%.02f EV"), d); + snprintf (b, sizeof (b), _(" (f/%.01f)"), pow (2, d / 2.)); + if (maxlen > strlen (val) + strlen (b)) + strncat (val, b, maxlen - strlen (val)); + break; + case EXIF_TAG_FOCAL_LENGTH: + CF (e, EXIF_FORMAT_RATIONAL, val, maxlen); + CC (e, 1, val, maxlen); + v_rat = exif_get_rational (e->data, o); + if (!v_rat.denominator) { + exif_entry_format_value(e, val, maxlen); + break; + } + + /* + * For calculation of the 35mm equivalent, + * Minolta cameras need a multiplier that depends on the + * camera model. + */ + d = 0.; + entry = exif_content_get_entry ( + e->parent->parent->ifd[EXIF_IFD_0], EXIF_TAG_MAKE); + if (entry && entry->data && + !strncmp ((char *)entry->data, "Minolta", 7)) { + entry = exif_content_get_entry ( + e->parent->parent->ifd[EXIF_IFD_0], + EXIF_TAG_MODEL); + if (entry && entry->data) { + if (!strncmp ((char *)entry->data, "DiMAGE 7", 8)) + d = 3.9; + else if (!strncmp ((char *)entry->data, "DiMAGE 5", 8)) + d = 4.9; + } + } + if (d) + snprintf (b, sizeof (b), _(" (35 equivalent: %d mm)"), + (int) (d * (double) v_rat.numerator / + (double) v_rat.denominator)); + + d = (double) v_rat.numerator / (double) v_rat.denominator; + snprintf (val, maxlen, "%.1f mm", d); + if (maxlen > strlen (val) + strlen (b)) + strncat (val, b, maxlen - strlen (val)); + break; + case EXIF_TAG_SUBJECT_DISTANCE: + CF (e, EXIF_FORMAT_RATIONAL, val, maxlen); + CC (e, 1, val, maxlen); + v_rat = exif_get_rational (e->data, o); + if (!v_rat.denominator) { + exif_entry_format_value(e, val, maxlen); + break; + } + d = (double) v_rat.numerator / (double) v_rat.denominator; + snprintf (val, maxlen, "%.1f m", d); + break; + case EXIF_TAG_EXPOSURE_TIME: + CF (e, EXIF_FORMAT_RATIONAL, val, maxlen); + CC (e, 1, val, maxlen); + v_rat = exif_get_rational (e->data, o); + if (!v_rat.denominator) { + exif_entry_format_value(e, val, maxlen); + break; + } + d = (double) v_rat.numerator / (double) v_rat.denominator; + if (d < 1) + snprintf (val, maxlen, _("1/%i"), (int) (0.5 + 1. / d)); + else + snprintf (val, maxlen, "%i", (int) d); + if (maxlen > strlen (val) + strlen (_(" sec."))) + strncat (val, _(" sec."), maxlen - strlen (val)); + break; + case EXIF_TAG_SHUTTER_SPEED_VALUE: + CF (e, EXIF_FORMAT_SRATIONAL, val, maxlen); + CC (e, 1, val, maxlen); + v_srat = exif_get_srational (e->data, o); + if (!v_srat.denominator) { + exif_entry_format_value(e, val, maxlen); + break; + } + d = (double) v_srat.numerator / (double) v_srat.denominator; + snprintf (val, maxlen, _("%.02f EV"), d); + d = 1. / pow (2, d); + if (d < 1) + snprintf (b, sizeof (b), _(" (1/%d sec.)"), (int) (1. / d)); + else + snprintf (b, sizeof (b), _(" (%d sec.)"), (int) d); + strncat (val, b, maxlen - strlen (val)); + break; + case EXIF_TAG_BRIGHTNESS_VALUE: + CF (e, EXIF_FORMAT_SRATIONAL, val, maxlen); + CC (e, 1, val, maxlen); + v_srat = exif_get_srational (e->data, o); + if (!v_srat.denominator) { + exif_entry_format_value(e, val, maxlen); + break; + } + d = (double) v_srat.numerator / (double) v_srat.denominator; + snprintf (val, maxlen, _("%.02f EV"), d); + snprintf (b, sizeof (b), _(" (%.02f cd/m^2)"), + 1. / (M_PI * 0.3048 * 0.3048) * pow (2, d)); + if (maxlen > strlen (val) + strlen (b)) + strncat (val, b, maxlen - strlen (val)); + break; + case EXIF_TAG_FILE_SOURCE: + CF (e, EXIF_FORMAT_UNDEFINED, val, maxlen); + CC (e, 1, val, maxlen); + v_byte = e->data[0]; + if (v_byte == 3) + strncpy (val, _("DSC"), maxlen); + else + snprintf (val, maxlen, _("Internal error (unknown " + "value %i)"), v_byte); + break; + case EXIF_TAG_COMPONENTS_CONFIGURATION: + CF (e, EXIF_FORMAT_UNDEFINED, val, maxlen); + CC (e, 4, val, maxlen); + for (i = 0; i < 4; i++) { + switch (e->data[i]) { + case 0: c = _("-"); break; + case 1: c = _("Y"); break; + case 2: c = _("Cb"); break; + case 3: c = _("Cr"); break; + case 4: c = _("R"); break; + case 5: c = _("G"); break; + case 6: c = _("B"); break; + default: c = _("Reserved"); break; + } + strncat (val, c, maxlen - strlen (val)); + if (i < 3) + strncat (val, " ", maxlen - strlen (val)); + } + break; + case EXIF_TAG_EXPOSURE_BIAS_VALUE: + CF (e, EXIF_FORMAT_SRATIONAL, val, maxlen); + CC (e, 1, val, maxlen); + v_srat = exif_get_srational (e->data, o); + if (!v_srat.denominator) { + exif_entry_format_value(e, val, maxlen); + break; + } + d = (double) v_srat.numerator / (double) v_srat.denominator; + snprintf (val, maxlen, _("%.02f EV"), d); + break; + case EXIF_TAG_SCENE_TYPE: + CF (e, EXIF_FORMAT_UNDEFINED, val, maxlen); + CC (e, 1, val, maxlen); + v_byte = e->data[0]; + if (v_byte == 1) + strncpy (val, _("Directly photographed"), maxlen); + else + snprintf (val, maxlen, _("Internal error (unknown " + "value %i)"), v_byte); + break; + case EXIF_TAG_YCBCR_SUB_SAMPLING: + CF (e, EXIF_FORMAT_SHORT, val, maxlen); + CC (e, 2, val, maxlen); + v_short = exif_get_short (e->data, o); + v_short2 = exif_get_short ( + e->data + exif_format_get_size (e->format), + o); + if ((v_short == 2) && (v_short2 == 1)) + strncpy (val, _("YCbCr4:2:2"), maxlen); + else if ((v_short == 2) && (v_short2 == 2)) + strncpy (val, _("YCbCr4:2:0"), maxlen); + else + snprintf (val, maxlen, "%u, %u", v_short, v_short2); + break; + case EXIF_TAG_SUBJECT_AREA: + CF (e, EXIF_FORMAT_SHORT, val, maxlen); + switch (e->components) { + case 2: + v_short = exif_get_short (e->data, o); + v_short2 = exif_get_short (e->data + 2, o); + snprintf (val, maxlen, "(x,y) = (%i,%i)", + v_short, v_short2); + break; + case 3: + v_short = exif_get_short (e->data, o); + v_short2 = exif_get_short (e->data + 2, o); + v_short3 = exif_get_short (e->data + 4, o); + snprintf (val, maxlen, _("Within distance %i of " + "(x,y) = (%i,%i)"), v_short3, v_short, + v_short2); + break; + case 4: + v_short = exif_get_short (e->data, o); + v_short2 = exif_get_short (e->data + 2, o); + v_short3 = exif_get_short (e->data + 4, o); + v_short4 = exif_get_short (e->data + 6, o); + snprintf (val, maxlen, _("Within rectangle " + "(width %i, height %i) around " + "(x,y) = (%i,%i)"), v_short3, v_short4, + v_short, v_short2); + break; + default: + snprintf (val, maxlen, _("Unexpected number " + "of components (%li, expected 2, 3, or 4)."), + e->components); + } + break; + case EXIF_TAG_GPS_VERSION_ID: + /* This is only valid in the GPS IFD */ + CF (e, EXIF_FORMAT_BYTE, val, maxlen); + CC (e, 4, val, maxlen); + v_byte = e->data[0]; + snprintf (val, maxlen, "%u", v_byte); + maxlen -= strlen (val); + for (i = 1; i < e->components; i++) { + v_byte = e->data[i]; + snprintf (b, sizeof (b), ".%u", v_byte); + strncat (val, b, maxlen); + maxlen -= strlen (b); + if ((signed)maxlen <= 0) break; + } + break; + case EXIF_TAG_INTEROPERABILITY_VERSION: + /* a.k.a. case EXIF_TAG_GPS_LATITUDE: */ + /* This tag occurs in EXIF_IFD_INTEROPERABILITY */ + if (e->format == EXIF_FORMAT_UNDEFINED) { + strncpy (val, (char *) e->data, MIN (maxlen, e->size)); + break; + } + /* EXIF_TAG_GPS_LATITUDE is the same numerically as + * EXIF_TAG_INTEROPERABILITY_VERSION but in EXIF_IFD_GPS + */ + exif_entry_format_value(e, val, maxlen); + break; + case EXIF_TAG_GPS_ALTITUDE_REF: + /* This is only valid in the GPS IFD */ + CF (e, EXIF_FORMAT_BYTE, val, maxlen); + CC (e, 1, val, maxlen); + v_byte = e->data[0]; + if (v_byte == 0) + strncpy (val, _("Sea level"), maxlen); + else if (v_byte == 1) + strncpy (val, _("Sea level reference"), maxlen); + else + snprintf (val, maxlen, _("Internal error (unknown " + "value %i)"), v_byte); + break; + case EXIF_TAG_GPS_TIME_STAMP: + /* This is only valid in the GPS IFD */ + CF (e, EXIF_FORMAT_RATIONAL, val, maxlen); + CC (e, 3, val, maxlen); + + v_rat = exif_get_rational (e->data, o); + if (!v_rat.denominator) { + exif_entry_format_value(e, val, maxlen); + break; + } + i = v_rat.numerator / v_rat.denominator; + + v_rat = exif_get_rational (e->data + + exif_format_get_size (e->format), + o); + if (!v_rat.denominator) { + exif_entry_format_value(e, val, maxlen); + break; + } + j = v_rat.numerator / v_rat.denominator; + + v_rat = exif_get_rational (e->data + + 2*exif_format_get_size (e->format), + o); + if (!v_rat.denominator) { + exif_entry_format_value(e, val, maxlen); + break; + } + d = (double) v_rat.numerator / (double) v_rat.denominator; + snprintf (val, maxlen, "%02u:%02u:%05.2f", i, j, d); + break; + + case EXIF_TAG_METERING_MODE: + case EXIF_TAG_COMPRESSION: + case EXIF_TAG_LIGHT_SOURCE: + case EXIF_TAG_FOCAL_PLANE_RESOLUTION_UNIT: + case EXIF_TAG_RESOLUTION_UNIT: + case EXIF_TAG_EXPOSURE_PROGRAM: + case EXIF_TAG_FLASH: + case EXIF_TAG_SUBJECT_DISTANCE_RANGE: + case EXIF_TAG_COLOR_SPACE: + CF (e,EXIF_FORMAT_SHORT, val, maxlen); + CC (e, 1, val, maxlen); + v_short = exif_get_short (e->data, o); + + /* Search the tag */ + for (i = 0; list2[i].tag && (list2[i].tag != e->tag); i++); + if (!list2[i].tag) { + snprintf (val, maxlen, _("Internal error (unknown " + "value %i)"), v_short); + break; + } + + /* Find the value */ + for (j = 0; list2[i].elem[j].values[0] && + (list2[i].elem[j].index < v_short); j++); + if (list2[i].elem[j].index != v_short) { + snprintf (val, maxlen, _("Internal error (unknown " + "value %i)"), v_short); + break; + } + + /* Find a short enough value */ + memset (val, 0, maxlen); + for (k = 0; list2[i].elem[j].values[k]; k++) { + size_t l = strlen (_(list2[i].elem[j].values[k])); + if ((maxlen > l) && (strlen (val) < l)) + strncpy (val, _(list2[i].elem[j].values[k]), maxlen); + } + if (!val[0]) snprintf (val, maxlen, "%i", v_short); + + break; + + case EXIF_TAG_PLANAR_CONFIGURATION: + case EXIF_TAG_SENSING_METHOD: + case EXIF_TAG_ORIENTATION: + case EXIF_TAG_YCBCR_POSITIONING: + case EXIF_TAG_PHOTOMETRIC_INTERPRETATION: + case EXIF_TAG_CUSTOM_RENDERED: + case EXIF_TAG_EXPOSURE_MODE: + case EXIF_TAG_WHITE_BALANCE: + case EXIF_TAG_SCENE_CAPTURE_TYPE: + case EXIF_TAG_GAIN_CONTROL: + case EXIF_TAG_SATURATION: + case EXIF_TAG_CONTRAST: + case EXIF_TAG_SHARPNESS: + CF (e, EXIF_FORMAT_SHORT, val, maxlen); + CC (e, 1, val, maxlen); + v_short = exif_get_short (e->data, o); + + /* Search the tag */ + for (i = 0; list[i].tag && (list[i].tag != e->tag); i++); + if (!list[i].tag) { + snprintf (val, maxlen, _("Internal error (unknown " + "value %i)"), v_short); + break; + } + + /* Find the value */ + for (j = 0; list[i].strings[j] && (j < v_short); j++); + if (!list[i].strings[j]) + snprintf (val, maxlen, "%i", v_short); + else if (!*list[i].strings[j]) + snprintf (val, maxlen, _("Unknown value %i"), v_short); + else + strncpy (val, _(list[i].strings[j]), maxlen); + break; + + case EXIF_TAG_XP_TITLE: + case EXIF_TAG_XP_COMMENT: + case EXIF_TAG_XP_AUTHOR: + case EXIF_TAG_XP_KEYWORDS: + case EXIF_TAG_XP_SUBJECT: + { + /* Sanity check the size to prevent overflow */ + if (e->size+sizeof(unsigned short) < e->size) break; + + /* The tag may not be U+0000-terminated , so make a local + U+0000-terminated copy before converting it */ + unsigned short *utf16 = exif_mem_alloc (e->priv->mem, e->size+sizeof(unsigned short)); + if (!utf16) break; + memcpy(utf16, e->data, e->size); + utf16[e->size/sizeof(unsigned short)] = 0; + + /* Warning! The texts are converted from UTF16 to UTF8 */ + /* FIXME: use iconv to convert into the locale encoding */ + exif_convert_utf16_to_utf8(val, utf16, maxlen); + exif_mem_free(e->priv->mem, utf16); + break; + } + + default: + /* Use a generic value formatting */ + exif_entry_format_value(e, val, maxlen); + } + + return val; +} + + +/*! + * \bug Log and report failed exif_mem_malloc() calls. + */ +void +exif_entry_initialize (ExifEntry *e, ExifTag tag) +{ + ExifRational r; + ExifByteOrder o; + + /* We need the byte order */ + if (!e || !e->parent || e->data || !e->parent->parent) + return; + o = exif_data_get_byte_order (e->parent->parent); + + e->tag = tag; + switch (tag) { + + /* LONG, 1 component, no default */ + case EXIF_TAG_PIXEL_X_DIMENSION: + case EXIF_TAG_PIXEL_Y_DIMENSION: + case EXIF_TAG_EXIF_IFD_POINTER: + case EXIF_TAG_GPS_INFO_IFD_POINTER: + case EXIF_TAG_INTEROPERABILITY_IFD_POINTER: + case EXIF_TAG_JPEG_INTERCHANGE_FORMAT_LENGTH: + case EXIF_TAG_JPEG_INTERCHANGE_FORMAT: + e->components = 1; + e->format = EXIF_FORMAT_LONG; + e->size = exif_format_get_size (e->format) * e->components; + e->data = exif_entry_alloc (e, e->size); + if (!e->data) break; + break; + + /* SHORT, 1 component, no default */ + case EXIF_TAG_SUBJECT_LOCATION: + case EXIF_TAG_SENSING_METHOD: + case EXIF_TAG_PHOTOMETRIC_INTERPRETATION: + case EXIF_TAG_COMPRESSION: + case EXIF_TAG_EXPOSURE_MODE: + case EXIF_TAG_WHITE_BALANCE: + case EXIF_TAG_FOCAL_LENGTH_IN_35MM_FILM: + case EXIF_TAG_GAIN_CONTROL: + case EXIF_TAG_SUBJECT_DISTANCE_RANGE: + case EXIF_TAG_FLASH: + case EXIF_TAG_ISO_SPEED_RATINGS: + + /* SHORT, 1 component, default 0 */ + case EXIF_TAG_IMAGE_WIDTH: + case EXIF_TAG_IMAGE_LENGTH: + case EXIF_TAG_EXPOSURE_PROGRAM: + case EXIF_TAG_LIGHT_SOURCE: + case EXIF_TAG_METERING_MODE: + case EXIF_TAG_CUSTOM_RENDERED: + case EXIF_TAG_SCENE_CAPTURE_TYPE: + case EXIF_TAG_CONTRAST: + case EXIF_TAG_SATURATION: + case EXIF_TAG_SHARPNESS: + e->components = 1; + e->format = EXIF_FORMAT_SHORT; + e->size = exif_format_get_size (e->format) * e->components; + e->data = exif_entry_alloc (e, e->size); + if (!e->data) break; + exif_set_short (e->data, o, 0); + break; + + /* SHORT, 1 component, default 1 */ + case EXIF_TAG_ORIENTATION: + case EXIF_TAG_PLANAR_CONFIGURATION: + case EXIF_TAG_YCBCR_POSITIONING: + e->components = 1; + e->format = EXIF_FORMAT_SHORT; + e->size = exif_format_get_size (e->format) * e->components; + e->data = exif_entry_alloc (e, e->size); + if (!e->data) break; + exif_set_short (e->data, o, 1); + break; + + /* SHORT, 1 component, default 2 */ + case EXIF_TAG_RESOLUTION_UNIT: + case EXIF_TAG_FOCAL_PLANE_RESOLUTION_UNIT: + e->components = 1; + e->format = EXIF_FORMAT_SHORT; + e->size = exif_format_get_size (e->format) * e->components; + e->data = exif_entry_alloc (e, e->size); + if (!e->data) break; + exif_set_short (e->data, o, 2); + break; + + /* SHORT, 1 component, default 3 */ + case EXIF_TAG_SAMPLES_PER_PIXEL: + e->components = 1; + e->format = EXIF_FORMAT_SHORT; + e->size = exif_format_get_size (e->format) * e->components; + e->data = exif_entry_alloc (e, e->size); + if (!e->data) break; + exif_set_short (e->data, o, 3); + break; + + /* SHORT, 1 component, default 0xffff */ + case EXIF_TAG_COLOR_SPACE: + e->components = 1; + e->format = EXIF_FORMAT_SHORT; + e->size = exif_format_get_size (e->format) * e->components; + e->data = exif_entry_alloc (e, e->size); + if (!e->data) break; + exif_set_short (e->data, o, 0xffff); + break; + + /* SHORT, 3 components, default 8 8 8 */ + case EXIF_TAG_BITS_PER_SAMPLE: + e->components = 3; + e->format = EXIF_FORMAT_SHORT; + e->size = exif_format_get_size (e->format) * e->components; + e->data = exif_entry_alloc (e, e->size); + if (!e->data) break; + exif_set_short (e->data, o, 8); + exif_set_short ( + e->data + exif_format_get_size (e->format), + o, 8); + exif_set_short ( + e->data + 2 * exif_format_get_size (e->format), + o, 8); + break; + + /* SHORT, 2 components, default 2 1 */ + case EXIF_TAG_YCBCR_SUB_SAMPLING: + e->components = 2; + e->format = EXIF_FORMAT_SHORT; + e->size = exif_format_get_size (e->format) * e->components; + e->data = exif_entry_alloc (e, e->size); + if (!e->data) break; + exif_set_short (e->data, o, 2); + exif_set_short ( + e->data + exif_format_get_size (e->format), + o, 1); + break; + + /* SRATIONAL, 1 component, no default */ + case EXIF_TAG_EXPOSURE_BIAS_VALUE: + case EXIF_TAG_BRIGHTNESS_VALUE: + case EXIF_TAG_SHUTTER_SPEED_VALUE: + e->components = 1; + e->format = EXIF_FORMAT_SRATIONAL; + e->size = exif_format_get_size (e->format) * e->components; + e->data = exif_entry_alloc (e, e->size); + if (!e->data) break; + break; + + /* RATIONAL, 1 component, no default */ + case EXIF_TAG_EXPOSURE_TIME: + case EXIF_TAG_FOCAL_PLANE_X_RESOLUTION: + case EXIF_TAG_FOCAL_PLANE_Y_RESOLUTION: + case EXIF_TAG_EXPOSURE_INDEX: + case EXIF_TAG_FLASH_ENERGY: + case EXIF_TAG_FNUMBER: + case EXIF_TAG_FOCAL_LENGTH: + case EXIF_TAG_SUBJECT_DISTANCE: + case EXIF_TAG_MAX_APERTURE_VALUE: + case EXIF_TAG_APERTURE_VALUE: + case EXIF_TAG_COMPRESSED_BITS_PER_PIXEL: + case EXIF_TAG_PRIMARY_CHROMATICITIES: + case EXIF_TAG_DIGITAL_ZOOM_RATIO: + e->components = 1; + e->format = EXIF_FORMAT_RATIONAL; + e->size = exif_format_get_size (e->format) * e->components; + e->data = exif_entry_alloc (e, e->size); + if (!e->data) break; + break; + + /* RATIONAL, 1 component, default 72/1 */ + case EXIF_TAG_X_RESOLUTION: + case EXIF_TAG_Y_RESOLUTION: + e->components = 1; + e->format = EXIF_FORMAT_RATIONAL; + e->size = exif_format_get_size (e->format) * e->components; + e->data = exif_entry_alloc (e, e->size); + if (!e->data) break; + r.numerator = 72; + r.denominator = 1; + exif_set_rational (e->data, o, r); + break; + + /* RATIONAL, 2 components, no default */ + case EXIF_TAG_WHITE_POINT: + e->components = 2; + e->format = EXIF_FORMAT_RATIONAL; + e->size = exif_format_get_size (e->format) * e->components; + e->data = exif_entry_alloc (e, e->size); + if (!e->data) break; + break; + + /* RATIONAL, 6 components */ + case EXIF_TAG_REFERENCE_BLACK_WHITE: + e->components = 6; + e->format = EXIF_FORMAT_RATIONAL; + e->size = exif_format_get_size (e->format) * e->components; + e->data = exif_entry_alloc (e, e->size); + if (!e->data) break; + r.denominator = 1; + r.numerator = 0; + exif_set_rational (e->data, o, r); + r.numerator = 255; + exif_set_rational ( + e->data + exif_format_get_size (e->format), o, r); + r.numerator = 0; + exif_set_rational ( + e->data + 2 * exif_format_get_size (e->format), o, r); + r.numerator = 255; + exif_set_rational ( + e->data + 3 * exif_format_get_size (e->format), o, r); + r.numerator = 0; + exif_set_rational ( + e->data + 4 * exif_format_get_size (e->format), o, r); + r.numerator = 255; + exif_set_rational ( + e->data + 5 * exif_format_get_size (e->format), o, r); + break; + + /* ASCII, 20 components */ + case EXIF_TAG_DATE_TIME: + case EXIF_TAG_DATE_TIME_ORIGINAL: + case EXIF_TAG_DATE_TIME_DIGITIZED: + { + time_t t; +#ifdef HAVE_LOCALTIME_R + struct tm tms; +#endif + struct tm *tm; + + t = time (NULL); +#ifdef HAVE_LOCALTIME_R + tm = localtime_r (&t, &tms); +#else + tm = localtime (&t); +#endif + e->components = 20; + e->format = EXIF_FORMAT_ASCII; + e->size = exif_format_get_size (e->format) * e->components; + e->data = exif_entry_alloc (e, e->size); + if (!e->data) break; + snprintf ((char *) e->data, e->size, + "%04i:%02i:%02i %02i:%02i:%02i", + tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, + tm->tm_hour, tm->tm_min, tm->tm_sec); + break; + } + + /* ASCII, no default */ + case EXIF_TAG_SUB_SEC_TIME: + case EXIF_TAG_SUB_SEC_TIME_ORIGINAL: + case EXIF_TAG_SUB_SEC_TIME_DIGITIZED: + e->components = 0; + e->format = EXIF_FORMAT_ASCII; + e->size = 0; + e->data = NULL; + break; + + /* ASCII, default "[None]" */ + case EXIF_TAG_IMAGE_DESCRIPTION: + case EXIF_TAG_MAKE: + case EXIF_TAG_MODEL: + case EXIF_TAG_SOFTWARE: + case EXIF_TAG_ARTIST: + e->components = strlen (_("[None]")) + 1; + e->format = EXIF_FORMAT_ASCII; + e->size = exif_format_get_size (e->format) * e->components; + e->data = exif_entry_alloc (e, e->size); + if (!e->data) break; + strncpy ((char *)e->data, _("[None]"), e->size); + break; + /* ASCII, default "[None]\0[None]\0" */ + case EXIF_TAG_COPYRIGHT: + e->components = (strlen (_("[None]")) + 1) * 2; + e->format = EXIF_FORMAT_ASCII; + e->size = exif_format_get_size (e->format) * e->components; + e->data = exif_entry_alloc (e, e->size); + if (!e->data) break; + strcpy (((char *)e->data) + 0, _("[None]")); + strcpy (((char *)e->data) + strlen (_("[None]")) + 1, _("[None]")); + break; + + /* UNDEFINED, 1 component, default 1 */ + case EXIF_TAG_SCENE_TYPE: + e->components = 1; + e->format = EXIF_FORMAT_UNDEFINED; + e->size = exif_format_get_size (e->format) * e->components; + e->data = exif_entry_alloc (e, e->size); + if (!e->data) break; + e->data[0] = 0x01; + break; + + /* UNDEFINED, 1 component, default 3 */ + case EXIF_TAG_FILE_SOURCE: + e->components = 1; + e->format = EXIF_FORMAT_UNDEFINED; + e->size = exif_format_get_size (e->format) * e->components; + e->data = exif_entry_alloc (e, e->size); + if (!e->data) break; + e->data[0] = 0x03; + break; + + /* UNDEFINED, 4 components, default 48 49 48 48 */ + case EXIF_TAG_FLASH_PIX_VERSION: + e->components = 4; + e->format = EXIF_FORMAT_UNDEFINED; + e->size = exif_format_get_size (e->format) * e->components; + e->data = exif_entry_alloc (e, e->size); + if (!e->data) break; + memcpy (e->data, "0100", 4); + break; + + /* UNDEFINED, 4 components, default 48 50 49 48 */ + case EXIF_TAG_EXIF_VERSION: + e->components = 4; + e->format = EXIF_FORMAT_UNDEFINED; + e->size = exif_format_get_size (e->format) * e->components; + e->data = exif_entry_alloc (e, e->size); + if (!e->data) break; + memcpy (e->data, "0210", 4); + break; + + /* UNDEFINED, 4 components, default 1 2 3 0 */ + case EXIF_TAG_COMPONENTS_CONFIGURATION: + e->components = 4; + e->format = EXIF_FORMAT_UNDEFINED; + e->size = exif_format_get_size (e->format) * e->components; + e->data = exif_entry_alloc (e, e->size); + if (!e->data) break; + e->data[0] = 1; + e->data[1] = 2; + e->data[2] = 3; + e->data[3] = 0; + break; + + /* UNDEFINED, no components, no default */ + /* Use this if the tag is otherwise unsupported */ + case EXIF_TAG_MAKER_NOTE: + case EXIF_TAG_USER_COMMENT: + default: + e->components = 0; + e->format = EXIF_FORMAT_UNDEFINED; + e->size = 0; + e->data = NULL; + break; + } +} diff --git a/libexif/exif-entry.h b/libexif/exif-entry.h new file mode 100644 index 0000000..1dcdc73 --- /dev/null +++ b/libexif/exif-entry.h @@ -0,0 +1,185 @@ +/*! \file exif-entry.h + * \brief Handling EXIF entries + */ +/* + * Copyright (c) 2001 Lutz Mueller <lutz@users.sourceforge.net> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA. + */ + +#ifndef __EXIF_ENTRY_H__ +#define __EXIF_ENTRY_H__ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/*! Data found in one EXIF tag. + * The #exif_entry_get_value function can provide access to the + * formatted contents, or the struct members can be used directly to + * access the raw contents. + */ +typedef struct _ExifEntry ExifEntry; +typedef struct _ExifEntryPrivate ExifEntryPrivate; + +#include <libexif/exif-content.h> +#include <libexif/exif-format.h> +#include <libexif/exif-mem.h> + +/*! Data found in one EXIF tag */ +struct _ExifEntry { + /*! EXIF tag for this entry */ + ExifTag tag; + + /*! Type of data in this entry */ + ExifFormat format; + + /*! Number of elements in the array, if this is an array entry. + * Contains 1 for non-array data types. */ + unsigned long components; + + /*! Pointer to the raw EXIF data for this entry. It is allocated + * by #exif_entry_initialize and is NULL beforehand. Data contained + * here may be manipulated using the functions in exif-utils.h */ + unsigned char *data; + + /*! Number of bytes in the buffer at \c data. This must be no less + * than exif_format_get_size(format)*components */ + unsigned int size; + + /*! #ExifContent containing this entry. + * \see exif_entry_get_ifd */ + ExifContent *parent; + + /*! Internal data to be used by libexif itself */ + ExifEntryPrivate *priv; +}; + +/* Lifecycle */ + +/*! Reserve memory for and initialize a new #ExifEntry. + * No memory is allocated for the \c data element of the returned #ExifEntry. + * + * \return new allocated #ExifEntry, or NULL on error + * + * \see exif_entry_new_mem, exif_entry_unref + */ +ExifEntry *exif_entry_new (void); + +/*! Reserve memory for and initialize new #ExifEntry using the specified + * memory allocator. + * No memory is allocated for the \c data element of the returned #ExifEntry. + * + * \return new allocated #ExifEntry, or NULL on error + * + * \see exif_entry_new, exif_entry_unref + */ +ExifEntry *exif_entry_new_mem (ExifMem *); + +/*! Increase reference counter for #ExifEntry. + * + * \param[in] entry #ExifEntry + * + * \see exif_entry_unref + */ +void exif_entry_ref (ExifEntry *entry); + +/*! Decrease reference counter for #ExifEntry. + * When the reference count drops to zero, free the entry. + * + * \param[in] entry #ExifEntry + */ +void exif_entry_unref (ExifEntry *entry); + +/*! Actually free the #ExifEntry. + * + * \deprecated Should not be called directly. Use #exif_entry_ref and + * #exif_entry_unref instead. + * + * \param[in] entry EXIF entry + */ +void exif_entry_free (ExifEntry *entry); + +/*! Initialize an empty #ExifEntry with default data in the correct format + * for the given tag. If the entry is already initialized, this function + * does nothing. + * This call allocates memory for the \c data element of the given #ExifEntry. + * That memory is freed at the same time as the #ExifEntry. + * + * \param[out] e entry to initialize + * \param[in] tag tag number to initialize as + */ +void exif_entry_initialize (ExifEntry *e, ExifTag tag); + +/*! Fix the type or format of the given EXIF entry to bring it into spec. + * If the data for this EXIF tag is in of the wrong type or is in an invalid + * format according to the EXIF specification, then it is converted to make it + * valid. This may involve, for example, converting an EXIF_FORMAT_LONG into a + * EXIF_FORMAT_SHORT. If the tag is unknown, its value is untouched. + * + * \note Unfortunately, some conversions are to a type with a more restricted + * range, which could have the side effect that the converted data becomes + * invalid. This is unlikely as the range of each tag in the standard is + * designed to encompass all likely data. + * + * \param[in,out] entry EXIF entry + */ +void exif_entry_fix (ExifEntry *entry); + + +/* For your convenience */ + +/*! Return a localized textual representation of the value of the EXIF entry. + * This is meant for display to the user. The format of each tag is subject + * to change between locales and in newer versions of libexif. Users who + * require the tag data in an unambiguous form should access the data members + * of the #ExifEntry structure directly. + * + * \warning The character set of the returned string may be in + * the encoding of the current locale or the native encoding + * of the camera. + * \bug The EXIF_TAG_XP_* tags are currently always returned in UTF-8, + * regardless of locale, and code points above U+FFFF are not + * supported. + * + * \param[in] entry EXIF entry + * \param[out] val buffer in which to store value + * \param[in] maxlen length of the buffer val + * \return val pointer + */ +const char *exif_entry_get_value (ExifEntry *entry, char *val, + unsigned int maxlen); + +/*! Dump text representation of #ExifEntry to stdout. + * This is intended for diagnostic purposes only. + * + * \param[in] entry EXIF tag data + * \param[in] indent how many levels deep to indent the data + */ +void exif_entry_dump (ExifEntry *entry, unsigned int indent); + +/*! Return the IFD number of the given #ExifEntry + * + * \param[in] e an #ExifEntry* + * \return #ExifIfd, or #EXIF_IFD_COUNT on error + */ +#define exif_entry_get_ifd(e) ((e)?exif_content_get_ifd((e)->parent):EXIF_IFD_COUNT) + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __EXIF_ENTRY_H__ */ diff --git a/libexif/exif-format.c b/libexif/exif-format.c new file mode 100644 index 0000000..2c63c33 --- /dev/null +++ b/libexif/exif-format.c @@ -0,0 +1,81 @@ +/* exif-format.c + * + * Copyright (c) 2001 Lutz Mueller <lutz@users.sourceforge.net> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA. + */ + +#include <config.h> + +#include <libexif/exif-format.h> +#include <libexif/i18n.h> + +#include <stdlib.h> + +/*! Table of data format types, descriptions and sizes. + * This table should be sorted in decreasing order of popularity in order + * to decrease the total average lookup time. + */ +static const struct { + ExifFormat format; + const char *name; + unsigned char size; +} ExifFormatTable[] = { + {EXIF_FORMAT_SHORT, N_("Short"), 2}, + {EXIF_FORMAT_RATIONAL, N_("Rational"), 8}, + {EXIF_FORMAT_SRATIONAL, N_("SRational"), 8}, + {EXIF_FORMAT_UNDEFINED, N_("Undefined"), 1}, + {EXIF_FORMAT_ASCII, N_("ASCII"), 1}, + {EXIF_FORMAT_LONG, N_("Long"), 4}, + {EXIF_FORMAT_BYTE, N_("Byte"), 1}, + {EXIF_FORMAT_SBYTE, N_("SByte"), 1}, + {EXIF_FORMAT_SSHORT, N_("SShort"), 2}, + {EXIF_FORMAT_SLONG, N_("SLong"), 4}, + {EXIF_FORMAT_FLOAT, N_("Float"), 4}, + {EXIF_FORMAT_DOUBLE, N_("Double"), 8}, + {0, NULL, 0} +}; + +const char * +exif_format_get_name (ExifFormat format) +{ + unsigned int i; + + /* FIXME: This belongs to somewhere else. */ + /* libexif should use the default system locale. + * If an application specifically requires UTF-8, then we + * must give the application a way to tell libexif that. + * + * bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8"); + */ + bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR); + + for (i = 0; ExifFormatTable[i].name; i++) + if (ExifFormatTable[i].format == format) + return _(ExifFormatTable[i].name); + return NULL; +} + +unsigned char +exif_format_get_size (ExifFormat format) +{ + unsigned int i; + + for (i = 0; ExifFormatTable[i].size; i++) + if (ExifFormatTable[i].format == format) + return ExifFormatTable[i].size; + return 0; +} diff --git a/libexif/exif-format.h b/libexif/exif-format.h new file mode 100644 index 0000000..b7a79a4 --- /dev/null +++ b/libexif/exif-format.h @@ -0,0 +1,65 @@ +/*! \file exif-format.h + * \brief Handling native EXIF data types + */ +/* + * + * Copyright (c) 2001 Lutz Mueller <lutz@users.sourceforge.net> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA. + */ + +#ifndef __EXIF_FORMAT_H__ +#define __EXIF_FORMAT_H__ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/*! EXIF tag data formats */ +typedef enum { + EXIF_FORMAT_BYTE = 1, + EXIF_FORMAT_ASCII = 2, + EXIF_FORMAT_SHORT = 3, + EXIF_FORMAT_LONG = 4, + EXIF_FORMAT_RATIONAL = 5, + EXIF_FORMAT_SBYTE = 6, + EXIF_FORMAT_UNDEFINED = 7, + EXIF_FORMAT_SSHORT = 8, + EXIF_FORMAT_SLONG = 9, + EXIF_FORMAT_SRATIONAL = 10, + EXIF_FORMAT_FLOAT = 11, + EXIF_FORMAT_DOUBLE = 12 +} ExifFormat; + +/*! Return a textual representation of the given EXIF data type. + * + * \param[in] format EXIF data format + * \return localized textual name + */ +const char *exif_format_get_name (ExifFormat format); + +/*! Return the raw size of the given EXIF data type. + * + * \param[in] format EXIF data format + * \return size in bytes + */ +unsigned char exif_format_get_size (ExifFormat format); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __EXIF_FORMAT_H__ */ diff --git a/libexif/exif-ifd.c b/libexif/exif-ifd.c new file mode 100644 index 0000000..f0f8816 --- /dev/null +++ b/libexif/exif-ifd.c @@ -0,0 +1,49 @@ +/* exif-ifd.c + * + * Copyright (c) 2002 Lutz Mueller <lutz@users.sourceforge.net> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA. + */ + +#include <config.h> + +#include <libexif/exif-ifd.h> + +#include <stdlib.h> + +static const struct { + ExifIfd ifd; + const char *name; +} ExifIfdTable[] = { + {EXIF_IFD_0, "0"}, + {EXIF_IFD_1, "1"}, + {EXIF_IFD_EXIF, "EXIF"}, + {EXIF_IFD_GPS, "GPS"}, + {EXIF_IFD_INTEROPERABILITY, "Interoperability"}, + {0, NULL} +}; + +const char * +exif_ifd_get_name (ExifIfd ifd) +{ + unsigned int i; + + for (i = 0; ExifIfdTable[i].name; i++) + if (ExifIfdTable[i].ifd == ifd) + break; + + return (ExifIfdTable[i].name); +} diff --git a/libexif/exif-ifd.h b/libexif/exif-ifd.h new file mode 100644 index 0000000..26c4053 --- /dev/null +++ b/libexif/exif-ifd.h @@ -0,0 +1,43 @@ +/* exif-ifd.h + * + * Copyright (c) 2002 Lutz Mueller <lutz@users.sourceforge.net> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA. + */ + +#ifndef __EXIF_IFD_H__ +#define __EXIF_IFD_H__ + +/*! Possible EXIF Image File Directories */ +typedef enum { + EXIF_IFD_0 = 0, /*!< */ + EXIF_IFD_1, /*!< */ + EXIF_IFD_EXIF, /*!< */ + EXIF_IFD_GPS, /*!< */ + EXIF_IFD_INTEROPERABILITY, /*!< */ + EXIF_IFD_COUNT /*!< Not a real value, just (max_value + 1). */ +} ExifIfd; + +/*! Return a textual name of the given IFD. The name is a short, unique, + * non-localized text string containing only US-ASCII alphanumeric + * characters. + * + * \param[in] ifd IFD + * \return textual name of the IFD + */ +const char *exif_ifd_get_name (ExifIfd ifd); + +#endif /* __EXIF_IFD_H__ */ diff --git a/libexif/exif-loader.c b/libexif/exif-loader.c new file mode 100644 index 0000000..317b86b --- /dev/null +++ b/libexif/exif-loader.c @@ -0,0 +1,434 @@ +/* exif-loader.c + * + * Copyright (c) 2002 Lutz Mueller <lutz@users.sourceforge.net> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA. + */ + +#include <config.h> + +#include <libexif/exif-loader.h> +#include <libexif/exif-utils.h> +#include <libexif/i18n.h> + +#include <sys/types.h> +#include <stdlib.h> +#include <string.h> +#include <stdio.h> + +#undef JPEG_MARKER_DHT +#define JPEG_MARKER_DHT 0xc4 +#undef JPEG_MARKER_SOI +#define JPEG_MARKER_SOI 0xd8 +#undef JPEG_MARKER_DQT +#define JPEG_MARKER_DQT 0xdb +#undef JPEG_MARKER_APP0 +#define JPEG_MARKER_APP0 0xe0 +#undef JPEG_MARKER_APP1 +#define JPEG_MARKER_APP1 0xe1 +#undef JPEG_MARKER_APP2 +#define JPEG_MARKER_APP2 0xe2 +#undef JPEG_MARKER_APP13 +#define JPEG_MARKER_APP13 0xed +#undef JPEG_MARKER_COM +#define JPEG_MARKER_COM 0xfe + +typedef enum { + EL_READ = 0, + EL_READ_SIZE_BYTE_24, + EL_READ_SIZE_BYTE_16, + EL_READ_SIZE_BYTE_08, + EL_READ_SIZE_BYTE_00, + EL_SKIP_BYTES, + EL_EXIF_FOUND, +} ExifLoaderState; + +typedef enum { + EL_DATA_FORMAT_UNKNOWN, + EL_DATA_FORMAT_EXIF, + EL_DATA_FORMAT_JPEG, + EL_DATA_FORMAT_FUJI_RAW +} ExifLoaderDataFormat; + +/*! \internal */ +struct _ExifLoader { + ExifLoaderState state; + ExifLoaderDataFormat data_format; + + /*! Small buffer used for detection of format */ + unsigned char b[12]; + + /*! Number of bytes in the small buffer \c b */ + unsigned char b_len; + + unsigned int size; + unsigned char *buf; + unsigned int bytes_read; + + unsigned int ref_count; + + ExifLog *log; + ExifMem *mem; +}; + +/*! Magic number for EXIF header */ +static const unsigned char ExifHeader[] = {0x45, 0x78, 0x69, 0x66, 0x00, 0x00}; + +static void * +exif_loader_alloc (ExifLoader *l, unsigned int i) +{ + void *d; + + if (!l || !i) + return NULL; + + d = exif_mem_alloc (l->mem, i); + if (d) + return d; + + EXIF_LOG_NO_MEMORY (l->log, "ExifLog", i); + return NULL; +} + +void +exif_loader_write_file (ExifLoader *l, const char *path) +{ + FILE *f; + int size; + unsigned char data[1024]; + + if (!l) + return; + + f = fopen (path, "rb"); + if (!f) { + exif_log (l->log, EXIF_LOG_CODE_NONE, "ExifLoader", + _("The file '%s' could not be opened."), path); + return; + } + while (1) { + size = fread (data, 1, sizeof (data), f); + if (size <= 0) + break; + if (!exif_loader_write (l, data, size)) + break; + } + fclose (f); +} + +static unsigned int +exif_loader_copy (ExifLoader *eld, unsigned char *buf, unsigned int len) +{ + if (!eld || (len && !buf) || (eld->bytes_read >= eld->size)) + return 0; + + /* If needed, allocate the buffer. */ + if (!eld->buf) + eld->buf = exif_loader_alloc (eld, eld->size); + if (!eld->buf) + return 0; + + /* Copy memory */ + len = MIN (len, eld->size - eld->bytes_read); + memcpy (eld->buf + eld->bytes_read, buf, len); + eld->bytes_read += len; + + return (eld->bytes_read >= eld->size) ? 0 : 1; +} + +unsigned char +exif_loader_write (ExifLoader *eld, unsigned char *buf, unsigned int len) +{ + unsigned int i; + + if (!eld || (len && !buf)) + return 0; + + switch (eld->state) { + case EL_EXIF_FOUND: + return exif_loader_copy (eld, buf, len); + case EL_SKIP_BYTES: + if (eld->size > len) { + eld->size -= len; + return 1; + } + len -= eld->size; + buf += eld->size; + eld->size = 0; + eld->b_len = 0; + switch (eld->data_format) { + case EL_DATA_FORMAT_FUJI_RAW: + eld->state = EL_READ_SIZE_BYTE_24; + break; + default: + eld->state = EL_READ; + break; + } + break; + + case EL_READ: + default: + break; + } + + if (!len) + return 1; + exif_log (eld->log, EXIF_LOG_CODE_DEBUG, "ExifLoader", + "Scanning %i byte(s) of data...", len); + + /* + * First fill the small buffer. Only continue if the buffer + * is filled. Note that EXIF data contains at least 12 bytes. + */ + i = MIN (len, sizeof (eld->b) - eld->b_len); + if (i) { + memcpy (&eld->b[eld->b_len], buf, i); + eld->b_len += i; + if (eld->b_len < sizeof (eld->b)) + return 1; + buf += i; + len -= i; + } + + switch (eld->data_format) { + case EL_DATA_FORMAT_UNKNOWN: + + /* Check the small buffer against known formats. */ + if (!memcmp (eld->b, "FUJIFILM", 8)) { + + /* Skip to byte 84. There is another offset there. */ + eld->data_format = EL_DATA_FORMAT_FUJI_RAW; + eld->size = 84; + eld->state = EL_SKIP_BYTES; + eld->size = 84; + + } else if (!memcmp (eld->b + 2, ExifHeader, sizeof (ExifHeader))) { + + /* Read the size (2 bytes). */ + eld->data_format = EL_DATA_FORMAT_EXIF; + eld->state = EL_READ_SIZE_BYTE_08; + } + default: + break; + } + + for (i = 0; i < sizeof (eld->b); i++) + switch (eld->state) { + case EL_EXIF_FOUND: + if (!exif_loader_copy (eld, eld->b + i, + sizeof (eld->b) - i)) + return 0; + return exif_loader_copy (eld, buf, len); + case EL_SKIP_BYTES: + eld->size--; + if (!eld->size) + eld->state = EL_READ; + break; + + case EL_READ_SIZE_BYTE_24: + eld->size |= eld->b[i] << 24; + eld->state = EL_READ_SIZE_BYTE_16; + break; + case EL_READ_SIZE_BYTE_16: + eld->size |= eld->b[i] << 16; + eld->state = EL_READ_SIZE_BYTE_08; + break; + case EL_READ_SIZE_BYTE_08: + eld->size |= eld->b[i] << 8; + eld->state = EL_READ_SIZE_BYTE_00; + break; + case EL_READ_SIZE_BYTE_00: + eld->size |= eld->b[i] << 0; + switch (eld->data_format) { + case EL_DATA_FORMAT_JPEG: + eld->state = EL_SKIP_BYTES; + eld->size -= 2; + break; + case EL_DATA_FORMAT_FUJI_RAW: + eld->data_format = EL_DATA_FORMAT_EXIF; + eld->state = EL_SKIP_BYTES; + eld->size -= 86; + break; + case EL_DATA_FORMAT_EXIF: + eld->state = EL_EXIF_FOUND; + break; + default: + break; + } + break; + + default: + switch (eld->b[i]) { + case JPEG_MARKER_APP1: + if (!memcmp (eld->b + i + 3, ExifHeader, MIN((ssize_t)(sizeof(ExifHeader)), MAX(0, ((ssize_t)(sizeof(eld->b))) - ((ssize_t)i) - 3)))) { + eld->data_format = EL_DATA_FORMAT_EXIF; + } else { + eld->data_format = EL_DATA_FORMAT_JPEG; /* Probably JFIF - keep searching for APP1 EXIF*/ + } + eld->size = 0; + eld->state = EL_READ_SIZE_BYTE_08; + break; + case JPEG_MARKER_DHT: + case JPEG_MARKER_DQT: + case JPEG_MARKER_APP0: + case JPEG_MARKER_APP2: + case JPEG_MARKER_APP13: + case JPEG_MARKER_COM: + eld->data_format = EL_DATA_FORMAT_JPEG; + eld->size = 0; + eld->state = EL_READ_SIZE_BYTE_08; + break; + case 0xff: + case JPEG_MARKER_SOI: + break; + default: + exif_log (eld->log, + EXIF_LOG_CODE_CORRUPT_DATA, + "ExifLoader", _("The data supplied " + "does not seem to contain " + "EXIF data.")); + exif_loader_reset (eld); + return 0; + } + } + + /* + * If we reach this point, the buffer has not been big enough + * to read all data we need. Fill it with new data. + */ + eld->b_len = 0; + return exif_loader_write (eld, buf, len); +} + +ExifLoader * +exif_loader_new (void) +{ + ExifMem *mem = exif_mem_new_default (); + ExifLoader *l = exif_loader_new_mem (mem); + + exif_mem_unref (mem); + + return l; +} + +ExifLoader * +exif_loader_new_mem (ExifMem *mem) +{ + ExifLoader *loader; + + if (!mem) + return NULL; + + loader = exif_mem_alloc (mem, sizeof (ExifLoader)); + if (!loader) + return NULL; + loader->ref_count = 1; + + loader->mem = mem; + exif_mem_ref (mem); + + return loader; +} + +void +exif_loader_ref (ExifLoader *loader) +{ + if (loader) + loader->ref_count++; +} + +static void +exif_loader_free (ExifLoader *loader) +{ + ExifMem *mem; + + if (!loader) + return; + + mem = loader->mem; + exif_loader_reset (loader); + exif_log_unref (loader->log); + exif_mem_free (mem, loader); + exif_mem_unref (mem); +} + +void +exif_loader_unref (ExifLoader *loader) +{ + if (!loader) + return; + if (!--loader->ref_count) + exif_loader_free (loader); +} + +void +exif_loader_reset (ExifLoader *loader) +{ + if (!loader) + return; + exif_mem_free (loader->mem, loader->buf); loader->buf = NULL; + loader->size = 0; + loader->bytes_read = 0; + loader->state = 0; + loader->b_len = 0; + loader->data_format = EL_DATA_FORMAT_UNKNOWN; +} + +ExifData * +exif_loader_get_data (ExifLoader *loader) +{ + ExifData *ed; + + if (!loader || (loader->data_format == EL_DATA_FORMAT_UNKNOWN) || + !loader->bytes_read) + return NULL; + + ed = exif_data_new_mem (loader->mem); + exif_data_log (ed, loader->log); + exif_data_load_data (ed, loader->buf, loader->bytes_read); + + return ed; +} + +void +exif_loader_get_buf (ExifLoader *loader, const unsigned char **buf, + unsigned int *buf_size) +{ + const unsigned char* b = NULL; + unsigned int s = 0; + + if (!loader || (loader->data_format == EL_DATA_FORMAT_UNKNOWN)) { + exif_log (loader->log, EXIF_LOG_CODE_DEBUG, "ExifLoader", + "Loader format unknown"); + } else { + b = loader->buf; + s = loader->bytes_read; + } + if (buf) + *buf = b; + if (buf_size) + *buf_size = s; +} + +void +exif_loader_log (ExifLoader *loader, ExifLog *log) +{ + if (!loader) + return; + exif_log_unref (loader->log); + loader->log = log; + exif_log_ref (log); +} diff --git a/libexif/exif-loader.h b/libexif/exif-loader.h new file mode 100644 index 0000000..62ee87c --- /dev/null +++ b/libexif/exif-loader.h @@ -0,0 +1,128 @@ +/*! \file exif-loader.h + * \brief Defines the ExifLoader type + */ +/* + * Copyright (c) 2003 Lutz Mueller <lutz@users.sourceforge.net> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA. + */ + +#ifndef __EXIF_LOADER_H__ +#define __EXIF_LOADER_H__ + +#include <libexif/exif-data.h> +#include <libexif/exif-log.h> +#include <libexif/exif-mem.h> + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/*! Data used by the loader interface */ +typedef struct _ExifLoader ExifLoader; + +/*! Allocate a new #ExifLoader. + * + * \return allocated ExifLoader + */ +ExifLoader *exif_loader_new (void); + +/*! Allocate a new #ExifLoader using the specified memory allocator. + * + * \param[in] mem the ExifMem + * \return allocated ExifLoader + */ +ExifLoader *exif_loader_new_mem (ExifMem *mem); + +/*! Increase the refcount of the #ExifLoader. + * + * \param[in] loader the ExifLoader to increase the refcount of. + */ +void exif_loader_ref (ExifLoader *loader); + +/*! Decrease the refcount of the #ExifLoader. + * If the refcount reaches 0, the loader is freed. + * + * \param[in] loader ExifLoader for which to decrease the refcount + */ +void exif_loader_unref (ExifLoader *loader); + +/*! Load a file into the given #ExifLoader from the filesystem. + * The relevant data is copied in raw form into the #ExifLoader. + * + * \param[in] loader loader to write to + * \param[in] fname path to the file to read + */ +void exif_loader_write_file (ExifLoader *loader, const char *fname); + +/*! Load a buffer into the #ExifLoader from a memory buffer. + * The relevant data is copied in raw form into the #ExifLoader. + * + * \param[in] loader loader to write to + * \param[in] buf buffer to read from + * \param[in] sz size of the buffer + * \return 1 while EXIF data is read (or while there is still hope that + * there will be EXIF data later on), 0 otherwise. + */ +unsigned char exif_loader_write (ExifLoader *loader, unsigned char *buf, unsigned int sz); + +/*! Free any data previously loaded and reset the #ExifLoader to its + * newly-initialized state. + * + * \param[in] loader the loader + */ +void exif_loader_reset (ExifLoader *loader); + +/*! Create an #ExifData from the data in the loader. The loader must + * already contain data from a previous call to #exif_loader_write_file + * or #exif_loader_write. + * + * \note The #ExifData returned is created using its default options, which + * may take effect before the data is returned. If other options are desired, + * an #ExifData must be created explicitly and data extracted from the loader + * using #exif_loader_get_buf instead. + * + * \param[in] loader the loader + * \return allocated ExifData + * + * \see exif_loader_get_buf + */ +ExifData *exif_loader_get_data (ExifLoader *loader); + +/*! Return the raw data read by the loader. The returned pointer is only + * guaranteed to be valid until the next call to a function modifying + * this #ExifLoader. Either or both of buf and buf_size may be NULL on + * entry, in which case that value is not returned. + * + * \param[in] loader the loader + * \param[out] buf read-only pointer to the data read by the loader, or NULL + * in case of error + * \param[out] buf_size size of the data at buf, or 0 in case of error + */ +void exif_loader_get_buf (ExifLoader *loader, const unsigned char **buf, + unsigned int *buf_size); + +/*! Set the log message object used by this #ExifLoader. + * \param[in] loader the loader + * \param[in] log #ExifLog + */ +void exif_loader_log (ExifLoader *loader, ExifLog *log); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __EXIF_LOADER_H__ */ diff --git a/libexif/exif-log.c b/libexif/exif-log.c new file mode 100644 index 0000000..2db18e3 --- /dev/null +++ b/libexif/exif-log.c @@ -0,0 +1,152 @@ +/* exif-log.c + * + * Copyright (c) 2004 Lutz Mueller <lutz@users.sourceforge.net> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA. + */ + +#include <config.h> + +#include <libexif/exif-log.h> +#include <libexif/i18n.h> + +#include <stdlib.h> +#include <string.h> + +struct _ExifLog { + unsigned int ref_count; + + ExifLogFunc func; + void *data; + + ExifMem *mem; +}; + +static const struct { + ExifLogCode code; + const char *title; + const char *message; +} codes[] = { + { EXIF_LOG_CODE_DEBUG, N_("Debugging information"), + N_("Debugging information is available.") }, + { EXIF_LOG_CODE_NO_MEMORY, N_("Not enough memory"), + N_("The system cannot provide enough memory.") }, + { EXIF_LOG_CODE_CORRUPT_DATA, N_("Corrupt data"), + N_("The data provided does not follow the specification.") }, + { 0, NULL, NULL } +}; + +const char * +exif_log_code_get_title (ExifLogCode code) +{ + unsigned int i; + + for (i = 0; codes[i].title; i++) if (codes[i].code == code) break; + return _(codes[i].title); +} + +const char * +exif_log_code_get_message (ExifLogCode code) +{ + unsigned int i; + + for (i = 0; codes[i].message; i++) if (codes[i].code == code) break; + return _(codes[i].message); +} + +ExifLog * +exif_log_new_mem (ExifMem *mem) +{ + ExifLog *log; + + log = exif_mem_alloc (mem, sizeof (ExifLog)); + if (!log) return NULL; + log->ref_count = 1; + + log->mem = mem; + exif_mem_ref (mem); + + return log; +} + +ExifLog * +exif_log_new (void) +{ + ExifMem *mem = exif_mem_new_default (); + ExifLog *log = exif_log_new_mem (mem); + + exif_mem_unref (mem); + + return log; +} + +void +exif_log_ref (ExifLog *log) +{ + if (!log) return; + log->ref_count++; +} + +void +exif_log_unref (ExifLog *log) +{ + if (!log) return; + if (log->ref_count > 0) log->ref_count--; + if (!log->ref_count) exif_log_free (log); +} + +void +exif_log_free (ExifLog *log) +{ + ExifMem *mem = log ? log->mem : NULL; + + if (!log) return; + + exif_mem_free (mem, log); + exif_mem_unref (mem); +} + +void +exif_log_set_func (ExifLog *log, ExifLogFunc func, void *data) +{ + if (!log) return; + log->func = func; + log->data = data; +} + +#ifdef NO_VERBOSE_TAG_STRINGS +/* exif_log forms part of the API and can't be commented away */ +#undef exif_log +#endif +void +exif_log (ExifLog *log, ExifLogCode code, const char *domain, + const char *format, ...) +{ + va_list args; + + va_start (args, format); + exif_logv (log, code, domain, format, args); + va_end (args); +} + +void +exif_logv (ExifLog *log, ExifLogCode code, const char *domain, + const char *format, va_list args) +{ + if (!log) return; + if (!log->func) return; + log->func (log, code, domain, format, args, log->data); +} diff --git a/libexif/exif-log.h b/libexif/exif-log.h new file mode 100644 index 0000000..9e71ad6 --- /dev/null +++ b/libexif/exif-log.h @@ -0,0 +1,116 @@ +/*! \file exif-log.h + * \brief Log message infrastructure + */ +/* + * Copyright (c) 2004 Lutz Mueller <lutz@users.sourceforge.net> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA. + */ + +#ifndef __EXIF_LOG_H__ +#define __EXIF_LOG_H__ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#include <libexif/exif-mem.h> +#include <stdarg.h> + +/*! State maintained by the logging interface */ +typedef struct _ExifLog ExifLog; + +/*! Create a new logging instance. + * \see exif_log_free + * + * \return new instance of #ExifLog + */ +ExifLog *exif_log_new (void); +ExifLog *exif_log_new_mem (ExifMem *); +void exif_log_ref (ExifLog *log); +void exif_log_unref (ExifLog *log); + +/*! Delete instance of #ExifLog. + * \see exif_log_new + * + * \param[in] log #ExifLog + * \return new instance of #ExifLog + */ +void exif_log_free (ExifLog *log); + +typedef enum { + EXIF_LOG_CODE_NONE, + EXIF_LOG_CODE_DEBUG, + EXIF_LOG_CODE_NO_MEMORY, + EXIF_LOG_CODE_CORRUPT_DATA +} ExifLogCode; + +/*! Return a textual description of the given class of error log. + * + * \param[in] code logging message class + * \return textual description of the log class + */ +const char *exif_log_code_get_title (ExifLogCode code); + +/*! Return a verbose description of the given class of error log. + * + * \param[in] code logging message class + * \return verbose description of the log class + */ +const char *exif_log_code_get_message (ExifLogCode code); + +/*! Log callback function prototype. + */ +typedef void (* ExifLogFunc) (ExifLog *log, ExifLogCode, const char *domain, + const char *format, va_list args, void *data); + +/*! Register log callback function. + * Calls to the log callback function are purely for diagnostic purposes. + * + * \param[in] log logging state variable + * \param[in] func callback function to set + * \param[in] data data to pass into callback function + */ +void exif_log_set_func (ExifLog *log, ExifLogFunc func, void *data); + +#ifndef NO_VERBOSE_TAG_STRINGS +void exif_log (ExifLog *log, ExifLogCode, const char *domain, + const char *format, ...) +#ifdef __GNUC__ + __attribute__((__format__(printf,4,5))) +#endif +; +#else +#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L +#define exif_log(...) do { } while (0) +#elif defined(__GNUC__) +#define exif_log(x...) do { } while (0) +#else +#define exif_log (void) +#endif +#endif + +void exif_logv (ExifLog *log, ExifLogCode, const char *domain, + const char *format, va_list args); + +/* For your convenience */ +#define EXIF_LOG_NO_MEMORY(l,d,s) exif_log ((l), EXIF_LOG_CODE_NO_MEMORY, (d), "Could not allocate %lu byte(s).", (unsigned long)(s)) + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __EXIF_LOG_H__ */ diff --git a/libexif/exif-mem.c b/libexif/exif-mem.c new file mode 100644 index 0000000..b4d7ece --- /dev/null +++ b/libexif/exif-mem.c @@ -0,0 +1,99 @@ +#include <libexif/exif-mem.h> + +#include <stdlib.h> + +struct _ExifMem { + unsigned int ref_count; + ExifMemAllocFunc alloc_func; + ExifMemReallocFunc realloc_func; + ExifMemFreeFunc free_func; +}; + +/*! Default memory allocation function. */ +static void * +exif_mem_alloc_func (ExifLong ds) +{ + return calloc ((size_t) ds, 1); +} + +/*! Default memory reallocation function. */ +static void * +exif_mem_realloc_func (void *d, ExifLong ds) +{ + return realloc (d, (size_t) ds); +} + +/*! Default memory free function. */ +static void +exif_mem_free_func (void *d) +{ + free (d); +} + +ExifMem * +exif_mem_new (ExifMemAllocFunc alloc_func, ExifMemReallocFunc realloc_func, + ExifMemFreeFunc free_func) +{ + ExifMem *mem; + + if (!alloc_func && !realloc_func) + return NULL; + mem = alloc_func ? alloc_func (sizeof (ExifMem)) : + realloc_func (NULL, sizeof (ExifMem)); + if (!mem) return NULL; + mem->ref_count = 1; + + mem->alloc_func = alloc_func; + mem->realloc_func = realloc_func; + mem->free_func = free_func; + + return mem; +} + +void +exif_mem_ref (ExifMem *mem) +{ + if (!mem) return; + mem->ref_count++; +} + +void +exif_mem_unref (ExifMem *mem) +{ + if (!mem) return; + if (!--mem->ref_count) + exif_mem_free (mem, mem); +} + +void +exif_mem_free (ExifMem *mem, void *d) +{ + if (!mem) return; + if (mem->free_func) { + mem->free_func (d); + return; + } +} + +void * +exif_mem_alloc (ExifMem *mem, ExifLong ds) +{ + if (!mem) return NULL; + if (mem->alloc_func || mem->realloc_func) + return mem->alloc_func ? mem->alloc_func (ds) : + mem->realloc_func (NULL, ds); + return NULL; +} + +void * +exif_mem_realloc (ExifMem *mem, void *d, ExifLong ds) +{ + return (mem && mem->realloc_func) ? mem->realloc_func (d, ds) : NULL; +} + +ExifMem * +exif_mem_new_default (void) +{ + return exif_mem_new (exif_mem_alloc_func, exif_mem_realloc_func, + exif_mem_free_func); +} diff --git a/libexif/exif-mem.h b/libexif/exif-mem.h new file mode 100644 index 0000000..fd8f2fa --- /dev/null +++ b/libexif/exif-mem.h @@ -0,0 +1,90 @@ +/*! \file exif-mem.h + * \brief Define the ExifMem data type and the associated functions. + * ExifMem defines the memory management functions used within libexif. + */ +/* exif-mem.h + * + * Copyright (c) 2003 Lutz Mueller <lutz@users.sourceforge.net> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA. + */ + +#ifndef __EXIF_MEM_H__ +#define __EXIF_MEM_H__ + +#include <libexif/exif-utils.h> + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/*! Should work like calloc() + * + * \param[in] s the size of the block to allocate. + * \return the allocated memory and initialized. + */ +typedef void * (* ExifMemAllocFunc) (ExifLong s); + +/*! Should work like realloc() + * + * \param[in] p the pointer to reallocate + * \param[in] s the size of the reallocated block + * \return allocated memory + */ +typedef void * (* ExifMemReallocFunc) (void *p, ExifLong s); + +/*! Free method for ExifMem + * + * \param[in] p the pointer to free + * \return the freed pointer + */ +typedef void (* ExifMemFreeFunc) (void *p); + +/*! ExifMem define a memory allocator */ +typedef struct _ExifMem ExifMem; + +/*! Create a new ExifMem + * + * \param[in] a the allocator function + * \param[in] r the reallocator function + * \param[in] f the free function + */ +ExifMem *exif_mem_new (ExifMemAllocFunc a, ExifMemReallocFunc r, + ExifMemFreeFunc f); +/*! Refcount an ExifMem + */ +void exif_mem_ref (ExifMem *); + +/*! Unrefcount an ExifMem. + * If the refcount reaches 0, the ExifMem is freed + */ +void exif_mem_unref (ExifMem *); + +void *exif_mem_alloc (ExifMem *m, ExifLong s); +void *exif_mem_realloc (ExifMem *m, void *p, ExifLong s); +void exif_mem_free (ExifMem *m, void *p); + +/*! Create a new ExifMem with default values for your convenience + * + * \return return a new default ExifMem + */ +ExifMem *exif_mem_new_default (void); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __EXIF_MEM_H__ */ diff --git a/libexif/exif-mnote-data-priv.h b/libexif/exif-mnote-data-priv.h new file mode 100644 index 0000000..7462c97 --- /dev/null +++ b/libexif/exif-mnote-data-priv.h @@ -0,0 +1,86 @@ +/* exif-mnote-data-priv.h + * + * Copyright (c) 2003 Lutz Mueller <lutz@users.sourceforge.net> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA. + */ + +#ifndef __EXIF_MNOTE_DATA_PRIV_H__ +#define __EXIF_MNOTE_DATA_PRIV_H__ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#include <libexif/exif-mnote-data.h> +#include <libexif/exif-byte-order.h> +#include <libexif/exif-log.h> + +/*! \internal */ +typedef struct _ExifMnoteDataMethods ExifMnoteDataMethods; + +/*! \internal */ +struct _ExifMnoteDataMethods { + + /* Life cycle */ + void (* free) (ExifMnoteData *); + + /* Modification */ + void (* save) (ExifMnoteData *, unsigned char **, unsigned int *); + void (* load) (ExifMnoteData *, const unsigned char *, unsigned int); + void (* set_offset) (ExifMnoteData *, unsigned int); + void (* set_byte_order) (ExifMnoteData *, ExifByteOrder); + + /* Query */ + unsigned int (* count) (ExifMnoteData *); + unsigned int (* get_id) (ExifMnoteData *, unsigned int); + const char * (* get_name) (ExifMnoteData *, unsigned int); + const char * (* get_title) (ExifMnoteData *, unsigned int); + const char * (* get_description) (ExifMnoteData *, unsigned int); + char * (* get_value) (ExifMnoteData *, unsigned int, char *val, unsigned int maxlen); +}; + +/*! \internal */ +typedef struct _ExifMnoteDataPriv ExifMnoteDataPriv; + +/*! \internal */ +struct _ExifMnoteData +{ + ExifMnoteDataPriv *priv; + + ExifMnoteDataMethods methods; + + /* Logging */ + ExifLog *log; + + /* Memory management */ + ExifMem *mem; +}; + +/*! \internal */ +void exif_mnote_data_construct (ExifMnoteData *, ExifMem *mem); + +/*! \internal */ +void exif_mnote_data_set_byte_order (ExifMnoteData *, ExifByteOrder); + +/*! \internal */ +void exif_mnote_data_set_offset (ExifMnoteData *, unsigned int); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __EXIF_MNOTE_PRIV_H__ */ diff --git a/libexif/exif-mnote-data.c b/libexif/exif-mnote-data.c new file mode 100644 index 0000000..248056e --- /dev/null +++ b/libexif/exif-mnote-data.c @@ -0,0 +1,158 @@ +/* exif-mnote-data.c + * + * Copyright (C) 2003 Lutz Mueller <lutz@users.sourceforge.net> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA. + */ + +#include <config.h> + +#include <libexif/exif-mnote-data.h> +#include <libexif/exif-mnote-data-priv.h> + +#include <stdlib.h> +#include <string.h> + +struct _ExifMnoteDataPriv +{ + unsigned int ref_count; +}; + +void +exif_mnote_data_construct (ExifMnoteData *d, ExifMem *mem) +{ + if (!d || !mem) return; + if (d->priv) return; + d->priv = exif_mem_alloc (mem, sizeof (ExifMnoteDataPriv)); + if (!d->priv) return; + + d->priv->ref_count = 1; + + d->mem = mem; + exif_mem_ref (mem); +} + +void +exif_mnote_data_ref (ExifMnoteData *d) +{ + if (d && d->priv) d->priv->ref_count++; +} + +static void +exif_mnote_data_free (ExifMnoteData *d) +{ + ExifMem *mem = d ? d->mem : NULL; + + if (!d) return; + if (d->priv) { + if (d->methods.free) d->methods.free (d); + exif_mem_free (mem, d->priv); + d->priv = NULL; + } + exif_log_unref (d->log); + exif_mem_free (mem, d); + exif_mem_unref (mem); +} + +void +exif_mnote_data_unref (ExifMnoteData *d) +{ + if (!d || !d->priv) return; + if (d->priv->ref_count > 0) d->priv->ref_count--; + if (!d->priv->ref_count) + exif_mnote_data_free (d); +} + +void +exif_mnote_data_load (ExifMnoteData *d, const unsigned char *buf, + unsigned int buf_size) +{ + if (!d || !d->methods.load) return; + d->methods.load (d, buf, buf_size); +} + +void +exif_mnote_data_save (ExifMnoteData *d, unsigned char **buf, + unsigned int *buf_size) +{ + if (!d || !d->methods.save) return; + d->methods.save (d, buf, buf_size); +} + +void +exif_mnote_data_set_byte_order (ExifMnoteData *d, ExifByteOrder o) +{ + if (!d || !d->methods.set_byte_order) return; + d->methods.set_byte_order (d, o); +} + +void +exif_mnote_data_set_offset (ExifMnoteData *d, unsigned int o) +{ + if (!d || !d->methods.set_offset) return; + d->methods.set_offset (d, o); +} + +unsigned int +exif_mnote_data_count (ExifMnoteData *d) +{ + if (!d || !d->methods.count) return 0; + return d->methods.count (d); +} + +unsigned int +exif_mnote_data_get_id (ExifMnoteData *d, unsigned int n) +{ + if (!d || !d->methods.get_id) return 0; + return d->methods.get_id (d, n); +} + +const char * +exif_mnote_data_get_name (ExifMnoteData *d, unsigned int n) +{ + if (!d || !d->methods.get_name) return NULL; + return d->methods.get_name (d, n); +} + +const char * +exif_mnote_data_get_title (ExifMnoteData *d, unsigned int n) +{ + if (!d || !d->methods.get_title) return NULL; + return d->methods.get_title (d, n); +} + +const char * +exif_mnote_data_get_description (ExifMnoteData *d, unsigned int n) +{ + if (!d || !d->methods.get_description) return NULL; + return d->methods.get_description (d, n); +} + +char * +exif_mnote_data_get_value (ExifMnoteData *d, unsigned int n, char *val, unsigned int maxlen) +{ + if (!d || !d->methods.get_value) return NULL; + return d->methods.get_value (d, n, val, maxlen); +} + +void +exif_mnote_data_log (ExifMnoteData *d, ExifLog *log) +{ + if (!d) return; + exif_log_unref (d->log); + d->log = log; + exif_log_ref (log); +} diff --git a/libexif/exif-mnote-data.h b/libexif/exif-mnote-data.h new file mode 100644 index 0000000..19e1de5 --- /dev/null +++ b/libexif/exif-mnote-data.h @@ -0,0 +1,122 @@ +/*! \file exif-mnote-data.h + * \brief Handling EXIF MakerNote tags + */ +/* + * Copyright (c) 2003 Lutz Mueller <lutz@users.sourceforge.net> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA. + */ + +#ifndef __EXIF_MNOTE_DATA_H__ +#define __EXIF_MNOTE_DATA_H__ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#include <libexif/exif-log.h> + +/*! Data found in the MakerNote tag */ +typedef struct _ExifMnoteData ExifMnoteData; + +void exif_mnote_data_ref (ExifMnoteData *); +void exif_mnote_data_unref (ExifMnoteData *); + +/*! Load the MakerNote data from a memory buffer. + * + * \param[in] d MakerNote data + * \param[in] buf pointer to raw MakerNote tag data + * \param[in] buf_siz number of bytes of data at buf + */ +void exif_mnote_data_load (ExifMnoteData *d, const unsigned char *buf, + unsigned int buf_siz); + +/*! + * Save the raw MakerNote data into a memory buffer. The buffer is + * allocated by this function and must subsequently be freed by the + * caller. + * + * \param[in,out] d extract the data from this structure + * \param[out] buf pointer to buffer pointer containing MakerNote data on return + * \param[out] buf_siz pointer to the size of the buffer + */ +void exif_mnote_data_save (ExifMnoteData *d, unsigned char **buf, + unsigned int *buf_siz); + +/*! Return the number of tags in the MakerNote. + * + * \param[in] d MakerNote data + * \return number of tags, or 0 if no MakerNote or the type is not supported + */ +unsigned int exif_mnote_data_count (ExifMnoteData *d); + +/*! Return the MakerNote tag number for the tag at the specified index within + * the MakerNote. + * + * \param[in] d MakerNote data + * \param[in] n index of the entry within the MakerNote data + * \return MakerNote tag number + */ +unsigned int exif_mnote_data_get_id (ExifMnoteData *d, unsigned int n); + +/*! Returns textual name of the given MakerNote tag. The name is a short, + * unique (within this type of MakerNote), non-localized text string + * containing only US-ASCII alphanumeric characters. + * + * \param[in] d MakerNote data + * \param[in] n index of the entry within the MakerNote data + * \return textual name of the tag + */ +const char *exif_mnote_data_get_name (ExifMnoteData *d, unsigned int n); + +/*! Returns textual title of the given MakerNote tag. + * The title is a short, localized textual description of the tag. + * + * \param[in] d MakerNote data + * \param[in] n index of the entry within the MakerNote data + * \return textual name of the tag + */ +const char *exif_mnote_data_get_title (ExifMnoteData *d, unsigned int n); + +/*! Returns verbose textual description of the given MakerNote tag. + * + * \param[in] d MakerNote data + * \param[in] n index of the entry within the MakerNote data + * \return textual description of the tag + */ +const char *exif_mnote_data_get_description (ExifMnoteData *d, unsigned int n); + +/*! Return a textual representation of the value of the MakerNote entry. + * + * \warning The character set of the returned string may be in + * the encoding of the current locale or the native encoding + * of the camera. + * + * \param[in] d MakerNote data + * \param[in] n index of the entry within the MakerNote data + * \param[out] val buffer in which to store value + * \param[in] maxlen length of the buffer val + * \return val pointer, or NULL on error + */ +char *exif_mnote_data_get_value (ExifMnoteData *d, unsigned int n, char *val, unsigned int maxlen); + +void exif_mnote_data_log (ExifMnoteData *, ExifLog *); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __EXIF_MNOTE_DATA_H__ */ diff --git a/libexif/exif-system.h b/libexif/exif-system.h new file mode 100644 index 0000000..81fa703 --- /dev/null +++ b/libexif/exif-system.h @@ -0,0 +1,32 @@ +/*! \file exif-system.h + * \brief System specific definitions, not for installation! + */ +/* + * Copyright (c) 2007 Hans Ulrich Niedermann <gp@n-dimensional.de> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA. + */ + +#ifndef EXIF_SYSTEM_H +#define EXIF_SYSTEM_H + +#if defined(__GNUC__) && (__GNUC__ >= 2) +# define UNUSED(param) UNUSED_PARAM_##param __attribute__((unused)) +#else +# define UNUSED(param) param +#endif + +#endif /* !defined(EXIF_SYSTEM_H) */ diff --git a/libexif/exif-tag.c b/libexif/exif-tag.c new file mode 100644 index 0000000..60f8331 --- /dev/null +++ b/libexif/exif-tag.c @@ -0,0 +1,1180 @@ +/* exif-tag.c + * + * Copyright (c) 2001 Lutz Mueller <lutz@users.sourceforge.net> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA. + */ + +#include <config.h> + +#include <libexif/exif-tag.h> +#include <libexif/i18n.h> + +#include <stdlib.h> +#include <string.h> + +#define ESL_NNNN { EXIF_SUPPORT_LEVEL_NOT_RECORDED, EXIF_SUPPORT_LEVEL_NOT_RECORDED, EXIF_SUPPORT_LEVEL_NOT_RECORDED, EXIF_SUPPORT_LEVEL_NOT_RECORDED } +#define ESL_OOOO { EXIF_SUPPORT_LEVEL_OPTIONAL, EXIF_SUPPORT_LEVEL_OPTIONAL, EXIF_SUPPORT_LEVEL_OPTIONAL, EXIF_SUPPORT_LEVEL_OPTIONAL } +#define ESL_MMMN { EXIF_SUPPORT_LEVEL_MANDATORY, EXIF_SUPPORT_LEVEL_MANDATORY, EXIF_SUPPORT_LEVEL_MANDATORY, EXIF_SUPPORT_LEVEL_NOT_RECORDED } +#define ESL_MMMM { EXIF_SUPPORT_LEVEL_MANDATORY, EXIF_SUPPORT_LEVEL_MANDATORY, EXIF_SUPPORT_LEVEL_MANDATORY, EXIF_SUPPORT_LEVEL_MANDATORY } +#define ESL_OMON { EXIF_SUPPORT_LEVEL_OPTIONAL, EXIF_SUPPORT_LEVEL_MANDATORY, EXIF_SUPPORT_LEVEL_OPTIONAL, EXIF_SUPPORT_LEVEL_NOT_RECORDED } +#define ESL_NNOO { EXIF_SUPPORT_LEVEL_NOT_RECORDED, EXIF_SUPPORT_LEVEL_NOT_RECORDED, EXIF_SUPPORT_LEVEL_OPTIONAL, EXIF_SUPPORT_LEVEL_OPTIONAL } +#define ESL_NNMN { EXIF_SUPPORT_LEVEL_NOT_RECORDED, EXIF_SUPPORT_LEVEL_NOT_RECORDED, EXIF_SUPPORT_LEVEL_MANDATORY, EXIF_SUPPORT_LEVEL_NOT_RECORDED } +#define ESL_NNMM { EXIF_SUPPORT_LEVEL_NOT_RECORDED, EXIF_SUPPORT_LEVEL_NOT_RECORDED, EXIF_SUPPORT_LEVEL_MANDATORY, EXIF_SUPPORT_LEVEL_MANDATORY } +#define ESL_NNNM { EXIF_SUPPORT_LEVEL_NOT_RECORDED, EXIF_SUPPORT_LEVEL_NOT_RECORDED, EXIF_SUPPORT_LEVEL_NOT_RECORDED, EXIF_SUPPORT_LEVEL_MANDATORY } +#define ESL_NNNO { EXIF_SUPPORT_LEVEL_NOT_RECORDED, EXIF_SUPPORT_LEVEL_NOT_RECORDED, EXIF_SUPPORT_LEVEL_NOT_RECORDED, EXIF_SUPPORT_LEVEL_OPTIONAL } +#define ESL_GPS { ESL_NNNN, ESL_NNNN, ESL_NNNN, ESL_OOOO, ESL_NNNN } + +/*! + * Table giving information about each EXIF tag. + * There may be more than one entry with the same tag value because some tags + * have different meanings depending on the IFD in which they appear. + * When there are such duplicate entries, there must be no overlap in their + * support levels. + * The entries MUST be sorted in tag order. + * The name and title are mandatory, but the description may be an empty + * string. None of the entries may be NULL except the final array terminator. + */ +static const struct TagEntry { + /*! Tag ID. There may be duplicate tags when the same number is used for + * different meanings in different IFDs. */ + ExifTag tag; + const char *name; + const char *title; + const char *description; + /*! indexed by the types [ExifIfd][ExifDataType] */ + ExifSupportLevel esl[EXIF_IFD_COUNT][EXIF_DATA_TYPE_COUNT]; +} ExifTagTable[] = { +#ifndef NO_VERBOSE_TAG_STRINGS + {EXIF_TAG_GPS_VERSION_ID, "GPSVersionID", N_("GPS Tag Version"), + N_("Indicates the version of <GPSInfoIFD>. The version is given " + "as 2.0.0.0. This tag is mandatory when <GPSInfo> tag is " + "present. (Note: The <GPSVersionID> tag is given in bytes, " + "unlike the <ExifVersion> tag. When the version is " + "2.0.0.0, the tag value is 02000000.H)."), ESL_GPS}, + {EXIF_TAG_INTEROPERABILITY_INDEX, "InteroperabilityIndex", + N_("Interoperability Index"), + N_("Indicates the identification of the Interoperability rule. " + "Use \"R98\" for stating ExifR98 Rules. Four bytes used " + "including the termination code (NULL). see the separate " + "volume of Recommended Exif Interoperability Rules (ExifR98) " + "for other tags used for ExifR98."), + { ESL_NNNN, ESL_NNNN, ESL_NNNN, ESL_NNNN, ESL_OOOO } }, + {EXIF_TAG_GPS_LATITUDE_REF, "GPSLatitudeRef", N_("North or South Latitude"), + N_("Indicates whether the latitude is north or south latitude. The " + "ASCII value 'N' indicates north latitude, and 'S' is south " + "latitude."), ESL_GPS}, + {EXIF_TAG_INTEROPERABILITY_VERSION, "InteroperabilityVersion", + N_("Interoperability Version"), "", + { ESL_NNNN, ESL_NNNN, ESL_NNNN, ESL_NNNN, ESL_OOOO } }, + {EXIF_TAG_GPS_LATITUDE, "GPSLatitude", N_("Latitude"), + N_("Indicates the latitude. The latitude is expressed as three " + "RATIONAL values giving the degrees, minutes, and seconds, " + "respectively. When degrees, minutes and seconds are expressed, " + "the format is dd/1,mm/1,ss/1. When degrees and minutes are used " + "and, for example, fractions of minutes are given up to two " + "decimal places, the format is dd/1,mmmm/100,0/1."), + ESL_GPS}, + {EXIF_TAG_GPS_LONGITUDE_REF, "GPSLongitudeRef", N_("East or West Longitude"), + N_("Indicates whether the longitude is east or west longitude. " + "ASCII 'E' indicates east longitude, and 'W' is west " + "longitude."), ESL_GPS}, + {EXIF_TAG_GPS_LONGITUDE, "GPSLongitude", N_("Longitude"), + N_("Indicates the longitude. The longitude is expressed as three " + "RATIONAL values giving the degrees, minutes, and seconds, " + "respectively. When degrees, minutes and seconds are expressed, " + "the format is ddd/1,mm/1,ss/1. When degrees and minutes are " + "used and, for example, fractions of minutes are given up to " + "two decimal places, the format is ddd/1,mmmm/100,0/1."), + ESL_GPS}, + {EXIF_TAG_GPS_ALTITUDE_REF, "GPSAltitudeRef", N_("Altitude Reference"), + N_("Indicates the altitude used as the reference altitude. If the " + "reference is sea level and the altitude is above sea level, 0 " + "is given. If the altitude is below sea level, a value of 1 is given " + "and the altitude is indicated as an absolute value in the " + "GSPAltitude tag. The reference unit is meters. Note that this tag " + "is BYTE type, unlike other reference tags."), ESL_GPS}, + {EXIF_TAG_GPS_ALTITUDE, "GPSAltitude", N_("Altitude"), + N_("Indicates the altitude based on the reference in GPSAltitudeRef. " + "Altitude is expressed as one RATIONAL value. The reference unit " + "is meters."), ESL_GPS}, + {EXIF_TAG_GPS_TIME_STAMP, "GPSTimeStamp", N_("GPS Time (Atomic Clock)"), + N_("Indicates the time as UTC (Coordinated Universal Time). " + "TimeStamp is expressed as three RATIONAL values giving " + "the hour, minute, and second."), ESL_GPS}, + {EXIF_TAG_GPS_SATELLITES, "GPSSatellites", N_("GPS Satellites"), + N_("Indicates the GPS satellites used for measurements. This " + "tag can be used to describe the number of satellites, their ID " + "number, angle of elevation, azimuth, SNR and other information " + "in ASCII notation. The format is not specified. If the GPS " + "receiver is incapable of taking measurements, value of the tag " + "shall be set to NULL."), ESL_GPS}, + {EXIF_TAG_GPS_STATUS, "GPSStatus", N_("GPS Receiver Status"), + N_("Indicates the status of the GPS receiver when the image is " + "recorded. 'A' means measurement is in progress, and 'V' means " + "the measurement is Interoperability."), ESL_GPS}, + {EXIF_TAG_GPS_MEASURE_MODE, "GPSMeasureMode", N_("GPS Measurement Mode"), + N_("Indicates the GPS measurement mode. '2' means " + "two-dimensional measurement and '3' means three-dimensional " + "measurement is in progress."), ESL_GPS}, + {EXIF_TAG_GPS_DOP, "GPSDOP", N_("Measurement Precision"), + N_("Indicates the GPS DOP (data degree of precision). An HDOP " + "value is written during two-dimensional measurement, and PDOP " + "during three-dimensional measurement."), ESL_GPS}, + {EXIF_TAG_GPS_SPEED_REF, "GPSSpeedRef", N_("Speed Unit"), + N_("Indicates the unit used to express the GPS receiver speed " + "of movement. 'K', 'M' and 'N' represent kilometers per hour, " + "miles per hour, and knots."), ESL_GPS}, + {EXIF_TAG_GPS_SPEED, "GPSSpeed", N_("Speed of GPS Receiver"), + N_("Indicates the speed of GPS receiver movement."), ESL_GPS}, + {EXIF_TAG_GPS_TRACK_REF, "GPSTrackRef", N_("Reference for direction of movement"), + N_("Indicates the reference for giving the direction of GPS " + "receiver movement. 'T' denotes true direction and 'M' is " + "magnetic direction."), ESL_GPS}, + {EXIF_TAG_GPS_TRACK, "GPSTrack", N_("Direction of Movement"), + N_("Indicates the direction of GPS receiver movement. The range " + "of values is from 0.00 to 359.99."), ESL_GPS}, + {EXIF_TAG_GPS_IMG_DIRECTION_REF, "GPSImgDirectionRef", N_("GPS Image Direction Reference"), + N_("Indicates the reference for giving the direction of the image when it is captured. " + "'T' denotes true direction and 'M' is magnetic direction."), ESL_GPS}, + {EXIF_TAG_GPS_IMG_DIRECTION, "GPSImgDirection", N_("GPS Image Direction"), + N_("Indicates the direction of the image when it was captured. The range of values is " + "from 0.00 to 359.99."), ESL_GPS}, + {EXIF_TAG_GPS_MAP_DATUM, "GPSMapDatum", N_("Geodetic Survey Data Used"), + N_("Indicates the geodetic survey data used by the GPS " + "receiver. If the survey data is restricted to Japan, the value " + "of this tag is 'TOKYO' or 'WGS-84'. If a GPS Info tag is " + "recorded, it is strongly recommended that this tag be recorded."), ESL_GPS}, + {EXIF_TAG_GPS_DEST_LATITUDE_REF, "GPSDestLatitudeRef", N_("Reference For Latitude of Destination"), + N_("Indicates whether the latitude of the destination point is " + "north or south latitude. The ASCII value 'N' indicates north " + "latitude, and 'S' is south latitude."), ESL_GPS}, + {EXIF_TAG_GPS_DEST_LATITUDE, "GPSDestLatitude", N_("Latitude of Destination"), + N_("Indicates the latitude of the destination point. The " + "latitude is expressed as three RATIONAL values giving the " + "degrees, minutes, and seconds, respectively. If latitude is " + "expressed as degrees, minutes and seconds, a typical format " + "would be dd/1,mm/1,ss/1. When degrees and minutes are used and, " + "for example, fractions of minutes are given up to two decimal " + "places, the format would be dd/1,mmmm/100,0/1."), ESL_GPS}, + {EXIF_TAG_GPS_DEST_LONGITUDE_REF, "GPSDestLongitudeRef", N_("Reference for Longitude of Destination"), + N_("Indicates whether the longitude of the destination point is " + "east or west longitude. ASCII 'E' indicates east longitude, and " + "'W' is west longitude."), ESL_GPS}, + {EXIF_TAG_GPS_DEST_LONGITUDE, "GPSDestLongitude", N_("Longitude of Destination"), + N_("Indicates the longitude of the destination point. The " + "longitude is expressed as three RATIONAL values giving the " + "degrees, minutes, and seconds, respectively. If longitude is " + "expressed as degrees, minutes and seconds, a typical format " + "would be ddd/1,mm/1,ss/1. When degrees and minutes are used " + "and, for example, fractions of minutes are given up to two " + "decimal places, the format would be ddd/1,mmmm/100,0/1."), + ESL_GPS}, + {EXIF_TAG_GPS_DEST_BEARING_REF, "GPSDestBearingRef", N_("Reference for Bearing of Destination"), + N_("Indicates the reference used for giving the bearing to " + "the destination point. 'T' denotes true direction and 'M' is " + "magnetic direction."), ESL_GPS}, + {EXIF_TAG_GPS_DEST_BEARING, "GPSDestBearing", N_("Bearing of Destination"), + N_("Indicates the bearing to the destination point. The range " + "of values is from 0.00 to 359.99."), ESL_GPS}, + {EXIF_TAG_GPS_DEST_DISTANCE_REF, "GPSDestDistanceRef", N_("Reference for Distance to Destination"), + N_("Indicates the unit used to express the distance to the " + "destination point. 'K', 'M' and 'N' represent kilometers, miles " + "and nautical miles."), ESL_GPS}, + {EXIF_TAG_GPS_DEST_DISTANCE, "GPSDestDistance", N_("Distance to Destination"), + N_("Indicates the distance to the destination point."), ESL_GPS}, + {EXIF_TAG_GPS_PROCESSING_METHOD, "GPSProcessingMethod", N_("Name of GPS Processing Method"), + N_("A character string recording the name of the method used " + "for location finding. The first byte indicates the character " + "code used, and this is followed by the name " + "of the method. Since the Type is not ASCII, NULL termination is " + "not necessary."), ESL_GPS}, + {EXIF_TAG_GPS_AREA_INFORMATION, "GPSAreaInformation", N_("Name of GPS Area"), + N_("A character string recording the name of the GPS area. The " + "first byte indicates the character code used, " + "and this is followed by the name of the GPS area. Since " + "the Type is not ASCII, NULL termination is not necessary."), ESL_GPS}, + {EXIF_TAG_GPS_DATE_STAMP, "GPSDateStamp", N_("GPS Date"), + N_("A character string recording date and time information " + "relative to UTC (Coordinated Universal Time). The format is " + "\"YYYY:MM:DD\". The length of the string is 11 bytes including " + "NULL."), ESL_GPS}, + {EXIF_TAG_GPS_DIFFERENTIAL, "GPSDifferential", N_("GPS Differential Correction"), + N_("Indicates whether differential correction is applied to the " + "GPS receiver."), ESL_GPS}, + /* Not in EXIF 2.2 */ + {EXIF_TAG_NEW_SUBFILE_TYPE, "NewSubfileType", + N_("New Subfile Type"), N_("A general indication of the kind of data " + "contained in this subfile.")}, + {EXIF_TAG_IMAGE_WIDTH, "ImageWidth", N_("Image Width"), + N_("The number of columns of image data, equal to the number of " + "pixels per row. In JPEG compressed data a JPEG marker is " + "used instead of this tag."), + { ESL_MMMN, ESL_MMMN, ESL_NNNN, ESL_NNNN, ESL_NNNN } }, + {EXIF_TAG_IMAGE_LENGTH, "ImageLength", N_("Image Length"), + N_("The number of rows of image data. In JPEG compressed data a " + "JPEG marker is used instead of this tag."), + { ESL_MMMN, ESL_MMMN, ESL_NNNN, ESL_NNNN, ESL_NNNN } }, + {EXIF_TAG_BITS_PER_SAMPLE, "BitsPerSample", N_("Bits per Sample"), + N_("The number of bits per image component. In this standard each " + "component of the image is 8 bits, so the value for this " + "tag is 8. See also <SamplesPerPixel>. In JPEG compressed data " + "a JPEG marker is used instead of this tag."), + { ESL_MMMN, ESL_MMMN, ESL_NNNN, ESL_NNNN, ESL_NNNN } }, + {EXIF_TAG_COMPRESSION, "Compression", N_("Compression"), + N_("The compression scheme used for the image data. When a " + "primary image is JPEG compressed, this designation is " + "not necessary and is omitted. When thumbnails use JPEG " + "compression, this tag value is set to 6."), + { ESL_MMMN, ESL_MMMM, ESL_NNNN, ESL_NNNN, ESL_NNNN } }, + {EXIF_TAG_PHOTOMETRIC_INTERPRETATION, "PhotometricInterpretation", + N_("Photometric Interpretation"), + N_("The pixel composition. In JPEG compressed data a JPEG " + "marker is used instead of this tag."), + { ESL_MMMN, ESL_MMMN, ESL_NNNN, ESL_NNNN, ESL_NNNN } }, + /* Not in EXIF 2.2 */ + {EXIF_TAG_FILL_ORDER, "FillOrder", N_("Fill Order"), ""}, + /* Not in EXIF 2.2 */ + {EXIF_TAG_DOCUMENT_NAME, "DocumentName", N_("Document Name"), ""}, + {EXIF_TAG_IMAGE_DESCRIPTION, "ImageDescription", + N_("Image Description"), + N_("A character string giving the title of the image. It may be " + "a comment such as \"1988 company picnic\" or " + "the like. Two-bytes character codes cannot be used. " + "When a 2-bytes code is necessary, the Exif Private tag " + "<UserComment> is to be used."), + { ESL_OOOO, ESL_OOOO, ESL_NNNN, ESL_NNNN, ESL_NNNN } }, + {EXIF_TAG_MAKE, "Make", N_("Manufacturer"), + N_("The manufacturer of the recording " + "equipment. This is the manufacturer of the DSC, scanner, " + "video digitizer or other equipment that generated the " + "image. When the field is left blank, it is treated as " + "unknown."), + { ESL_OOOO, ESL_OOOO, ESL_NNNN, ESL_NNNN, ESL_NNNN } }, + {EXIF_TAG_MODEL, "Model", N_("Model"), + N_("The model name or model number of the equipment. This is the " + "model name or number of the DSC, scanner, video digitizer " + "or other equipment that generated the image. When the field " + "is left blank, it is treated as unknown."), + { ESL_OOOO, ESL_OOOO, ESL_NNNN, ESL_NNNN, ESL_NNNN } }, + {EXIF_TAG_STRIP_OFFSETS, "StripOffsets", N_("Strip Offsets"), + N_("For each strip, the byte offset of that strip. It is " + "recommended that this be selected so the number of strip " + "bytes does not exceed 64 Kbytes. With JPEG compressed " + "data this designation is not needed and is omitted. See also " + "<RowsPerStrip> and <StripByteCounts>."), + { ESL_MMMN, ESL_MMMN, ESL_NNNN, ESL_NNNN, ESL_NNNN } }, + {EXIF_TAG_ORIENTATION, "Orientation", N_("Orientation"), + N_("The image orientation viewed in terms of rows and columns."), + { ESL_OOOO, ESL_OOOO, ESL_NNNN, ESL_NNNN, ESL_NNNN } }, + {EXIF_TAG_SAMPLES_PER_PIXEL, "SamplesPerPixel", + N_("Samples per Pixel"), + N_("The number of components per pixel. Since this standard applies " + "to RGB and YCbCr images, the value set for this tag is 3. " + "In JPEG compressed data a JPEG marker is used instead of this " + "tag."), + { ESL_MMMN, ESL_MMMN, ESL_NNNN, ESL_NNNN, ESL_NNNN } }, + {EXIF_TAG_ROWS_PER_STRIP, "RowsPerStrip", N_("Rows per Strip"), + N_("The number of rows per strip. This is the number of rows " + "in the image of one strip when an image is divided into " + "strips. With JPEG compressed data this designation is not " + "needed and is omitted. See also <StripOffsets> and " + "<StripByteCounts>."), + { ESL_MMMN, ESL_MMMN, ESL_NNNN, ESL_NNNN, ESL_NNNN } }, + {EXIF_TAG_STRIP_BYTE_COUNTS, "StripByteCounts", N_("Strip Byte Count"), + N_("The total number of bytes in each strip. With JPEG compressed " + "data this designation is not needed and is omitted."), + { ESL_MMMN, ESL_MMMN, ESL_NNNN, ESL_NNNN, ESL_NNNN } }, + {EXIF_TAG_X_RESOLUTION, "XResolution", N_("X-Resolution"), + N_("The number of pixels per <ResolutionUnit> in the <ImageWidth> " + "direction. When the image resolution is unknown, 72 [dpi] " + "is designated."), + { ESL_MMMM, ESL_MMMM, ESL_NNNN, ESL_NNNN, ESL_NNNN } }, + {EXIF_TAG_Y_RESOLUTION, "YResolution", N_("Y-Resolution"), + N_("The number of pixels per <ResolutionUnit> in the <ImageLength> " + "direction. The same value as <XResolution> is designated."), + { ESL_MMMM, ESL_MMMM, ESL_NNNN, ESL_NNNN, ESL_NNNN } }, + {EXIF_TAG_PLANAR_CONFIGURATION, "PlanarConfiguration", + N_("Planar Configuration"), + N_("Indicates whether pixel components are recorded in a chunky " + "or planar format. In JPEG compressed files a JPEG marker " + "is used instead of this tag. If this field does not exist, " + "the TIFF default of 1 (chunky) is assumed."), + { ESL_OMON, ESL_OMON, ESL_NNNN, ESL_NNNN, ESL_NNNN } }, + {EXIF_TAG_RESOLUTION_UNIT, "ResolutionUnit", N_("Resolution Unit"), + N_("The unit for measuring <XResolution> and <YResolution>. The same " + "unit is used for both <XResolution> and <YResolution>. If " + "the image resolution is unknown, 2 (inches) is designated."), + { ESL_MMMM, ESL_MMMM, ESL_NNNN, ESL_NNNN, ESL_NNNN } }, + {EXIF_TAG_TRANSFER_FUNCTION, "TransferFunction", + N_("Transfer Function"), + N_("A transfer function for the image, described in tabular style. " + "Normally this tag is not necessary, since color space is " + "specified in the color space information tag (<ColorSpace>)."), + { ESL_OOOO, ESL_OOOO, ESL_NNNN, ESL_NNNN, ESL_NNNN } }, + {EXIF_TAG_SOFTWARE, "Software", N_("Software"), + N_("This tag records the name and version of the software or " + "firmware of the camera or image input device used to " + "generate the image. The detailed format is not specified, but " + "it is recommended that the example shown below be " + "followed. When the field is left blank, it is treated as " + "unknown."), + { ESL_OOOO, ESL_OOOO, ESL_NNNN, ESL_NNNN, ESL_NNNN } }, + {EXIF_TAG_DATE_TIME, "DateTime", N_("Date and Time"), + N_("The date and time of image creation. In this standard " + "(EXIF-2.1) it is the date and time the file was changed."), + { ESL_OOOO, ESL_OOOO, ESL_NNNN, ESL_NNNN, ESL_NNNN } }, + {EXIF_TAG_ARTIST, "Artist", N_("Artist"), + N_("This tag records the name of the camera owner, photographer or " + "image creator. The detailed format is not specified, but it is " + "recommended that the information be written as in the example " + "below for ease of Interoperability. When the field is " + "left blank, it is treated as unknown."), + { ESL_OOOO, ESL_OOOO, ESL_NNNN, ESL_NNNN, ESL_NNNN } }, + {EXIF_TAG_WHITE_POINT, "WhitePoint", N_("White Point"), + N_("The chromaticity of the white point of the image. Normally " + "this tag is not necessary, since color space is specified " + "in the color space information tag (<ColorSpace>)."), + { ESL_OOOO, ESL_OOOO, ESL_NNNN, ESL_NNNN, ESL_NNNN } }, + {EXIF_TAG_PRIMARY_CHROMATICITIES, "PrimaryChromaticities", + N_("Primary Chromaticities"), + N_("The chromaticity of the three primary colors of the image. " + "Normally this tag is not necessary, since color space is " + "specified in the color space information tag (<ColorSpace>)."), + { ESL_OOOO, ESL_OOOO, ESL_NNNN, ESL_NNNN, ESL_NNNN } }, + /* Not in EXIF 2.2 */ + {EXIF_TAG_SUB_IFDS, "SubIFDs", "SubIFD Offsets", N_("Defined by Adobe Corporation " + "to enable TIFF Trees within a TIFF file.")}, + /* Not in EXIF 2.2 */ + {EXIF_TAG_TRANSFER_RANGE, "TransferRange", N_("Transfer Range"), ""}, + /* Not in EXIF 2.2 */ + {EXIF_TAG_JPEG_PROC, "JPEGProc", "JPEGProc", ""}, + {EXIF_TAG_JPEG_INTERCHANGE_FORMAT, "JPEGInterchangeFormat", + N_("JPEG Interchange Format"), + N_("The offset to the start byte (SOI) of JPEG compressed " + "thumbnail data. This is not used for primary image " + "JPEG data."), + { ESL_NNNN, ESL_NNNM, ESL_NNNN, ESL_NNNN, ESL_NNNN } }, + {EXIF_TAG_JPEG_INTERCHANGE_FORMAT_LENGTH, + "JPEGInterchangeFormatLength", N_("JPEG Interchange Format Length"), + N_("The number of bytes of JPEG compressed thumbnail data. This " + "is not used for primary image JPEG data. JPEG thumbnails " + "are not divided but are recorded as a continuous JPEG " + "bitstream from SOI to EOI. Appn and COM markers should " + "not be recorded. Compressed thumbnails must be recorded in no " + "more than 64 Kbytes, including all other data to be " + "recorded in APP1."), + { ESL_NNNN, ESL_NNNM, ESL_NNNN, ESL_NNNN, ESL_NNNN } }, + {EXIF_TAG_YCBCR_COEFFICIENTS, "YCbCrCoefficients", + N_("YCbCr Coefficients"), + N_("The matrix coefficients for transformation from RGB to YCbCr " + "image data. No default is given in TIFF; but here the " + "value given in \"Color Space Guidelines\", is used " + "as the default. The color space is declared in a " + "color space information tag, with the default being the value " + "that gives the optimal image characteristics " + "Interoperability this condition."), + { ESL_NNOO, ESL_NNOO, ESL_NNNN, ESL_NNNN, ESL_NNNN } }, + {EXIF_TAG_YCBCR_SUB_SAMPLING, "YCbCrSubSampling", + N_("YCbCr Sub-Sampling"), + N_("The sampling ratio of chrominance components in relation to the " + "luminance component. In JPEG compressed data a JPEG marker " + "is used instead of this tag."), + { ESL_NNMN, ESL_NNMN, ESL_NNNN, ESL_NNNN, ESL_NNNN } }, + {EXIF_TAG_YCBCR_POSITIONING, "YCbCrPositioning", + N_("YCbCr Positioning"), + N_("The position of chrominance components in relation to the " + "luminance component. This field is designated only for " + "JPEG compressed data or uncompressed YCbCr data. The TIFF " + "default is 1 (centered); but when Y:Cb:Cr = 4:2:2 it is " + "recommended in this standard that 2 (co-sited) be used to " + "record data, in order to improve the image quality when viewed " + "on TV systems. When this field does not exist, the reader shall " + "assume the TIFF default. In the case of Y:Cb:Cr = 4:2:0, the " + "TIFF default (centered) is recommended. If the reader " + "does not have the capability of supporting both kinds of " + "<YCbCrPositioning>, it shall follow the TIFF default regardless " + "of the value in this field. It is preferable that readers " + "be able to support both centered and co-sited positioning."), + { ESL_NNMM, ESL_NNOO, ESL_NNNN, ESL_NNNN, ESL_NNNN } }, + {EXIF_TAG_REFERENCE_BLACK_WHITE, "ReferenceBlackWhite", + N_("Reference Black/White"), + N_("The reference black point value and reference white point " + "value. No defaults are given in TIFF, but the values " + "below are given as defaults here. The color space is declared " + "in a color space information tag, with the default " + "being the value that gives the optimal image characteristics " + "Interoperability these conditions."), + { ESL_OOOO, ESL_OOOO, ESL_NNNN, ESL_NNNN, ESL_NNNN } }, + /* Not in EXIF 2.2 */ + {EXIF_TAG_XML_PACKET, "XMLPacket", N_("XML Packet"), N_("XMP Metadata")}, + /* Not in EXIF 2.2 */ + {EXIF_TAG_RELATED_IMAGE_FILE_FORMAT, "RelatedImageFileFormat", + "RelatedImageFileFormat", ""}, + /* Not in EXIF 2.2 */ + {EXIF_TAG_RELATED_IMAGE_WIDTH, "RelatedImageWidth", + "RelatedImageWidth", ""}, + /* Not in EXIF 2.2 */ + {EXIF_TAG_RELATED_IMAGE_LENGTH, "RelatedImageLength", + "RelatedImageLength", ""}, + /* Not in EXIF 2.2 */ + {EXIF_TAG_CFA_REPEAT_PATTERN_DIM, "CFARepeatPatternDim", + "CFARepeatPatternDim", ""}, + /* Not in EXIF 2.2 */ + {EXIF_TAG_CFA_PATTERN, "CFAPattern", + N_("CFA Pattern"), + N_("Indicates the color filter array (CFA) geometric pattern of the " + "image sensor when a one-chip color area sensor is used. " + "It does not apply to all sensing methods.")}, + /* Not in EXIF 2.2 */ + {EXIF_TAG_BATTERY_LEVEL, "BatteryLevel", N_("Battery Level"), ""}, + {EXIF_TAG_COPYRIGHT, "Copyright", N_("Copyright"), + N_("Copyright information. In this standard the tag is used to " + "indicate both the photographer and editor copyrights. It is " + "the copyright notice of the person or organization claiming " + "rights to the image. The Interoperability copyright " + "statement including date and rights should be written in this " + "field; e.g., \"Copyright, John Smith, 19xx. All rights " + "reserved.\". In this standard the field records both the " + "photographer and editor copyrights, with each recorded in a " + "separate part of the statement. When there is a clear " + "distinction between the photographer and editor copyrights, " + "these are to be written in the order of photographer followed " + "by editor copyright, separated by NULL (in this case, " + "since the statement also ends with a NULL, there are two NULL " + "codes) (see example 1). When only the photographer is given, " + "it is terminated by one NULL code (see example 2). When only " + "the editor copyright is given, " + "the photographer copyright part consists of one space followed " + "by a terminating NULL code, then the editor copyright is given " + "(see example 3). When the field is left blank, it is treated " + "as unknown."), + { ESL_OOOO, ESL_OOOO, ESL_NNNN, ESL_NNNN, ESL_NNNN } }, + {EXIF_TAG_EXPOSURE_TIME, "ExposureTime", N_("Exposure Time"), + N_("Exposure time, given in seconds (sec)."), + { ESL_NNNN, ESL_NNNN, ESL_OOOO, ESL_NNNN, ESL_NNNN } }, + {EXIF_TAG_FNUMBER, "FNumber", N_("F-Number"), + N_("The F number."), + { ESL_NNNN, ESL_NNNN, ESL_OOOO, ESL_NNNN, ESL_NNNN } }, + /* Not in EXIF 2.2 */ + {EXIF_TAG_IPTC_NAA, "IPTC/NAA", "IPTC/NAA", ""}, + /* Not in EXIF 2.2 */ + {EXIF_TAG_IMAGE_RESOURCES, "ImageResources", N_("Image Resources Block"), ""}, + {EXIF_TAG_EXIF_IFD_POINTER, "ExifIfdPointer", "ExifIFDPointer", + N_("A pointer to the Exif IFD. Interoperability, Exif IFD has the " + "same structure as that of the IFD specified in TIFF. " + "ordinarily, however, it does not contain image data as in " + "the case of TIFF."), + { ESL_NNNN, ESL_NNNN, ESL_NNNN, ESL_NNNN, ESL_NNNN } }, + /* Not in EXIF 2.2 */ + {EXIF_TAG_INTER_COLOR_PROFILE, "InterColorProfile", + "InterColorProfile", ""}, + {EXIF_TAG_EXPOSURE_PROGRAM, "ExposureProgram", N_("Exposure Program"), + N_("The class of the program used by the camera to set exposure " + "when the picture is taken."), + { ESL_NNNN, ESL_NNNN, ESL_OOOO, ESL_NNNN, ESL_NNNN } }, + {EXIF_TAG_SPECTRAL_SENSITIVITY, "SpectralSensitivity", + N_("Spectral Sensitivity"), + N_("Indicates the spectral sensitivity of each channel of the " + "camera used. The tag value is an ASCII string compatible " + "with the standard developed by the ASTM Technical Committee."), + { ESL_NNNN, ESL_NNNN, ESL_OOOO, ESL_NNNN, ESL_NNNN } }, + {EXIF_TAG_GPS_INFO_IFD_POINTER, "GPSInfoIFDPointer", + N_("GPS Info IFD Pointer"), + N_("A pointer to the GPS Info IFD. The " + "Interoperability structure of the GPS Info IFD, like that of " + "Exif IFD, has no image data."), + { ESL_NNNN, ESL_NNNN, ESL_NNNN, ESL_NNNN, ESL_NNNN } }, + + {EXIF_TAG_ISO_SPEED_RATINGS, "ISOSpeedRatings", + N_("ISO Speed Ratings"), + N_("Indicates the ISO Speed and ISO Latitude of the camera or " + "input device as specified in ISO 12232."), + { ESL_NNNN, ESL_NNNN, ESL_OOOO, ESL_NNNN, ESL_NNNN } }, + {EXIF_TAG_OECF, "OECF", N_("Opto-Electronic Conversion Function"), + N_("Indicates the Opto-Electronic Conversion Function (OECF) " + "specified in ISO 14524. <OECF> is the relationship between " + "the camera optical input and the image values."), + { ESL_NNNN, ESL_NNNN, ESL_OOOO, ESL_NNNN, ESL_NNNN } }, + /* Not in EXIF 2.2 */ + {EXIF_TAG_TIME_ZONE_OFFSET, "TimeZoneOffset", N_("Time Zone Offset"), + N_("Encodes time zone of camera clock relative to GMT.")}, + {EXIF_TAG_EXIF_VERSION, "ExifVersion", N_("Exif Version"), + N_("The version of this standard supported. Nonexistence of this " + "field is taken to mean nonconformance to the standard."), + { ESL_NNNN, ESL_NNNN, ESL_MMMM, ESL_NNNN, ESL_NNNN } }, + {EXIF_TAG_DATE_TIME_ORIGINAL, "DateTimeOriginal", + N_("Date and Time (Original)"), + N_("The date and time when the original image data was generated. " + "For a digital still camera " + "the date and time the picture was taken are recorded."), + { ESL_NNNN, ESL_NNNN, ESL_OOOO, ESL_NNNN, ESL_NNNN } }, + {EXIF_TAG_DATE_TIME_DIGITIZED, "DateTimeDigitized", + N_("Date and Time (Digitized)"), + N_("The date and time when the image was stored as digital data."), + { ESL_NNNN, ESL_NNNN, ESL_OOOO, ESL_NNNN, ESL_NNNN } }, + {EXIF_TAG_COMPONENTS_CONFIGURATION, "ComponentsConfiguration", + N_("Components Configuration"), + N_("Information specific to compressed data. The channels of " + "each component are arranged in order from the 1st " + "component to the 4th. For uncompressed data the data " + "arrangement is given in the <PhotometricInterpretation> tag. " + "However, since <PhotometricInterpretation> can only " + "express the order of Y, Cb and Cr, this tag is provided " + "for cases when compressed data uses components other than " + "Y, Cb, and Cr and to enable support of other sequences."), + { ESL_NNNN, ESL_NNNN, ESL_NNNM, ESL_NNNN, ESL_NNNN } }, + {EXIF_TAG_COMPRESSED_BITS_PER_PIXEL, "CompressedBitsPerPixel", + N_("Compressed Bits per Pixel"), + N_("Information specific to compressed data. The compression mode " + "used for a compressed image is indicated in unit bits " + "per pixel."), + { ESL_NNNN, ESL_NNNN, ESL_NNNO, ESL_NNNN, ESL_NNNN } }, + {EXIF_TAG_SHUTTER_SPEED_VALUE, "ShutterSpeedValue", N_("Shutter Speed"), + N_("Shutter speed. The unit is the APEX (Additive System of " + "Photographic Exposure) setting."), + { ESL_NNNN, ESL_NNNN, ESL_OOOO, ESL_NNNN, ESL_NNNN } }, + {EXIF_TAG_APERTURE_VALUE, "ApertureValue", N_("Aperture"), + N_("The lens aperture. The unit is the APEX value."), + { ESL_NNNN, ESL_NNNN, ESL_OOOO, ESL_NNNN, ESL_NNNN } }, + {EXIF_TAG_BRIGHTNESS_VALUE, "BrightnessValue", N_("Brightness"), + N_("The value of brightness. The unit is the APEX value. " + "Ordinarily it is given in the range of -99.99 to 99.99."), + { ESL_NNNN, ESL_NNNN, ESL_OOOO, ESL_NNNN, ESL_NNNN } }, + {EXIF_TAG_EXPOSURE_BIAS_VALUE, "ExposureBiasValue", + N_("Exposure Bias"), + N_("The exposure bias. The units is the APEX value. Ordinarily " + "it is given in the range of -99.99 to 99.99."), + { ESL_NNNN, ESL_NNNN, ESL_OOOO, ESL_NNNN, ESL_NNNN } }, + {EXIF_TAG_MAX_APERTURE_VALUE, "MaxApertureValue", N_("Maximum Aperture Value"), + N_("The smallest F number of the lens. The unit is the APEX value. " + "Ordinarily it is given in the range of 00.00 to 99.99, " + "but it is not limited to this range."), + { ESL_NNNN, ESL_NNNN, ESL_OOOO, ESL_NNNN, ESL_NNNN } }, + {EXIF_TAG_SUBJECT_DISTANCE, "SubjectDistance", + N_("Subject Distance"), + N_("The distance to the subject, given in meters."), + { ESL_NNNN, ESL_NNNN, ESL_OOOO, ESL_NNNN, ESL_NNNN } }, + {EXIF_TAG_METERING_MODE, "MeteringMode", N_("Metering Mode"), + N_("The metering mode."), + { ESL_NNNN, ESL_NNNN, ESL_OOOO, ESL_NNNN, ESL_NNNN } }, + {EXIF_TAG_LIGHT_SOURCE, "LightSource", N_("Light Source"), + N_("The kind of light source."), + { ESL_NNNN, ESL_NNNN, ESL_OOOO, ESL_NNNN, ESL_NNNN } }, + {EXIF_TAG_FLASH, "Flash", N_("Flash"), + N_("This tag is recorded when an image is taken using a strobe " + "light (flash)."), + { ESL_NNNN, ESL_NNNN, ESL_OOOO, ESL_NNNN, ESL_NNNN } }, + {EXIF_TAG_FOCAL_LENGTH, "FocalLength", N_("Focal Length"), + N_("The actual focal length of the lens, in mm. Conversion is not " + "made to the focal length of a 35 mm film camera."), + { ESL_NNNN, ESL_NNNN, ESL_OOOO, ESL_NNNN, ESL_NNNN } }, + {EXIF_TAG_SUBJECT_AREA, "SubjectArea", N_("Subject Area"), + N_("This tag indicates the location and area of the main subject " + "in the overall scene."), + { ESL_NNNN, ESL_NNNN, ESL_OOOO, ESL_NNNN, ESL_NNNN } }, + /* Not in EXIF 2.2 */ + {EXIF_TAG_TIFF_EP_STANDARD_ID, "TIFF/EPStandardID", N_("TIFF/EP Standard ID"), ""}, + {EXIF_TAG_MAKER_NOTE, "MakerNote", N_("Maker Note"), + N_("A tag for manufacturers of Exif writers to record any desired " + "information. The contents are up to the manufacturer."), + { ESL_NNNN, ESL_NNNN, ESL_OOOO, ESL_NNNN, ESL_NNNN } }, + {EXIF_TAG_USER_COMMENT, "UserComment", N_("User Comment"), + N_("A tag for Exif users to write keywords or comments on the image " + "besides those in <ImageDescription>, and without the " + "character code limitations of the <ImageDescription> tag. The " + "character code used in the <UserComment> tag is identified " + "based on an ID code in a fixed 8-byte area at the start of " + "the tag data area. The unused portion of the area is padded " + "with NULL (\"00.h\"). ID codes are assigned by means of " + "registration. The designation method and references for each " + "character code are defined in the specification. The value of " + "CountN is determined based on the 8 bytes in the character code " + "area and the number of bytes in the user comment part. Since " + "the TYPE is not ASCII, NULL termination is not necessary. " + "The ID code for the <UserComment> area may be a Defined code " + "such as JIS or ASCII, or may be Undefined. The Undefined name " + "is UndefinedText, and the ID code is filled with 8 bytes of all " + "\"NULL\" (\"00.H\"). An Exif reader that reads the " + "<UserComment> tag must have a function for determining the " + "ID code. This function is not required in Exif readers that " + "do not use the <UserComment> tag. " + "When a <UserComment> area is set aside, it is recommended that " + "the ID code be ASCII and that the following user comment " + "part be filled with blank characters [20.H]."), + { ESL_NNNN, ESL_NNNN, ESL_OOOO, ESL_NNNN, ESL_NNNN } }, + {EXIF_TAG_SUB_SEC_TIME, "SubsecTime", N_("Sub-second Time"), + N_("A tag used to record fractions of seconds for the " + "<DateTime> tag."), + { ESL_NNNN, ESL_NNNN, ESL_OOOO, ESL_NNNN, ESL_NNNN } }, + {EXIF_TAG_SUB_SEC_TIME_ORIGINAL, "SubSecTimeOriginal", + N_("Sub-second Time (Original)"), + N_("A tag used to record fractions of seconds for the " + "<DateTimeOriginal> tag."), + { ESL_NNNN, ESL_NNNN, ESL_OOOO, ESL_NNNN, ESL_NNNN } }, + {EXIF_TAG_SUB_SEC_TIME_DIGITIZED, "SubSecTimeDigitized", + N_("Sub-second Time (Digitized)"), + N_("A tag used to record fractions of seconds for the " + "<DateTimeDigitized> tag."), + { ESL_NNNN, ESL_NNNN, ESL_OOOO, ESL_NNNN, ESL_NNNN } }, + /* Not in EXIF 2.2 (Microsoft extension) */ + {EXIF_TAG_XP_TITLE, "XPTitle", N_("XP Title"), + N_("A character string giving the title of the image, encoded in " + "UTF-16LE."), + { ESL_OOOO, ESL_NNNN, ESL_NNNN, ESL_NNNN, ESL_NNNN } }, + /* Not in EXIF 2.2 (Microsoft extension) */ + {EXIF_TAG_XP_COMMENT, "XPComment", N_("XP Comment"), + N_("A character string containing a comment about the image, encoded " + "in UTF-16LE."), + { ESL_OOOO, ESL_NNNN, ESL_NNNN, ESL_NNNN, ESL_NNNN } }, + /* Not in EXIF 2.2 (Microsoft extension) */ + {EXIF_TAG_XP_AUTHOR, "XPAuthor", N_("XP Author"), + N_("A character string containing the name of the image creator, " + "encoded in UTF-16LE."), + { ESL_OOOO, ESL_NNNN, ESL_NNNN, ESL_NNNN, ESL_NNNN } }, + /* Not in EXIF 2.2 (Microsoft extension) */ + {EXIF_TAG_XP_KEYWORDS, "XPKeywords", N_("XP Keywords"), + N_("A character string containing key words describing the image, " + "encoded in UTF-16LE."), + { ESL_OOOO, ESL_NNNN, ESL_NNNN, ESL_NNNN, ESL_NNNN } }, + /* Not in EXIF 2.2 (Microsoft extension) */ + {EXIF_TAG_XP_SUBJECT, "XPSubject", N_("XP Subject"), + N_("A character string giving the image subject, encoded in " + "UTF-16LE."), + { ESL_OOOO, ESL_NNNN, ESL_NNNN, ESL_NNNN, ESL_NNNN } }, + {EXIF_TAG_FLASH_PIX_VERSION, "FlashPixVersion", "FlashPixVersion", + N_("The FlashPix format version supported by a FPXR file."), + { ESL_NNNN, ESL_NNNN, ESL_MMMM, ESL_NNNN, ESL_NNNN } }, + {EXIF_TAG_COLOR_SPACE, "ColorSpace", N_("Color Space"), + N_("The color space information tag is always " + "recorded as the color space specifier. Normally sRGB (=1) " + "is used to define the color space based on the PC monitor " + "conditions and environment. If a color space other than " + "sRGB is used, Uncalibrated (=FFFF.H) is set. Image data " + "recorded as Uncalibrated can be treated as sRGB when it is " + "converted to FlashPix."), + { ESL_NNNN, ESL_NNNN, ESL_MMMM, ESL_NNNN, ESL_NNNN } }, + {EXIF_TAG_PIXEL_X_DIMENSION, "PixelXDimension", N_("Pixel X Dimension"), + N_("Information specific to compressed data. When a " + "compressed file is recorded, the valid width of the " + "meaningful image must be recorded in this tag, whether or " + "not there is padding data or a restart marker. This tag " + "should not exist in an uncompressed file."), + { ESL_NNNN, ESL_NNNN, ESL_NNNM, ESL_NNNN, ESL_NNNN } }, + {EXIF_TAG_PIXEL_Y_DIMENSION, "PixelYDimension", N_("Pixel Y Dimension"), + N_("Information specific to compressed data. When a compressed " + "file is recorded, the valid height of the meaningful image " + "must be recorded in this tag, whether or not there is padding " + "data or a restart marker. This tag should not exist in an " + "uncompressed file. " + "Since data padding is unnecessary in the vertical direction, " + "the number of lines recorded in this valid image height tag " + "will in fact be the same as that recorded in the SOF."), + { ESL_NNNN, ESL_NNNN, ESL_NNNM, ESL_NNNN, ESL_NNNN } }, + {EXIF_TAG_RELATED_SOUND_FILE, "RelatedSoundFile", + N_("Related Sound File"), + N_("This tag is used to record the name of an audio file related " + "to the image data. The only relational information " + "recorded here is the Exif audio file name and extension (an " + "ASCII string consisting of 8 characters + '.' + 3 " + "characters). The path is not recorded. Stipulations on audio " + "and file naming conventions are defined in the specification. " + "When using this tag, audio files must be recorded in " + "conformance to the Exif audio format. Writers are also allowed " + "to store the data such as Audio within APP2 as FlashPix " + "extension stream data. " + "The mapping of Exif image files and audio files is done " + "in any of three ways, [1], [2] and [3]. If multiple files " + "are mapped to one file as in [2] or [3], the above " + "format is used to record just one audio file name. If " + "there are multiple audio files, the first recorded file is " + "given. In the case of [3], for example, for the " + "Exif image file \"DSC00001.JPG\" only \"SND00001.WAV\" is " + "given as the related Exif audio file. When there are three " + "Exif audio files \"SND00001.WAV\", \"SND00002.WAV\" and " + "\"SND00003.WAV\", the Exif image file name for each of them, " + "\"DSC00001.JPG\", is indicated. By combining multiple " + "relational information, a variety of playback possibilities " + "can be supported. The method of using relational information " + "is left to the implementation on the playback side. Since this " + "information is an ASCII character string, it is terminated by " + "NULL. When this tag is used to map audio files, the relation " + "of the audio file to image data must also be indicated on the " + "audio file end."), + { ESL_NNNN, ESL_NNNN, ESL_OOOO, ESL_NNNN, ESL_NNNN } }, + {EXIF_TAG_INTEROPERABILITY_IFD_POINTER, "InteroperabilityIFDPointer", + N_("Interoperability IFD Pointer"), + N_("Interoperability IFD is composed of tags which stores the " + "information to ensure the Interoperability and pointed " + "by the following tag located in Exif IFD. " + "The Interoperability structure of Interoperability IFD is " + "the same as TIFF defined IFD structure " + "but does not contain the " + "image data characteristically compared with normal TIFF " + "IFD."), + { ESL_NNNN, ESL_NNNN, ESL_NNNN, ESL_NNNN, ESL_NNNN } }, + {EXIF_TAG_FLASH_ENERGY, "FlashEnergy", N_("Flash Energy"), + N_("Indicates the strobe energy at the time the image is " + "captured, as measured in Beam Candle Power Seconds (BCPS)."), + { ESL_NNNN, ESL_NNNN, ESL_OOOO, ESL_NNNN, ESL_NNNN } }, + {EXIF_TAG_SPATIAL_FREQUENCY_RESPONSE, "SpatialFrequencyResponse", + N_("Spatial Frequency Response"), + N_("This tag records the camera or input device spatial frequency " + "table and SFR values in the direction of image width, " + "image height, and diagonal direction, as specified in ISO " + "12233."), + { ESL_NNNN, ESL_NNNN, ESL_OOOO, ESL_NNNN, ESL_NNNN } }, + {EXIF_TAG_FOCAL_PLANE_X_RESOLUTION, "FocalPlaneXResolution", + N_("Focal Plane X-Resolution"), + N_("Indicates the number of pixels in the image width (X) direction " + "per <FocalPlaneResolutionUnit> on the camera focal plane."), + { ESL_NNNN, ESL_NNNN, ESL_OOOO, ESL_NNNN, ESL_NNNN } }, + {EXIF_TAG_FOCAL_PLANE_Y_RESOLUTION, "FocalPlaneYResolution", + N_("Focal Plane Y-Resolution"), + N_("Indicates the number of pixels in the image height (V) direction " + "per <FocalPlaneResolutionUnit> on the camera focal plane."), + { ESL_NNNN, ESL_NNNN, ESL_OOOO, ESL_NNNN, ESL_NNNN } }, + {EXIF_TAG_FOCAL_PLANE_RESOLUTION_UNIT, "FocalPlaneResolutionUnit", + N_("Focal Plane Resolution Unit"), + N_("Indicates the unit for measuring <FocalPlaneXResolution> and " + "<FocalPlaneYResolution>. This value is the same as the " + "<ResolutionUnit>."), + { ESL_NNNN, ESL_NNNN, ESL_OOOO, ESL_NNNN, ESL_NNNN } }, + {EXIF_TAG_SUBJECT_LOCATION, "SubjectLocation", + N_("Subject Location"), + N_("Indicates the location of the main subject in the scene. The " + "value of this tag represents the pixel at the center of the " + "main subject relative to the left edge, prior to rotation " + "processing as per the <Rotation> tag. The first value " + "indicates the X column number and the second indicates " + "the Y row number."), + { ESL_NNNN, ESL_NNNN, ESL_OOOO, ESL_NNNN, ESL_NNNN } }, + {EXIF_TAG_EXPOSURE_INDEX, "ExposureIndex", N_("Exposure Index"), + N_("Indicates the exposure index selected on the camera or " + "input device at the time the image is captured."), + { ESL_NNNN, ESL_NNNN, ESL_OOOO, ESL_NNNN, ESL_NNNN } }, + {EXIF_TAG_SENSING_METHOD, "SensingMethod", N_("Sensing Method"), + N_("Indicates the image sensor type on the camera or input " + "device."), + { ESL_NNNN, ESL_NNNN, ESL_OOOO, ESL_NNNN, ESL_NNNN } }, + {EXIF_TAG_FILE_SOURCE, "FileSource", N_("File Source"), + N_("Indicates the image source. If a DSC recorded the image, " + "the tag value of this tag always be set to 3, indicating " + "that the image was recorded on a DSC."), + { ESL_NNNN, ESL_NNNN, ESL_OOOO, ESL_NNNN, ESL_NNNN } }, + {EXIF_TAG_SCENE_TYPE, "SceneType", N_("Scene Type"), + N_("Indicates the type of scene. If a DSC recorded the image, " + "this tag value must always be set to 1, indicating that the " + "image was directly photographed."), + { ESL_NNNN, ESL_NNNN, ESL_OOOO, ESL_NNNN, ESL_NNNN } }, + {EXIF_TAG_NEW_CFA_PATTERN, "CFAPattern", + N_("CFA Pattern"), + N_("Indicates the color filter array (CFA) geometric pattern of the " + "image sensor when a one-chip color area sensor is used. " + "It does not apply to all sensing methods."), + { ESL_NNNN, ESL_NNNN, ESL_OOOO, ESL_NNNN, ESL_NNNN } }, + {EXIF_TAG_CUSTOM_RENDERED, "CustomRendered", N_("Custom Rendered"), + N_("This tag indicates the use of special processing on image " + "data, such as rendering geared to output. When special " + "processing is performed, the reader is expected to disable " + "or minimize any further processing."), + { ESL_NNNN, ESL_NNNN, ESL_OOOO, ESL_NNNN, ESL_NNNN } }, + {EXIF_TAG_EXPOSURE_MODE, "ExposureMode", N_("Exposure Mode"), + N_("This tag indicates the exposure mode set when the image was " + "shot. In auto-bracketing mode, the camera shoots a series of " + "frames of the same scene at different exposure settings."), + { ESL_NNNN, ESL_NNNN, ESL_OOOO, ESL_NNNN, ESL_NNNN } }, + {EXIF_TAG_WHITE_BALANCE, "WhiteBalance", N_("White Balance"), + N_("This tag indicates the white balance mode set when the image " + "was shot."), + { ESL_NNNN, ESL_NNNN, ESL_OOOO, ESL_NNNN, ESL_NNNN } }, + {EXIF_TAG_DIGITAL_ZOOM_RATIO, "DigitalZoomRatio", + N_("Digital Zoom Ratio"), + N_("This tag indicates the digital zoom ratio when the image was " + "shot. If the numerator of the recorded value is 0, this " + "indicates that digital zoom was not used."), + { ESL_NNNN, ESL_NNNN, ESL_OOOO, ESL_NNNN, ESL_NNNN } }, + {EXIF_TAG_FOCAL_LENGTH_IN_35MM_FILM, "FocalLengthIn35mmFilm", + N_("Focal Length in 35mm Film"), + N_("This tag indicates the equivalent focal length assuming a " + "35mm film camera, in mm. A value of 0 means the focal " + "length is unknown. Note that this tag differs from the " + "FocalLength tag."), + { ESL_NNNN, ESL_NNNN, ESL_OOOO, ESL_NNNN, ESL_NNNN } }, + {EXIF_TAG_SCENE_CAPTURE_TYPE, "SceneCaptureType", + N_("Scene Capture Type"), + N_("This tag indicates the type of scene that was shot. It can " + "also be used to record the mode in which the image was " + "shot. Note that this differs from the scene type " + "<SceneType> tag."), + { ESL_NNNN, ESL_NNNN, ESL_OOOO, ESL_NNNN, ESL_NNNN } }, + {EXIF_TAG_GAIN_CONTROL, "GainControl", N_("Gain Control"), + N_("This tag indicates the degree of overall image gain " + "adjustment."), + { ESL_NNNN, ESL_NNNN, ESL_OOOO, ESL_NNNN, ESL_NNNN } }, + {EXIF_TAG_CONTRAST, "Contrast", N_("Contrast"), + N_("This tag indicates the direction of contrast processing " + "applied by the camera when the image was shot."), + { ESL_NNNN, ESL_NNNN, ESL_OOOO, ESL_NNNN, ESL_NNNN } }, + {EXIF_TAG_SATURATION, "Saturation", N_("Saturation"), + N_("This tag indicates the direction of saturation processing " + "applied by the camera when the image was shot."), + { ESL_NNNN, ESL_NNNN, ESL_OOOO, ESL_NNNN, ESL_NNNN } }, + {EXIF_TAG_SHARPNESS, "Sharpness", N_("Sharpness"), + N_("This tag indicates the direction of sharpness processing " + "applied by the camera when the image was shot."), + { ESL_NNNN, ESL_NNNN, ESL_OOOO, ESL_NNNN, ESL_NNNN } }, + {EXIF_TAG_DEVICE_SETTING_DESCRIPTION, "DeviceSettingDescription", + N_("Device Setting Description"), + N_("This tag indicates information on the picture-taking " + "conditions of a particular camera model. The tag is used " + "only to indicate the picture-taking conditions in the " + "reader."), + { ESL_NNNN, ESL_NNNN, ESL_OOOO, ESL_NNNN, ESL_NNNN } }, + {EXIF_TAG_SUBJECT_DISTANCE_RANGE, "SubjectDistanceRange", + N_("Subject Distance Range"), + N_("This tag indicates the distance to the subject."), + { ESL_NNNN, ESL_NNNN, ESL_OOOO, ESL_NNNN, ESL_NNNN } }, + {EXIF_TAG_IMAGE_UNIQUE_ID, "ImageUniqueID", N_("Image Unique ID"), + N_("This tag indicates an identifier assigned uniquely to " + "each image. It is recorded as an ASCII string equivalent " + "to hexadecimal notation and 128-bit fixed length."), + { ESL_NNNN, ESL_NNNN, ESL_OOOO, ESL_NNNN, ESL_NNNN } }, + /* Not in EXIF 2.2 */ + {EXIF_TAG_GAMMA, "Gamma", N_("Gamma"), + N_("Indicates the value of coefficient gamma.")}, + /* Not in EXIF 2.2 */ + {EXIF_TAG_PRINT_IMAGE_MATCHING, "PrintImageMatching", N_("PRINT Image Matching"), + N_("Related to Epson's PRINT Image Matching technology")}, + /* Not in EXIF 2.2 (from the Microsoft HD Photo specification) */ + {EXIF_TAG_PADDING, "Padding", N_("Padding"), + N_("This tag reserves space that can be reclaimed later when " + "additional metadata are added. New metadata can be written " + "in place by replacing this tag with a smaller data element " + "and using the reclaimed space to store the new or expanded " + "metadata tags."), + { ESL_OOOO, ESL_NNNN, ESL_OOOO, ESL_NNNN, ESL_NNNN } }, +#endif + {0, NULL, NULL, NULL} +}; + +/* For now, do not use these functions. */ + +/*! + * Return the number of entries in the EXIF tag table, including the + * terminating NULL entry. + */ +inline unsigned int +exif_tag_table_count (void) +{ + return sizeof (ExifTagTable) / sizeof (ExifTagTable[0]); +} + + +ExifTag +exif_tag_table_get_tag (unsigned int n) +{ + return (n < exif_tag_table_count ()) ? ExifTagTable[n].tag : 0; +} + +const char * +exif_tag_table_get_name (unsigned int n) +{ + return (n < exif_tag_table_count ()) ? ExifTagTable[n].name : NULL; +} + +/*! + * Compares the tag with that in entry. + * \param[in] tag pointer to integer tag value + * \param[in] entry pointer to a struct TagEntry + * \return 0 if tags are equal, <0 if tag < entry, >0 if tag > entry + */ +static int +match_tag(const void *tag, const void *entry) +{ + return *(int*)tag - ((struct TagEntry *)entry)->tag; +} + + +/*! + * Finds the first entry in the EXIF tag table with the given tag number + * using a binary search. + * \param[in] tag to find + * \return index into table, or -1 if not found + */ +static int +exif_tag_table_first(ExifTag tag) +{ + int i; + struct TagEntry *entry = bsearch(&tag, ExifTagTable, + exif_tag_table_count()-1, sizeof(struct TagEntry), match_tag); + if (!entry) + return -1; /* Not found */ + + /* Calculate index of found entry */ + i = entry - ExifTagTable; + + /* There may be other entries with the same tag number, so search + * backwards to find the first + */ + while ((i > 0) && (ExifTagTable[i-1].tag == tag)) { + --i; + } + return i; +} + +#define RECORDED \ +((ExifTagTable[i].esl[ifd][EXIF_DATA_TYPE_UNCOMPRESSED_CHUNKY] != EXIF_SUPPORT_LEVEL_NOT_RECORDED) || \ + (ExifTagTable[i].esl[ifd][EXIF_DATA_TYPE_UNCOMPRESSED_PLANAR] != EXIF_SUPPORT_LEVEL_NOT_RECORDED) || \ + (ExifTagTable[i].esl[ifd][EXIF_DATA_TYPE_UNCOMPRESSED_YCC] != EXIF_SUPPORT_LEVEL_NOT_RECORDED) || \ + (ExifTagTable[i].esl[ifd][EXIF_DATA_TYPE_COMPRESSED] != EXIF_SUPPORT_LEVEL_NOT_RECORDED)) + +const char * +exif_tag_get_name_in_ifd (ExifTag tag, ExifIfd ifd) +{ + unsigned int i; + int first; + + if (ifd >= EXIF_IFD_COUNT) + return NULL; + first = exif_tag_table_first(tag); + if (first < 0) + return NULL; + + for (i = first; ExifTagTable[i].name; i++) { + if (ExifTagTable[i].tag == tag) { + if (RECORDED) + break; + } else + return NULL; /* Recorded tag not found in the table */ + } + return ExifTagTable[i].name; +} + +const char * +exif_tag_get_title_in_ifd (ExifTag tag, ExifIfd ifd) +{ + unsigned int i; + int first; + + if (ifd >= EXIF_IFD_COUNT) + return NULL; + first = exif_tag_table_first(tag); + if (first < 0) + return NULL; + + for (i = first; ExifTagTable[i].name; i++) { + if (ExifTagTable[i].tag == tag) { + if (RECORDED) + break; + } else + return NULL; /* Recorded tag not found in the table */ + } + /* FIXME: This belongs to somewhere else. */ + /* libexif should use the default system locale. + * If an application specifically requires UTF-8, then we + * must give the application a way to tell libexif that. + * + * bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8"); + */ + bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR); + return _(ExifTagTable[i].title); +} + +const char * +exif_tag_get_description_in_ifd (ExifTag tag, ExifIfd ifd) +{ + unsigned int i; + int first; + + if (ifd >= EXIF_IFD_COUNT) + return NULL; + first = exif_tag_table_first(tag); + if (first < 0) + return NULL; + + for (i = first; ExifTagTable[i].name; i++) { + if (ExifTagTable[i].tag == tag) { + if (RECORDED) + break; + } else + return NULL; /* Recorded tag not found in the table */ + } + + /* GNU gettext acts strangely when given an empty string */ + if (!ExifTagTable[i].description || !*ExifTagTable[i].description) + return ""; + + /* libexif should use the default system locale. + * If an application specifically requires UTF-8, then we + * must give the application a way to tell libexif that. + * + * bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8"); + */ + bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR); + return _(ExifTagTable[i].description); +} + + +/********************************************************************** + * convenience functions + **********************************************************************/ + +/* generic part: iterate through IFD list and return first result */ +typedef const char * (*get_stuff_func) (ExifTag tag, ExifIfd ifd); + +static const char * +exif_tag_get_stuff (ExifTag tag, get_stuff_func func) +{ + /* Search IFDs in this order, in decreasing order of number of valid tags */ + static const ExifIfd ifds[EXIF_IFD_COUNT] = { + EXIF_IFD_EXIF, + EXIF_IFD_0, + EXIF_IFD_1, + EXIF_IFD_INTEROPERABILITY, + EXIF_IFD_GPS + }; + int i; + for (i=0; i<EXIF_IFD_COUNT; i++) { + const char *result = func(tag, ifds[i]); + if (result != NULL) { + return result; + } + } + return (const char *) NULL; +} + +/* explicit functions */ +const char * +exif_tag_get_name (ExifTag tag) +{ + return exif_tag_get_stuff(tag, exif_tag_get_name_in_ifd); +} + +const char * +exif_tag_get_title (ExifTag tag) +{ + return exif_tag_get_stuff(tag, exif_tag_get_title_in_ifd); +} + +const char * +exif_tag_get_description (ExifTag tag) +{ + return exif_tag_get_stuff(tag, exif_tag_get_description_in_ifd); +} + + + +ExifTag +exif_tag_from_name (const char *name) +{ + unsigned int i; + unsigned int result=0; + + if (!name) return 0; + + for (i = 0; ExifTagTable[i].name; i++) + if (!strcmp (ExifTagTable[i].name, name)) { + result = ExifTagTable[i].tag; + break; + } + return result; +} + +/*! Return the support level of a tag in the given IFD with the given data + * type. If the tag is not specified in the EXIF standard, this function + * returns EXIF_SUPPORT_LEVEL_NOT_RECORDED. + * + * \param[in] tag EXIF tag + * \param[in] ifd a valid IFD (not EXIF_IFD_COUNT) + * \param[in] t a valid data type (not EXIF_DATA_TYPE_UNKNOWN) + * \return the level of support for this tag + */ +static inline ExifSupportLevel +get_support_level_in_ifd (ExifTag tag, ExifIfd ifd, ExifDataType t) +{ + unsigned int i; + int first = exif_tag_table_first(tag); + if (first < 0) + return EXIF_SUPPORT_LEVEL_NOT_RECORDED; + + for (i = first; ExifTagTable[i].name; i++) { + if (ExifTagTable[i].tag == tag) { + const ExifSupportLevel supp = ExifTagTable[i].esl[ifd][t]; + if (supp != EXIF_SUPPORT_LEVEL_NOT_RECORDED) + return supp; + /* Try looking for another entry */ + } else { + break; /* We've reached the end of the matching tags */ + } + } + return EXIF_SUPPORT_LEVEL_NOT_RECORDED; +} + +/*! Return the support level of a tag in the given IFD, regardless of the + * data type. If the support level varies depending on the data type, this + * function returns EXIF_SUPPORT_LEVEL_UNKNOWN. If the tag is not specified + * in the EXIF standard, this function returns EXIF_SUPPORT_LEVEL_UNKNOWN. + * + * \param[in] tag EXIF tag + * \param[in] ifd a valid IFD (not EXIF_IFD_COUNT) + * \return the level of support for this tag + */ +static inline ExifSupportLevel +get_support_level_any_type (ExifTag tag, ExifIfd ifd) +{ + unsigned int i; + int first = exif_tag_table_first(tag); + if (first < 0) + return EXIF_SUPPORT_LEVEL_UNKNOWN; + + for (i = first; ExifTagTable[i].name; i++) { + if (ExifTagTable[i].tag == tag) { + /* + * Check whether the support level is the same for all possible + * data types and isn't marked not recorded. + */ + const ExifSupportLevel supp = ExifTagTable[i].esl[ifd][0]; + /* If level is not recorded, keep searching for another */ + if (supp != EXIF_SUPPORT_LEVEL_NOT_RECORDED) { + unsigned int dt; + for (dt = 0; dt < EXIF_DATA_TYPE_COUNT; ++dt) { + if (ExifTagTable[i].esl[ifd][dt] != supp) + break; + } + if (dt == EXIF_DATA_TYPE_COUNT) + /* Support level is always the same, so return it */ + return supp; + } + /* Keep searching the table for another tag for our IFD */ + } else { + break; /* We've reached the end of the matching tags */ + } + } + return EXIF_SUPPORT_LEVEL_UNKNOWN; +} + +ExifSupportLevel +exif_tag_get_support_level_in_ifd (ExifTag tag, ExifIfd ifd, ExifDataType t) +{ + if (ifd >= EXIF_IFD_COUNT) + return EXIF_SUPPORT_LEVEL_UNKNOWN; + + if (t >= EXIF_DATA_TYPE_COUNT) + return get_support_level_any_type (tag, ifd); + + return get_support_level_in_ifd (tag, ifd, t); +} diff --git a/libexif/exif-tag.h b/libexif/exif-tag.h new file mode 100644 index 0000000..d8b8657 --- /dev/null +++ b/libexif/exif-tag.h @@ -0,0 +1,287 @@ +/*! \file exif-tag.h + * \brief Handling EXIF tags + */ +/* + * Copyright (c) 2001 Lutz Mueller <lutz@users.sourceforge.net> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA. + */ + +#ifndef __EXIF_TAG_H__ +#define __EXIF_TAG_H__ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#include <libexif/exif-ifd.h> +#include <libexif/exif-data-type.h> + +/*! EXIF tags */ +typedef enum { + EXIF_TAG_INTEROPERABILITY_INDEX = 0x0001, + EXIF_TAG_INTEROPERABILITY_VERSION = 0x0002, + EXIF_TAG_NEW_SUBFILE_TYPE = 0x00fe, + EXIF_TAG_IMAGE_WIDTH = 0x0100, + EXIF_TAG_IMAGE_LENGTH = 0x0101, + EXIF_TAG_BITS_PER_SAMPLE = 0x0102, + EXIF_TAG_COMPRESSION = 0x0103, + EXIF_TAG_PHOTOMETRIC_INTERPRETATION = 0x0106, + EXIF_TAG_FILL_ORDER = 0x010a, + EXIF_TAG_DOCUMENT_NAME = 0x010d, + EXIF_TAG_IMAGE_DESCRIPTION = 0x010e, + EXIF_TAG_MAKE = 0x010f, + EXIF_TAG_MODEL = 0x0110, + EXIF_TAG_STRIP_OFFSETS = 0x0111, + EXIF_TAG_ORIENTATION = 0x0112, + EXIF_TAG_SAMPLES_PER_PIXEL = 0x0115, + EXIF_TAG_ROWS_PER_STRIP = 0x0116, + EXIF_TAG_STRIP_BYTE_COUNTS = 0x0117, + EXIF_TAG_X_RESOLUTION = 0x011a, + EXIF_TAG_Y_RESOLUTION = 0x011b, + EXIF_TAG_PLANAR_CONFIGURATION = 0x011c, + EXIF_TAG_RESOLUTION_UNIT = 0x0128, + EXIF_TAG_TRANSFER_FUNCTION = 0x012d, + EXIF_TAG_SOFTWARE = 0x0131, + EXIF_TAG_DATE_TIME = 0x0132, + EXIF_TAG_ARTIST = 0x013b, + EXIF_TAG_WHITE_POINT = 0x013e, + EXIF_TAG_PRIMARY_CHROMATICITIES = 0x013f, + EXIF_TAG_SUB_IFDS = 0x014a, + EXIF_TAG_TRANSFER_RANGE = 0x0156, + EXIF_TAG_JPEG_PROC = 0x0200, + EXIF_TAG_JPEG_INTERCHANGE_FORMAT = 0x0201, + EXIF_TAG_JPEG_INTERCHANGE_FORMAT_LENGTH = 0x0202, + EXIF_TAG_YCBCR_COEFFICIENTS = 0x0211, + EXIF_TAG_YCBCR_SUB_SAMPLING = 0x0212, + EXIF_TAG_YCBCR_POSITIONING = 0x0213, + EXIF_TAG_REFERENCE_BLACK_WHITE = 0x0214, + EXIF_TAG_XML_PACKET = 0x02bc, + EXIF_TAG_RELATED_IMAGE_FILE_FORMAT = 0x1000, + EXIF_TAG_RELATED_IMAGE_WIDTH = 0x1001, + EXIF_TAG_RELATED_IMAGE_LENGTH = 0x1002, + EXIF_TAG_CFA_REPEAT_PATTERN_DIM = 0x828d, + EXIF_TAG_CFA_PATTERN = 0x828e, + EXIF_TAG_BATTERY_LEVEL = 0x828f, + EXIF_TAG_COPYRIGHT = 0x8298, + EXIF_TAG_EXPOSURE_TIME = 0x829a, + EXIF_TAG_FNUMBER = 0x829d, + EXIF_TAG_IPTC_NAA = 0x83bb, + EXIF_TAG_IMAGE_RESOURCES = 0x8649, + EXIF_TAG_EXIF_IFD_POINTER = 0x8769, + EXIF_TAG_INTER_COLOR_PROFILE = 0x8773, + EXIF_TAG_EXPOSURE_PROGRAM = 0x8822, + EXIF_TAG_SPECTRAL_SENSITIVITY = 0x8824, + EXIF_TAG_GPS_INFO_IFD_POINTER = 0x8825, + EXIF_TAG_ISO_SPEED_RATINGS = 0x8827, + EXIF_TAG_OECF = 0x8828, + EXIF_TAG_TIME_ZONE_OFFSET = 0x882a, + EXIF_TAG_EXIF_VERSION = 0x9000, + EXIF_TAG_DATE_TIME_ORIGINAL = 0x9003, + EXIF_TAG_DATE_TIME_DIGITIZED = 0x9004, + EXIF_TAG_COMPONENTS_CONFIGURATION = 0x9101, + EXIF_TAG_COMPRESSED_BITS_PER_PIXEL = 0x9102, + EXIF_TAG_SHUTTER_SPEED_VALUE = 0x9201, + EXIF_TAG_APERTURE_VALUE = 0x9202, + EXIF_TAG_BRIGHTNESS_VALUE = 0x9203, + EXIF_TAG_EXPOSURE_BIAS_VALUE = 0x9204, + EXIF_TAG_MAX_APERTURE_VALUE = 0x9205, + EXIF_TAG_SUBJECT_DISTANCE = 0x9206, + EXIF_TAG_METERING_MODE = 0x9207, + EXIF_TAG_LIGHT_SOURCE = 0x9208, + EXIF_TAG_FLASH = 0x9209, + EXIF_TAG_FOCAL_LENGTH = 0x920a, + EXIF_TAG_SUBJECT_AREA = 0x9214, + EXIF_TAG_TIFF_EP_STANDARD_ID = 0x9216, + EXIF_TAG_MAKER_NOTE = 0x927c, + EXIF_TAG_USER_COMMENT = 0x9286, + EXIF_TAG_SUB_SEC_TIME = 0x9290, + EXIF_TAG_SUB_SEC_TIME_ORIGINAL = 0x9291, + EXIF_TAG_SUB_SEC_TIME_DIGITIZED = 0x9292, + EXIF_TAG_XP_TITLE = 0x9c9b, + EXIF_TAG_XP_COMMENT = 0x9c9c, + EXIF_TAG_XP_AUTHOR = 0x9c9d, + EXIF_TAG_XP_KEYWORDS = 0x9c9e, + EXIF_TAG_XP_SUBJECT = 0x9c9f, + EXIF_TAG_FLASH_PIX_VERSION = 0xa000, + EXIF_TAG_COLOR_SPACE = 0xa001, + EXIF_TAG_PIXEL_X_DIMENSION = 0xa002, + EXIF_TAG_PIXEL_Y_DIMENSION = 0xa003, + EXIF_TAG_RELATED_SOUND_FILE = 0xa004, + EXIF_TAG_INTEROPERABILITY_IFD_POINTER = 0xa005, + EXIF_TAG_FLASH_ENERGY = 0xa20b, + EXIF_TAG_SPATIAL_FREQUENCY_RESPONSE = 0xa20c, + EXIF_TAG_FOCAL_PLANE_X_RESOLUTION = 0xa20e, + EXIF_TAG_FOCAL_PLANE_Y_RESOLUTION = 0xa20f, + EXIF_TAG_FOCAL_PLANE_RESOLUTION_UNIT = 0xa210, + EXIF_TAG_SUBJECT_LOCATION = 0xa214, + EXIF_TAG_EXPOSURE_INDEX = 0xa215, + EXIF_TAG_SENSING_METHOD = 0xa217, + EXIF_TAG_FILE_SOURCE = 0xa300, + EXIF_TAG_SCENE_TYPE = 0xa301, + EXIF_TAG_NEW_CFA_PATTERN = 0xa302, + EXIF_TAG_CUSTOM_RENDERED = 0xa401, + EXIF_TAG_EXPOSURE_MODE = 0xa402, + EXIF_TAG_WHITE_BALANCE = 0xa403, + EXIF_TAG_DIGITAL_ZOOM_RATIO = 0xa404, + EXIF_TAG_FOCAL_LENGTH_IN_35MM_FILM = 0xa405, + EXIF_TAG_SCENE_CAPTURE_TYPE = 0xa406, + EXIF_TAG_GAIN_CONTROL = 0xa407, + EXIF_TAG_CONTRAST = 0xa408, + EXIF_TAG_SATURATION = 0xa409, + EXIF_TAG_SHARPNESS = 0xa40a, + EXIF_TAG_DEVICE_SETTING_DESCRIPTION = 0xa40b, + EXIF_TAG_SUBJECT_DISTANCE_RANGE = 0xa40c, + EXIF_TAG_IMAGE_UNIQUE_ID = 0xa420, + EXIF_TAG_GAMMA = 0xa500, + EXIF_TAG_PRINT_IMAGE_MATCHING = 0xc4a5, + EXIF_TAG_PADDING = 0xea1c +} ExifTag; + +/* GPS tags overlap with above ones. */ +#define EXIF_TAG_GPS_VERSION_ID 0x0000 +#define EXIF_TAG_GPS_LATITUDE_REF 0x0001 /* INTEROPERABILITY_INDEX */ +#define EXIF_TAG_GPS_LATITUDE 0x0002 /* INTEROPERABILITY_VERSION */ +#define EXIF_TAG_GPS_LONGITUDE_REF 0x0003 +#define EXIF_TAG_GPS_LONGITUDE 0x0004 +#define EXIF_TAG_GPS_ALTITUDE_REF 0x0005 +#define EXIF_TAG_GPS_ALTITUDE 0x0006 +#define EXIF_TAG_GPS_TIME_STAMP 0x0007 +#define EXIF_TAG_GPS_SATELLITES 0x0008 +#define EXIF_TAG_GPS_STATUS 0x0009 +#define EXIF_TAG_GPS_MEASURE_MODE 0x000a +#define EXIF_TAG_GPS_DOP 0x000b +#define EXIF_TAG_GPS_SPEED_REF 0x000c +#define EXIF_TAG_GPS_SPEED 0x000d +#define EXIF_TAG_GPS_TRACK_REF 0x000e +#define EXIF_TAG_GPS_TRACK 0x000f +#define EXIF_TAG_GPS_IMG_DIRECTION_REF 0x0010 +#define EXIF_TAG_GPS_IMG_DIRECTION 0x0011 +#define EXIF_TAG_GPS_MAP_DATUM 0x0012 +#define EXIF_TAG_GPS_DEST_LATITUDE_REF 0x0013 +#define EXIF_TAG_GPS_DEST_LATITUDE 0x0014 +#define EXIF_TAG_GPS_DEST_LONGITUDE_REF 0x0015 +#define EXIF_TAG_GPS_DEST_LONGITUDE 0x0016 +#define EXIF_TAG_GPS_DEST_BEARING_REF 0x0017 +#define EXIF_TAG_GPS_DEST_BEARING 0x0018 +#define EXIF_TAG_GPS_DEST_DISTANCE_REF 0x0019 +#define EXIF_TAG_GPS_DEST_DISTANCE 0x001a +#define EXIF_TAG_GPS_PROCESSING_METHOD 0x001b +#define EXIF_TAG_GPS_AREA_INFORMATION 0x001c +#define EXIF_TAG_GPS_DATE_STAMP 0x001d +#define EXIF_TAG_GPS_DIFFERENTIAL 0x001e + +/*! What level of support a tag enjoys in the EXIF standard */ +typedef enum { + /*! The meaning of this tag is unknown */ + EXIF_SUPPORT_LEVEL_UNKNOWN = 0, + + /*! This tag is not allowed in the given IFD */ + EXIF_SUPPORT_LEVEL_NOT_RECORDED, + + /*! This tag is mandatory in the given IFD */ + EXIF_SUPPORT_LEVEL_MANDATORY, + + /*! This tag is optional in the given IFD */ + EXIF_SUPPORT_LEVEL_OPTIONAL +} ExifSupportLevel; + +/*! Return the tag ID given its unique textual name. + * + * \param[in] name tag name + * \return tag ID, or 0 if tag not found + * \note The tag not found value cannot be distinguished from a legitimate + * tag number 0. + */ +ExifTag exif_tag_from_name (const char *name); + +/*! Return a textual name of the given tag when found in the given IFD. The + * name is a short, unique, non-localized text string containing only + * US-ASCII alphanumeric characters. + * + * \param[in] tag EXIF tag + * \param[in] ifd IFD + * \return textual name of the tag, or NULL if the tag is unknown + */ +const char *exif_tag_get_name_in_ifd (ExifTag tag, ExifIfd ifd); + +/*! Return a textual title of the given tag when found in the given IFD. + * The title is a short, localized description of the tag. + * + * \param[in] tag EXIF tag + * \param[in] ifd IFD + * \return textual title of the tag, or NULL if the tag is unknown + */ +const char *exif_tag_get_title_in_ifd (ExifTag tag, ExifIfd ifd); + +/*! Return a verbose textual description of the given tag when found in the + * given IFD. The description is a verbose, localized description of the tag. + * + * \param[in] tag EXIF tag + * \param[in] ifd IFD + * \return textual description of the tag, or NULL if the tag is unknown + */ +const char *exif_tag_get_description_in_ifd (ExifTag tag, ExifIfd ifd); + +/*! Return whether the given tag is mandatory or not in the given IFD and + * data type according to the EXIF specification. If the IFD given is + * EXIF_IFD_COUNT, the result is EXIF_SUPPORT_LEVEL_UNKNOWN. If the data + * type is EXIF_DATA_TYPE_UNKNOWN, the result is + * EXIF_SUPPORT_LEVEL_UNKNOWN unless the support level is the same for + * all data types. + * + * \param[in] tag EXIF tag + * \param[in] ifd IFD or EXIF_IFD_COUNT + * \param[in] t data type or EXIF_DATA_TYPE_UNKNOWN + * \return the level of support for this tag + */ +ExifSupportLevel exif_tag_get_support_level_in_ifd (ExifTag tag, ExifIfd ifd, + ExifDataType t); + +/* Don't use these functions. They are here for compatibility only. */ + +/*! \deprecated Use #exif_tag_get_name_in_ifd instead */ +const char *exif_tag_get_name (ExifTag tag); + +/*! \deprecated Use #exif_tag_get_title_in_ifd instead */ +const char *exif_tag_get_title (ExifTag tag); + +/*! \deprecated Use #exif_tag_get_description_in_ifd instead */ +const char *exif_tag_get_description (ExifTag tag); + + +/* For now, do not use these functions. */ + +/*! \internal */ +ExifTag exif_tag_table_get_tag (unsigned int n); + +/*! \internal */ +const char *exif_tag_table_get_name (unsigned int n); + +/*! \internal */ +unsigned int exif_tag_table_count (void); + + +/* Don't use these definitions. They are here for compatibility only. */ + +/*! \deprecated Use EXIF_TAG_PRINT_IMAGE_MATCHING instead. */ +#define EXIF_TAG_UNKNOWN_C4A5 EXIF_TAG_PRINT_IMAGE_MATCHING + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __EXIF_TAG_H__ */ diff --git a/libexif/exif-utils.c b/libexif/exif-utils.c new file mode 100644 index 0000000..f375de1 --- /dev/null +++ b/libexif/exif-utils.c @@ -0,0 +1,253 @@ +/* exif-utils.c + * + * Copyright (c) 2001 Lutz Mueller <lutz@users.sourceforge.net> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA. + */ + +#include <config.h> + +#include <libexif/exif-utils.h> + +void +exif_array_set_byte_order (ExifFormat f, unsigned char *b, unsigned int n, + ExifByteOrder o_orig, ExifByteOrder o_new) +{ + unsigned int j; + unsigned int fs = exif_format_get_size (f); + ExifShort s; + ExifSShort ss; + ExifLong l; + ExifSLong sl; + ExifRational r; + ExifSRational sr; + + if (!b || !n || !fs) return; + + switch (f) { + case EXIF_FORMAT_SHORT: + for (j = 0; j < n; j++) { + s = exif_get_short (b + j * fs, o_orig); + exif_set_short (b + j * fs, o_new, s); + } + break; + case EXIF_FORMAT_SSHORT: + for (j = 0; j < n; j++) { + ss = exif_get_sshort (b + j * fs, o_orig); + exif_set_sshort (b + j * fs, o_new, ss); + } + break; + case EXIF_FORMAT_LONG: + for (j = 0; j < n; j++) { + l = exif_get_long (b + j * fs, o_orig); + exif_set_long (b + j * fs, o_new, l); + } + break; + case EXIF_FORMAT_RATIONAL: + for (j = 0; j < n; j++) { + r = exif_get_rational (b + j * fs, o_orig); + exif_set_rational (b + j * fs, o_new, r); + } + break; + case EXIF_FORMAT_SLONG: + for (j = 0; j < n; j++) { + sl = exif_get_slong (b + j * fs, o_orig); + exif_set_slong (b + j * fs, o_new, sl); + } + break; + case EXIF_FORMAT_SRATIONAL: + for (j = 0; j < n; j++) { + sr = exif_get_srational (b + j * fs, o_orig); + exif_set_srational (b + j * fs, o_new, sr); + } + break; + case EXIF_FORMAT_UNDEFINED: + case EXIF_FORMAT_BYTE: + case EXIF_FORMAT_ASCII: + default: + /* Nothing here. */ + break; + } +} + +ExifSShort +exif_get_sshort (const unsigned char *buf, ExifByteOrder order) +{ + if (!buf) return 0; + switch (order) { + case EXIF_BYTE_ORDER_MOTOROLA: + return ((buf[0] << 8) | buf[1]); + case EXIF_BYTE_ORDER_INTEL: + return ((buf[1] << 8) | buf[0]); + } + + /* Won't be reached */ + return (0); +} + +ExifShort +exif_get_short (const unsigned char *buf, ExifByteOrder order) +{ + return (exif_get_sshort (buf, order) & 0xffff); +} + +void +exif_set_sshort (unsigned char *b, ExifByteOrder order, ExifSShort value) +{ + if (!b) return; + switch (order) { + case EXIF_BYTE_ORDER_MOTOROLA: + b[0] = (unsigned char) (value >> 8); + b[1] = (unsigned char) value; + break; + case EXIF_BYTE_ORDER_INTEL: + b[0] = (unsigned char) value; + b[1] = (unsigned char) (value >> 8); + break; + } +} + +void +exif_set_short (unsigned char *b, ExifByteOrder order, ExifShort value) +{ + exif_set_sshort (b, order, value); +} + +ExifSLong +exif_get_slong (const unsigned char *b, ExifByteOrder order) +{ + if (!b) return 0; + switch (order) { + case EXIF_BYTE_ORDER_MOTOROLA: + return ((b[0] << 24) | (b[1] << 16) | (b[2] << 8) | b[3]); + case EXIF_BYTE_ORDER_INTEL: + return ((b[3] << 24) | (b[2] << 16) | (b[1] << 8) | b[0]); + } + + /* Won't be reached */ + return (0); +} + +void +exif_set_slong (unsigned char *b, ExifByteOrder order, ExifSLong value) +{ + if (!b) return; + switch (order) { + case EXIF_BYTE_ORDER_MOTOROLA: + b[0] = (unsigned char) (value >> 24); + b[1] = (unsigned char) (value >> 16); + b[2] = (unsigned char) (value >> 8); + b[3] = (unsigned char) value; + break; + case EXIF_BYTE_ORDER_INTEL: + b[3] = (unsigned char) (value >> 24); + b[2] = (unsigned char) (value >> 16); + b[1] = (unsigned char) (value >> 8); + b[0] = (unsigned char) value; + break; + } +} + +ExifLong +exif_get_long (const unsigned char *buf, ExifByteOrder order) +{ + return (exif_get_slong (buf, order) & 0xffffffff); +} + +void +exif_set_long (unsigned char *b, ExifByteOrder order, ExifLong value) +{ + exif_set_slong (b, order, value); +} + +ExifSRational +exif_get_srational (const unsigned char *buf, ExifByteOrder order) +{ + ExifSRational r; + + r.numerator = buf ? exif_get_slong (buf, order) : 0; + r.denominator = buf ? exif_get_slong (buf + 4, order) : 0; + + return (r); +} + +ExifRational +exif_get_rational (const unsigned char *buf, ExifByteOrder order) +{ + ExifRational r; + + r.numerator = buf ? exif_get_long (buf, order) : 0; + r.denominator = buf ? exif_get_long (buf + 4, order) : 0; + + return (r); +} + +void +exif_set_rational (unsigned char *buf, ExifByteOrder order, + ExifRational value) +{ + if (!buf) return; + exif_set_long (buf, order, value.numerator); + exif_set_long (buf + 4, order, value.denominator); +} + +void +exif_set_srational (unsigned char *buf, ExifByteOrder order, + ExifSRational value) +{ + if (!buf) return; + exif_set_slong (buf, order, value.numerator); + exif_set_slong (buf + 4, order, value.denominator); +} + +/*! This function converts rather UCS-2LE than UTF-16 to UTF-8. + * It should really be replaced by iconv(). + */ +void +exif_convert_utf16_to_utf8 (char *out, const unsigned short *in, int maxlen) +{ + if (maxlen <= 0) { + return; + } + while (*in) { + if (*in < 0x80) { + if (maxlen > 1) { + *out++ = (char)*in++; + maxlen--; + } else { + break; + } + } else if (*in < 0x800) { + if (maxlen > 2) { + *out++ = ((*in >> 6) & 0x1F) | 0xC0; + *out++ = (*in++ & 0x3F) | 0x80; + maxlen -= 2; + } else { + break; + } + } else { + if (maxlen > 3) { + *out++ = ((*in >> 12) & 0x0F) | 0xE0; + *out++ = ((*in >> 6) & 0x3F) | 0x80; + *out++ = (*in++ & 0x3F) | 0x80; + maxlen -= 3; + } else { + break; + } + } + } + *out = 0; +} diff --git a/libexif/exif-utils.h b/libexif/exif-utils.h new file mode 100644 index 0000000..7861564 --- /dev/null +++ b/libexif/exif-utils.h @@ -0,0 +1,194 @@ +/*! \file exif-utils.h + * \brief EXIF data manipulation functions and types + */ +/* + * Copyright (c) 2001 Lutz Mueller <lutz@users.sourceforge.net> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA. + */ + +#ifndef __EXIF_UTILS_H__ +#define __EXIF_UTILS_H__ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#include <libexif/exif-byte-order.h> +#include <libexif/exif-format.h> +#include <libexif/_stdint.h> + + +/* If these definitions don't work for you, please let us fix the + * macro generating _stdint.h */ + +/*! EXIF Unsigned Byte data type */ +typedef unsigned char ExifByte; /* 1 byte */ + +/*! EXIF Signed Byte data type */ +typedef signed char ExifSByte; /* 1 byte */ + +/*! EXIF Text String data type */ +typedef char * ExifAscii; + +/*! EXIF Unsigned Short data type */ +typedef uint16_t ExifShort; /* 2 bytes */ + +/*! EXIF Signed Short data type */ +typedef int16_t ExifSShort; /* 2 bytes */ + +/*! EXIF Unsigned Long data type */ +typedef uint32_t ExifLong; /* 4 bytes */ + +/*! EXIF Signed Long data type */ +typedef int32_t ExifSLong; /* 4 bytes */ + +/*! EXIF Unsigned Rational data type */ +typedef struct {ExifLong numerator; ExifLong denominator;} ExifRational; + +typedef char ExifUndefined; /* 1 byte */ + +/*! EXIF Signed Rational data type */ +typedef struct {ExifSLong numerator; ExifSLong denominator;} ExifSRational; + + +/*! Retrieve an #ExifShort value from memory. + * + * \param[in] b pointer to raw EXIF value in memory + * \param[in] order byte order of raw value + * \return value + */ +ExifShort exif_get_short (const unsigned char *b, ExifByteOrder order); + +/*! Retrieve an #ExifSShort value from memory. + * + * \param[in] b pointer to raw EXIF value in memory + * \param[in] order byte order of raw value + * \return value + */ +ExifSShort exif_get_sshort (const unsigned char *b, ExifByteOrder order); + +/*! Retrieve an #ExifLong value from memory. + * + * \param[in] b pointer to raw EXIF value in memory + * \param[in] order byte order of raw value + * \return value + */ +ExifLong exif_get_long (const unsigned char *b, ExifByteOrder order); + +/*! Retrieve an #ExifSLong value from memory. + * + * \param[in] b pointer to raw EXIF value in memory + * \param[in] order byte order of raw value + * \return value + */ +ExifSLong exif_get_slong (const unsigned char *b, ExifByteOrder order); + +/*! Retrieve an #ExifRational value from memory. + * + * \param[in] b pointer to raw EXIF value in memory + * \param[in] order byte order of raw value + * \return value + */ +ExifRational exif_get_rational (const unsigned char *b, ExifByteOrder order); + +/*! Retrieve an #ExifSRational value from memory. + * + * \param[in] b pointer to raw EXIF value in memory + * \param[in] order byte order of raw value + * \return value + */ +ExifSRational exif_get_srational (const unsigned char *b, ExifByteOrder order); + +/*! Store an ExifShort value into memory in EXIF format. + * + * \param[out] b buffer in which to write raw value + * \param[in] order byte order to use + * \param[in] value data value to store + */ +void exif_set_short (unsigned char *b, ExifByteOrder order, + ExifShort value); + +/*! Store an ExifSShort value into memory in EXIF format. + * + * \param[out] b buffer in which to write raw value + * \param[in] order byte order to use + * \param[in] value data value to store + */ +void exif_set_sshort (unsigned char *b, ExifByteOrder order, + ExifSShort value); + +/*! Store an ExifLong value into memory in EXIF format. + * + * \param[out] b buffer in which to write raw value + * \param[in] order byte order to use + * \param[in] value data value to store + */ +void exif_set_long (unsigned char *b, ExifByteOrder order, + ExifLong value); + +/*! Store an ExifSLong value into memory in EXIF format. + * + * \param[out] b buffer in which to write raw value + * \param[in] order byte order to use + * \param[in] value data value to store + */ +void exif_set_slong (unsigned char *b, ExifByteOrder order, + ExifSLong value); + +/*! Store an ExifRational value into memory in EXIF format. + * + * \param[out] b buffer in which to write raw value + * \param[in] order byte order to use + * \param[in] value data value to store + */ +void exif_set_rational (unsigned char *b, ExifByteOrder order, + ExifRational value); + +/*! Store an ExifSRational value into memory in EXIF format. + * + * \param[out] b buffer in which to write raw value + * \param[in] order byte order to use + * \param[in] value data value to store + */ +void exif_set_srational (unsigned char *b, ExifByteOrder order, + ExifSRational value); + +/*! \internal */ +void exif_convert_utf16_to_utf8 (char *out, const unsigned short *in, int maxlen); + +/* Please do not use this function outside of the library. */ + +/*! \internal */ +void exif_array_set_byte_order (ExifFormat, unsigned char *, unsigned int, + ExifByteOrder o_orig, ExifByteOrder o_new); + +#undef MIN +#define MIN(a, b) (((a) < (b)) ? (a) : (b)) + +#undef MAX +#define MAX(a, b) (((a) > (b)) ? (a) : (b)) + +/* For compatibility with older versions */ + +/*! \deprecated Use EXIF_TAG_SUB_SEC_TIME instead. */ +#define EXIF_TAG_SUBSEC_TIME EXIF_TAG_SUB_SEC_TIME + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __EXIF_UTILS_H__ */ diff --git a/libexif/exif.h b/libexif/exif.h new file mode 100644 index 0000000..1c8e0f6 --- /dev/null +++ b/libexif/exif.h @@ -0,0 +1,87 @@ +/*! \file exif.h exif/exif.h + * \brief Dummy header file for documentation purposes + * \date 2007 + * \author Hans Ulrich Niedermann, et. al. + * + * \mainpage The libexif library + * + * \section general_notes General Notes + * + * This documentation is work in progress, as is the code itself. + * + * \section using_libexif Using libexif + * + * \#include <libexif/exif-data.h> + * + * libexif provides a libexif.pc file for use with pkgconfig on the + * libexif installation. If you are using libtool to build your + * package, you can also make use of libexif-uninstalled.pc. + * + * An application using libexif would typically first create an #ExifLoader to + * load EXIF data into memory. From there, it would extract that data as + * an #ExifData to start manipulating it. Each IFD is represented by its own + * #ExifContent within that #ExifData, which contains all the tag data in + * #ExifEntry form. If the MakerNote data is required, an #ExifMnoteData + * can be extracted from the #ExifData and manipulated with the MakerNote + * functions. + * + * libexif is written in C using an object-based style that defines + * sets of functions that operate on each data structure. + * + * \section data_structures Primary Data Structures + * + * #ExifLoader + * State maintained by the loader interface while importing EXIF data + * from an external file or memory + * + * #ExifData + * The entirety of EXIF data found in an image + * + * #ExifContent + * All EXIF tags in a single IFD + * + * #ExifEntry + * Data found in a single EXIF tag + * + * #ExifMnoteData + * All data found in the MakerNote tag + * + * #ExifLog + * State maintained by the logging interface + * + * \section string_conventions String Conventions + * + * Strings are 8 bit characters ("char*"). When libexif is compiled with + * NLS, character set and encoding are as set in the current locale, + * except for strings that come directly from the data in EXIF + * tags which are generally returned in raw form. Most EXIF strings are + * defined to be plain 7-bit ASCII so this raw form should be acceptable in + * any UNIX locale, but some software ignores the specification and + * writes 8-bit characters. It is up to the application to detect this + * and deal with it intelligently. + * + * \section memory_management Memory Management Patterns + * + * For pointers to data objects, libexif uses reference counting. The + * pattern is to use the foo_new() function to create a data object, + * foo_ref() to increase the reference counter, and foo_unref() to + * decrease the reference counter and possibly free(3)ing the memory. + * + * Libexif by default relies on the calloc(3), realloc(3), and free(3) + * functions, but the libexif user can tell libexif to use their + * special memory management functions at runtime. + * + * \section thread_safety Thread Safety + * + * libexif is thread safe when the underlying C library is also thread safe. + * Some C libraries may require defining a special macro (like _REENTRANT) + * to ensure this, or may require linking to a special thread-safe version of + * the library. + * + * The programmer must ensure that each object allocated by libexif is only + * used in a single thread at once. For example, an ExifData* allocated + * in one thread can't be used in a second thread if there is any chance + * that the first thread could use it at the same time. Multiple threads + * can use libexif without issues if they never share handles. + * + */ diff --git a/libexif/fuji/Makefile-files b/libexif/fuji/Makefile-files new file mode 100644 index 0000000..3a520b3 --- /dev/null +++ b/libexif/fuji/Makefile-files @@ -0,0 +1,7 @@ +# -*- Makefile -*- +noinst_LTLIBRARIES += libmnote-fuji.la +libmnote_fuji_la_SOURCES = \ + fuji/mnote-fuji-entry.c fuji/mnote-fuji-entry.h \ + fuji/exif-mnote-data-fuji.c fuji/exif-mnote-data-fuji.h \ + fuji/mnote-fuji-tag.c fuji/mnote-fuji-tag.h +libmnote_fuji_la_LIBADD = $(LTLIBINTL) diff --git a/libexif/fuji/exif-mnote-data-fuji.c b/libexif/fuji/exif-mnote-data-fuji.c new file mode 100644 index 0000000..9514654 --- /dev/null +++ b/libexif/fuji/exif-mnote-data-fuji.c @@ -0,0 +1,349 @@ +/* exif-mnote-data-fuji.c + * + * Copyright (c) 2002 Lutz Mueller <lutz@users.sourceforge.net> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA. + */ + +#include <stdlib.h> +#include <string.h> + + +#include <config.h> +#include <libexif/exif-byte-order.h> +#include <libexif/exif-utils.h> + +#include "exif-mnote-data-fuji.h" + +struct _MNoteFujiDataPrivate { + ExifByteOrder order; +}; + +static void +exif_mnote_data_fuji_clear (ExifMnoteDataFuji *n) +{ + ExifMnoteData *d = (ExifMnoteData *) n; + unsigned int i; + + if (!n) return; + + if (n->entries) { + for (i = 0; i < n->count; i++) + if (n->entries[i].data) { + exif_mem_free (d->mem, n->entries[i].data); + n->entries[i].data = NULL; + } + exif_mem_free (d->mem, n->entries); + n->entries = NULL; + n->count = 0; + } +} + +static void +exif_mnote_data_fuji_free (ExifMnoteData *n) +{ + if (!n) return; + + exif_mnote_data_fuji_clear ((ExifMnoteDataFuji *) n); +} + +static char * +exif_mnote_data_fuji_get_value (ExifMnoteData *d, unsigned int i, char *val, unsigned int maxlen) +{ + ExifMnoteDataFuji *n = (ExifMnoteDataFuji *) d; + + if (!d || !val) return NULL; + if (i > n->count -1) return NULL; +/* + exif_log (d->log, EXIF_LOG_CODE_DEBUG, "ExifMnoteDataFuji", + "Querying value for tag '%s'...", + mnote_fuji_tag_get_name (n->entries[i].tag)); +*/ + return mnote_fuji_entry_get_value (&n->entries[i], val, maxlen); +} + +static void +exif_mnote_data_fuji_save (ExifMnoteData *ne, unsigned char **buf, + unsigned int *buf_size) +{ + ExifMnoteDataFuji *n = (ExifMnoteDataFuji *) ne; + size_t i, o, s, doff; + unsigned char *t; + size_t ts; + + if (!n || !buf || !buf_size) return; + + /* + * Allocate enough memory for all entries and the number + * of entries. + */ + *buf_size = 8 + 4 + 2 + n->count * 12 + 4; + *buf = exif_mem_alloc (ne->mem, *buf_size); + if (!*buf) { + *buf_size = 0; + return; + } + + /* + * Header: "FUJIFILM" and 4 bytes offset to the first entry. + * As the first entry will start right thereafter, the offset is 12. + */ + memcpy (*buf, "FUJIFILM", 8); + exif_set_long (*buf + 8, n->order, 12); + + /* Save the number of entries */ + exif_set_short (*buf + 8 + 4, n->order, (ExifShort) n->count); + + /* Save each entry */ + for (i = 0; i < n->count; i++) { + o = 8 + 4 + 2 + i * 12; + exif_set_short (*buf + o + 0, n->order, (ExifShort) n->entries[i].tag); + exif_set_short (*buf + o + 2, n->order, (ExifShort) n->entries[i].format); + exif_set_long (*buf + o + 4, n->order, n->entries[i].components); + o += 8; + s = exif_format_get_size (n->entries[i].format) * + n->entries[i].components; + if (s > 65536) { + /* Corrupt data: EXIF data size is limited to the + * maximum size of a JPEG segment (64 kb). + */ + continue; + } + if (s > 4) { + ts = *buf_size + s; + + /* Ensure even offsets. Set padding bytes to 0. */ + if (s & 1) ts += 1; + t = exif_mem_realloc (ne->mem, *buf, ts); + if (!t) { + return; + } + *buf = t; + *buf_size = ts; + doff = *buf_size - s; + if (s & 1) { doff--; *(*buf + *buf_size - 1) = '\0'; } + exif_set_long (*buf + o, n->order, doff); + } else + doff = o; + + /* + * Write the data. Fill unneeded bytes with 0. Do not + * crash if data is NULL. + */ + if (!n->entries[i].data) memset (*buf + doff, 0, s); + else memcpy (*buf + doff, n->entries[i].data, s); + } +} + +static void +exif_mnote_data_fuji_load (ExifMnoteData *en, + const unsigned char *buf, unsigned int buf_size) +{ + ExifMnoteDataFuji *n = (ExifMnoteDataFuji*) en; + ExifLong c; + size_t i, tcount, o, datao; + + if (!n || !buf || !buf_size) { + exif_log (en->log, EXIF_LOG_CODE_CORRUPT_DATA, + "ExifMnoteDataFuji", "Short MakerNote"); + return; + } + datao = 6 + n->offset; + if ((datao + 12 < datao) || (datao + 12 < 12) || (datao + 12 > buf_size)) { + exif_log (en->log, EXIF_LOG_CODE_CORRUPT_DATA, + "ExifMnoteDataFuji", "Short MakerNote"); + return; + } + + n->order = EXIF_BYTE_ORDER_INTEL; + datao += exif_get_long (buf + datao + 8, EXIF_BYTE_ORDER_INTEL); + if ((datao + 2 < datao) || (datao + 2 < 2) || + (datao + 2 > buf_size)) { + exif_log (en->log, EXIF_LOG_CODE_CORRUPT_DATA, + "ExifMnoteDataFuji", "Short MakerNote"); + return; + } + + /* Read the number of tags */ + c = exif_get_short (buf + datao, EXIF_BYTE_ORDER_INTEL); + datao += 2; + + /* Remove any old entries */ + exif_mnote_data_fuji_clear (n); + + /* Reserve enough space for all the possible MakerNote tags */ + n->entries = exif_mem_alloc (en->mem, sizeof (MnoteFujiEntry) * c); + if (!n->entries) { + EXIF_LOG_NO_MEMORY(en->log, "ExifMnoteDataFuji", sizeof (MnoteFujiEntry) * c); + return; + } + + /* Parse all c entries, storing ones that are successfully parsed */ + tcount = 0; + for (i = c, o = datao; i; --i, o += 12) { + size_t s; + if ((o + 12 < o) || (o + 12 < 12) || (o + 12 > buf_size)) { + exif_log (en->log, EXIF_LOG_CODE_CORRUPT_DATA, + "ExifMnoteDataFuji", "Short MakerNote"); + break; + } + + n->entries[tcount].tag = exif_get_short (buf + o, n->order); + n->entries[tcount].format = exif_get_short (buf + o + 2, n->order); + n->entries[tcount].components = exif_get_long (buf + o + 4, n->order); + n->entries[tcount].order = n->order; + + exif_log (en->log, EXIF_LOG_CODE_DEBUG, "ExifMnoteDataFuji", + "Loading entry 0x%x ('%s')...", n->entries[tcount].tag, + mnote_fuji_tag_get_name (n->entries[tcount].tag)); + + /* + * Size? If bigger than 4 bytes, the actual data is not + * in the entry but somewhere else (offset). + */ + s = exif_format_get_size (n->entries[tcount].format) * n->entries[tcount].components; + n->entries[tcount].size = s; + if (s) { + size_t dataofs = o + 8; + if (s > 4) + /* The data in this case is merely a pointer */ + dataofs = exif_get_long (buf + dataofs, n->order) + 6 + n->offset; + if ((dataofs + s < dataofs) || (dataofs + s < s) || + (dataofs + s >= buf_size)) { + exif_log (en->log, EXIF_LOG_CODE_CORRUPT_DATA, + "ExifMnoteDataFuji", "Tag data past end of " + "buffer (%u >= %u)", dataofs + s, buf_size); + continue; + } + + n->entries[tcount].data = exif_mem_alloc (en->mem, s); + if (!n->entries[tcount].data) { + EXIF_LOG_NO_MEMORY(en->log, "ExifMnoteDataFuji", s); + continue; + } + memcpy (n->entries[tcount].data, buf + dataofs, s); + } + + /* Tag was successfully parsed */ + ++tcount; + } + /* Store the count of successfully parsed tags */ + n->count = tcount; +} + +static unsigned int +exif_mnote_data_fuji_count (ExifMnoteData *n) +{ + return n ? ((ExifMnoteDataFuji *) n)->count : 0; +} + +static unsigned int +exif_mnote_data_fuji_get_id (ExifMnoteData *d, unsigned int n) +{ + ExifMnoteDataFuji *note = (ExifMnoteDataFuji *) d; + + if (!note) return 0; + if (note->count <= n) return 0; + return note->entries[n].tag; +} + +static const char * +exif_mnote_data_fuji_get_name (ExifMnoteData *d, unsigned int i) +{ + ExifMnoteDataFuji *n = (ExifMnoteDataFuji *) d; + + if (!n) return NULL; + if (i >= n->count) return NULL; + return mnote_fuji_tag_get_name (n->entries[i].tag); +} + +static const char * +exif_mnote_data_fuji_get_title (ExifMnoteData *d, unsigned int i) +{ + ExifMnoteDataFuji *n = (ExifMnoteDataFuji *) d; + + if (!n) return NULL; + if (i >= n->count) return NULL; + return mnote_fuji_tag_get_title (n->entries[i].tag); +} + +static const char * +exif_mnote_data_fuji_get_description (ExifMnoteData *d, unsigned int i) +{ + ExifMnoteDataFuji *n = (ExifMnoteDataFuji *) d; + + if (!n) return NULL; + if (i >= n->count) return NULL; + return mnote_fuji_tag_get_description (n->entries[i].tag); +} + +static void +exif_mnote_data_fuji_set_byte_order (ExifMnoteData *d, ExifByteOrder o) +{ + ExifByteOrder o_orig; + ExifMnoteDataFuji *n = (ExifMnoteDataFuji *) d; + unsigned int i; + + if (!n) return; + + o_orig = n->order; + n->order = o; + for (i = 0; i < n->count; i++) { + n->entries[i].order = o; + exif_array_set_byte_order (n->entries[i].format, n->entries[i].data, + n->entries[i].components, o_orig, o); + } +} + +static void +exif_mnote_data_fuji_set_offset (ExifMnoteData *n, unsigned int o) +{ + if (n) ((ExifMnoteDataFuji *) n)->offset = o; +} + +int +exif_mnote_data_fuji_identify (const ExifData *ed, const ExifEntry *e) +{ + return ((e->size >= 12) && !memcmp (e->data, "FUJIFILM", 8)); +} + +ExifMnoteData * +exif_mnote_data_fuji_new (ExifMem *mem) +{ + ExifMnoteData *d; + + if (!mem) return NULL; + + d = exif_mem_alloc (mem, sizeof (ExifMnoteDataFuji)); + if (!d) return NULL; + + exif_mnote_data_construct (d, mem); + + /* Set up function pointers */ + d->methods.free = exif_mnote_data_fuji_free; + d->methods.set_byte_order = exif_mnote_data_fuji_set_byte_order; + d->methods.set_offset = exif_mnote_data_fuji_set_offset; + d->methods.load = exif_mnote_data_fuji_load; + d->methods.save = exif_mnote_data_fuji_save; + d->methods.count = exif_mnote_data_fuji_count; + d->methods.get_id = exif_mnote_data_fuji_get_id; + d->methods.get_name = exif_mnote_data_fuji_get_name; + d->methods.get_title = exif_mnote_data_fuji_get_title; + d->methods.get_description = exif_mnote_data_fuji_get_description; + d->methods.get_value = exif_mnote_data_fuji_get_value; + + return d; +} diff --git a/libexif/fuji/exif-mnote-data-fuji.h b/libexif/fuji/exif-mnote-data-fuji.h new file mode 100644 index 0000000..2a7cd3e --- /dev/null +++ b/libexif/fuji/exif-mnote-data-fuji.h @@ -0,0 +1,53 @@ +/* exif-mnote-data-fuji.h + * + * Copyright (c) 2002 Lutz Mueller <lutz@users.sourceforge.net> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA. + */ + +#ifndef __MNOTE_FUJI_CONTENT_H__ +#define __MNOTE_FUJI_CONTENT_H__ + +#include <libexif/exif-mnote-data.h> +#include <libexif/exif-mnote-data-priv.h> +#include <libexif/exif-data.h> +#include <libexif/fuji/mnote-fuji-entry.h> + +typedef struct _ExifMnoteDataFuji ExifMnoteDataFuji; + +struct _ExifMnoteDataFuji { + ExifMnoteData parent; + + MnoteFujiEntry *entries; + unsigned int count; + + ExifByteOrder order; + unsigned int offset; +}; + +/*! Detect if MakerNote is recognized as one handled by the Fuji module. + * + * \param[in] ed image #ExifData to identify as as a Fuji type + * \param[in] e #ExifEntry for EXIF_TAG_MAKER_NOTE, from within ed but + * duplicated here for convenience + * \return 0 if not recognized, nonzero if recognized. The specific nonzero + * value returned may identify a subtype unique within this module. + */ +int exif_mnote_data_fuji_identify (const ExifData *ed, const ExifEntry *e); + +ExifMnoteData *exif_mnote_data_fuji_new (ExifMem *); + +#endif /* __MNOTE_FUJI_CONTENT_H__ */ diff --git a/libexif/fuji/mnote-fuji-entry.c b/libexif/fuji/mnote-fuji-entry.c new file mode 100644 index 0000000..0ca1634 --- /dev/null +++ b/libexif/fuji/mnote-fuji-entry.c @@ -0,0 +1,306 @@ +/* mnote-fuji-entry.c + * + * Copyright (c) 2002 Lutz Mueller <lutz@users.sourceforge.net> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA. + */ + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +#include <config.h> + +#include <libexif/i18n.h> + +#include "mnote-fuji-entry.h" + +#define CF(format,target,v,maxlen) \ +{ \ + if (format != target) { \ + snprintf (v, maxlen, \ + _("Invalid format '%s', " \ + "expected '%s'."), \ + exif_format_get_name (format), \ + exif_format_get_name (target)); \ + break; \ + } \ +} + +#define CC(number,target,v,maxlen) \ +{ \ + if (number != target) { \ + snprintf (v, maxlen, \ + _("Invalid number of components (%i, " \ + "expected %i)."), (int) number, (int) target); \ + break; \ + } \ +} + +static const struct { + ExifTag tag; + struct { + int index; + const char *string; + } elem[22]; +} items[] = { +#ifndef NO_VERBOSE_TAG_DATA + { MNOTE_FUJI_TAG_SHARPNESS, + { {1, N_("Softest")}, + {2, N_("Soft")}, + {3, N_("Normal")}, + {4, N_("Hard")}, + {5, N_("Hardest")}, + {0x0082, N_("Medium soft")}, + {0x0084, N_("Medium hard")}, + {0x8000, N_("Film simulation mode")}, + {0xFFFF, N_("Off")}, + {0, NULL}}}, + { MNOTE_FUJI_TAG_WHITE_BALANCE, + { {0, N_("Auto")}, + {0x100, N_("Daylight")}, + {0x200, N_("Cloudy")}, + {0x300, N_("Daylight fluorescent")}, + {0x301, N_("Day white fluorescent")}, + {0x302, N_("White fluorescent")}, + {0x400, N_("Incandescent")}, + {0x500, N_("Flash")}, + {0xF00, N_("Custom")}, + {0, NULL}}}, + { MNOTE_FUJI_TAG_COLOR, + { {0, N_("Standard")}, + {0x0080, N_("Medium high")}, + {0x0100, N_("High")}, + {0x0180, N_("Medium low")}, + {0x0200, N_("Original")}, + {0x0300, N_("Black & white")}, + {0x8000, N_("Film simulation mode")}, + {0, NULL}}}, + { MNOTE_FUJI_TAG_TONE, + { {0, N_("Standard")}, + {0x0080, N_("Medium hard")}, + {0x0100, N_("Hard")}, + {0x0180, N_("Medium soft")}, + {0x0200, N_("Original")}, + {0x8000, N_("Film simulation mode")}, + {0, NULL}}}, + { MNOTE_FUJI_TAG_FLASH_MODE, + { {0, N_("Auto")}, + {1, N_("On")}, + {2, N_("Off")}, + {3, N_("Red-eye reduction")}, + {0, NULL}}}, + { MNOTE_FUJI_TAG_MACRO, + { {0, N_("Off")}, + {1, N_("On")}, + {0, NULL}}}, + { MNOTE_FUJI_TAG_FOCUS_MODE, + { {0, N_("Auto")}, + {1, N_("Manual")}, + {0, NULL}}}, + { MNOTE_FUJI_TAG_SLOW_SYNC, + { {0, N_("Off")}, + {1, N_("On")}, + {0, NULL}}}, + { MNOTE_FUJI_TAG_PICTURE_MODE, + { {0, N_("Auto")}, + {1, N_("Portrait")}, + {2, N_("Landscape")}, + {4, N_("Sports")}, + {5, N_("Night")}, + {6, N_("Program AE")}, + {7, N_("Natural photo")}, + {8, N_("Vibration reduction")}, + {0x000A, N_("Sunset")}, + {0x000B, N_("Museum")}, + {0x000C, N_("Party")}, + {0x000D, N_("Flower")}, + {0x000E, N_("Text")}, + {0x000F, N_("NP & flash")}, + {0x0010, N_("Beach")}, + {0x0011, N_("Snow")}, + {0x0012, N_("Fireworks")}, + {0x0013, N_("Underwater")}, + {0x0100, N_("Aperture priority AE")}, + {0x0200, N_("Shutter priority AE")}, + {0x0300, N_("Manual exposure")}, + {0, NULL}}}, + { MNOTE_FUJI_TAG_CONT_TAKING, + { {0, N_("Off")}, + {1, N_("On")}, + {0, NULL}}}, + { MNOTE_FUJI_TAG_FINEPIX_COLOR, + { {0x00, N_("F-Standard")}, + {0x10, N_("F-Chrome")}, + {0x30, N_("F-B&W")}, + {0, NULL}}}, + { MNOTE_FUJI_TAG_BLUR_CHECK, + { {0, N_("No blur")}, + {1, N_("Blur warning")}, + {0, NULL}}}, + { MNOTE_FUJI_TAG_FOCUS_CHECK, + { {0, N_("Focus good")}, + {1, N_("Out of focus")}, + {0, NULL}}}, + { MNOTE_FUJI_TAG_AUTO_EXPOSURE_CHECK, + { {0, N_("AE good")}, + {1, N_("Over exposed")}, + {0, NULL}}}, + { MNOTE_FUJI_TAG_DYNAMIC_RANGE, + { {1, N_("Standard")}, + {3, N_("Wide")}, + {0, NULL}}}, + { MNOTE_FUJI_TAG_FILM_MODE, + { {0, N_("F0/Standard")}, + {0x0100, N_("F1/Studio portrait")}, + {0x0110, N_("F1a/Professional portrait")}, + {0x0120, N_("F1b/Professional portrait")}, + {0x0130, N_("F1c/Professional portrait")}, + {0x0200, N_("F2/Fujichrome")}, + {0x0300, N_("F3/Studio portrait Ex")}, + {0x0400, N_("F4/Velvia")}, + {0, NULL}}}, + { MNOTE_FUJI_TAG_DYNAMIC_RANGE_SETTING, + { {0, N_("Auto (100-400%)")}, + {1, N_("RAW")}, + {0x0100, N_("Standard (100%)")}, + {0x0200, N_("Wide1 (230%)")}, + {0x0201, N_("Wide2 (400%)")}, + {0x8000, N_("Film simulation mode")}, + {0, NULL}}}, +#endif + {0, {{0, NULL}}} +}; + + +char * +mnote_fuji_entry_get_value (MnoteFujiEntry *entry, + char *val, unsigned int maxlen) +{ + ExifLong vl; + ExifSLong vsl; + ExifShort vs, vs2; + ExifRational vr; + ExifSRational vsr; + int i, j; + + if (!entry) return (NULL); + + memset (val, 0, maxlen); + maxlen--; + + switch (entry->tag) { + case MNOTE_FUJI_TAG_VERSION: + CF (entry->format, EXIF_FORMAT_UNDEFINED, val, maxlen); + CC (entry->components, 4, val, maxlen); + memcpy (val, entry->data, MIN(maxlen, entry->size)); + break; + case MNOTE_FUJI_TAG_SHARPNESS: + case MNOTE_FUJI_TAG_WHITE_BALANCE: + case MNOTE_FUJI_TAG_COLOR: + case MNOTE_FUJI_TAG_TONE: + case MNOTE_FUJI_TAG_FLASH_MODE: + case MNOTE_FUJI_TAG_MACRO: + case MNOTE_FUJI_TAG_FOCUS_MODE: + case MNOTE_FUJI_TAG_SLOW_SYNC: + case MNOTE_FUJI_TAG_PICTURE_MODE: + case MNOTE_FUJI_TAG_CONT_TAKING: + case MNOTE_FUJI_TAG_FINEPIX_COLOR: + case MNOTE_FUJI_TAG_BLUR_CHECK: + case MNOTE_FUJI_TAG_FOCUS_CHECK: + case MNOTE_FUJI_TAG_AUTO_EXPOSURE_CHECK: + case MNOTE_FUJI_TAG_DYNAMIC_RANGE: + case MNOTE_FUJI_TAG_FILM_MODE: + case MNOTE_FUJI_TAG_DYNAMIC_RANGE_SETTING: + CF (entry->format, EXIF_FORMAT_SHORT, val, maxlen); + CC (entry->components, 1, val, maxlen); + vs = exif_get_short (entry->data, entry->order); + + /* search the tag */ + for (i = 0; (items[i].tag && items[i].tag != entry->tag); i++); + if (!items[i].tag) { + snprintf (val, maxlen, + _("Internal error (unknown value %i)"), vs); + break; + } + + /* find the value */ + for (j = 0; items[i].elem[j].string && + (items[i].elem[j].index < vs); j++); + if (items[i].elem[j].index != vs) { + snprintf (val, maxlen, + _("Internal error (unknown value %i)"), vs); + break; + } + strncpy (val, _(items[i].elem[j].string), maxlen); + break; + case MNOTE_FUJI_TAG_FOCUS_POINT: + CF (entry->format, EXIF_FORMAT_SHORT, val, maxlen); + CC (entry->components, 2, val, maxlen); + vs = exif_get_short (entry->data, entry->order); + vs2 = exif_get_short (entry->data+2, entry->order); + snprintf (val, maxlen, "%i, %i", vs, vs2); + break; + case MNOTE_FUJI_TAG_MIN_FOCAL_LENGTH: + case MNOTE_FUJI_TAG_MAX_FOCAL_LENGTH: + CF (entry->format, EXIF_FORMAT_RATIONAL, val, maxlen); + CC (entry->components, 1, val, maxlen); + vr = exif_get_rational (entry->data, entry->order); + if (!vr.denominator) break; + snprintf (val, maxlen, _("%2.2f mm"), (double) vr.numerator / + vr.denominator); + break; + + default: + switch (entry->format) { + case EXIF_FORMAT_ASCII: + strncpy (val, (char *)entry->data, MIN(maxlen, entry->size)); + break; + case EXIF_FORMAT_SHORT: + vs = exif_get_short (entry->data, entry->order); + snprintf (val, maxlen, "%i", vs); + break; + case EXIF_FORMAT_LONG: + vl = exif_get_long (entry->data, entry->order); + snprintf (val, maxlen, "%lu", (long unsigned) vl); + break; + case EXIF_FORMAT_SLONG: + vsl = exif_get_slong (entry->data, entry->order); + snprintf (val, maxlen, "%li", (long int) vsl); + break; + case EXIF_FORMAT_RATIONAL: + vr = exif_get_rational (entry->data, entry->order); + if (!vr.denominator) break; + snprintf (val, maxlen, "%2.4f", (double) vr.numerator / + vr.denominator); + break; + case EXIF_FORMAT_SRATIONAL: + vsr = exif_get_srational (entry->data, entry->order); + if (!vsr.denominator) break; + snprintf (val, maxlen, "%2.4f", (double) vsr.numerator / + vsr.denominator); + break; + case EXIF_FORMAT_UNDEFINED: + default: + snprintf (val, maxlen, _("%i bytes unknown data"), + entry->size); + break; + } + break; + } + + return (val); +} diff --git a/libexif/fuji/mnote-fuji-entry.h b/libexif/fuji/mnote-fuji-entry.h new file mode 100644 index 0000000..a8395c5 --- /dev/null +++ b/libexif/fuji/mnote-fuji-entry.h @@ -0,0 +1,45 @@ +/* mnote-fuji-entry.h + * + * Copyright (c) 2002 Lutz Mueller <lutz@users.sourceforge.net> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA. + */ + +#ifndef __MNOTE_FUJI_ENTRY_H__ +#define __MNOTE_FUJI_ENTRY_H__ + +#include <libexif/exif-format.h> +#include <libexif/fuji/mnote-fuji-tag.h> + +typedef struct _MnoteFujiEntry MnoteFujiEntry; +typedef struct _MnoteFujiEntryPrivate MnoteFujiEntryPrivate; + +#include <libexif/fuji/exif-mnote-data-fuji.h> + +struct _MnoteFujiEntry { + MnoteFujiTag tag; + ExifFormat format; + unsigned long components; + + unsigned char *data; + unsigned int size; + + ExifByteOrder order; +}; + +char *mnote_fuji_entry_get_value (MnoteFujiEntry *entry, char *val, unsigned int maxlen); + +#endif /* __MNOTE_FUJI_ENTRY_H__ */ diff --git a/libexif/fuji/mnote-fuji-tag.c b/libexif/fuji/mnote-fuji-tag.c new file mode 100644 index 0000000..3b80597 --- /dev/null +++ b/libexif/fuji/mnote-fuji-tag.c @@ -0,0 +1,105 @@ +/* mnote-fuji-tag.c + * + * Copyright (c) 2002 Lutz Mueller <lutz@users.sourceforge.net> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA. + */ + +#include <stdlib.h> + +#include <config.h> +#include <libexif/i18n.h> + +#include "mnote-fuji-tag.h" + + +static const struct { + MnoteFujiTag tag; + const char *name; + const char *title; + const char *description; +} table[] = { +#ifndef NO_VERBOSE_TAG_STRINGS + {MNOTE_FUJI_TAG_VERSION, "Version", N_("Maker Note Version"), ""}, + {MNOTE_FUJI_TAG_SERIAL_NUMBER, "SerialNumber", N_("Serial Number"), N_("This number is unique and based on the date of manufacture.")}, + {MNOTE_FUJI_TAG_QUALITY, "Quality", N_("Quality"), ""}, + {MNOTE_FUJI_TAG_SHARPNESS, "Sharpness", N_("Sharpness"), ""}, + {MNOTE_FUJI_TAG_WHITE_BALANCE, "WhiteBalance", N_("White Balance"), ""}, + {MNOTE_FUJI_TAG_COLOR, "ChromaticitySaturation", N_("Chromaticity Saturation"), ""}, + {MNOTE_FUJI_TAG_TONE, "Contrast", N_("Contrast"), ""}, + {MNOTE_FUJI_TAG_FLASH_MODE, "FlashMode", N_("Flash Mode"), ""}, + {MNOTE_FUJI_TAG_FLASH_STRENGTH, "FlashStrength", N_("Flash Firing Strength Compensation"), ""}, + {MNOTE_FUJI_TAG_MACRO, "MacroMode", N_("Macro Mode"), ""}, + {MNOTE_FUJI_TAG_FOCUS_MODE, "FocusingMode", N_("Focusing Mode"), ""}, + {MNOTE_FUJI_TAG_FOCUS_POINT, "FocusPoint", N_("Focus Point"), ""}, + {MNOTE_FUJI_TAG_SLOW_SYNC, "SlowSynchro", N_("Slow Synchro Mode"), ""}, + {MNOTE_FUJI_TAG_PICTURE_MODE, "PictureMode", N_("Picture Mode"), ""}, + {MNOTE_FUJI_TAG_CONT_TAKING, "ContinuousTaking", N_("Continuous Taking"), ""}, + {MNOTE_FUJI_TAG_SEQUENCE_NUMBER, "ContinuousSequence", N_("Continuous Sequence Number"), ""}, + {MNOTE_FUJI_TAG_FINEPIX_COLOR, "FinePixColor", N_("FinePix Color"), ""}, + {MNOTE_FUJI_TAG_BLUR_CHECK, "BlurCheck", N_("Blur Check"), ""}, + {MNOTE_FUJI_TAG_FOCUS_CHECK, "AutoFocusCheck", N_("Auto Focus Check"), ""}, + {MNOTE_FUJI_TAG_AUTO_EXPOSURE_CHECK, "AutoExposureCheck", N_("Auto Exposure Check"), ""}, + {MNOTE_FUJI_TAG_DYNAMIC_RANGE, "DynamicRange", N_("Dynamic Range"), ""}, + {MNOTE_FUJI_TAG_FILM_MODE, "FilmMode", N_("Film Simulation Mode"), ""}, + {MNOTE_FUJI_TAG_DYNAMIC_RANGE_SETTING, "DRangeMode", N_("Dynamic Range Wide Mode"), ""}, + {MNOTE_FUJI_TAG_DEV_DYNAMIC_RANGE_SETTING, "DevDRangeMode", N_("Development Dynamic Range Wide Mode"), ""}, + {MNOTE_FUJI_TAG_MIN_FOCAL_LENGTH, "MinFocalLen", N_("Minimum Focal Length"), ""}, + {MNOTE_FUJI_TAG_MAX_FOCAL_LENGTH, "MaxFocalLen", N_("Maximum Focal Length"), ""}, + {MNOTE_FUJI_TAG_MAX_APERT_AT_MIN_FOC, "MaxApertAtMinFoc", N_("Maximum Aperture at Minimum Focal"), ""}, + {MNOTE_FUJI_TAG_MAX_APERT_AT_MAX_FOC, "MaxApertAtMaxFoc", N_("Maximum Aperture at Maximum Focal"), ""}, + {MNOTE_FUJI_TAG_FILE_SOURCE, "FileSource", N_("File Source"), ""}, + {MNOTE_FUJI_TAG_ORDER_NUMBER, "OrderNumber", N_("Order Number"), ""}, + {MNOTE_FUJI_TAG_FRAME_NUMBER, "FrameNumber", N_("Frame Number"), ""}, +#endif + {0, NULL, NULL, NULL} +}; + +const char * +mnote_fuji_tag_get_name (MnoteFujiTag t) +{ + unsigned int i; + + for (i = 0; i < sizeof (table) / sizeof (table[0]); i++) + if (table[i].tag == t) return (table[i].name); + return NULL; +} + +const char * +mnote_fuji_tag_get_title (MnoteFujiTag t) +{ + unsigned int i; + + bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR); + for (i = 0; i < sizeof (table) / sizeof (table[0]); i++) + if (table[i].tag == t) return (_(table[i].title)); + return NULL; +} + +const char * +mnote_fuji_tag_get_description (MnoteFujiTag t) +{ + unsigned int i; + + for (i = 0; i < sizeof (table) / sizeof (table[0]); i++) + if (table[i].tag == t) { + if (!table[i].description || !*table[i].description) + return ""; + bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR); + return _(table[i].description); + } + return NULL; +} diff --git a/libexif/fuji/mnote-fuji-tag.h b/libexif/fuji/mnote-fuji-tag.h new file mode 100644 index 0000000..1d250e4 --- /dev/null +++ b/libexif/fuji/mnote-fuji-tag.h @@ -0,0 +1,92 @@ +/* mnote-fuji-tag.h + * + * Copyright (c) 2002 Lutz Mueller <lutz@users.sourceforge.net> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA. + */ + +#ifndef __MNOTE_FUJI_TAG_H__ +#define __MNOTE_FUJI_TAG_H__ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#include <libexif/exif-data.h> + +enum _MnoteFujiTag { + MNOTE_FUJI_TAG_VERSION = 0x0000, + MNOTE_FUJI_TAG_SERIAL_NUMBER = 0x0010, + MNOTE_FUJI_TAG_QUALITY = 0x1000, + MNOTE_FUJI_TAG_SHARPNESS = 0x1001, + MNOTE_FUJI_TAG_WHITE_BALANCE = 0x1002, + MNOTE_FUJI_TAG_COLOR = 0x1003, + MNOTE_FUJI_TAG_TONE = 0x1004, + MNOTE_FUJI_TAG_UNKNOWN_1006 = 0x1006, + MNOTE_FUJI_TAG_UNKNOWN_1007 = 0x1007, + MNOTE_FUJI_TAG_UNKNOWN_1008 = 0x1008, + MNOTE_FUJI_TAG_UNKNOWN_1009 = 0x1009, + MNOTE_FUJI_TAG_UNKNOWN_100A = 0x100A, + MNOTE_FUJI_TAG_UNKNOWN_100B = 0x100B, + MNOTE_FUJI_TAG_FLASH_MODE = 0x1010, + MNOTE_FUJI_TAG_FLASH_STRENGTH = 0x1011, + MNOTE_FUJI_TAG_MACRO = 0x1020, + MNOTE_FUJI_TAG_FOCUS_MODE = 0x1021, + MNOTE_FUJI_TAG_UNKNOWN_1022 = 0x1022, + MNOTE_FUJI_TAG_FOCUS_POINT = 0x1023, + MNOTE_FUJI_TAG_UNKNOWN_1024 = 0x1024, + MNOTE_FUJI_TAG_UNKNOWN_1025 = 0x1025, + MNOTE_FUJI_TAG_SLOW_SYNC = 0x1030, + MNOTE_FUJI_TAG_PICTURE_MODE = 0x1031, + MNOTE_FUJI_TAG_UNKNOWN_1032 = 0x1032, + MNOTE_FUJI_TAG_CONT_TAKING = 0x1100, + MNOTE_FUJI_TAG_SEQUENCE_NUMBER = 0x1101, + MNOTE_FUJI_TAG_UNKNOWN_1200 = 0x1200, + MNOTE_FUJI_TAG_FINEPIX_COLOR = 0x1210, + MNOTE_FUJI_TAG_BLUR_CHECK = 0x1300, + MNOTE_FUJI_TAG_FOCUS_CHECK = 0x1301, + MNOTE_FUJI_TAG_AUTO_EXPOSURE_CHECK = 0x1302, + MNOTE_FUJI_TAG_UNKNOWN_1303 = 0x1303, + MNOTE_FUJI_TAG_DYNAMIC_RANGE = 0x1400, + MNOTE_FUJI_TAG_FILM_MODE = 0x1401, + MNOTE_FUJI_TAG_DYNAMIC_RANGE_SETTING = 0x1402, + MNOTE_FUJI_TAG_DEV_DYNAMIC_RANGE_SETTING= 0x1403, + MNOTE_FUJI_TAG_MIN_FOCAL_LENGTH = 0x1404, + MNOTE_FUJI_TAG_MAX_FOCAL_LENGTH = 0x1405, + MNOTE_FUJI_TAG_MAX_APERT_AT_MIN_FOC = 0x1406, + MNOTE_FUJI_TAG_MAX_APERT_AT_MAX_FOC = 0x1407, + MNOTE_FUJI_TAG_UNKNOWN_1408 = 0x1408, + MNOTE_FUJI_TAG_UNKNOWN_1409 = 0x1409, + MNOTE_FUJI_TAG_UNKNOWN_140A = 0x140A, + MNOTE_FUJI_TAG_UNKNOWN_1410 = 0x1410, + MNOTE_FUJI_TAG_UNKNOWN_1421 = 0x1421, + MNOTE_FUJI_TAG_UNKNOWN_4100 = 0x4100, + MNOTE_FUJI_TAG_UNKNOWN_4800 = 0x4800, + MNOTE_FUJI_TAG_FILE_SOURCE = 0x8000, + MNOTE_FUJI_TAG_ORDER_NUMBER = 0x8002, + MNOTE_FUJI_TAG_FRAME_NUMBER = 0x8003, +}; +typedef enum _MnoteFujiTag MnoteFujiTag; + +const char *mnote_fuji_tag_get_name (MnoteFujiTag tag); +const char *mnote_fuji_tag_get_title (MnoteFujiTag tag); +const char *mnote_fuji_tag_get_description (MnoteFujiTag tag); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __MNOTE_FUJI_TAG_H__ */ diff --git a/libexif/i18n.h b/libexif/i18n.h new file mode 100644 index 0000000..dbfe258 --- /dev/null +++ b/libexif/i18n.h @@ -0,0 +1,52 @@ +/* i18n.h + * + * Copyright (c) 2001 Lutz Mueller <lutz@users.sourceforge.net> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA. + */ + +#ifndef __I18N_H__ +#define __I18N_H__ + +#include "config.h" + +#ifdef ENABLE_NLS +# include <libintl.h> +# undef _ +# define _(String) dgettext (GETTEXT_PACKAGE, String) +# ifdef gettext_noop +# define N_(String) gettext_noop (String) +# else +# define N_(String) (String) +# endif +#else +# define textdomain(String) (String) +# define gettext(String) (String) +# define ngettext(String1,String2,Count) (Count==1?String1:String2) +# define dgettext(Domain,Message) (Message) +# define dcgettext(Domain,Message,Type) (Message) +#ifdef __WATCOMC__ +# define bind_textdomain_codeset(Domain,Codeset) +# define bindtextdomain(Domain,Directory) +#else +# define bind_textdomain_codeset(Domain,Codeset) (Codeset) +# define bindtextdomain(Domain,Directory) (Domain) +#endif +# define _(String) (String) +# define N_(String) (String) +#endif + +#endif /* __I18N_H__ */ diff --git a/libexif/libexif.sym b/libexif/libexif.sym new file mode 100644 index 0000000..f1d77cf --- /dev/null +++ b/libexif/libexif.sym @@ -0,0 +1,129 @@ +exif_array_set_byte_order +exif_byte_order_get_name +exif_content_add_entry +exif_content_dump +exif_content_fix +exif_content_foreach_entry +exif_content_free +exif_content_get_entry +exif_content_get_ifd +exif_content_log +exif_content_new +exif_content_new_mem +exif_content_ref +exif_content_remove_entry +exif_content_unref +exif_data_dump +exif_data_fix +exif_data_foreach_content +exif_data_free +exif_data_get_byte_order +exif_data_get_data_type +exif_data_get_log +exif_data_get_mnote_data +exif_data_load_data +exif_data_log +exif_data_new +exif_data_new_from_data +exif_data_new_from_file +exif_data_new_mem +exif_data_option_get_description +exif_data_option_get_name +exif_data_ref +exif_data_save_data +exif_data_set_byte_order +exif_data_set_data_type +exif_data_set_option +exif_data_unref +exif_data_unset_option +exif_entry_dump +exif_entry_fix +exif_entry_free +exif_entry_get_value +exif_entry_initialize +exif_entry_new +exif_entry_new_mem +exif_entry_ref +exif_entry_unref +exif_format_get_name +exif_format_get_size +exif_get_long +exif_get_rational +exif_get_short +exif_get_slong +exif_get_srational +exif_get_sshort +exif_ifd_get_name +exif_loader_get_data +exif_loader_log +exif_loader_new +exif_loader_new_mem +exif_loader_ref +exif_loader_reset +exif_loader_unref +exif_loader_write +exif_loader_write_file +exif_log +exif_log_code_get_message +exif_log_code_get_title +exif_log_free +exif_log_new +exif_log_new_mem +exif_log_ref +exif_log_set_func +exif_log_unref +exif_logv +exif_mem_alloc +exif_mem_free +exif_mem_new +exif_mem_new_default +exif_mem_realloc +exif_mem_ref +exif_mem_unref +exif_mnote_data_canon_new +exif_mnote_data_construct +exif_mnote_data_count +exif_mnote_data_get_description +exif_mnote_data_get_id +exif_mnote_data_get_name +exif_mnote_data_get_title +exif_mnote_data_get_value +exif_mnote_data_load +exif_mnote_data_log +exif_mnote_data_olympus_new +exif_mnote_data_pentax_new +exif_mnote_data_ref +exif_mnote_data_save +exif_mnote_data_set_byte_order +exif_mnote_data_set_offset +exif_mnote_data_unref +exif_set_long +exif_set_rational +exif_set_short +exif_set_slong +exif_set_srational +exif_set_sshort +exif_tag_from_name +exif_tag_get_description +exif_tag_get_description_in_ifd +exif_tag_get_name +exif_tag_get_name_in_ifd +exif_tag_get_support_level_in_ifd +exif_tag_get_title +exif_tag_get_title_in_ifd +exif_tag_table_count +exif_tag_table_get_name +exif_tag_table_get_tag +mnote_canon_entry_get_value +mnote_canon_tag_get_description +mnote_canon_tag_get_name +mnote_canon_tag_get_title +mnote_olympus_entry_get_value +mnote_olympus_tag_get_description +mnote_olympus_tag_get_name +mnote_olympus_tag_get_title +mnote_pentax_entry_get_value +mnote_pentax_tag_get_description +mnote_pentax_tag_get_name +mnote_pentax_tag_get_title +exif_loader_get_buf diff --git a/libexif/olympus/Makefile-files b/libexif/olympus/Makefile-files new file mode 100644 index 0000000..b7b6b30 --- /dev/null +++ b/libexif/olympus/Makefile-files @@ -0,0 +1,7 @@ +# -*- Makefile -*- +noinst_LTLIBRARIES += libmnote-olympus.la +libmnote_olympus_la_SOURCES = \ + olympus/mnote-olympus-entry.c olympus/mnote-olympus-entry.h \ + olympus/exif-mnote-data-olympus.c olympus/exif-mnote-data-olympus.h \ + olympus/mnote-olympus-tag.c olympus/mnote-olympus-tag.h +libmnote_olympus_la_LIBADD = $(LTLIBINTL) diff --git a/libexif/olympus/exif-mnote-data-olympus.c b/libexif/olympus/exif-mnote-data-olympus.c new file mode 100644 index 0000000..099671d --- /dev/null +++ b/libexif/olympus/exif-mnote-data-olympus.c @@ -0,0 +1,659 @@ +/* exif-mnote-data-olympus.c + * + * Copyright (c) 2002, 2003 Lutz Mueller <lutz@users.sourceforge.net> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA. + */ + +#include <config.h> +#include "exif-mnote-data-olympus.h" + +#include <stdlib.h> +#include <string.h> +#include <stdio.h> + +#include <libexif/exif-utils.h> +#include <libexif/exif-data.h> + +#define DEBUG + +/* Uncomment this to fix a problem with Sanyo MakerNotes. It's probably best + * not to in most cases because it seems to only affect the thumbnail tag + * which is duplicated in IFD 1, and fixing the offset could actually cause + * problems with other software that expects the broken form. + */ +/*#define EXIF_OVERCOME_SANYO_OFFSET_BUG */ + +static enum OlympusVersion +exif_mnote_data_olympus_identify_variant (const unsigned char *buf, + unsigned int buf_size); + + +static void +exif_mnote_data_olympus_clear (ExifMnoteDataOlympus *n) +{ + ExifMnoteData *d = (ExifMnoteData *) n; + unsigned int i; + + if (!n) return; + + if (n->entries) { + for (i = 0; i < n->count; i++) + if (n->entries[i].data) { + exif_mem_free (d->mem, n->entries[i].data); + n->entries[i].data = NULL; + } + exif_mem_free (d->mem, n->entries); + n->entries = NULL; + n->count = 0; + } +} + +static void +exif_mnote_data_olympus_free (ExifMnoteData *n) +{ + if (!n) return; + + exif_mnote_data_olympus_clear ((ExifMnoteDataOlympus *) n); +} + +static char * +exif_mnote_data_olympus_get_value (ExifMnoteData *d, unsigned int i, char *val, unsigned int maxlen) +{ + ExifMnoteDataOlympus *n = (ExifMnoteDataOlympus *) d; + + if (!d || !val) return NULL; + if (i > n->count -1) return NULL; +/* + exif_log (d->log, EXIF_LOG_CODE_DEBUG, "ExifMnoteDataOlympus", + "Querying value for tag '%s'...", + mnote_olympus_tag_get_name (n->entries[i].tag)); +*/ + return mnote_olympus_entry_get_value (&n->entries[i], val, maxlen); +} + + + + +/** + * @brief save the MnoteData from ne to buf + * + * @param ne extract the data from this structure + * @param *buf write the mnoteData to this buffer (buffer will be allocated) + * @param buf_size the size of the buffer + */ +static void +exif_mnote_data_olympus_save (ExifMnoteData *ne, + unsigned char **buf, unsigned int *buf_size) +{ + ExifMnoteDataOlympus *n = (ExifMnoteDataOlympus *) ne; + size_t i, o, s, doff, base = 0, o2 = 6 + 2; + size_t datao = 0; + unsigned char *t; + size_t ts; + + if (!n || !buf || !buf_size) return; + + /* + * Allocate enough memory for all entries and the number of entries. + */ + *buf_size = 6 + 2 + 2 + n->count * 12; + switch (n->version) { + case olympusV1: + case sanyoV1: + case epsonV1: + *buf = exif_mem_alloc (ne->mem, *buf_size); + if (!*buf) { + EXIF_LOG_NO_MEMORY(ne->log, "ExifMnoteDataOlympus", *buf_size); + return; + } + + /* Write the header and the number of entries. */ + strcpy ((char *)*buf, n->version==sanyoV1?"SANYO": + (n->version==epsonV1?"EPSON":"OLYMP")); + exif_set_short (*buf + 6, n->order, (ExifShort) 1); + datao = n->offset; + break; + + case olympusV2: + *buf_size += 8-6 + 4; + *buf = exif_mem_alloc (ne->mem, *buf_size); + if (!*buf) { + EXIF_LOG_NO_MEMORY(ne->log, "ExifMnoteDataOlympus", *buf_size); + return; + } + + /* Write the header and the number of entries. */ + strcpy ((char *)*buf, "OLYMPUS"); + exif_set_short (*buf + 8, n->order, (ExifShort) ( + (n->order == EXIF_BYTE_ORDER_INTEL) ? + ('I' << 8) | 'I' : + ('M' << 8) | 'M')); + exif_set_short (*buf + 10, n->order, (ExifShort) 3); + o2 += 4; + break; + + case nikonV1: + base = MNOTE_NIKON1_TAG_BASE; + + /* v1 has offsets based to main IFD, not makernote IFD */ + datao += n->offset + 10; + /* subtract the size here, so the increment in the next case will not harm us */ + *buf_size -= 8 + 2; + /* Fall through to nikonV2 handler */ + case nikonV2: + /* Write out V0 files in V2 format */ + case nikonV0: + *buf_size += 8 + 2; + *buf_size += 4; /* Next IFD pointer */ + *buf = exif_mem_alloc (ne->mem, *buf_size); + if (!*buf) { + EXIF_LOG_NO_MEMORY(ne->log, "ExifMnoteDataOlympus", *buf_size); + return; + } + + /* Write the header and the number of entries. */ + strcpy ((char *)*buf, "Nikon"); + (*buf)[6] = n->version; + + if (n->version != nikonV1) { + exif_set_short (*buf + 10, n->order, (ExifShort) ( + (n->order == EXIF_BYTE_ORDER_INTEL) ? + ('I' << 8) | 'I' : + ('M' << 8) | 'M')); + exif_set_short (*buf + 12, n->order, (ExifShort) 0x2A); + exif_set_long (*buf + 14, n->order, (ExifShort) 8); + o2 += 2 + 8; + } + datao -= 10; + /* Reset next IFD pointer */ + exif_set_long (*buf + o2 + 2 + n->count * 12, n->order, 0); + break; + + default: + return; + } + + exif_set_short (*buf + o2, n->order, (ExifShort) n->count); + o2 += 2; + + /* Save each entry */ + for (i = 0; i < n->count; i++) { + o = o2 + i * 12; + exif_set_short (*buf + o + 0, n->order, + (ExifShort) (n->entries[i].tag - base)); + exif_set_short (*buf + o + 2, n->order, + (ExifShort) n->entries[i].format); + exif_set_long (*buf + o + 4, n->order, + n->entries[i].components); + o += 8; + s = exif_format_get_size (n->entries[i].format) * + n->entries[i].components; + if (s > 65536) { + /* Corrupt data: EXIF data size is limited to the + * maximum size of a JPEG segment (64 kb). + */ + continue; + } + if (s > 4) { + doff = *buf_size; + ts = *buf_size + s; + t = exif_mem_realloc (ne->mem, *buf, + sizeof (char) * ts); + if (!t) { + EXIF_LOG_NO_MEMORY(ne->log, "ExifMnoteDataOlympus", ts); + return; + } + *buf = t; + *buf_size = ts; + exif_set_long (*buf + o, n->order, datao + doff); + } else + doff = o; + + /* Write the data. */ + if (n->entries[i].data) { + memcpy (*buf + doff, n->entries[i].data, s); + } else { + /* Most certainly damaged input file */ + memset (*buf + doff, 0, s); + } + } +} + +static void +exif_mnote_data_olympus_load (ExifMnoteData *en, + const unsigned char *buf, unsigned int buf_size) +{ + ExifMnoteDataOlympus *n = (ExifMnoteDataOlympus *) en; + ExifShort c; + size_t i, tcount, o, o2, datao = 6, base = 0; + + if (!n || !buf || !buf_size) { + exif_log (en->log, EXIF_LOG_CODE_CORRUPT_DATA, + "ExifMnoteDataOlympus", "Short MakerNote"); + return; + } + o2 = 6 + n->offset; /* Start of interesting data */ + if ((o2 + 10 < o2) || (o2 + 10 < 10) || (o2 + 10 > buf_size)) { + exif_log (en->log, EXIF_LOG_CODE_CORRUPT_DATA, + "ExifMnoteDataOlympus", "Short MakerNote"); + return; + } + + /* + * Olympus headers start with "OLYMP" and need to have at least + * a size of 22 bytes (6 for 'OLYMP', 2 other bytes, 2 for the + * number of entries, and 12 for one entry. + * + * Sanyo format is identical and uses identical tags except that + * header starts with "SANYO". + * + * Epson format is identical and uses identical tags except that + * header starts with "EPSON". + * + * Nikon headers start with "Nikon" (6 bytes including '\0'), + * version number (1 or 2). + * + * Version 1 continues with 0, 1, 0, number_of_tags, + * or just with number_of_tags (models D1H, D1X...). + * + * Version 2 continues with an unknown byte (0 or 10), + * two unknown bytes (0), "MM" or "II", another byte 0 and + * lastly 0x2A. + */ + n->version = exif_mnote_data_olympus_identify_variant(buf+o2, buf_size-o2); + switch (n->version) { + case olympusV1: + case sanyoV1: + case epsonV1: + exif_log (en->log, EXIF_LOG_CODE_DEBUG, "ExifMnoteDataOlympus", + "Parsing Olympus/Sanyo/Epson maker note v1..."); + + /* The number of entries is at position 8. */ + if (buf[o2 + 6] == 1) + n->order = EXIF_BYTE_ORDER_INTEL; + else if (buf[o2 + 6 + 1] == 1) + n->order = EXIF_BYTE_ORDER_MOTOROLA; + o2 += 8; + if (o2 + 2 > buf_size) return; + c = exif_get_short (buf + o2, n->order); + if ((!(c & 0xFF)) && (c > 0x500)) { + if (n->order == EXIF_BYTE_ORDER_INTEL) { + n->order = EXIF_BYTE_ORDER_MOTOROLA; + } else { + n->order = EXIF_BYTE_ORDER_INTEL; + } + } + break; + + case olympusV2: + /* Olympus S760, S770 */ + datao = o2; + o2 += 8; + exif_log (en->log, EXIF_LOG_CODE_DEBUG, "ExifMnoteDataOlympus", + "Parsing Olympus maker note v2 (0x%02x, %02x, %02x, %02x)...", + buf[o2], buf[o2 + 1], buf[o2 + 2], buf[o2 + 3]); + + if ((buf[o2] == 'I') && (buf[o2 + 1] == 'I')) + n->order = EXIF_BYTE_ORDER_INTEL; + else if ((buf[o2] == 'M') && (buf[o2 + 1] == 'M')) + n->order = EXIF_BYTE_ORDER_MOTOROLA; + + /* The number of entries is at position 8+4. */ + o2 += 4; + break; + + case nikonV1: + o2 += 6; + if (o2 >= buf_size) return; + exif_log (en->log, EXIF_LOG_CODE_DEBUG, "ExifMnoteDataOlympus", + "Parsing Nikon maker note v1 (0x%02x, %02x, %02x, " + "%02x, %02x, %02x, %02x, %02x)...", + buf[o2 + 0], buf[o2 + 1], buf[o2 + 2], buf[o2 + 3], + buf[o2 + 4], buf[o2 + 5], buf[o2 + 6], buf[o2 + 7]); + + /* Skip version number */ + o2 += 1; + + /* Skip an unknown byte (00 or 0A). */ + o2 += 1; + + base = MNOTE_NIKON1_TAG_BASE; + /* Fix endianness, if needed */ + if (o2 + 2 > buf_size) return; + c = exif_get_short (buf + o2, n->order); + if ((!(c & 0xFF)) && (c > 0x500)) { + if (n->order == EXIF_BYTE_ORDER_INTEL) { + n->order = EXIF_BYTE_ORDER_MOTOROLA; + } else { + n->order = EXIF_BYTE_ORDER_INTEL; + } + } + break; + + case nikonV2: + o2 += 6; + if (o2 >= buf_size) return; + exif_log (en->log, EXIF_LOG_CODE_DEBUG, "ExifMnoteDataOlympus", + "Parsing Nikon maker note v2 (0x%02x, %02x, %02x, " + "%02x, %02x, %02x, %02x, %02x)...", + buf[o2 + 0], buf[o2 + 1], buf[o2 + 2], buf[o2 + 3], + buf[o2 + 4], buf[o2 + 5], buf[o2 + 6], buf[o2 + 7]); + + /* Skip version number */ + o2 += 1; + + /* Skip an unknown byte (00 or 0A). */ + o2 += 1; + + /* Skip 2 unknown bytes (00 00). */ + o2 += 2; + + /* + * Byte order. From here the data offset + * gets calculated. + */ + datao = o2; + if (o2 >= buf_size) return; + if (!strncmp ((char *)&buf[o2], "II", 2)) + n->order = EXIF_BYTE_ORDER_INTEL; + else if (!strncmp ((char *)&buf[o2], "MM", 2)) + n->order = EXIF_BYTE_ORDER_MOTOROLA; + else { + exif_log (en->log, EXIF_LOG_CODE_DEBUG, + "ExifMnoteDataOlympus", "Unknown " + "byte order '%c%c'", buf[o2], + buf[o2 + 1]); + return; + } + o2 += 2; + + /* Skip 2 unknown bytes (00 2A). */ + o2 += 2; + + /* Go to where the number of entries is. */ + if (o2 + 4 > buf_size) return; + o2 = datao + exif_get_long (buf + o2, n->order); + break; + + case nikonV0: + exif_log (en->log, EXIF_LOG_CODE_DEBUG, "ExifMnoteDataOlympus", + "Parsing Nikon maker note v0 (0x%02x, %02x, %02x, " + "%02x, %02x, %02x, %02x, %02x)...", + buf[o2 + 0], buf[o2 + 1], buf[o2 + 2], buf[o2 + 3], + buf[o2 + 4], buf[o2 + 5], buf[o2 + 6], buf[o2 + 7]); + /* 00 1b is # of entries in Motorola order - the rest should also be in MM order */ + n->order = EXIF_BYTE_ORDER_MOTOROLA; + break; + + default: + exif_log (en->log, EXIF_LOG_CODE_DEBUG, "ExifMnoteDataOlympus", + "Unknown Olympus variant %i.", n->version); + return; + } + + /* Sanity check the offset */ + if ((o2 + 2 < o2) || (o2 + 2 < 2) || (o2 + 2 > buf_size)) { + exif_log (en->log, EXIF_LOG_CODE_CORRUPT_DATA, + "ExifMnoteOlympus", "Short MakerNote"); + return; + } + + /* Read the number of tags */ + c = exif_get_short (buf + o2, n->order); + o2 += 2; + + /* Remove any old entries */ + exif_mnote_data_olympus_clear (n); + + /* Reserve enough space for all the possible MakerNote tags */ + n->entries = exif_mem_alloc (en->mem, sizeof (MnoteOlympusEntry) * c); + if (!n->entries) { + EXIF_LOG_NO_MEMORY(en->log, "ExifMnoteOlympus", sizeof (MnoteOlympusEntry) * c); + return; + } + + /* Parse all c entries, storing ones that are successfully parsed */ + tcount = 0; + for (i = c, o = o2; i; --i, o += 12) { + size_t s; + if ((o + 12 < o) || (o + 12 < 12) || (o + 12 > buf_size)) { + exif_log (en->log, EXIF_LOG_CODE_CORRUPT_DATA, + "ExifMnoteOlympus", "Short MakerNote"); + break; + } + + n->entries[tcount].tag = exif_get_short (buf + o, n->order) + base; + n->entries[tcount].format = exif_get_short (buf + o + 2, n->order); + n->entries[tcount].components = exif_get_long (buf + o + 4, n->order); + n->entries[tcount].order = n->order; + + exif_log (en->log, EXIF_LOG_CODE_DEBUG, "ExifMnoteOlympus", + "Loading entry 0x%x ('%s')...", n->entries[tcount].tag, + mnote_olympus_tag_get_name (n->entries[tcount].tag)); +/* exif_log (en->log, EXIF_LOG_CODE_DEBUG, "ExifMnoteOlympus", + "0x%x %d %ld*(%d)", + n->entries[tcount].tag, + n->entries[tcount].format, + n->entries[tcount].components, + (int)exif_format_get_size(n->entries[tcount].format)); */ + + /* + * Size? If bigger than 4 bytes, the actual data is not + * in the entry but somewhere else (offset). + */ + s = exif_format_get_size (n->entries[tcount].format) * + n->entries[tcount].components; + n->entries[tcount].size = s; + if (s) { + size_t dataofs = o + 8; + if (s > 4) { + /* The data in this case is merely a pointer */ + dataofs = exif_get_long (buf + dataofs, n->order) + datao; +#ifdef EXIF_OVERCOME_SANYO_OFFSET_BUG + /* Some Sanyo models (e.g. VPC-C5, C40) suffer from a bug when + * writing the offset for the MNOTE_OLYMPUS_TAG_THUMBNAILIMAGE + * tag in its MakerNote. The offset is actually the absolute + * position in the file instead of the position within the IFD. + */ + if (dataofs + s > buf_size && n->version == sanyoV1) { + /* fix pointer */ + dataofs -= datao + 6; + exif_log (en->log, EXIF_LOG_CODE_DEBUG, + "ExifMnoteOlympus", + "Inconsistent thumbnail tag offset; attempting to recover"); + } +#endif + } + if ((dataofs + s < dataofs) || (dataofs + s < s) || + (dataofs + s > buf_size)) { + exif_log (en->log, EXIF_LOG_CODE_DEBUG, + "ExifMnoteOlympus", + "Tag data past end of buffer (%u > %u)", + dataofs + s, buf_size); + continue; + } + + n->entries[tcount].data = exif_mem_alloc (en->mem, s); + if (!n->entries[tcount].data) { + EXIF_LOG_NO_MEMORY(en->log, "ExifMnoteOlympus", s); + continue; + } + memcpy (n->entries[tcount].data, buf + dataofs, s); + } + + /* Tag was successfully parsed */ + ++tcount; + } + /* Store the count of successfully parsed tags */ + n->count = tcount; +} + +static unsigned int +exif_mnote_data_olympus_count (ExifMnoteData *n) +{ + return n ? ((ExifMnoteDataOlympus *) n)->count : 0; +} + +static unsigned int +exif_mnote_data_olympus_get_id (ExifMnoteData *d, unsigned int n) +{ + ExifMnoteDataOlympus *note = (ExifMnoteDataOlympus *) d; + + if (!note) return 0; + if (note->count <= n) return 0; + return note->entries[n].tag; +} + +static const char * +exif_mnote_data_olympus_get_name (ExifMnoteData *d, unsigned int i) +{ + ExifMnoteDataOlympus *n = (ExifMnoteDataOlympus *) d; + + if (!n) return NULL; + if (i >= n->count) return NULL; + return mnote_olympus_tag_get_name (n->entries[i].tag); +} + +static const char * +exif_mnote_data_olympus_get_title (ExifMnoteData *d, unsigned int i) +{ + ExifMnoteDataOlympus *n = (ExifMnoteDataOlympus *) d; + + if (!n) return NULL; + if (i >= n->count) return NULL; + return mnote_olympus_tag_get_title (n->entries[i].tag); +} + +static const char * +exif_mnote_data_olympus_get_description (ExifMnoteData *d, unsigned int i) +{ + ExifMnoteDataOlympus *n = (ExifMnoteDataOlympus *) d; + + if (!n) return NULL; + if (i >= n->count) return NULL; + return mnote_olympus_tag_get_description (n->entries[i].tag); +} + +static void +exif_mnote_data_olympus_set_byte_order (ExifMnoteData *d, ExifByteOrder o) +{ + ExifByteOrder o_orig; + ExifMnoteDataOlympus *n = (ExifMnoteDataOlympus *) d; + unsigned int i; + + if (!n) return; + + o_orig = n->order; + n->order = o; + for (i = 0; i < n->count; i++) { + n->entries[i].order = o; + exif_array_set_byte_order (n->entries[i].format, n->entries[i].data, + n->entries[i].components, o_orig, o); + } +} + +static void +exif_mnote_data_olympus_set_offset (ExifMnoteData *n, unsigned int o) +{ + if (n) ((ExifMnoteDataOlympus *) n)->offset = o; +} + +static enum OlympusVersion +exif_mnote_data_olympus_identify_variant (const unsigned char *buf, + unsigned int buf_size) +{ + /* Olympus, Nikon, Sanyo, Epson */ + if (buf_size >= 8) { + /* Match the terminating NUL character, too */ + if (!memcmp (buf, "OLYMPUS", 8)) + return olympusV2; + else if (!memcmp (buf, "OLYMP", 6)) + return olympusV1; + else if (!memcmp (buf, "SANYO", 6)) + return sanyoV1; + else if (!memcmp (buf, "EPSON", 6)) + return epsonV1; + else if (!memcmp (buf, "Nikon", 6)) { + switch (buf[6]) { + case 1: return nikonV1; + case 2: return nikonV2; + default: return 0; /* Unrecognized Nikon variant */ + } + } + } + + /* Another variant of Nikon */ + if ((buf_size >= 2) && (buf[0] == 0x00) && (buf[1] == 0x1b)) { + return nikonV0; + } + + return unrecognized; +} + +int +exif_mnote_data_olympus_identify (const ExifData *ed, const ExifEntry *e) +{ + int variant = exif_mnote_data_olympus_identify_variant(e->data, e->size); + + if (variant == nikonV0) { + /* This variant needs some extra checking with the Make */ + char value[5]; + ExifEntry *em = exif_data_get_entry (ed, EXIF_TAG_MAKE); + variant = unrecognized; + + if (em) { + const char *v = exif_entry_get_value (em, value, sizeof(value)); + if (v && (!strncmp (v, "Nikon", sizeof(value)) || + !strncmp (v, "NIKON", sizeof(value)) )) + /* When saved, this variant will be written out like the + * alternative nikonV2 form above instead + */ + variant = nikonV0; + } + } + + return variant; +} + + +ExifMnoteData * +exif_mnote_data_olympus_new (ExifMem *mem) +{ + ExifMnoteData *d; + + if (!mem) return NULL; + + d = exif_mem_alloc (mem, sizeof (ExifMnoteDataOlympus)); + if (!d) return NULL; + + exif_mnote_data_construct (d, mem); + + /* Set up function pointers */ + d->methods.free = exif_mnote_data_olympus_free; + d->methods.set_byte_order = exif_mnote_data_olympus_set_byte_order; + d->methods.set_offset = exif_mnote_data_olympus_set_offset; + d->methods.load = exif_mnote_data_olympus_load; + d->methods.save = exif_mnote_data_olympus_save; + d->methods.count = exif_mnote_data_olympus_count; + d->methods.get_id = exif_mnote_data_olympus_get_id; + d->methods.get_name = exif_mnote_data_olympus_get_name; + d->methods.get_title = exif_mnote_data_olympus_get_title; + d->methods.get_description = exif_mnote_data_olympus_get_description; + d->methods.get_value = exif_mnote_data_olympus_get_value; + + return d; +} diff --git a/libexif/olympus/exif-mnote-data-olympus.h b/libexif/olympus/exif-mnote-data-olympus.h new file mode 100644 index 0000000..d08b0f4 --- /dev/null +++ b/libexif/olympus/exif-mnote-data-olympus.h @@ -0,0 +1,67 @@ +/* mnote-olympus-data.h + * + * Copyright (c) 2002 Lutz Mueller <lutz@users.sourceforge.net> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA. + */ + +#ifndef __MNOTE_OLYMPUS_CONTENT_H__ +#define __MNOTE_OLYMPUS_CONTENT_H__ + +#include <libexif/exif-mnote-data-priv.h> +#include <libexif/olympus/mnote-olympus-entry.h> +#include <libexif/exif-byte-order.h> +#include <libexif/exif-data.h> +#include <libexif/exif-mem.h> + +enum OlympusVersion { + unrecognized = 0, + nikonV1 = 1, + nikonV2 = 2, + olympusV1 = 3, + olympusV2 = 4, + sanyoV1 = 5, + epsonV1 = 6, + nikonV0 = 7 +}; + + +typedef struct _ExifMnoteDataOlympus ExifMnoteDataOlympus; + +struct _ExifMnoteDataOlympus { + ExifMnoteData parent; + + MnoteOlympusEntry *entries; + unsigned int count; + + ExifByteOrder order; + unsigned int offset; + enum OlympusVersion version; +}; + +/*! Detect if MakerNote is recognized as one handled by the Olympus module. + * + * \param[in] ed image #ExifData to identify as as an Olympus type + * \param[in] e #ExifEntry for EXIF_TAG_MAKER_NOTE, from within ed but + * duplicated here for convenience + * \return 0 if not recognized, nonzero if recognized. The specific nonzero + * value returned may identify a subtype unique within this module. + */ +int exif_mnote_data_olympus_identify (const ExifData *ed, const ExifEntry *e); + +ExifMnoteData *exif_mnote_data_olympus_new (ExifMem *); + +#endif /* __MNOTE_OLYMPUS_CONTENT_H__ */ diff --git a/libexif/olympus/mnote-olympus-entry.c b/libexif/olympus/mnote-olympus-entry.c new file mode 100644 index 0000000..96c919d --- /dev/null +++ b/libexif/olympus/mnote-olympus-entry.c @@ -0,0 +1,827 @@ +/* mnote-olympus-entry.c + * + * Copyright (c) 2002-2009 Lutz Mueller <lutz@users.sourceforge.net> et. al. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA. + */ + +#include <config.h> +#include "mnote-olympus-entry.h" + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include <libexif/exif-format.h> +#include <libexif/exif-utils.h> +#include <libexif/exif-entry.h> +#include <libexif/i18n.h> + +#define CF(format,target,v,maxlen) \ +{ \ + if (format != target) { \ + snprintf (v, maxlen, \ + _("Invalid format '%s', " \ + "expected '%s'."), \ + exif_format_get_name (format), \ + exif_format_get_name (target)); \ + break; \ + } \ +} + +#define CF2(format,target1,target2,v,maxlen) \ +{ \ + if ((format != target1) && (format != target2)) { \ + snprintf (v, maxlen, \ + _("Invalid format '%s', " \ + "expected '%s' or '%s'."), \ + exif_format_get_name (format), \ + exif_format_get_name (target1), \ + exif_format_get_name (target2)); \ + break; \ + } \ +} + +#define CC(number,target,v,maxlen) \ +{ \ + if (number != target) { \ + snprintf (v, maxlen, \ + _("Invalid number of components (%i, " \ + "expected %i)."), (int) number, (int) target); \ + break; \ + } \ +} + +#define CC2(number,t1,t2,v,maxlen) \ +{ \ + if ((number < t1) || (number > t2)) { \ + snprintf (v, maxlen, \ + _("Invalid number of components (%i, " \ + "expected %i or %i)."), (int) number, \ + (int) t1, (int) t2); \ + break; \ + } \ +} + +#define R2L(n) ((n).denominator ? (long)(n).numerator/(n).denominator : 0L) +#define R2D(n) ((n).denominator ? (double)(n).numerator/(n).denominator : 0.0) + +static const struct { + ExifTag tag; + ExifFormat fmt; + struct { + int index; + const char *string; + } elem[24]; +} items[] = { +#ifndef NO_VERBOSE_TAG_DATA + { MNOTE_NIKON_TAG_LENSTYPE, EXIF_FORMAT_BYTE, + { {0, N_("AF non D lens")}, + {1, N_("Manual")}, + {2, N_("AF-D or AF-S lens")}, + {6, N_("AF-D G lens")}, + {10, N_("AF-D VR lens")}, + {14, N_("AF-D G VR lens")}, + {0, NULL}}}, + { MNOTE_NIKON_TAG_FLASHUSED, EXIF_FORMAT_BYTE, + { {0, N_("Flash did not fire")}, + {4, N_("Flash unit unknown")}, + {7, N_("Flash is external")}, + {9, N_("Flash is on camera")}, + {0, NULL}}}, + { MNOTE_NIKON1_TAG_QUALITY, EXIF_FORMAT_SHORT, + { {1, N_("VGA basic")}, + {2, N_("VGA normal")}, + {3, N_("VGA fine")}, + {4, N_("SXGA basic")}, + {5, N_("SXGA normal")}, + {6, N_("SXGA fine")}, + {10, N_("2 Mpixel basic")}, + {11, N_("2 Mpixel normal")}, + {12, N_("2 Mpixel fine")}, + {0, NULL}}}, + { MNOTE_NIKON1_TAG_COLORMODE, EXIF_FORMAT_SHORT, + { {1, N_("Color")}, + {2, N_("Monochrome")}, + {0, NULL}}}, + { MNOTE_NIKON1_TAG_IMAGEADJUSTMENT, EXIF_FORMAT_SHORT, + { {0, N_("Normal")}, + {1, N_("Bright+")}, + {2, N_("Bright-")}, + {3, N_("Contrast+")}, + {4, N_("Contrast-")}, + {0, NULL}}}, + { MNOTE_NIKON1_TAG_CCDSENSITIVITY, EXIF_FORMAT_SHORT, + { {0, N_("ISO 80")}, + {2, N_("ISO 160")}, + {4, N_("ISO 320")}, + {5, N_("ISO 100")}, + {0, NULL}}}, + { MNOTE_NIKON1_TAG_WHITEBALANCE, EXIF_FORMAT_SHORT, + { {0, N_("Auto")}, + {1, N_("Preset")}, + {2, N_("Daylight")}, + {3, N_("Incandescence")}, + {4, N_("Fluorescence")}, + {5, N_("Cloudy")}, + {6, N_("SpeedLight")}, + {0, NULL}}}, + { MNOTE_NIKON1_TAG_CONVERTER, EXIF_FORMAT_SHORT, + { {0, N_("No fisheye")}, + {1, N_("Fisheye on")}, + {0, NULL}}}, + { MNOTE_OLYMPUS_TAG_QUALITY, EXIF_FORMAT_SHORT, + { {1, N_("Normal, SQ")}, + {2, N_("Normal, HQ")}, + {3, N_("Normal, SHQ")}, + {4, N_("Normal, RAW")}, + {5, N_("Normal, SQ1")}, + {6, N_("Normal, SQ2")}, + {7, N_("Normal, super high")}, + {17, N_("Normal, standard")}, + {0x101, N_("Fine, SQ")}, + {0x102, N_("Fine, HQ")}, + {0x103, N_("Fine, SHQ")}, + {0x104, N_("Fine, RAW")}, + {0x105, N_("Fine, SQ1")}, + {0x106, N_("Fine, SQ2")}, + {0x107, N_("Fine, super high")}, + {0x201, N_("Super fine, SQ")}, + {0x202, N_("Super fine, HQ")}, + {0x203, N_("Super fine, SHQ")}, + {0x204, N_("Super fine, RAW")}, + {0x205, N_("Super fine, SQ1")}, + {0x206, N_("Super fine, SQ2")}, + {0x207, N_("Super fine, super high")}, + {0x211, N_("Super fine, high")}, + {0, NULL}}}, + { MNOTE_OLYMPUS_TAG_MACRO, EXIF_FORMAT_SHORT, + { {0, N_("No")}, + {1, N_("Yes")}, + {2, N_("Super macro")}, + {0, NULL}}}, + { MNOTE_OLYMPUS_TAG_BWMODE, EXIF_FORMAT_SHORT, + { {0, N_("No")}, + {1, N_("Yes")}, + {0, NULL}}}, + { MNOTE_OLYMPUS_TAG_ONETOUCHWB, EXIF_FORMAT_SHORT, + { {0, N_("Off")}, + {1, N_("On")}, + {2, N_("On (Preset)")}, + {0, NULL}}}, + { MNOTE_OLYMPUS_TAG_FLASHMODE, EXIF_FORMAT_SHORT, + { {0, N_("Auto")}, + {1, N_("Red-eye reduction")}, + {2, N_("Fill")}, + {3, N_("Off")}, + {0, NULL}}}, + { MNOTE_OLYMPUS_TAG_FLASHDEVICE, EXIF_FORMAT_SHORT, + { {0, N_("None")}, + {1, N_("Internal")}, + {4, N_("External")}, + {5, N_("Internal + external")}, + {0, NULL}}}, + { MNOTE_OLYMPUS_TAG_FOCUSRANGE, EXIF_FORMAT_SHORT, + { {0, N_("Normal")}, + {1, N_("Macro")}, + {0, NULL}}}, + { MNOTE_OLYMPUS_TAG_MANFOCUS, EXIF_FORMAT_SHORT, + { {0, N_("Auto")}, + {1, N_("Manual")}, + {0, NULL}}}, + { MNOTE_OLYMPUS_TAG_SHARPNESS, EXIF_FORMAT_SHORT, + { {0, N_("Normal")}, + {1, N_("Hard")}, + {2, N_("Soft")}, + {0, NULL}}}, + { MNOTE_OLYMPUS_TAG_EXTERNALFLASHBOUNCE, EXIF_FORMAT_SHORT, + { {0, N_("No")}, + {1, N_("Yes")}, + {0, NULL}}}, + { MNOTE_OLYMPUS_TAG_CONTRAST, EXIF_FORMAT_SHORT, + { {0, N_("Hard")}, + {1, N_("Normal")}, + {2, N_("Soft")}, + {0, NULL}}}, + { MNOTE_OLYMPUS_TAG_PREVIEWIMAGEVALID, EXIF_FORMAT_LONG, + { {0, N_("No")}, + {1, N_("Yes")}, + {0, NULL}}}, + { MNOTE_OLYMPUS_TAG_CCDSCANMODE, EXIF_FORMAT_SHORT, + { {0, N_("Interlaced")}, + {1, N_("Progressive")}, + {0, NULL}}}, + + { MNOTE_SANYO_TAG_SEQUENTIALSHOT, EXIF_FORMAT_SHORT, + { {0, N_("None")}, + {1, N_("Standard")}, + {2, N_("Best")}, + {3, N_("Adjust exposure")}, + {0, NULL}}}, + { MNOTE_SANYO_TAG_FOCUSMODE, EXIF_FORMAT_SHORT, + { {1, N_("Spot focus")}, + {2, N_("Normal focus")}, + {0, NULL}}}, + { MNOTE_SANYO_TAG_RECORDSHUTTERRELEASE, EXIF_FORMAT_SHORT, + { {0, N_("Record while down")}, + {1, N_("Press start, press stop")}, + {0, NULL}}}, + { MNOTE_SANYO_TAG_RESAVED, EXIF_FORMAT_SHORT, + { {0, N_("No")}, + {1, N_("Yes")}, + {0, NULL}}}, + { MNOTE_SANYO_TAG_CCDSENSITIVITY, EXIF_FORMAT_SHORT, + { {0, N_("Auto")}, + {1, N_("ISO 50")}, + {3, N_("ISO 100")}, + {4, N_("ISO 200")}, + {5, N_("ISO 400")}, + {0, NULL}}}, + { MNOTE_SANYO_TAG_SCENESELECT, EXIF_FORMAT_SHORT, + { {0, N_("Off")}, + {1, N_("Sport")}, + {2, N_("TV")}, + {3, N_("Night")}, + {4, N_("User 1")}, + {5, N_("User 2")}, + {6, N_("Lamp")}, + {0, NULL}}}, + { MNOTE_SANYO_TAG_SEQUENCESHOTINTERVAL, EXIF_FORMAT_SHORT, + { {0, N_("5 frames/sec")}, + {1, N_("10 frames/sec")}, + {2, N_("15 frames/sec")}, + {3, N_("20 frames/sec")}, + {0, NULL}}}, +#endif + { 0, 0, { { 0, NULL } } } +}; + +char * +mnote_olympus_entry_get_value (MnoteOlympusEntry *entry, char *v, unsigned int maxlen) +{ + char buf[30]; + ExifLong vl; + ExifShort vs = 0; + ExifSShort vss = 0; + ExifRational vr, vr2; + ExifSRational vsr; + int i, j; + double r, b; + + if (!entry) + return (NULL); + + memset (v, 0, maxlen); + maxlen--; + + if ((!entry->data) && (entry->components > 0)) + return (v); + + if ((!entry->data) && (entry->size > 0)) + return NULL; /* internal inconsistency error */ + + switch (entry->tag) { + + /* Nikon */ + case MNOTE_NIKON_TAG_FIRMWARE: + CF (entry->format, EXIF_FORMAT_UNDEFINED, v, maxlen); + CC (entry->components, 4, v, maxlen); + vl = exif_get_long (entry->data, entry->order); + if ((vl & 0xF0F0F0F0) == 0x30303030) { + memcpy (v, entry->data, MIN (maxlen, 4)); + } else { + snprintf (v, maxlen, "%04lx", (long unsigned int) vl); + } + break; + case MNOTE_NIKON_TAG_ISO: + CF (entry->format, EXIF_FORMAT_SHORT, v, maxlen); + CC (entry->components, 2, v, maxlen); + /*vs = exif_get_short (entry->data, entry->order);*/ + vs = exif_get_short (entry->data + 2, entry->order); + snprintf (v, maxlen, "ISO %hd", vs); + break; + case MNOTE_NIKON_TAG_ISO2: + CF (entry->format, EXIF_FORMAT_SHORT, v, maxlen); + CC (entry->components, 2, v, maxlen); + /*vs = exif_get_short (entry->data, entry->order);*/ + vs = exif_get_short (entry->data + 2, entry->order); + snprintf (v, maxlen, "ISO2 %hd", vs); + break; + case MNOTE_NIKON_TAG_QUALITY: + case MNOTE_NIKON_TAG_COLORMODE: + case MNOTE_NIKON_TAG_COLORMODE1: + case MNOTE_NIKON_TAG_WHITEBALANCE: + case MNOTE_NIKON_TAG_SHARPENING: + case MNOTE_NIKON_TAG_FOCUSMODE: + case MNOTE_NIKON_TAG_FLASHSETTING: + case MNOTE_NIKON_TAG_ISOSELECTION: + case MNOTE_NIKON_TAG_FLASHMODE: + case MNOTE_NIKON_TAG_IMAGEADJUSTMENT: + case MNOTE_NIKON_TAG_ADAPTER: + case MNOTE_NIKON_TAG_SATURATION2: + case MNOTE_EPSON_TAG_SOFTWARE: + CF (entry->format, EXIF_FORMAT_ASCII, v, maxlen); + memcpy(v, entry->data, MIN (maxlen, entry->size)); + break; + case MNOTE_NIKON_TAG_TOTALPICTURES: + case MNOTE_EPSON_TAG_IMAGE_WIDTH: + case MNOTE_EPSON_TAG_IMAGE_HEIGHT: + CF (entry->format, EXIF_FORMAT_LONG, v, maxlen); + CC (entry->components, 1, v, maxlen); + vl = exif_get_long (entry->data, entry->order); + snprintf (v, maxlen, "%lu", (long unsigned int) vl ); + break; + case MNOTE_NIKON_TAG_LENS_FSTOPS: + case MNOTE_NIKON_TAG_EXPOSUREDIFF: { + unsigned char a,b,c,d; + CF (entry->format, EXIF_FORMAT_UNDEFINED, v, maxlen); + CC (entry->components, 4, v, maxlen); + vl = exif_get_long (entry->data, entry->order); + a = (vl>>24)&0xff; b = (vl>>16)&0xff; c = (vl>>8)&0xff; d = (vl)&0xff; + snprintf (v, maxlen, "%.1f", c?(float)a*((float)b/(float)c):0 ); + break; + } + case MNOTE_NIKON_TAG_FLASHEXPCOMPENSATION: + case MNOTE_NIKON_TAG_FLASHEXPOSUREBRACKETVAL: + CF (entry->format, EXIF_FORMAT_UNDEFINED, v, maxlen); + CC (entry->components, 4, v, maxlen); + vl = exif_get_long (entry->data, entry->order); + snprintf (v, maxlen, "%.1f", ((long unsigned int) vl>>24)/6.0 ); + break; + case MNOTE_NIKON_TAG_SATURATION: + case MNOTE_NIKON_TAG_WHITEBALANCEFINE: + case MNOTE_NIKON_TAG_HUE: + case MNOTE_OLYMPUS_TAG_SENSORTEMPERATURE: + case MNOTE_OLYMPUS_TAG_LENSTEMPERATURE: + CF (entry->format, EXIF_FORMAT_SSHORT, v, maxlen); + CC (entry->components, 1, v, maxlen); + vs = exif_get_short (entry->data, entry->order); + snprintf (v, maxlen, "%hd", vs); + break; + case MNOTE_NIKON_TAG_WHITEBALANCERB: + CF (entry->format, EXIF_FORMAT_RATIONAL, v, maxlen); + CC (entry->components, 4, v, maxlen); + vr = exif_get_rational (entry->data, entry->order); + r = R2D(vr); + vr = exif_get_rational (entry->data+8, entry->order); + b = R2D(vr); + snprintf (v, maxlen, _("Red Correction %f, blue Correction %f"), r,b); + break; + case MNOTE_NIKON_TAG_MANUALFOCUSDISTANCE: + CF (entry->format, EXIF_FORMAT_RATIONAL, v, maxlen); + CC (entry->components, 1, v, maxlen); + vr = exif_get_rational (entry->data, entry->order); + if (!vr.numerator || !vr.denominator) { + strncpy (v, _("No manual focus selection"), maxlen); + } else { + r = R2D(vr); + snprintf (v, maxlen, _("%2.2f meters"), r); + } + break; + case MNOTE_NIKON_TAG_SENSORPIXELSIZE: + CF (entry->format, EXIF_FORMAT_RATIONAL, v, maxlen); + CC (entry->components, 2, v, maxlen); + vr = exif_get_rational (entry->data, entry->order); + vr2 = exif_get_rational (entry->data+8, entry->order); + r = R2D(vr); + b = R2D(vr2); + snprintf (v, maxlen, "%2.2f x %2.2f um", r, b); + break; + case MNOTE_NIKON_TAG_BRACKETING: + CF2 (entry->format, EXIF_FORMAT_BYTE, EXIF_FORMAT_SHORT, v, maxlen); + CC (entry->components, 1, v, maxlen); + if (EXIF_FORMAT_SHORT == entry->format) { + vs = exif_get_short (entry->data, entry->order); + } else { + vs = entry->data[0]; + } + snprintf (v, maxlen, "%hd", vs); + break; + case MNOTE_NIKON_TAG_AFFOCUSPOSITION: + CF (entry->format, EXIF_FORMAT_UNDEFINED, v, maxlen); + CC (entry->components, 4, v, maxlen); + switch ( *( entry->data+1) ) { + case 0: strncpy (v, _("AF position: center"), maxlen); break; + case 1: strncpy (v, _("AF position: top"), maxlen); break; + case 2: strncpy (v, _("AF position: bottom"), maxlen); break; + case 3: strncpy (v, _("AF position: left"), maxlen); break; + case 4: strncpy (v, _("AF position: right"), maxlen); break; + case 5: strncpy (v, _("AF position: upper-left"), maxlen); break; + case 6: strncpy (v, _("AF position: upper-right"), maxlen); break; + case 7: strncpy (v, _("AF position: lower-left"), maxlen); break; + case 8: strncpy (v, _("AF position: lower-right"), maxlen); break; + case 9: strncpy (v, _("AF position: far left"), maxlen); break; + case 10: strncpy (v, _("AF position: far right"), maxlen); break; + default: strncpy (v, _("Unknown AF position"), maxlen); + } + break; + case MNOTE_OLYMPUS_TAG_FLASHDEVICE: + CF (entry->format, EXIF_FORMAT_SHORT, v, maxlen); + CC (entry->components, 2, v, maxlen); + vs = exif_get_short(entry->data, entry->order); + /* search for the tag */ + for (i = 0; (items[i].tag && items[i].tag != entry->tag); i++) + ; + if (!items[i].tag) { + snprintf (v, maxlen, _("Internal error (unknown value %hi)"), vs); + break; + } + CF (entry->format, items[i].fmt, v, maxlen); + /* find the value */ + for (j = 0; items[i].elem[j].string && + (items[i].elem[j].index < vs); j++); + if (items[i].elem[j].index != vs) { + snprintf (v, maxlen, _("Unknown value %hi"), vs); + break; + } + strncpy (v, _(items[i].elem[j].string), maxlen); + break; + case MNOTE_OLYMPUS_TAG_DIGIZOOM: + if (entry->format == EXIF_FORMAT_RATIONAL) { + CC (entry->components, 1, v, maxlen); + vr = exif_get_rational (entry->data, entry->order); + if (!vr.numerator || !vr.denominator) { + strncpy (v, _("None"), maxlen); + } else { + r = R2D(vr); + snprintf (v, maxlen, "%2.2f", r); + } + break; + } + /* fall through to handle SHORT version of this tag */ + case MNOTE_NIKON_TAG_LENSTYPE: + case MNOTE_NIKON_TAG_FLASHUSED: + case MNOTE_NIKON1_TAG_QUALITY: + case MNOTE_NIKON1_TAG_COLORMODE: + case MNOTE_NIKON1_TAG_IMAGEADJUSTMENT: + case MNOTE_NIKON1_TAG_CCDSENSITIVITY: + case MNOTE_NIKON1_TAG_WHITEBALANCE: + case MNOTE_NIKON1_TAG_CONVERTER: + case MNOTE_OLYMPUS_TAG_QUALITY: + case MNOTE_OLYMPUS_TAG_MACRO: + case MNOTE_OLYMPUS_TAG_BWMODE: + case MNOTE_OLYMPUS_TAG_ONETOUCHWB: + case MNOTE_OLYMPUS_TAG_FLASHMODE: + case MNOTE_OLYMPUS_TAG_FOCUSRANGE: + case MNOTE_OLYMPUS_TAG_MANFOCUS: + case MNOTE_OLYMPUS_TAG_SHARPNESS: + case MNOTE_OLYMPUS_TAG_EXTERNALFLASHBOUNCE: + case MNOTE_OLYMPUS_TAG_CONTRAST: + case MNOTE_OLYMPUS_TAG_PREVIEWIMAGEVALID: + case MNOTE_OLYMPUS_TAG_CCDSCANMODE: + case MNOTE_SANYO_TAG_SEQUENTIALSHOT: + case MNOTE_SANYO_TAG_FOCUSMODE: + case MNOTE_SANYO_TAG_RECORDSHUTTERRELEASE: + case MNOTE_SANYO_TAG_RESAVED: + case MNOTE_SANYO_TAG_CCDSENSITIVITY: + case MNOTE_SANYO_TAG_SCENESELECT: + case MNOTE_SANYO_TAG_SEQUENCESHOTINTERVAL: + CC (entry->components, 1, v, maxlen); + switch (entry->format) { + case EXIF_FORMAT_BYTE: + case EXIF_FORMAT_UNDEFINED: + vs = entry->data[0]; + break; + case EXIF_FORMAT_SHORT: + vs = exif_get_short(entry->data, entry->order); + break; + default: + vs = 0; + break; + } + /* search for the tag */ + for (i = 0; (items[i].tag && items[i].tag != entry->tag); i++) + ; + if (!items[i].tag) { + snprintf (v, maxlen, _("Internal error (unknown value %hi)"), vs); + break; + } + CF (entry->format, items[i].fmt, v, maxlen); + /* find the value */ + for (j = 0; items[i].elem[j].string && + (items[i].elem[j].index < vs); j++); + if (items[i].elem[j].index != vs) { + snprintf (v, maxlen, _("Unknown value %hi"), vs); + break; + } + strncpy (v, _(items[i].elem[j].string), maxlen); + break; + case MNOTE_OLYMPUS_TAG_NOISEREDUCTION: + case MNOTE_SANYO_TAG_WIDERANGE: + case MNOTE_SANYO_TAG_COLORADJUSTMENTMODE: + case MNOTE_SANYO_TAG_QUICKSHOT: + case MNOTE_SANYO_TAG_VOICEMEMO: + case MNOTE_SANYO_TAG_FLICKERREDUCE: + case MNOTE_SANYO_TAG_OPTICALZOOM: + case MNOTE_SANYO_TAG_DIGITALZOOM: + case MNOTE_SANYO_TAG_LIGHTSOURCESPECIAL: + CF (entry->format, EXIF_FORMAT_SHORT, v, maxlen); + CC (entry->components, 1, v, maxlen); + vs = exif_get_short (entry->data, entry->order); + switch (vs) { + case 0: + strncpy (v, _("Off"), maxlen); + break; + case 1: + strncpy (v, _("On"), maxlen); + break; + default: + sprintf (buf, _("Unknown %hu"), vs); + strncat (v, buf, maxlen - strlen (v)); + break; + } + break; + case MNOTE_SANYO_TAG_SELFTIMER: + CF (entry->format, EXIF_FORMAT_SHORT, v, maxlen); + CC (entry->components, 1, v, maxlen); + vs = exif_get_short (entry->data, entry->order); + switch (vs) { + case 0: + strncpy (v, _("Off"), maxlen); + break; + case 1: + strncpy (v, _("On"), maxlen); + break; + case 2: + strncpy (v, _("2 sec."), maxlen); + break; + default: + sprintf (buf, _("Unknown %hu"), vs); + strncat (v, buf, maxlen - strlen (v)); + break; + } + break; + case MNOTE_NIKON_TAG_LENS: + CF (entry->format, EXIF_FORMAT_RATIONAL, v, maxlen); + CC (entry->components, 4, v, maxlen); + { + double c,d; + unsigned long a,b; + vr = exif_get_rational (entry->data, entry->order); + a = R2L(vr); + vr = exif_get_rational (entry->data+8, entry->order); + b = R2L(vr); + vr = exif_get_rational (entry->data+16, entry->order); + c = R2D(vr); + vr = exif_get_rational (entry->data+24, entry->order); + d = R2D(vr); + snprintf (v, maxlen, "%ld-%ldmm 1:%3.1f - %3.1f",a,b,c,d); + } + break; + + /* Olympus */ + case MNOTE_OLYMPUS_TAG_MODE: + CF (entry->format, EXIF_FORMAT_LONG, v, maxlen); + CC (entry->components, 3, v, maxlen); + vl = exif_get_long (entry->data, entry->order); + switch (vl) { + case 0: + strncpy (v, _("Normal"), maxlen); + break; + case 1: + strncpy (v, _("Unknown"), maxlen); + break; + case 2: + strncpy (v, _("Fast"), maxlen); + break; + case 3: + strncpy (v, _("Panorama"), maxlen); + break; + default: + snprintf (v, maxlen, "%li", (long int) vl); + } + vl = exif_get_long (entry->data + 4, entry->order); + snprintf (buf, sizeof (buf), "/%li/", (long int) vl); + strncat (v, buf, maxlen - strlen (v)); + vl = exif_get_long (entry->data + 8, entry->order); + switch (vl) { + case 1: + strncat (v, _("Left to right"), maxlen - strlen (v)); + break; + case 2: + strncat (v, _("Right to left"), maxlen - strlen (v)); + break; + case 3: + strncat (v, _("Bottom to top"), maxlen - strlen (v)); + break; + case 4: + strncat (v, _("Top to bottom"), maxlen - strlen (v)); + break; + default: + snprintf (buf, sizeof (buf), "%li", + (long int) vl); + strncat (v, buf, maxlen - strlen (v)); + } + break; + case MNOTE_OLYMPUS_TAG_LENSDISTORTION: + if (entry->format == EXIF_FORMAT_SHORT) { + /* Epson uses a single SHORT here */ + CC (entry->components, 1, v, maxlen); + vs = exif_get_short (entry->data, entry->order); + sprintf (buf, "%hu", vs); + strncat (v, buf, maxlen - strlen (v)); + } else { + /* Others use an array of SSHORT here */ + CC (entry->components, 6, v, maxlen); + CF (entry->format, EXIF_FORMAT_SSHORT, v, maxlen); + for (i=0; i < (int)entry->components; ++i) { + vss = exif_get_sshort (entry->data+2*i, entry->order); + sprintf (buf, "%hd ", vss); + strncat (v, buf, maxlen - strlen (v)); + } + } + break; + case MNOTE_OLYMPUS_TAG_COLORCONTROL: + CF (entry->format, EXIF_FORMAT_SHORT, v, maxlen); + CC (entry->components, 6, v, maxlen); + for (i=0; i < (int)entry->components; ++i) { + vs = exif_get_short (entry->data+2*i, entry->order); + sprintf (buf, "%hu ", vs); + strncat (v, buf, maxlen - strlen (v)); + } + break; + case MNOTE_OLYMPUS_TAG_VERSION: + CF (entry->format, EXIF_FORMAT_ASCII, v, maxlen); + CC2 (entry->components, 5, 8, v, maxlen); + strncpy (v, (char *)entry->data, MIN (maxlen, entry->size)); + break; + case MNOTE_OLYMPUS_TAG_SERIALNUMBER2: + CF (entry->format, EXIF_FORMAT_ASCII, v, maxlen); + strncpy (v, (char *)entry->data, MIN (maxlen, entry->size)); + break; + case MNOTE_OLYMPUS_TAG_INFO: + CF (entry->format, EXIF_FORMAT_ASCII, v, maxlen); + CC2 (entry->components, 52, 60, v, maxlen); + strncpy (v, (char *)entry->data, MIN (maxlen, entry->size)); + break; + case MNOTE_OLYMPUS_TAG_ID: + CF (entry->format, EXIF_FORMAT_UNDEFINED, v, maxlen); + CC (entry->components, 32, v, maxlen); + strncpy (v, (char *)entry->data, MIN (maxlen, entry->size)); + break; + case MNOTE_OLYMPUS_TAG_UNKNOWN_4: + CF (entry->format, EXIF_FORMAT_LONG, v, maxlen); + CC (entry->components, 30, v, maxlen); + for (i=0; i < (int)entry->components; ++i) { + vl = exif_get_long (entry->data+4*i, entry->order); + sprintf (buf, "%lu ", (unsigned long)vl); + strncat (v, buf, maxlen - strlen (v)); + } + break; + case MNOTE_OLYMPUS_TAG_FOCUSDIST: + CF (entry->format, EXIF_FORMAT_RATIONAL, v, maxlen); + CC (entry->components, 1, v, maxlen); + vr = exif_get_rational (entry->data, entry->order); + if (!vr.numerator || !vr.denominator) { + strncpy (v, _("Unknown"), maxlen); + } + else { + unsigned long tmp = vr.numerator / vr.denominator; + snprintf (v, maxlen, "%li mm", tmp); + } + break; + case MNOTE_OLYMPUS_TAG_WBALANCE: + CF (entry->format, EXIF_FORMAT_SHORT, v, maxlen); + CC (entry->components, 2, v, maxlen); + vs = exif_get_short (entry->data, entry->order); + switch (vs) { + case 1: + strncpy (v, _("Automatic"), maxlen); + break; + case 2: + { + ExifShort v2 = exif_get_short (entry->data + 2, entry->order); + unsigned long colorTemp = 0; + switch (v2) { + case 2: + colorTemp = 3000; + break; + case 3: + colorTemp = 3700; + break; + case 4: + colorTemp = 4000; + break; + case 5: + colorTemp = 4500; + break; + case 6: + colorTemp = 5500; + break; + case 7: + colorTemp = 6500; + break; + case 9: + colorTemp = 7500; + break; + } + if (colorTemp) { + snprintf (v, maxlen, _("Manual: %liK"), colorTemp); + } + else { + strncpy (v, _("Manual: unknown"), maxlen); + } + + } + break; + case 3: + strncpy (v, _("One-touch"), maxlen); + break; + default: + strncpy (v, _("Unknown"), maxlen); + break; + } + break; + case MNOTE_OLYMPUS_TAG_REDBALANCE: + case MNOTE_OLYMPUS_TAG_BLUEBALANCE: + CF (entry->format, EXIF_FORMAT_SHORT, v, maxlen); + CC (entry->components, 2, v, maxlen); + vs = exif_get_short (entry->data, entry->order); + snprintf (v, maxlen, "%hu ", vs); + vs = exif_get_short (entry->data + 2, entry->order); + sprintf (buf, "%hu", vs); + strncat (v, buf, maxlen - strlen (v)); + break; + case MNOTE_OLYMPUS_TAG_BLACKLEVEL: + case MNOTE_NIKON_TAG_IMAGEBOUNDARY: + CC (entry->components, 4, v, maxlen); + /* Fall through to COLORMATRIX */ + case MNOTE_OLYMPUS_TAG_COLORMATRIX: + CF (entry->format, EXIF_FORMAT_SHORT, v, maxlen); + if (entry->tag == MNOTE_OLYMPUS_TAG_COLORMATRIX) + CC (entry->components, 9, v, maxlen); + for (i=0; i < (int)entry->components; ++i) { + vs = exif_get_short (entry->data+2*i, entry->order); + sprintf (buf, "%hu ", vs); + strncat (v, buf, maxlen - strlen (v)); + } + break; + case MNOTE_NIKON1_TAG_FOCUS: + case MNOTE_NIKON_TAG_DIGITALZOOM: + case MNOTE_NIKON1_TAG_DIGITALZOOM: + case MNOTE_OLYMPUS_TAG_FOCALPLANEDIAGONAL: + CF (entry->format, EXIF_FORMAT_RATIONAL, v, maxlen); + /* Fall through to default handler for display */ + default: + switch (entry->format) { + case EXIF_FORMAT_ASCII: + strncpy (v, (char *)entry->data, MIN (maxlen, entry->size)); + break; + case EXIF_FORMAT_SHORT: + CC (entry->components, 1, v, maxlen); + vs = exif_get_short (entry->data, entry->order); + snprintf (v, maxlen, "%hu", vs); + break; + case EXIF_FORMAT_LONG: + CC (entry->components, 1, v, maxlen); + vl = exif_get_long (entry->data, entry->order); + snprintf (v, maxlen, "%li", (long int) vl); + break; + case EXIF_FORMAT_RATIONAL: + CC (entry->components, 1, v, maxlen); + vr = exif_get_rational (entry->data, entry->order); + if (!vr.denominator) { + strncpy (v, _("Infinite"), maxlen); + } else { + r = R2D(vr); + snprintf (v, maxlen, "%2.3f", r); + } + break; + case EXIF_FORMAT_SRATIONAL: + CC (entry->components, 1, v, maxlen); + vsr = exif_get_srational (entry->data, entry->order); + if (!vsr.denominator) { + strncpy (v, _("Infinite"), maxlen); + } else { + r = R2D(vsr); + snprintf (v, maxlen, "%2.3f", r); + } + break; + case EXIF_FORMAT_UNDEFINED: + default: + snprintf (v, maxlen, _("%i bytes unknown data: "), + entry->size); + for (i = 0; i < (int)entry->size; i++) { + sprintf (buf, "%02x", entry->data[i]); + strncat (v, buf, maxlen - strlen (v)); + } + break; + } + break; + } + + return (v); +} diff --git a/libexif/olympus/mnote-olympus-entry.h b/libexif/olympus/mnote-olympus-entry.h new file mode 100644 index 0000000..f1b0a98 --- /dev/null +++ b/libexif/olympus/mnote-olympus-entry.h @@ -0,0 +1,43 @@ +/* mnote-olympus-entry.h + * + * Copyright (c) 2002 Lutz Mueller <lutz@users.sourceforge.net> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA. + */ + +#ifndef __MNOTE_OLYMPUS_ENTRY_H__ +#define __MNOTE_OLYMPUS_ENTRY_H__ + +#include <libexif/exif-format.h> +#include <libexif/exif-byte-order.h> +#include <libexif/olympus/mnote-olympus-tag.h> + +typedef struct _MnoteOlympusEntry MnoteOlympusEntry; + +struct _MnoteOlympusEntry { + MnoteOlympusTag tag; + ExifFormat format; + unsigned long components; + + unsigned char *data; + unsigned int size; + + ExifByteOrder order; +}; + +char *mnote_olympus_entry_get_value (MnoteOlympusEntry *entry, char *val, unsigned int maxlen); + +#endif /* __MNOTE_OLYMPUS_ENTRY_H__ */ diff --git a/libexif/olympus/mnote-olympus-tag.c b/libexif/olympus/mnote-olympus-tag.c new file mode 100644 index 0000000..3810352 --- /dev/null +++ b/libexif/olympus/mnote-olympus-tag.c @@ -0,0 +1,230 @@ +/* mnote-olympus-tag.c: + * + * Copyright (c) 2002 Lutz Mueller <lutz@users.sourceforge.net> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA. + */ + +#include <config.h> +#include "mnote-olympus-tag.h" + +#include <libexif/i18n.h> +#include <libexif/exif-utils.h> + +#include <stdlib.h> + +static const struct { + MnoteOlympusTag tag; + const char *name; + const char *title; + const char *description; +} table[] = { +#ifndef NO_VERBOSE_TAG_STRINGS + /* Nikon v2 */ + {MNOTE_NIKON_TAG_FIRMWARE, "Firmware", N_("Firmware Version"), ""}, + {MNOTE_NIKON_TAG_ISO, "ISO", N_("ISO Setting"), ""}, + {MNOTE_NIKON_TAG_COLORMODE1, "ColorMode1", N_("Color Mode (?)"), ""}, + {MNOTE_NIKON_TAG_QUALITY, "Quality", N_("Quality"), ""}, + {MNOTE_NIKON_TAG_WHITEBALANCE, "WhiteBalance", N_("White Balance"), ""}, + {MNOTE_NIKON_TAG_SHARPENING, "Sharpening", N_("Image Sharpening"), ""}, + {MNOTE_NIKON_TAG_FOCUSMODE, "FocusMode", N_("Focus Mode"), ""}, + {MNOTE_NIKON_TAG_FLASHSETTING, "FlashSetting", N_("Flash Setting"), ""}, + {MNOTE_NIKON_TAG_FLASHMODE, "FlashMode", N_("Flash Mode"), ""}, + {MNOTE_NIKON_TAG_WHITEBALANCEFINE,"WhiteBalanceFine",N_("White Balance Fine Adjustment"), ""}, + {MNOTE_NIKON_TAG_WHITEBALANCERB, "WhiteBalanceRB", N_("White Balance RB"), ""}, + {MNOTE_NIKON_TAG_UNKNOWN_0X000D, NULL, NULL, NULL}, + {MNOTE_NIKON_TAG_ISOSELECTION, "ISOSelection", N_("ISO Selection"), ""}, + {MNOTE_NIKON_TAG_PREVIEWIMAGE_IFD_POINTER, "PreviewImage", N_("Preview Image IFD"), N_("Offset of the preview image directory (IFD) inside the file.")}, + {MNOTE_NIKON_TAG_EXPOSUREDIFF, "ExposureDiff", N_("Exposurediff ?"), ""}, + {MNOTE_NIKON_TAG_FLASHEXPCOMPENSATION, "FlashExpCompensation", N_("Flash Exposure Compensation"), ""}, + {MNOTE_NIKON_TAG_ISO2, "ISO", N_("ISO Setting"), ""}, + {MNOTE_NIKON_TAG_IMAGEBOUNDARY, "ImageBoundary", N_("Image Boundary"), ""}, + {MNOTE_NIKON_TAG_UNKNOWN_0X0017, NULL, NULL, NULL}, + {MNOTE_NIKON_TAG_FLASHEXPOSUREBRACKETVAL, "FlashExposureBracketVal", N_("Flash Exposure Bracket Value"), ""}, + {MNOTE_NIKON_TAG_EXPOSUREBRACKETVAL, "ExposureBracketVal", N_("Exposure Bracket Value"), ""}, + {MNOTE_NIKON_TAG_IMAGEADJUSTMENT, "ImageAdjustment", N_("Image Adjustment"), ""}, + {MNOTE_NIKON_TAG_TONECOMPENSATION, "ToneCompensation", N_("Tone Compensation"), ""}, + {MNOTE_NIKON_TAG_ADAPTER, "Adapter", N_("Adapter"), ""}, + {MNOTE_NIKON_TAG_LENSTYPE, "LensType", N_("Lens Type"), ""}, + {MNOTE_NIKON_TAG_LENS, "Lens", N_("Lens"), ""}, + {MNOTE_NIKON_TAG_MANUALFOCUSDISTANCE, "ManualFocusDistance", N_("Manual Focus Distance"), ""}, + {MNOTE_NIKON_TAG_DIGITALZOOM, "DigitalZoom", N_("Digital Zoom"), ""}, + {MNOTE_NIKON_TAG_FLASHUSED, "FlashUsed", N_("Flash Used"), ""}, + {MNOTE_NIKON_TAG_AFFOCUSPOSITION, "AFFocusPosition", N_("AF Focus Position"), ""}, + {MNOTE_NIKON_TAG_BRACKETING, "Bracketing", N_("Bracketing"), ""}, + {MNOTE_NIKON_TAG_UNKNOWN_0X008A, NULL, NULL, NULL}, + {MNOTE_NIKON_TAG_LENS_FSTOPS, "LensFStops", N_("Lens F Stops"), ""}, + {MNOTE_NIKON_TAG_CURVE, "Curve,", N_("Contrast Curve"), ""}, + {MNOTE_NIKON_TAG_COLORMODE, "ColorMode,", N_("Color Mode"), ""}, + {MNOTE_NIKON_TAG_LIGHTTYPE, "LightType,", N_("Light Type"), ""}, + {MNOTE_NIKON_TAG_UNKNOWN_0X0091, NULL, NULL, NULL}, + {MNOTE_NIKON_TAG_HUE, "Hue", N_("Hue Adjustment"), ""}, + {MNOTE_NIKON_TAG_SATURATION, "Saturation", N_("Saturation"), ""}, + {MNOTE_NIKON_TAG_NOISEREDUCTION, "NoiseReduction,", N_("Noise Reduction"), ""}, + {MNOTE_NIKON_TAG_UNKNOWN_0X0097, NULL, NULL, NULL}, + {MNOTE_NIKON_TAG_UNKNOWN_0X0098, NULL, NULL, NULL}, + {MNOTE_NIKON_TAG_SENSORPIXELSIZE, "SensorPixelSize", N_("Sensor Pixel Size"), ""}, + {MNOTE_NIKON_TAG_UNKNOWN_0X009B, NULL, NULL, NULL}, + {MNOTE_NIKON_TAG_SERIALNUMBER, "SerialNumber", N_("Serial Number"), ""}, + {MNOTE_NIKON_TAG_IMAGE_DATASIZE, "ImageDataSize", N_("Image Data Size"), N_("Size of compressed image data in bytes.")}, + {MNOTE_NIKON_TAG_UNKNOWN_0X00A3, NULL, NULL, NULL}, + {MNOTE_NIKON_TAG_TOTALPICTURES, "TotalPictures,", N_("Total Number of Pictures Taken"), ""}, + {MNOTE_NIKON_TAG_UNKNOWN_0X00A8, NULL, NULL, NULL}, + {MNOTE_NIKON_TAG_OPTIMIZATION, "Optimization,", N_("Optimize Image"), ""}, + {MNOTE_NIKON_TAG_SATURATION, "Saturation", N_("Saturation"), ""}, + {MNOTE_NIKON_TAG_VARIPROGRAM, "VariProgram", N_("Vari Program"), ""}, + {MNOTE_NIKON_TAG_CAPTUREEDITORDATA, "CaptureEditorData", N_("Capture Editor Data"), ""}, + {MNOTE_NIKON_TAG_CAPTUREEDITORVER, "CaptureEditorVer", N_("Capture Editor Version"), ""}, + {MNOTE_NIKON_TAG_UNKNOWN_0X0E0E, NULL, NULL, NULL}, + {MNOTE_NIKON_TAG_UNKNOWN_0X0E10, NULL, NULL, NULL}, + {MNOTE_NIKON1_TAG_UNKNOWN_0X0002, NULL, NULL, NULL}, + {MNOTE_NIKON1_TAG_QUALITY, "Quality", N_("Quality"), ""}, + {MNOTE_NIKON1_TAG_COLORMODE, "ColorMode,", N_("Color Mode"), ""}, + {MNOTE_NIKON1_TAG_IMAGEADJUSTMENT, "ImageAdjustment", N_("Image Adjustment"), ""}, + {MNOTE_NIKON1_TAG_CCDSENSITIVITY, "CCDSensitivity", N_("CCD Sensitivity"), ""}, + {MNOTE_NIKON1_TAG_WHITEBALANCE, "WhiteBalance", N_("White Balance"), ""}, + {MNOTE_NIKON1_TAG_FOCUS, "Focus", N_("Focus"), ""}, + {MNOTE_NIKON1_TAG_UNKNOWN_0X0009, NULL, NULL, NULL}, + {MNOTE_NIKON1_TAG_DIGITALZOOM, "DigitalZoom", N_("Digital Zoom"), ""}, + {MNOTE_NIKON1_TAG_CONVERTER, "Converter", N_("Converter"), ""}, + + /* Olympus & some Sanyo */ + {MNOTE_OLYMPUS_TAG_THUMBNAILIMAGE, "ThumbnailImage", N_("Thumbnail Image"), ""}, + {MNOTE_OLYMPUS_TAG_MODE, "Mode", N_("Speed/Sequence/Panorama Direction"), ""}, + {MNOTE_OLYMPUS_TAG_QUALITY, "Quality", N_("Quality"), ""}, + {MNOTE_OLYMPUS_TAG_MACRO, "Macro", N_("Macro"), ""}, + {MNOTE_OLYMPUS_TAG_BWMODE, "BWMode", N_("Black & White Mode"), ""}, + {MNOTE_OLYMPUS_TAG_DIGIZOOM, "DigiZoom", N_("Digital Zoom"), ""}, + {MNOTE_OLYMPUS_TAG_FOCALPLANEDIAGONAL, "FocalPlaneDiagonal", N_("Focal Plane Diagonal"), ""}, + {MNOTE_OLYMPUS_TAG_LENSDISTORTION, "LensDistortionParams", N_("Lens Distortion Parameters"), ""}, + {MNOTE_OLYMPUS_TAG_VERSION, "FirmwareVersion", N_("Firmware Version"), ""}, + {MNOTE_OLYMPUS_TAG_INFO, "Info", N_("Info"), ""}, + {MNOTE_OLYMPUS_TAG_ID, "CameraID", N_("Camera ID"), ""}, + {MNOTE_OLYMPUS_TAG_PRECAPTUREFRAMES, "PreCaptureFrames", N_("Precapture Frames"), ""}, + {MNOTE_OLYMPUS_TAG_WHITEBOARD, "WhiteBoard", N_("White Board"), ""}, + {MNOTE_OLYMPUS_TAG_ONETOUCHWB, "OneTouchWB", N_("One Touch White Balance"), ""}, + {MNOTE_OLYMPUS_TAG_WHITEBALANCEBRACKET, "WhiteBalanceBracket", N_("White Balance Bracket"), ""}, + {MNOTE_OLYMPUS_TAG_WHITEBALANCEBIAS, "WhiteBalanceBias", N_("White Balance Bias"), ""}, + {MNOTE_OLYMPUS_TAG_DATADUMP, "DataDump", N_("Data Dump"), NULL}, + {MNOTE_OLYMPUS_TAG_UNKNOWN_4, NULL, NULL, NULL}, + {MNOTE_OLYMPUS_TAG_SHUTTERSPEED, "ShutterSpeed", N_("Shutter Speed"), ""}, + {MNOTE_OLYMPUS_TAG_ISOVALUE, "ISOValue", N_("ISO Value"), ""}, + {MNOTE_OLYMPUS_TAG_APERTUREVALUE, "ApertureValue", N_("Aperture Value"), ""}, + {MNOTE_OLYMPUS_TAG_BRIGHTNESSVALUE, "BrightnessValue", N_("Brightness Value"), ""}, + {MNOTE_OLYMPUS_TAG_FLASHMODE, "FlashMode", N_("Flash Mode"), ""}, + {MNOTE_OLYMPUS_TAG_FLASHDEVICE, "FlashDevice", N_("Flash Device"), ""}, + {MNOTE_OLYMPUS_TAG_EXPOSURECOMP, "ExposureCompensation", N_("Exposure Compensation"), ""}, + {MNOTE_OLYMPUS_TAG_SENSORTEMPERATURE, "SensorTemperature", N_("Sensor Temperature"), ""}, + {MNOTE_OLYMPUS_TAG_LENSTEMPERATURE, "LensTemperature", N_("Lens Temperature"), ""}, + {MNOTE_OLYMPUS_TAG_LIGHTCONDITION, "LightCondition", N_("Light Condition"), ""}, + {MNOTE_OLYMPUS_TAG_FOCUSRANGE, "FocusRange", N_("Focus Range"), ""}, + {MNOTE_OLYMPUS_TAG_MANFOCUS, "FocusMode", N_("Focus Mode"), "Automatic or manual focusing mode"}, + {MNOTE_OLYMPUS_TAG_FOCUSDIST, "ManualFocusDistance", N_("Manual Focus Distance"), ""}, + {MNOTE_OLYMPUS_TAG_ZOOMSTEPCOUNT, "ZoomStepCount", N_("Zoom Step Count"), ""}, + {MNOTE_OLYMPUS_TAG_FOCUSSTEPCOUNT, "FocusStepCount", N_("Focus Step Count"), ""}, + {MNOTE_OLYMPUS_TAG_SHARPNESS, "Sharpness", N_("Sharpness Setting"), ""}, + {MNOTE_OLYMPUS_TAG_FLASHCHARGELEVEL, "FlashChargeLevel", N_("Flash Charge Level"), ""}, + {MNOTE_OLYMPUS_TAG_COLORMATRIX, "ColorMatrix", N_("Color Matrix"), ""}, + {MNOTE_OLYMPUS_TAG_BLACKLEVEL, "BlackLevel", N_("Black Level"), ""}, + {MNOTE_OLYMPUS_TAG_WBALANCE, "WhiteBalance", N_("White Balance Setting"), ""}, + {MNOTE_OLYMPUS_TAG_REDBALANCE, "RedBalance", N_("Red Balance"), ""}, + {MNOTE_OLYMPUS_TAG_BLUEBALANCE, "BlueBalance", N_("Blue Balance"), ""}, + {MNOTE_OLYMPUS_TAG_COLORMATRIXNUMBER, "ColorMatrixNumber", N_("Color Matrix Number"), ""}, + {MNOTE_OLYMPUS_TAG_SERIALNUMBER2, "SerialNumber", N_("Serial Number"), ""}, + {MNOTE_OLYMPUS_TAG_FLASHEXPOSURECOMP, "FlashExposureComp", N_("Flash Exposure Comp"), ""}, + {MNOTE_OLYMPUS_TAG_INTERNALFLASHTABLE, "InternalFlashTable", N_("Internal Flash Table"), ""}, + {MNOTE_OLYMPUS_TAG_EXTERNALFLASHGVALUE, "ExternalFlashGValue", N_("External Flash G Value"), ""}, + {MNOTE_OLYMPUS_TAG_EXTERNALFLASHBOUNCE, "ExternalFlashBounce", N_("External Flash Bounce"), ""}, + {MNOTE_OLYMPUS_TAG_EXTERNALFLASHZOOM, "ExternalFlashZoom", N_("External Flash Zoom"), ""}, + {MNOTE_OLYMPUS_TAG_EXTERNALFLASHMODE, "ExternalFlashMode", N_("External Flash Mode"), ""}, + {MNOTE_OLYMPUS_TAG_CONTRAST, "Contrast", N_("Contrast Setting"), ""}, + {MNOTE_OLYMPUS_TAG_SHARPNESSFACTOR, "SharpnessFactor", N_("Sharpness Factor"), ""}, + {MNOTE_OLYMPUS_TAG_COLORCONTROL, "ColorControl", N_("Color Control"), ""}, + {MNOTE_OLYMPUS_TAG_IMAGEWIDTH, "OlympusImageWidth", N_("Olympus Image Width"), ""}, + {MNOTE_OLYMPUS_TAG_IMAGEHEIGHT, "OlympusImageHeight", N_("Olympus Image Height"), ""}, + {MNOTE_OLYMPUS_TAG_SCENEDETECT, "SceneDetect", N_("Scene Detect"), ""}, + {MNOTE_OLYMPUS_TAG_COMPRESSIONRATIO, "CompressionRatio", N_("Compression Ratio"), ""}, + {MNOTE_OLYMPUS_TAG_PREVIEWIMAGEVALID, "PreviewImageValid", N_("Preview Image Valid"), ""}, + {MNOTE_OLYMPUS_TAG_AFRESULT, "AFResult", N_("AF Result"), ""}, + {MNOTE_OLYMPUS_TAG_CCDSCANMODE, "CCDScanMode", N_("CCD Scan Mode"), ""}, + {MNOTE_OLYMPUS_TAG_NOISEREDUCTION, "NoiseReduction", N_("Noise Reduction"), ""}, + {MNOTE_OLYMPUS_TAG_INFINITYLENSSTEP, "InfinityLensStep", N_("Infinity Lens Step"), ""}, + {MNOTE_OLYMPUS_TAG_NEARLENSSTEP, "NearLensStep", N_("Near Lens Step"), ""}, + {MNOTE_OLYMPUS_TAG_LIGHTVALUECENTER, "LightValueCenter", N_("Light Value Center"), ""}, + {MNOTE_OLYMPUS_TAG_LIGHTVALUEPERIPHERY, "LightValuePeriphery", N_("Light Value Periphery"), ""}, + + /* Sanyo */ + {MNOTE_SANYO_TAG_SEQUENTIALSHOT, "SequentialShot", N_("Sequential Shot"), ""}, + {MNOTE_SANYO_TAG_WIDERANGE, "WideRange", N_("Wide Range"), ""}, + {MNOTE_SANYO_TAG_COLORADJUSTMENTMODE, "ColorAdjustmentMode", N_("Color Adjustment Mode"), ""}, + {MNOTE_SANYO_TAG_FOCUSMODE, "FocusMode", N_("Focus Mode"), ""}, + {MNOTE_SANYO_TAG_QUICKSHOT, "QuickShot", N_("Quick Shot"), ""}, + {MNOTE_SANYO_TAG_SELFTIMER, "SelfTimer", N_("Self-timer"), ""}, + {MNOTE_SANYO_TAG_VOICEMEMO, "VoiceMemo", N_("Voice Memo"), ""}, + {MNOTE_SANYO_TAG_RECORDSHUTTERRELEASE, "RecordShutterRelease", N_("Record Shutter Release"), ""}, + {MNOTE_SANYO_TAG_FLICKERREDUCE, "FlickerReduce", N_("Flicker Reduce"), ""}, + {MNOTE_SANYO_TAG_OPTICALZOOM, "OpticalZoom", N_("Optical Zoom"), ""}, + {MNOTE_SANYO_TAG_DIGITALZOOM, "DigitalZoom", N_("Digital Zoom"), ""}, + {MNOTE_SANYO_TAG_LIGHTSOURCESPECIAL, "LightSourceSpecial", N_("Light Source Special"), ""}, + {MNOTE_SANYO_TAG_RESAVED, "Resaved", N_("Resaved"), ""}, + {MNOTE_SANYO_TAG_CCDSENSITIVITY, "CCDSensitivity", N_("CCD Sensitivity"), ""}, + {MNOTE_SANYO_TAG_SCENESELECT, "SceneSelect", N_("Scene Select"), ""}, + {MNOTE_SANYO_TAG_MANUALFOCUSDISTANCE, "ManualFocusDistance", N_("Manual Focus Distance"), ""}, + {MNOTE_SANYO_TAG_SEQUENCESHOTINTERVAL, "SequenceShotInterval", N_("Sequence Shot Interval"), ""}, + + /* Epson */ + {MNOTE_EPSON_TAG_IMAGE_WIDTH, "EpsonImageWidth", N_("Epson Image Width"), ""}, + {MNOTE_EPSON_TAG_IMAGE_HEIGHT, "EpsonImageHeight", N_("Epson Image Height"), ""}, + {MNOTE_EPSON_TAG_SOFTWARE, "EpsonSoftware", N_("Epson Software Version"), ""}, +#endif + {0, NULL, NULL, NULL} +}; + +const char * +mnote_olympus_tag_get_name (MnoteOlympusTag t) +{ + unsigned int i; + + for (i = 0; i < sizeof (table) / sizeof (table[0]); i++) + if (table[i].tag == t) return (table[i].name); + return NULL; +} + +const char * +mnote_olympus_tag_get_title (MnoteOlympusTag t) +{ + unsigned int i; + + bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR); + for (i = 0; i < sizeof (table) / sizeof (table[0]); i++) + if (table[i].tag == t) return (_(table[i].title)); + return NULL; +} + +const char * +mnote_olympus_tag_get_description (MnoteOlympusTag t) +{ + unsigned int i; + + for (i = 0; i < sizeof (table) / sizeof (table[0]); i++) + if (table[i].tag == t) { + if (!table[i].description || !*table[i].description) + return ""; + bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR); + return _(table[i].description); + } + return NULL; +} diff --git a/libexif/olympus/mnote-olympus-tag.h b/libexif/olympus/mnote-olympus-tag.h new file mode 100644 index 0000000..2c3de82 --- /dev/null +++ b/libexif/olympus/mnote-olympus-tag.h @@ -0,0 +1,229 @@ +/* mnote-olympus-tag.h + * + * Copyright (c) 2002 Lutz Mueller <lutz@users.sourceforge.net> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA. + */ + +#ifndef __MNOTE_OLYMPUS_TAG_H__ +#define __MNOTE_OLYMPUS_TAG_H__ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +enum _MnoteOlympusTag { + + /* Nikon v.2 */ + MNOTE_NIKON_TAG_FIRMWARE = 0x0001, + MNOTE_NIKON_TAG_ISO = 0x0002, + MNOTE_NIKON_TAG_COLORMODE1 = 0x0003, + MNOTE_NIKON_TAG_QUALITY = 0x0004, + MNOTE_NIKON_TAG_WHITEBALANCE = 0x0005, + MNOTE_NIKON_TAG_SHARPENING = 0x0006, + MNOTE_NIKON_TAG_FOCUSMODE = 0x0007, + MNOTE_NIKON_TAG_FLASHSETTING = 0x0008, + MNOTE_NIKON_TAG_FLASHMODE = 0x0009, + MNOTE_NIKON_TAG_WHITEBALANCEFINE = 0x000b, + MNOTE_NIKON_TAG_WHITEBALANCERB = 0x000c, + MNOTE_NIKON_TAG_UNKNOWN_0X000D = 0x000d, + MNOTE_NIKON_TAG_EXPOSUREDIFF = 0x000e, + MNOTE_NIKON_TAG_ISOSELECTION = 0x000f, + MNOTE_NIKON_TAG_PREVIEWIMAGE_IFD_POINTER= 0x0011, + MNOTE_NIKON_TAG_FLASHEXPCOMPENSATION = 0x0012, + MNOTE_NIKON_TAG_ISO2 = 0x0013, + MNOTE_NIKON_TAG_IMAGEBOUNDARY = 0x0016, + MNOTE_NIKON_TAG_UNKNOWN_0X0017 = 0x0017, + MNOTE_NIKON_TAG_FLASHEXPOSUREBRACKETVAL = 0x0018, + MNOTE_NIKON_TAG_EXPOSUREBRACKETVAL = 0x0019, + MNOTE_NIKON_TAG_IMAGEADJUSTMENT = 0x0080, + MNOTE_NIKON_TAG_TONECOMPENSATION = 0x0081, + MNOTE_NIKON_TAG_ADAPTER = 0x0082, + MNOTE_NIKON_TAG_LENSTYPE = 0x0083, + MNOTE_NIKON_TAG_LENS = 0x0084, + MNOTE_NIKON_TAG_MANUALFOCUSDISTANCE = 0x0085, + MNOTE_NIKON_TAG_DIGITALZOOM = 0x0086, + MNOTE_NIKON_TAG_FLASHUSED = 0x0087, + MNOTE_NIKON_TAG_AFFOCUSPOSITION = 0x0088, + MNOTE_NIKON_TAG_BRACKETING = 0x0089, + MNOTE_NIKON_TAG_UNKNOWN_0X008A = 0x008a, + MNOTE_NIKON_TAG_LENS_FSTOPS = 0x008b, + MNOTE_NIKON_TAG_CURVE = 0x008c, + MNOTE_NIKON_TAG_COLORMODE = 0x008d, + MNOTE_NIKON_TAG_LIGHTTYPE = 0x0090, + MNOTE_NIKON_TAG_UNKNOWN_0X0091 = 0x0091, + MNOTE_NIKON_TAG_HUE = 0x0092, + MNOTE_NIKON_TAG_SATURATION = 0x0094, + MNOTE_NIKON_TAG_NOISEREDUCTION = 0x0095, + MNOTE_NIKON_TAG_UNKNOWN_0X0097 = 0x0097, + MNOTE_NIKON_TAG_UNKNOWN_0X0098 = 0x0098, + MNOTE_NIKON_TAG_SENSORPIXELSIZE = 0x009a, + MNOTE_NIKON_TAG_UNKNOWN_0X009B = 0x009b, + MNOTE_NIKON_TAG_SERIALNUMBER = 0x00a0, + MNOTE_NIKON_TAG_IMAGE_DATASIZE = 0x00a2, + MNOTE_NIKON_TAG_UNKNOWN_0X00A3 = 0x00a3, + MNOTE_NIKON_TAG_TOTALPICTURES = 0x00a7, + MNOTE_NIKON_TAG_UNKNOWN_0X00A8 = 0x00a8, + MNOTE_NIKON_TAG_OPTIMIZATION = 0x00a9, + MNOTE_NIKON_TAG_SATURATION2 = 0x00aa, + MNOTE_NIKON_TAG_VARIPROGRAM = 0x00ab, + MNOTE_NIKON_TAG_CAPTUREEDITORDATA = 0x0e01, + MNOTE_NIKON_TAG_CAPTUREEDITORVER = 0x0e09, + MNOTE_NIKON_TAG_UNKNOWN_0X0E0E = 0x0e0e, + MNOTE_NIKON_TAG_UNKNOWN_0X0E10 = 0x0e10, + + /* Nikon v1: real values + our proprietary base to distinguish from v2 */ + MNOTE_NIKON1_TAG_BASE = 0x8000, + MNOTE_NIKON1_TAG_UNKNOWN_0X0002 = 0x0002 + MNOTE_NIKON1_TAG_BASE, + MNOTE_NIKON1_TAG_QUALITY = 0x0003 + MNOTE_NIKON1_TAG_BASE, + MNOTE_NIKON1_TAG_COLORMODE = 0x0004 + MNOTE_NIKON1_TAG_BASE, + MNOTE_NIKON1_TAG_IMAGEADJUSTMENT = 0x0005 + MNOTE_NIKON1_TAG_BASE, + MNOTE_NIKON1_TAG_CCDSENSITIVITY = 0x0006 + MNOTE_NIKON1_TAG_BASE, + MNOTE_NIKON1_TAG_WHITEBALANCE = 0x0007 + MNOTE_NIKON1_TAG_BASE, + MNOTE_NIKON1_TAG_FOCUS = 0x0008 + MNOTE_NIKON1_TAG_BASE, + MNOTE_NIKON1_TAG_UNKNOWN_0X0009 = 0x0009 + MNOTE_NIKON1_TAG_BASE, + MNOTE_NIKON1_TAG_DIGITALZOOM = 0x000a + MNOTE_NIKON1_TAG_BASE, + MNOTE_NIKON1_TAG_CONVERTER = 0x000b + MNOTE_NIKON1_TAG_BASE, + + /* Olympus and some Sanyo */ + MNOTE_OLYMPUS_TAG_THUMBNAILIMAGE = 0x0100, + MNOTE_OLYMPUS_TAG_MODE = 0x0200, + MNOTE_OLYMPUS_TAG_QUALITY = 0x0201, + MNOTE_OLYMPUS_TAG_MACRO = 0x0202, + MNOTE_OLYMPUS_TAG_BWMODE = 0x0203, + MNOTE_OLYMPUS_TAG_DIGIZOOM = 0x0204, + MNOTE_OLYMPUS_TAG_FOCALPLANEDIAGONAL = 0x0205, + MNOTE_OLYMPUS_TAG_LENSDISTORTION = 0x0206, + MNOTE_OLYMPUS_TAG_VERSION = 0x0207, + MNOTE_OLYMPUS_TAG_INFO = 0x0208, + MNOTE_OLYMPUS_TAG_ID = 0x0209, + MNOTE_OLYMPUS_TAG_PRECAPTUREFRAMES = 0x0300, + MNOTE_OLYMPUS_TAG_WHITEBOARD = 0x0301, + MNOTE_OLYMPUS_TAG_ONETOUCHWB = 0x0302, + MNOTE_OLYMPUS_TAG_WHITEBALANCEBRACKET = 0x0303, + MNOTE_OLYMPUS_TAG_WHITEBALANCEBIAS = 0x0304, + MNOTE_OLYMPUS_TAG_DATADUMP = 0x0f00, + MNOTE_OLYMPUS_TAG_UNKNOWN_4 = 0x0f04, + MNOTE_OLYMPUS_TAG_SHUTTERSPEED = 0x1000, + MNOTE_OLYMPUS_TAG_ISOVALUE = 0x1001, + MNOTE_OLYMPUS_TAG_APERTUREVALUE = 0x1002, + MNOTE_OLYMPUS_TAG_BRIGHTNESSVALUE = 0x1003, + MNOTE_OLYMPUS_TAG_FLASHMODE = 0x1004, + MNOTE_OLYMPUS_TAG_FLASHDEVICE = 0x1005, + MNOTE_OLYMPUS_TAG_EXPOSURECOMP = 0x1006, + MNOTE_OLYMPUS_TAG_SENSORTEMPERATURE = 0x1007, + MNOTE_OLYMPUS_TAG_LENSTEMPERATURE = 0x1008, + MNOTE_OLYMPUS_TAG_LIGHTCONDITION = 0x1009, + MNOTE_OLYMPUS_TAG_FOCUSRANGE = 0x100a, + MNOTE_OLYMPUS_TAG_MANFOCUS = 0x100b, + MNOTE_OLYMPUS_TAG_FOCUSDIST = 0x100c, + MNOTE_OLYMPUS_TAG_ZOOMSTEPCOUNT = 0x100d, + MNOTE_OLYMPUS_TAG_FOCUSSTEPCOUNT = 0x100e, + MNOTE_OLYMPUS_TAG_SHARPNESS = 0x100f, + MNOTE_OLYMPUS_TAG_FLASHCHARGELEVEL = 0x1010, + MNOTE_OLYMPUS_TAG_COLORMATRIX = 0x1011, + MNOTE_OLYMPUS_TAG_BLACKLEVEL = 0x1012, + MNOTE_OLYMPUS_TAG_WBALANCE = 0x1015, + MNOTE_OLYMPUS_TAG_REDBALANCE = 0x1017, + MNOTE_OLYMPUS_TAG_BLUEBALANCE = 0x1018, + MNOTE_OLYMPUS_TAG_COLORMATRIXNUMBER = 0x1019, + MNOTE_OLYMPUS_TAG_SERIALNUMBER2 = 0x101a, + MNOTE_OLYMPUS_TAG_FLASHEXPOSURECOMP = 0x1023, + MNOTE_OLYMPUS_TAG_INTERNALFLASHTABLE = 0x1024, + MNOTE_OLYMPUS_TAG_EXTERNALFLASHGVALUE = 0x1025, + MNOTE_OLYMPUS_TAG_EXTERNALFLASHBOUNCE = 0x1026, + MNOTE_OLYMPUS_TAG_EXTERNALFLASHZOOM = 0x1027, + MNOTE_OLYMPUS_TAG_EXTERNALFLASHMODE = 0x1028, + MNOTE_OLYMPUS_TAG_CONTRAST = 0x1029, + MNOTE_OLYMPUS_TAG_SHARPNESSFACTOR = 0x102a, + MNOTE_OLYMPUS_TAG_COLORCONTROL = 0x102b, + MNOTE_OLYMPUS_TAG_IMAGEWIDTH = 0x102e, + MNOTE_OLYMPUS_TAG_IMAGEHEIGHT = 0x102f, + MNOTE_OLYMPUS_TAG_SCENEDETECT = 0x1030, + MNOTE_OLYMPUS_TAG_COMPRESSIONRATIO = 0x1034, + MNOTE_OLYMPUS_TAG_PREVIEWIMAGEVALID = 0x1035, + MNOTE_OLYMPUS_TAG_AFRESULT = 0x1038, + MNOTE_OLYMPUS_TAG_CCDSCANMODE = 0x1039, + MNOTE_OLYMPUS_TAG_NOISEREDUCTION = 0x103a, + MNOTE_OLYMPUS_TAG_INFINITYLENSSTEP = 0x103b, + MNOTE_OLYMPUS_TAG_NEARLENSSTEP = 0x103c, + MNOTE_OLYMPUS_TAG_LIGHTVALUECENTER = 0x103d, + MNOTE_OLYMPUS_TAG_LIGHTVALUEPERIPHERY = 0x103e, + + /* Epson */ + MNOTE_EPSON_TAG_IMAGE_WIDTH = 0x020b, + MNOTE_EPSON_TAG_IMAGE_HEIGHT = 0x020c, + MNOTE_EPSON_TAG_SOFTWARE = 0x020d, + + /* Sanyo */ + MNOTE_SANYO_TAG_SEQUENTIALSHOT = 0x020e, + MNOTE_SANYO_TAG_WIDERANGE = 0x020f, + MNOTE_SANYO_TAG_COLORADJUSTMENTMODE = 0x0210, + MNOTE_SANYO_TAG_FOCUSMODE = 0x0212, + MNOTE_SANYO_TAG_QUICKSHOT = 0x0213, + MNOTE_SANYO_TAG_SELFTIMER = 0x0214, + MNOTE_SANYO_TAG_VOICEMEMO = 0x0216, + MNOTE_SANYO_TAG_RECORDSHUTTERRELEASE = 0x0217, + MNOTE_SANYO_TAG_FLICKERREDUCE = 0x0218, + MNOTE_SANYO_TAG_OPTICALZOOM = 0x0219, + MNOTE_SANYO_TAG_CCDSENSITIVITY = 0x021a, + MNOTE_SANYO_TAG_DIGITALZOOM = 0x021b, + MNOTE_SANYO_TAG_LIGHTSOURCESPECIAL = 0x021d, + MNOTE_SANYO_TAG_RESAVED = 0x021e, + MNOTE_SANYO_TAG_SCENESELECT = 0x021f, + MNOTE_SANYO_TAG_MANUALFOCUSDISTANCE = 0x0223, + MNOTE_SANYO_TAG_SEQUENCESHOTINTERVAL = 0x0224, +}; +typedef enum _MnoteOlympusTag MnoteOlympusTag; + +/* Don't use these definitions. They are here for compatibility only. */ +#define MNOTE_OLYMPUS_TAG_UNKNOWN_1 MNOTE_OLYMPUS_TAG_BWMODE +#define MNOTE_OLYMPUS_TAG_UNKNOWN_2 MNOTE_OLYMPUS_TAG_FOCALPLANEDIAGONAL +#define MNOTE_OLYMPUS_TAG_UNKNOWN_3 MNOTE_OLYMPUS_TAG_LENSDISTORTION +#define MNOTE_OLYMPUS_TAG_UNKNOWN_5 MNOTE_OLYMPUS_TAG_DATADUMP +#define MNOTE_NIKON_TAG_PREVIEWIMAGE MNOTE_NIKON_TAG_PREVIEWIMAGE_IFD_POINTER + +/*! Return a textual name of the given tag within the Olympus-style MakerNote. + * The name is a short, unique, non-localized text string containing only + * US-ASCII alphanumeric characters. + * + * \param[in] tag Olympus-style MakerNote tag + * \return textual name of the tag, or NULL if the tag is unknown + */ +const char *mnote_olympus_tag_get_name (MnoteOlympusTag tag); + +/*! Return a textual title of the given tag within the Olympus-style MakerNote. + * The title is a short, localized description of the tag. + * + * \param[in] tag Olympus-style MakerNote tag + * \return textual title of the tag, or NULL if the tag is unknown + */ +const char *mnote_olympus_tag_get_title (MnoteOlympusTag tag); + +/*! Return a verbose textual description of the given tag within the + * Olympus-style MakerNote. + * The description is a verbose, localized description of the tag. + * + * \param[in] tag EXIF tag + * \return textual description of the tag, or NULL if the tag is unknown + */ +const char *mnote_olympus_tag_get_description (MnoteOlympusTag tag); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __MNOTE_OLYMPUS_TAG_H__ */ diff --git a/libexif/pentax/Makefile-files b/libexif/pentax/Makefile-files new file mode 100644 index 0000000..bcc0ac5 --- /dev/null +++ b/libexif/pentax/Makefile-files @@ -0,0 +1,7 @@ +# -*- Makefile -*- +noinst_LTLIBRARIES += libmnote-pentax.la +libmnote_pentax_la_SOURCES = \ + pentax/mnote-pentax-entry.c pentax/mnote-pentax-entry.h \ + pentax/exif-mnote-data-pentax.c pentax/exif-mnote-data-pentax.h \ + pentax/mnote-pentax-tag.c pentax/mnote-pentax-tag.h +libmnote_pentax_la_LIBADD = $(LTLIBINTL) diff --git a/libexif/pentax/exif-mnote-data-pentax.c b/libexif/pentax/exif-mnote-data-pentax.c new file mode 100644 index 0000000..757bb72 --- /dev/null +++ b/libexif/pentax/exif-mnote-data-pentax.c @@ -0,0 +1,449 @@ +/* exif-mnote-data-pentax.c + * + * Copyright (c) 2002, 2003 Lutz Mueller <lutz@users.sourceforge.net> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA. + */ + +#include "config.h" +#include "exif-mnote-data-pentax.h" + +#include <stdlib.h> +#include <string.h> +#include <stdio.h> + +#include <libexif/exif-byte-order.h> +#include <libexif/exif-utils.h> + +static void +exif_mnote_data_pentax_clear (ExifMnoteDataPentax *n) +{ + ExifMnoteData *d = (ExifMnoteData *) n; + unsigned int i; + + if (!n) return; + + if (n->entries) { + for (i = 0; i < n->count; i++) + if (n->entries[i].data) { + exif_mem_free (d->mem, n->entries[i].data); + n->entries[i].data = NULL; + } + exif_mem_free (d->mem, n->entries); + n->entries = NULL; + n->count = 0; + } +} + +static void +exif_mnote_data_pentax_free (ExifMnoteData *n) +{ + if (!n) return; + + exif_mnote_data_pentax_clear ((ExifMnoteDataPentax *) n); +} + +static char * +exif_mnote_data_pentax_get_value (ExifMnoteData *d, unsigned int i, char *val, unsigned int maxlen) +{ + ExifMnoteDataPentax *n = (ExifMnoteDataPentax *) d; + + if (!n) return NULL; + if (n->count <= i) return NULL; + return mnote_pentax_entry_get_value (&n->entries[i], val, maxlen); +} + +/** + * @brief save the MnoteData from ne to buf + * + * @param ne extract the data from this structure + * @param *buf write the mnoteData to this buffer (buffer will be allocated) + * @param buf_size the final size of the buffer + */ +static void +exif_mnote_data_pentax_save (ExifMnoteData *ne, + unsigned char **buf, unsigned int *buf_size) +{ + ExifMnoteDataPentax *n = (ExifMnoteDataPentax *) ne; + size_t i, + base = 0, /* internal MakerNote tag number offset */ + o2 = 4 + 2; /* offset to first tag entry, past header */ + size_t datao = n->offset; /* this MakerNote style uses offsets + based on main IFD, not makernote IFD */ + + if (!n || !buf || !buf_size) return; + + /* + * Allocate enough memory for header, the number of entries, entries, + * and next IFD pointer + */ + *buf_size = o2 + 2 + n->count * 12 + 4; + switch (n->version) { + case casioV2: + base = MNOTE_PENTAX2_TAG_BASE; + *buf = exif_mem_alloc (ne->mem, *buf_size); + if (!*buf) { + EXIF_LOG_NO_MEMORY(ne->log, "ExifMnoteDataPentax", *buf_size); + return; + } + /* Write the magic header */ + strcpy ((char *)*buf, "QVC"); + exif_set_short (*buf + 4, n->order, (ExifShort) 0); + + break; + + case pentaxV3: + base = MNOTE_PENTAX2_TAG_BASE; + *buf = exif_mem_alloc (ne->mem, *buf_size); + if (!*buf) { + EXIF_LOG_NO_MEMORY(ne->log, "ExifMnoteDataPentax", *buf_size); + return; + } + + /* Write the magic header */ + strcpy ((char *)*buf, "AOC"); + exif_set_short (*buf + 4, n->order, (ExifShort) ( + (n->order == EXIF_BYTE_ORDER_INTEL) ? + ('I' << 8) | 'I' : + ('M' << 8) | 'M')); + break; + + case pentaxV2: + base = MNOTE_PENTAX2_TAG_BASE; + *buf = exif_mem_alloc (ne->mem, *buf_size); + if (!*buf) { + EXIF_LOG_NO_MEMORY(ne->log, "ExifMnoteDataPentax", *buf_size); + return; + } + + /* Write the magic header */ + strcpy ((char *)*buf, "AOC"); + exif_set_short (*buf + 4, n->order, (ExifShort) 0); + break; + + case pentaxV1: + /* It looks like this format doesn't have a magic header as + * such, just has a fixed number of entries equal to 0x001b */ + *buf_size -= 6; + o2 -= 6; + *buf = exif_mem_alloc (ne->mem, *buf_size); + if (!*buf) { + EXIF_LOG_NO_MEMORY(ne->log, "ExifMnoteDataPentax", *buf_size); + return; + } + break; + + default: + /* internal error */ + return; + } + + /* Write the number of entries. */ + exif_set_short (*buf + o2, n->order, (ExifShort) n->count); + o2 += 2; + + /* Save each entry */ + for (i = 0; i < n->count; i++) { + size_t doff; /* offset to current data portion of tag */ + size_t s; + unsigned char *t; + size_t o = o2 + i * 12; /* current offset into output buffer */ + exif_set_short (*buf + o + 0, n->order, + (ExifShort) (n->entries[i].tag - base)); + exif_set_short (*buf + o + 2, n->order, + (ExifShort) n->entries[i].format); + exif_set_long (*buf + o + 4, n->order, + n->entries[i].components); + o += 8; + s = exif_format_get_size (n->entries[i].format) * + n->entries[i].components; + if (s > 65536) { + /* Corrupt data: EXIF data size is limited to the + * maximum size of a JPEG segment (64 kb). + */ + continue; + } + if (s > 4) { + size_t ts = *buf_size + s; + doff = *buf_size; + t = exif_mem_realloc (ne->mem, *buf, + sizeof (char) * ts); + if (!t) { + EXIF_LOG_NO_MEMORY(ne->log, "ExifMnoteDataPentax", ts); + return; + } + *buf = t; + *buf_size = ts; + exif_set_long (*buf + o, n->order, datao + doff); + } else + doff = o; + + /* Write the data. */ + if (n->entries[i].data) { + memcpy (*buf + doff, n->entries[i].data, s); + } else { + /* Most certainly damaged input file */ + memset (*buf + doff, 0, s); + } + } + + /* Sanity check the buffer size */ + if (*buf_size < (o2 + n->count * 12 + 4)) { + exif_log (ne->log, EXIF_LOG_CODE_CORRUPT_DATA, "ExifMnoteDataPentax", + "Buffer overflow"); + } + + /* Reset next IFD pointer */ + exif_set_long (*buf + o2 + n->count * 12, n->order, 0); +} + +static void +exif_mnote_data_pentax_load (ExifMnoteData *en, + const unsigned char *buf, unsigned int buf_size) +{ + ExifMnoteDataPentax *n = (ExifMnoteDataPentax *) en; + size_t i, tcount, o, datao, base = 0; + ExifShort c; + + if (!n || !buf || !buf_size) { + exif_log (en->log, EXIF_LOG_CODE_CORRUPT_DATA, + "ExifMnoteDataPentax", "Short MakerNote"); + return; + } + datao = 6 + n->offset; + if ((datao + 8 < datao) || (datao + 8 < 8) || (datao + 8 > buf_size)) { + exif_log (en->log, EXIF_LOG_CODE_CORRUPT_DATA, + "ExifMnoteDataPentax", "Short MakerNote"); + return; + } + + /* Detect variant of Pentax/Casio MakerNote found */ + if (!memcmp(buf + datao, "AOC", 4)) { + if ((buf[datao + 4] == 'I') && (buf[datao + 5] == 'I')) { + n->version = pentaxV3; + n->order = EXIF_BYTE_ORDER_INTEL; + } else if ((buf[datao + 4] == 'M') && (buf[datao + 5] == 'M')) { + n->version = pentaxV3; + n->order = EXIF_BYTE_ORDER_MOTOROLA; + } else { + /* Uses Casio v2 tags */ + n->version = pentaxV2; + } + exif_log (en->log, EXIF_LOG_CODE_DEBUG, "ExifMnoteDataPentax", + "Parsing Pentax maker note v%d...", (int)n->version); + datao += 4 + 2; + base = MNOTE_PENTAX2_TAG_BASE; + } else if (!memcmp(buf + datao, "QVC", 4)) { + exif_log (en->log, EXIF_LOG_CODE_DEBUG, "ExifMnoteDataPentax", + "Parsing Casio maker note v2..."); + n->version = casioV2; + base = MNOTE_CASIO2_TAG_BASE; + datao += 4 + 2; + } else { + /* probably assert(!memcmp(buf + datao, "\x00\x1b", 2)) */ + exif_log (en->log, EXIF_LOG_CODE_DEBUG, "ExifMnoteDataPentax", + "Parsing Pentax maker note v1..."); + n->version = pentaxV1; + } + + /* Read the number of tags */ + c = exif_get_short (buf + datao, n->order); + datao += 2; + + /* Remove any old entries */ + exif_mnote_data_pentax_clear (n); + + /* Reserve enough space for all the possible MakerNote tags */ + n->entries = exif_mem_alloc (en->mem, sizeof (MnotePentaxEntry) * c); + if (!n->entries) { + EXIF_LOG_NO_MEMORY(en->log, "ExifMnoteDataPentax", sizeof (MnotePentaxEntry) * c); + return; + } + + /* Parse all c entries, storing ones that are successfully parsed */ + tcount = 0; + for (i = c, o = datao; i; --i, o += 12) { + size_t s; + if ((o + 12 < o) || (o + 12 < 12) || (o + 12 > buf_size)) { + exif_log (en->log, EXIF_LOG_CODE_CORRUPT_DATA, + "ExifMnoteDataPentax", "Short MakerNote"); + break; + } + + n->entries[tcount].tag = exif_get_short (buf + o + 0, n->order) + base; + n->entries[tcount].format = exif_get_short (buf + o + 2, n->order); + n->entries[tcount].components = exif_get_long (buf + o + 4, n->order); + n->entries[tcount].order = n->order; + + exif_log (en->log, EXIF_LOG_CODE_DEBUG, "ExifMnotePentax", + "Loading entry 0x%x ('%s')...", n->entries[tcount].tag, + mnote_pentax_tag_get_name (n->entries[tcount].tag)); + + /* + * Size? If bigger than 4 bytes, the actual data is not + * in the entry but somewhere else (offset). + */ + s = exif_format_get_size (n->entries[tcount].format) * + n->entries[tcount].components; + n->entries[tcount].size = s; + if (s) { + size_t dataofs = o + 8; + if (s > 4) + /* The data in this case is merely a pointer */ + dataofs = exif_get_long (buf + dataofs, n->order) + 6; + if ((dataofs + s < dataofs) || (dataofs + s < s) || + (dataofs + s > buf_size)) { + exif_log (en->log, EXIF_LOG_CODE_DEBUG, + "ExifMnoteDataPentax", "Tag data past end " + "of buffer (%u > %u)", dataofs + s, buf_size); + continue; + } + + n->entries[tcount].data = exif_mem_alloc (en->mem, s); + if (!n->entries[tcount].data) { + EXIF_LOG_NO_MEMORY(en->log, "ExifMnoteDataPentax", s); + continue; + } + memcpy (n->entries[tcount].data, buf + dataofs, s); + } + + /* Tag was successfully parsed */ + ++tcount; + } + /* Store the count of successfully parsed tags */ + n->count = tcount; +} + +static unsigned int +exif_mnote_data_pentax_count (ExifMnoteData *n) +{ + return n ? ((ExifMnoteDataPentax *) n)->count : 0; +} + +static unsigned int +exif_mnote_data_pentax_get_id (ExifMnoteData *d, unsigned int n) +{ + ExifMnoteDataPentax *note = (ExifMnoteDataPentax *) d; + + if (!note) return 0; + if (note->count <= n) return 0; + return note->entries[n].tag; +} + +static const char * +exif_mnote_data_pentax_get_name (ExifMnoteData *d, unsigned int n) +{ + ExifMnoteDataPentax *note = (ExifMnoteDataPentax *) d; + + if (!note) return NULL; + if (note->count <= n) return NULL; + return mnote_pentax_tag_get_name (note->entries[n].tag); +} + +static const char * +exif_mnote_data_pentax_get_title (ExifMnoteData *d, unsigned int n) +{ + ExifMnoteDataPentax *note = (ExifMnoteDataPentax *) d; + + if (!note) return NULL; + if (note->count <= n) return NULL; + return mnote_pentax_tag_get_title (note->entries[n].tag); +} + +static const char * +exif_mnote_data_pentax_get_description (ExifMnoteData *d, unsigned int n) +{ + ExifMnoteDataPentax *note = (ExifMnoteDataPentax *) d; + + if (!note) return NULL; + if (note->count <= n) return NULL; + return mnote_pentax_tag_get_description (note->entries[n].tag); +} + +static void +exif_mnote_data_pentax_set_offset (ExifMnoteData *d, unsigned int o) +{ + if (d) ((ExifMnoteDataPentax *) d)->offset = o; +} + +static void +exif_mnote_data_pentax_set_byte_order (ExifMnoteData *d, ExifByteOrder o) +{ + ExifByteOrder o_orig; + ExifMnoteDataPentax *n = (ExifMnoteDataPentax *) d; + unsigned int i; + + if (!n) return; + + o_orig = n->order; + n->order = o; + for (i = 0; i < n->count; i++) { + n->entries[i].order = o; + exif_array_set_byte_order (n->entries[i].format, n->entries[i].data, + n->entries[i].components, o_orig, o); + } +} + +int +exif_mnote_data_pentax_identify (const ExifData *ed, const ExifEntry *e) +{ + if ((e->size >= 8) && !memcmp (e->data, "AOC", 4)) { + if (((e->data[4] == 'I') && (e->data[5] == 'I')) || + ((e->data[4] == 'M') && (e->data[5] == 'M'))) + return pentaxV3; + else + /* Uses Casio v2 tags */ + return pentaxV2; + } + + if ((e->size >= 8) && !memcmp (e->data, "QVC", 4)) + return casioV2; + + /* This isn't a very robust test, so make sure it's done last */ + /* Maybe we should additionally check for a make of Asahi or Pentax */ + if ((e->size >= 2) && (e->data[0] == 0x00) && (e->data[1] == 0x1b)) + return pentaxV1; + + return 0; +} + +ExifMnoteData * +exif_mnote_data_pentax_new (ExifMem *mem) +{ + ExifMnoteData *d; + + if (!mem) return NULL; + + d = exif_mem_alloc (mem, sizeof (ExifMnoteDataPentax)); + if (!d) return NULL; + + exif_mnote_data_construct (d, mem); + + /* Set up function pointers */ + d->methods.free = exif_mnote_data_pentax_free; + d->methods.set_byte_order = exif_mnote_data_pentax_set_byte_order; + d->methods.set_offset = exif_mnote_data_pentax_set_offset; + d->methods.load = exif_mnote_data_pentax_load; + d->methods.save = exif_mnote_data_pentax_save; + d->methods.count = exif_mnote_data_pentax_count; + d->methods.get_id = exif_mnote_data_pentax_get_id; + d->methods.get_name = exif_mnote_data_pentax_get_name; + d->methods.get_title = exif_mnote_data_pentax_get_title; + d->methods.get_description = exif_mnote_data_pentax_get_description; + d->methods.get_value = exif_mnote_data_pentax_get_value; + + return d; +} diff --git a/libexif/pentax/exif-mnote-data-pentax.h b/libexif/pentax/exif-mnote-data-pentax.h new file mode 100644 index 0000000..da9f79a --- /dev/null +++ b/libexif/pentax/exif-mnote-data-pentax.h @@ -0,0 +1,59 @@ +/* exif-mnote-data-pentax.h + * + * Copyright (c) 2002 Lutz Mueller <lutz@users.sourceforge.net> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA. + */ + +#ifndef __EXIF_MNOTE_DATA_PENTAX_H__ +#define __EXIF_MNOTE_DATA_PENTAX_H__ + +#include <libexif/exif-byte-order.h> +#include <libexif/exif-mnote-data.h> +#include <libexif/exif-mnote-data-priv.h> +#include <libexif/pentax/mnote-pentax-entry.h> +#include <libexif/exif-data.h> +#include <libexif/exif-mem.h> + +enum PentaxVersion {pentaxV1 = 1, pentaxV2 = 2, pentaxV3 = 3, casioV2 = 4 }; + +typedef struct _ExifMnoteDataPentax ExifMnoteDataPentax; + +struct _ExifMnoteDataPentax { + ExifMnoteData parent; + + MnotePentaxEntry *entries; + unsigned int count; + + ExifByteOrder order; + unsigned int offset; + + enum PentaxVersion version; +}; + +/*! Detect if MakerNote is recognized as one handled by the Pentax module. + * + * \param[in] ed image #ExifData to identify as as a Pentax type + * \param[in] e #ExifEntry for EXIF_TAG_MAKER_NOTE, from within ed but + * duplicated here for convenience + * \return 0 if not recognized, nonzero if recognized. The specific nonzero + * value returned may identify a subtype unique within this module. + */ +int exif_mnote_data_pentax_identify (const ExifData *ed, const ExifEntry *e); + +ExifMnoteData *exif_mnote_data_pentax_new (ExifMem *); + +#endif /* __EXIF_MNOTE_DATA_PENTAX_H__ */ diff --git a/libexif/pentax/mnote-pentax-entry.c b/libexif/pentax/mnote-pentax-entry.c new file mode 100644 index 0000000..7e97c2c --- /dev/null +++ b/libexif/pentax/mnote-pentax-entry.c @@ -0,0 +1,459 @@ +/* mnote-pentax-entry.c + * + * Copyright (c) 2002 Lutz Mueller <lutz@users.sourceforge.net> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA. + */ + +#include <config.h> +#include "mnote-pentax-entry.h" + +#include <libexif/i18n.h> + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include <libexif/exif-format.h> +#include <libexif/exif-utils.h> +#include <libexif/exif-entry.h> + + +#define CF(format,target,v,maxlen) \ +{ \ + if (format != target) { \ + snprintf (v, maxlen, \ + _("Invalid format '%s', " \ + "expected '%s'."), \ + exif_format_get_name (format), \ + exif_format_get_name (target)); \ + break; \ + } \ +} + +#define CC(number,target,v,maxlen) \ +{ \ + if (number != target) { \ + snprintf (v, maxlen, \ + _("Invalid number of components (%i, " \ + "expected %i)."), (int) number, (int) target); \ + break; \ + } \ +} + +#define CC2(number,t1,t2,v,maxlen) \ +{ \ + if ((number != t1) && (number != t2)) { \ + snprintf (v, maxlen, \ + _("Invalid number of components (%i, " \ + "expected %i or %i)."), (int) number, \ + (int) t1, (int) t2); \ + break; \ + } \ +} + +static const struct { + ExifTag tag; + struct { + int index; + const char *string; + } elem[33]; +} items[] = { +#ifndef NO_VERBOSE_TAG_DATA + { MNOTE_PENTAX_TAG_MODE, + { {0, N_("Auto")}, + {1, N_("Night scene")}, + {2, N_("Manual")}, + {4, N_("Multi-exposure")}, + {0, NULL}}}, + { MNOTE_PENTAX_TAG_QUALITY, + { {0, N_("Good")}, + {1, N_("Better")}, + {2, N_("Best")},{0,NULL}}}, + { MNOTE_PENTAX_TAG_FOCUS, + { {2, N_("Custom")}, + {3, N_("Auto")}, + {0, NULL}}}, + { MNOTE_PENTAX_TAG_FLASH, + { {1, N_("Auto")}, + {2, N_("Flash on")}, + {4, N_("Flash off")}, + {6, N_("Red-eye reduction")}, + {0, NULL}}}, + { MNOTE_PENTAX_TAG_WHITE_BALANCE, + { {0, N_("Auto")}, + {1, N_("Daylight")}, + {2, N_("Shade")}, + {3, N_("Tungsten")}, + {4, N_("Fluorescent")}, + {5, N_("Manual")}, + {0, NULL}}}, + { MNOTE_PENTAX_TAG_SHARPNESS, + { {0, N_("Normal")}, + {1, N_("Soft")}, + {2, N_("Hard")}, + {0, NULL}}}, + { MNOTE_PENTAX_TAG_CONTRAST, + { {0, N_("Normal")}, + {1, N_("Low")}, + {2, N_("High")}, + {0, NULL}}}, + { MNOTE_PENTAX_TAG_SATURATION, + { {0, N_("Normal")}, + {1, N_("Low")}, + {2, N_("High")}, + {0, NULL}}}, + { MNOTE_PENTAX_TAG_ISO_SPEED, + { {10, N_("100")}, + {16, N_("200")}, + {100, N_("100")}, + {200, N_("200")}, + { 0, NULL}}}, + { MNOTE_PENTAX_TAG_COLOR, + { {1, N_("Full")}, + {2, N_("Black & white")}, + {3, N_("Sepia")}, + {0, NULL}}}, + { MNOTE_PENTAX2_TAG_MODE, + { {0, N_("Auto")}, + {1, N_("Night scene")}, + {2, N_("Manual")}, + {4, N_("Multi-exposure")}, + {0, NULL}}}, + { MNOTE_PENTAX2_TAG_QUALITY, + { {0, N_("Good")}, + {1, N_("Better")}, + {2, N_("Best")}, + {3, N_("TIFF")}, + {4, N_("RAW")}, + {0, NULL}}}, + { MNOTE_PENTAX2_TAG_IMAGE_SIZE, + { {0, "640x480"}, + {1, N_("Full")}, + {2, "1024x768"}, + {3, "1280x960"}, + {4, "1600x1200"}, + {5, "2048x1536"}, + {8, N_("2560x1920 or 2304x1728")}, + {9, "3072x2304"}, + {10, "3264x2448"}, + {19, "320x240"}, + {20, "2288x1712"}, + {21, "2592x1944"}, + {22, N_("2304x1728 or 2592x1944")}, + {23, "3056x2296"}, + {25, N_("2816x2212 or 2816x2112")}, + {27, "3648x2736"}, + {36, "3008x2008"}, + {0, NULL}}}, + { MNOTE_PENTAX2_TAG_PICTURE_MODE, + { {0, N_("Program")}, + {2, N_("Program AE")}, + {3, N_("Manual")}, + {5, N_("Portrait")}, + {6, N_("Landscape")}, + {8, N_("Sport")}, + {9, N_("Night scene")}, + {11, N_("Soft")}, + {12, N_("Surf & snow")}, + {13, N_("Sunset or candlelight")}, + {14, N_("Autumn")}, + {15, N_("Macro")}, + {17, N_("Fireworks")}, + {18, N_("Text")}, + {19, N_("Panorama")}, + {30, N_("Self portrait")}, + {31, N_("Illustrations")}, + {33, N_("Digital filter")}, + {37, N_("Museum")}, + {38, N_("Food")}, + {40, N_("Green mode")}, + {49, N_("Light pet")}, + {50, N_("Dark pet")}, + {51, N_("Medium pet")}, + {53, N_("Underwater")}, + {54, N_("Candlelight")}, + {55, N_("Natural skin tone")}, + {56, N_("Synchro sound record")}, + {58, N_("Frame composite")}, + {0, NULL}}}, + { MNOTE_PENTAX2_TAG_FLASH_MODE, + { {0x0000, N_("Auto, did not fire")}, + {0x0001, N_("Off")}, + {0x0003, N_("Auto, did not fire, red-eye reduction")}, + {0x0100, N_("Auto, fired")}, + {0x0102, N_("On")}, + {0x0103, N_("Auto, fired, red-eye reduction")}, + {0x0104, N_("On, red-eye reduction")}, + {0x0105, N_("On, wireless")}, + {0x0108, N_("On, soft")}, + {0x0109, N_("On, slow-sync")}, + {0x010a, N_("On, slow-sync, red-eye reduction")}, + {0x010b, N_("On, trailing-curtain sync")}, + {0, NULL}}}, + { MNOTE_PENTAX2_TAG_FOCUS_MODE, + { {0, N_("Normal")}, + {1, N_("Macro")}, + {2, N_("Infinity")}, + {3, N_("Manual")}, + {5, N_("Pan focus")}, + {16, N_("AF-S")}, + {17, N_("AF-C")}, + {0, NULL}}}, + { MNOTE_PENTAX2_TAG_AFPOINT_SELECTED, + { {1, N_("Upper-left")}, + {2, N_("Top")}, + {3, N_("Upper-right")}, + {4, N_("Left")}, + {5, N_("Mid-left")}, + {6, N_("Center")}, + {7, N_("Mid-right")}, + {8, N_("Right")}, + {9, N_("Lower-left")}, + {10, N_("Bottom")}, + {11, N_("Lower-right")}, + {0xfffe, N_("Fixed center")}, + {0xffff, N_("Auto")}, + {0, NULL}}}, + { MNOTE_PENTAX2_TAG_AUTO_AFPOINT, + { {0, N_("Multiple")}, + {1, N_("Top-left")}, + {2, N_("Top-center")}, + {3, N_("Top-right")}, + {4, N_("Left")}, + {5, N_("Center")}, + {6, N_("Right")}, + {7, N_("Bottom-left")}, + {8, N_("Bottom-center")}, + {9, N_("Bottom-right")}, + {0xffff, N_("None")}, + {0, NULL}}}, + { MNOTE_PENTAX2_TAG_WHITE_BALANCE, + { {0, N_("Auto")}, + {1, N_("Daylight")}, + {2, N_("Shade")}, + {3, N_("Fluorescent")}, + {4, N_("Tungsten")}, + {5, N_("Manual")}, + {6, N_("Daylight fluorescent")}, + {7, N_("Day white fluorescent")}, + {8, N_("White fluorescent")}, + {9, N_("Flash")}, + {10, N_("Cloudy")}, + {0xfffe, N_("Unknown")}, + {0xffff, N_("User selected")}, + {0, NULL}}}, + {MNOTE_CASIO2_TAG_BESTSHOT_MODE, + { {0, N_("Off")}, + {1, N_("On")}, + {0, NULL}}}, +#endif + {0, {{0, NULL}}} +}; + +/* Two-component values */ +static const struct { + ExifTag tag; + struct { + int index1, index2; + const char *string; + } elem[39]; +} items2[] = { +#ifndef NO_VERBOSE_TAG_DATA + { MNOTE_PENTAX2_TAG_IMAGE_SIZE, + { {0, 0, "2304x1728"}, + {4, 0, "1600x1200"}, + {5, 0, "2048x1536"}, + {8, 0, "2560x1920"}, + {34, 0, "1536x1024"}, + {36, 0, N_("3008x2008 or 3040x2024")}, + {37, 0, "3008x2000"}, + {35, 1, "2400x1600"}, + {32, 2, "960x480"}, + {33, 2, "1152x768"}, + {34, 2, "1536x1024"}, + {0, 0, NULL}}}, + { MNOTE_PENTAX2_TAG_PICTURE_MODE, + { {0, 0, N_("Auto")}, + {5, 0, N_("Portrait")}, + {53, 0, N_("Underwater")}, + {255, 0, N_("Digital filter?")}, + {5, 1, N_("Portrait")}, + {9, 1, N_("Night scene")}, + {13, 1, N_("Candlelight")}, + {15, 1, N_("Macro")}, + {53, 1, N_("Underwater")}, + {0, 2, N_("Program AE")}, + {5, 2, N_("Portrait")}, + {6, 2, N_("Landscape")}, + {0, 0, NULL}}}, +#endif + {0, {{0, 0, NULL}}} +}; + +char * +mnote_pentax_entry_get_value (MnotePentaxEntry *entry, + char *val, unsigned int maxlen) +{ + ExifLong vl; + ExifShort vs, vs2; + int i = 0, j = 0; + + if (!entry) return (NULL); + + memset (val, 0, maxlen); + maxlen--; + + switch (entry->tag) { + case MNOTE_PENTAX_TAG_MODE: + case MNOTE_PENTAX_TAG_QUALITY: + case MNOTE_PENTAX_TAG_FOCUS: + case MNOTE_PENTAX_TAG_FLASH: + case MNOTE_PENTAX_TAG_WHITE_BALANCE: + case MNOTE_PENTAX_TAG_SHARPNESS: + case MNOTE_PENTAX_TAG_CONTRAST: + case MNOTE_PENTAX_TAG_SATURATION: + case MNOTE_PENTAX_TAG_ISO_SPEED: + case MNOTE_PENTAX_TAG_COLOR: + case MNOTE_PENTAX2_TAG_MODE: + case MNOTE_PENTAX2_TAG_QUALITY: + case MNOTE_PENTAX2_TAG_FLASH_MODE: + case MNOTE_PENTAX2_TAG_FOCUS_MODE: + case MNOTE_PENTAX2_TAG_AFPOINT_SELECTED: + case MNOTE_PENTAX2_TAG_AUTO_AFPOINT: + case MNOTE_PENTAX2_TAG_WHITE_BALANCE: + case MNOTE_PENTAX2_TAG_PICTURE_MODE: + case MNOTE_PENTAX2_TAG_IMAGE_SIZE: + case MNOTE_CASIO2_TAG_BESTSHOT_MODE: + CF (entry->format, EXIF_FORMAT_SHORT, val, maxlen); + CC2 (entry->components, 1, 2, val, maxlen); + if (entry->components == 1) { + vs = exif_get_short (entry->data, entry->order); + + /* search the tag */ + for (i = 0; (items[i].tag && items[i].tag != entry->tag); i++); + if (!items[i].tag) { + snprintf (val, maxlen, + _("Internal error (unknown value %i)"), vs); + break; + } + + /* find the value */ + for (j = 0; items[i].elem[j].string && + (items[i].elem[j].index < vs); j++); + if (items[i].elem[j].index != vs) { + snprintf (val, maxlen, + _("Internal error (unknown value %i)"), vs); + break; + } + strncpy (val, _(items[i].elem[j].string), maxlen); + } else { + /* Two-component values */ + CF (entry->format, EXIF_FORMAT_SHORT, val, maxlen); + CC2 (entry->components, 1, 2, val, maxlen); + vs = exif_get_short (entry->data, entry->order); + vs2 = exif_get_short (entry->data+2, entry->order) << 16; + + /* search the tag */ + for (i = 0; (items2[i].tag && items2[i].tag != entry->tag); i++); + if (!items2[i].tag) { + snprintf (val, maxlen, + _("Internal error (unknown value %i %i)"), vs, vs2); + break; + } + + /* find the value */ + for (j = 0; items2[i].elem[j].string && ((items2[i].elem[j].index2 < vs2) + || ((items2[i].elem[j].index2 == vs2) && (items2[i].elem[j].index1 < vs))); j++); + if ((items2[i].elem[j].index1 != vs) || (items2[i].elem[j].index2 != vs2)) { + snprintf (val, maxlen, + _("Internal error (unknown value %i %i)"), vs, vs2); + break; + } + strncpy (val, _(items2[i].elem[j].string), maxlen); + } + break; + + case MNOTE_PENTAX_TAG_ZOOM: + CF (entry->format, EXIF_FORMAT_LONG, val, maxlen); + CC (entry->components, 1, val, maxlen); + vl = exif_get_long (entry->data, entry->order); + snprintf (val, maxlen, "%li", (long int) vl); + break; + case MNOTE_PENTAX_TAG_PRINTIM: + CF (entry->format, EXIF_FORMAT_UNDEFINED, val, maxlen); + CC (entry->components, 124, val, maxlen); + snprintf (val, maxlen, _("%i bytes unknown data"), + entry->size); + break; + case MNOTE_PENTAX_TAG_TZ_CITY: + case MNOTE_PENTAX_TAG_TZ_DST: + CF (entry->format, EXIF_FORMAT_UNDEFINED, val, maxlen); + CC (entry->components, 4, val, maxlen); + strncpy (val, (char*)entry->data, MIN(maxlen, entry->size)); + break; + case MNOTE_PENTAX2_TAG_DATE: + CF (entry->format, EXIF_FORMAT_UNDEFINED, val, maxlen); + CC (entry->components, 4, val, maxlen); + /* Note: format is UNDEFINED, not SHORT -> order is fixed: MOTOROLA */ + vs = exif_get_short (entry->data, EXIF_BYTE_ORDER_MOTOROLA); + snprintf (val, maxlen, "%i:%02i:%02i", vs, entry->data[2], entry->data[3]); + break; + case MNOTE_PENTAX2_TAG_TIME: + CF (entry->format, EXIF_FORMAT_UNDEFINED, val, maxlen); + CC2 (entry->components, 3, 4, val, maxlen); + snprintf (val, maxlen, "%02i:%02i:%02i", entry->data[0], entry->data[1], entry->data[2]); + break; + default: + switch (entry->format) { + case EXIF_FORMAT_ASCII: + strncpy (val, (char *)entry->data, MIN(maxlen, entry->size)); + break; + case EXIF_FORMAT_SHORT: + { + const unsigned char *data = entry->data; + size_t k, len = strlen(val); + for(k=0; k<entry->components; k++) { + vs = exif_get_short (data, entry->order); + snprintf (val+len, maxlen-len, "%i ", vs); + len = strlen(val); + data += 2; + } + } + break; + case EXIF_FORMAT_LONG: + { + const unsigned char *data = entry->data; + size_t k, len = strlen(val); + for(k=0; k<entry->components; k++) { + vl = exif_get_long (data, entry->order); + snprintf (val+len, maxlen-len, "%li", (long int) vl); + len = strlen(val); + data += 4; + } + } + break; + case EXIF_FORMAT_UNDEFINED: + default: + snprintf (val, maxlen, _("%i bytes unknown data"), + entry->size); + break; + } + break; + } + + return (val); +} diff --git a/libexif/pentax/mnote-pentax-entry.h b/libexif/pentax/mnote-pentax-entry.h new file mode 100644 index 0000000..4547ec3 --- /dev/null +++ b/libexif/pentax/mnote-pentax-entry.h @@ -0,0 +1,43 @@ +/* mnote-pentax-entry.h + * + * Copyright (c) 2002 Lutz Mueller <lutz@users.sourceforge.net> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA. + */ + +#ifndef __MNOTE_PENTAX_ENTRY_H__ +#define __MNOTE_PENTAX_ENTRY_H__ + +#include <libexif/exif-format.h> +#include <libexif/exif-byte-order.h> +#include <libexif/pentax/mnote-pentax-tag.h> + +typedef struct _MnotePentaxEntry MnotePentaxEntry; + +struct _MnotePentaxEntry { + MnotePentaxTag tag; + ExifFormat format; + unsigned long components; + + unsigned char *data; + unsigned int size; + + ExifByteOrder order; +}; + +char *mnote_pentax_entry_get_value (MnotePentaxEntry *entry, char *val, unsigned int maxlen); + +#endif /* __MNOTE_PENTAX_ENTRY_H__ */ diff --git a/libexif/pentax/mnote-pentax-tag.c b/libexif/pentax/mnote-pentax-tag.c new file mode 100644 index 0000000..740f135 --- /dev/null +++ b/libexif/pentax/mnote-pentax-tag.c @@ -0,0 +1,175 @@ +/* mnote-pentax-tag.c: + * + * Copyright (c) 2002 Lutz Mueller <lutz@users.sourceforge.net> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA. + */ + +#include <config.h> +#include "mnote-pentax-tag.h" + +#include <stdlib.h> + +#include <libexif/i18n.h> + +static const struct { + MnotePentaxTag tag; + const char *name; + const char *title; + const char *description; +} table[] = { +#ifndef NO_VERBOSE_TAG_STRINGS + {MNOTE_PENTAX_TAG_MODE, "Mode", N_("Capture Mode"), ""}, + {MNOTE_PENTAX_TAG_QUALITY, "Quality", N_("Quality Level"), ""}, + {MNOTE_PENTAX_TAG_FOCUS, "Focus", N_("Focus Mode"), ""}, + {MNOTE_PENTAX_TAG_FLASH, "Flash", N_("Flash Mode"), ""}, + {MNOTE_PENTAX_TAG_UNKNOWN_05, NULL, NULL, NULL}, + {MNOTE_PENTAX_TAG_UNKNOWN_06, NULL, NULL, NULL}, + {MNOTE_PENTAX_TAG_WHITE_BALANCE, "WhiteBalance", N_("White Balance"), ""}, + {MNOTE_PENTAX_TAG_UNKNOWN_08, NULL, NULL, NULL}, + {MNOTE_PENTAX_TAG_UNKNOWN_09, NULL, NULL, NULL}, + {MNOTE_PENTAX_TAG_ZOOM, "Zoom", N_("Zoom"), NULL}, + {MNOTE_PENTAX_TAG_SHARPNESS, "Sharpness", N_("Sharpness"), ""}, + {MNOTE_PENTAX_TAG_CONTRAST, "Contrast", N_("Contrast"), ""}, + {MNOTE_PENTAX_TAG_SATURATION, "Saturation", N_("Saturation"), ""}, + {MNOTE_PENTAX_TAG_UNKNOWN_14, NULL, NULL, NULL}, + {MNOTE_PENTAX_TAG_UNKNOWN_15, NULL, NULL, NULL}, + {MNOTE_PENTAX_TAG_UNKNOWN_16, NULL, NULL, NULL}, + {MNOTE_PENTAX_TAG_UNKNOWN_17, NULL, NULL, NULL}, + {MNOTE_PENTAX_TAG_UNKNOWN_18, NULL, NULL, NULL}, + {MNOTE_PENTAX_TAG_UNKNOWN_19, NULL, NULL, NULL}, + {MNOTE_PENTAX_TAG_ISO_SPEED, "ISOSpeed", N_("ISO Speed"), ""}, + {MNOTE_PENTAX_TAG_UNKNOWN_21, NULL, NULL, NULL}, + {MNOTE_PENTAX_TAG_COLOR, "Color", N_("Colors"), ""}, + {MNOTE_PENTAX_TAG_UNKNOWN_24, NULL, NULL, NULL}, + {MNOTE_PENTAX_TAG_UNKNOWN_25, NULL, NULL, NULL}, + {MNOTE_PENTAX_TAG_PRINTIM, "PrintIM", N_("PrintIM Settings"), ""}, + {MNOTE_PENTAX_TAG_TZ_CITY, "TimeZone", N_("Time Zone"), ""}, + {MNOTE_PENTAX_TAG_TZ_DST, "DaylightSavings", N_("Daylight Savings"), ""}, + + {MNOTE_PENTAX2_TAG_MODE, "Mode", N_("Capture Mode"), ""}, + {MNOTE_PENTAX2_TAG_PREVIEW_SIZE, "PentaxPreviewSize", N_("Preview Size"), ""}, + {MNOTE_PENTAX2_TAG_PREVIEW_LENGTH, "PentaxPreviewLength", N_("Preview Length"), ""}, + {MNOTE_PENTAX2_TAG_PREVIEW_START, "PentaxPreviewStart", N_("Preview Start"), ""}, + {MNOTE_PENTAX2_TAG_MODEL_ID, "ModelID", N_("Model Identification"), ""}, + {MNOTE_PENTAX2_TAG_DATE, "Date", N_("Date"), ""}, + {MNOTE_PENTAX2_TAG_TIME, "Time", N_("Time"), ""}, + {MNOTE_PENTAX2_TAG_QUALITY, "Quality", N_("Quality Level"), ""}, + {MNOTE_PENTAX2_TAG_IMAGE_SIZE, "ImageSize", N_("Image Size"), ""}, + {MNOTE_PENTAX2_TAG_PICTURE_MODE, "PictureMode", N_("Picture Mode"), ""}, + {MNOTE_PENTAX2_TAG_FLASH_MODE, "FlashMode", N_("Flash Mode"), ""}, + {MNOTE_PENTAX2_TAG_FOCUS_MODE, "FocusMode", N_("Focus Mode"), ""}, + {MNOTE_PENTAX2_TAG_AFPOINT_SELECTED, "AFPointSelected", N_("AF Point Selected"), ""}, + {MNOTE_PENTAX2_TAG_AUTO_AFPOINT, "AutoAFPoint", N_("Auto AF Point"), ""}, + {MNOTE_PENTAX2_TAG_FOCUS_POSITION, "FocusPosition", N_("Focus Position"), ""}, + {MNOTE_PENTAX2_TAG_EXPOSURE_TIME, "ExposureTime", N_("Exposure Time"), ""}, + {MNOTE_PENTAX2_TAG_FNUMBER, "FNumber", N_("F-Number"), ""}, + {MNOTE_PENTAX2_TAG_ISO, "ISO", N_("ISO Number"), ""}, + {MNOTE_PENTAX2_TAG_EXPOSURE_COMPENSATION, "ExposureCompensation", N_("Exposure Compensation"), ""}, + {MNOTE_PENTAX2_TAG_METERING_MODE, "MeteringMode", N_("Metering Mode"), ""}, + {MNOTE_PENTAX2_TAG_AUTO_BRACKETING, "AutoBracketing", N_("Auto Bracketing"), ""}, + {MNOTE_PENTAX2_TAG_WHITE_BALANCE, "WhiteBalance", N_("White Balance"), ""}, + {MNOTE_PENTAX2_TAG_WHITE_BALANCE_MODE, "WhiteBalanceMode", N_("White Balance Mode"), ""}, + {MNOTE_PENTAX2_TAG_BLUE_BALANCE, "BlueBalance", N_("Blue Balance"), ""}, + {MNOTE_PENTAX2_TAG_RED_BALANCE, "RedBalance", N_("Red Balance"), ""}, + {MNOTE_PENTAX2_TAG_FOCAL_LENGTH, "FocalLength", N_("Focal Length"), ""}, + {MNOTE_PENTAX2_TAG_DIGITAL_ZOOM, "DigitalZoom", N_("Digital Zoom"), ""}, + {MNOTE_PENTAX2_TAG_SATURATION, "Saturation", N_("Saturation"), ""}, + {MNOTE_PENTAX2_TAG_CONTRAST, "Contrast", N_("Contrast"), ""}, + {MNOTE_PENTAX2_TAG_SHARPNESS, "Sharpness", N_("Sharpness"), ""}, + {MNOTE_PENTAX2_TAG_WORLDTIME_LOCATION, "WorldTimeLocation", N_("World Time Location"), ""}, + {MNOTE_PENTAX2_TAG_HOMETOWN_CITY, "HometownCity", N_("Hometown City"), ""}, + {MNOTE_PENTAX2_TAG_DESTINATION_CITY, "DestinationCity", N_("Destination City"), ""}, + {MNOTE_PENTAX2_TAG_HOMETOWN_DST, "HometownDST,", N_("Hometown DST"), N_("Home Daylight Savings Time")}, + {MNOTE_PENTAX2_TAG_DESTINATION_DST, "DestinationDST", N_("Destination DST"), N_("Destination Daylight Savings Time")}, + {MNOTE_PENTAX2_TAG_FRAME_NUMBER, "FrameNumber", N_("Frame Number"), ""}, + {MNOTE_PENTAX2_TAG_IMAGE_PROCESSING, "ImageProcessing", N_("Image Processing"), ""}, + {MNOTE_PENTAX2_TAG_PICTURE_MODE2, "PictureMode2", N_("Picture Mode (2)"), ""}, + {MNOTE_PENTAX2_TAG_DRIVE_MODE, "DriveMode", N_("Drive Mode"), ""}, + {MNOTE_PENTAX2_TAG_COLOR_SPACE, "ColorSpace", N_("Color Space"), ""}, + {MNOTE_PENTAX2_TAG_IMAGE_AREA_OFFSET, "ImageAreaOffset", N_("Image Area Offset"), ""}, + {MNOTE_PENTAX2_TAG_RAW_IMAGE_SIZE, "RawImageSize", N_("Raw Image Size"), ""}, + {MNOTE_PENTAX2_TAG_AFPOINTS_USED, "AfPointsUsed,", N_("Autofocus Points Used"), ""}, + {MNOTE_PENTAX2_TAG_LENS_TYPE, "LensType", N_("Lens Type"), ""}, + {MNOTE_PENTAX2_TAG_CAMERA_TEMPERATURE, "CameraTemperature", N_("Camera Temperature"), ""}, + {MNOTE_PENTAX2_TAG_NOISE_REDUCTION, "NoiseReduction", N_("Noise Reduction"), ""}, + {MNOTE_PENTAX2_TAG_FLASH_EXPOSURE_COMP, "FlashExposureComp", N_("Flash Exposure Compensation"), ""}, + {MNOTE_PENTAX2_TAG_IMAGE_TONE, "ImageTone", N_("Image Tone"), ""}, + {MNOTE_PENTAX2_TAG_SHAKE_REDUCTION_INFO, "ShakeReductionInfo,", N_("Shake Reduction Info"), ""}, + {MNOTE_PENTAX2_TAG_BLACK_POINT, "BlackPoint", N_("Black Point"), ""}, + {MNOTE_PENTAX2_TAG_WHITE_POINT, "WhitePoint", N_("White Point"), ""}, + {MNOTE_PENTAX2_TAG_AE_INFO, "AEInfo", N_("AE Info"), ""}, + {MNOTE_PENTAX2_TAG_LENS_INFO, "LensInfo", N_("Lens Info"), ""}, + {MNOTE_PENTAX2_TAG_FLASH_INFO, "FlashInfo", N_("Flash Info"), ""}, + {MNOTE_PENTAX2_TAG_CAMERA_INFO, "CameraInfo", N_("Camera Info"), ""}, + {MNOTE_PENTAX2_TAG_BATTERY_INFO, "BatteryInfo", N_("Battery Info"), ""}, + {MNOTE_PENTAX2_TAG_HOMETOWN_CITY_CODE, "HometownCityCode", N_("Hometown City Code"), ""}, + {MNOTE_PENTAX2_TAG_DESTINATION_CITY_CODE, "DestinationCityCode", N_("Destination City Code"), ""}, + + {MNOTE_CASIO2_TAG_PREVIEW_START, "CasioPreviewStart", N_("Preview Start"), ""}, + {MNOTE_CASIO2_TAG_WHITE_BALANCE_BIAS, "WhiteBalanceBias", N_("White Balance Bias"), ""}, + {MNOTE_CASIO2_TAG_WHITE_BALANCE, "WhiteBalance", N_("White Balance"), ""}, + {MNOTE_CASIO2_TAG_OBJECT_DISTANCE, "ObjectDistance", N_("Object Distance"), N_("Distance of photographed object in millimeters.")}, + {MNOTE_CASIO2_TAG_FLASH_DISTANCE, "FlashDistance", N_("Flash Distance"), ""}, + {MNOTE_CASIO2_TAG_RECORD_MODE, "RecordMode", N_("Record Mode"), ""}, + {MNOTE_CASIO2_TAG_SELF_TIMER, "SelfTimer", N_("Self-timer"), ""}, + {MNOTE_CASIO2_TAG_QUALITY, "CasioQuality", N_("Quality Level"), ""}, + {MNOTE_CASIO2_TAG_FOCUS_MODE, "CasioFocusMode", N_("Focus Mode"), ""}, + {MNOTE_CASIO2_TAG_TIME_ZONE, "TimeZone", N_("Time Zone"), ""}, + {MNOTE_CASIO2_TAG_BESTSHOT_MODE, "BestshotMode", N_("Bestshot Mode"), ""}, + {MNOTE_CASIO2_TAG_CCS_ISO_SENSITIVITY, "CCSISOSensitivity", N_("CCS ISO Sensitivity"), ""}, + {MNOTE_CASIO2_TAG_COLOR_MODE, "ColorMode", N_("Color Mode"), ""}, + {MNOTE_CASIO2_TAG_ENHANCEMENT, "Enhancement", N_("Enhancement"), ""}, + {MNOTE_CASIO2_TAG_FINER, "Finer", N_("Finer"), ""}, +#endif + {0, NULL, NULL, NULL} +}; + +const char * +mnote_pentax_tag_get_name (MnotePentaxTag t) +{ + unsigned int i; + + for (i = 0; i < sizeof (table) / sizeof (table[0]); i++) + if (table[i].tag == t) return (table[i].name); + return NULL; +} + +const char * +mnote_pentax_tag_get_title (MnotePentaxTag t) +{ + unsigned int i; + + bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR); + for (i = 0; i < sizeof (table) / sizeof (table[0]); i++) + if (table[i].tag == t) return (_(table[i].title)); + return NULL; +} + +const char * +mnote_pentax_tag_get_description (MnotePentaxTag t) +{ + unsigned int i; + + for (i = 0; i < sizeof (table) / sizeof (table[0]); i++) + if (table[i].tag == t) { + if (!table[i].description || !*table[i].description) + return ""; + bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR); + return _(table[i].description); + } + return NULL; +} diff --git a/libexif/pentax/mnote-pentax-tag.h b/libexif/pentax/mnote-pentax-tag.h new file mode 100644 index 0000000..51b2aec --- /dev/null +++ b/libexif/pentax/mnote-pentax-tag.h @@ -0,0 +1,153 @@ +/* mnote-pentax-tag.h + * + * Copyright (c) 2002, 2003 Lutz Mueller <lutz@users.sourceforge.net> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA. + */ + +#ifndef __MNOTE_PENTAX_TAG_H__ +#define __MNOTE_PENTAX_TAG_H__ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/* + * Missing features which are probably in the unknowns somewhere ... + * 1/ AF Area (Wide, Spot, Free) + * 2/ AE Metering (Multi segment, Centre-weighted, Spot) + * 3/ + */ + +enum _MnotePentaxTag { + MNOTE_PENTAX_TAG_MODE = 0x0001, + MNOTE_PENTAX_TAG_QUALITY = 0x0002, + MNOTE_PENTAX_TAG_FOCUS = 0x0003, + MNOTE_PENTAX_TAG_FLASH = 0x0004, + MNOTE_PENTAX_TAG_UNKNOWN_05 = 0x0005, + MNOTE_PENTAX_TAG_UNKNOWN_06 = 0x0006, + MNOTE_PENTAX_TAG_WHITE_BALANCE = 0x0007, + MNOTE_PENTAX_TAG_UNKNOWN_08 = 0x0008, + MNOTE_PENTAX_TAG_UNKNOWN_09 = 0x0009, + MNOTE_PENTAX_TAG_ZOOM = 0x000a, + MNOTE_PENTAX_TAG_SHARPNESS = 0x000b, + MNOTE_PENTAX_TAG_CONTRAST = 0x000c, + MNOTE_PENTAX_TAG_SATURATION = 0x000d, + MNOTE_PENTAX_TAG_UNKNOWN_14 = 0x000e, + MNOTE_PENTAX_TAG_UNKNOWN_15 = 0x000f, + MNOTE_PENTAX_TAG_UNKNOWN_16 = 0x0010, + MNOTE_PENTAX_TAG_UNKNOWN_17 = 0x0011, + MNOTE_PENTAX_TAG_UNKNOWN_18 = 0x0012, + MNOTE_PENTAX_TAG_UNKNOWN_19 = 0x0013, + MNOTE_PENTAX_TAG_ISO_SPEED = 0x0014, + MNOTE_PENTAX_TAG_UNKNOWN_21 = 0x0015, + MNOTE_PENTAX_TAG_COLOR = 0x0017, + MNOTE_PENTAX_TAG_UNKNOWN_24 = 0x0018, + MNOTE_PENTAX_TAG_UNKNOWN_25 = 0x0019, + MNOTE_PENTAX_TAG_PRINTIM = 0x0e00, + MNOTE_PENTAX_TAG_TZ_CITY = 0x1000, + MNOTE_PENTAX_TAG_TZ_DST = 0x1001, + + /* Pentax v2, v3: real values + our proprietary base to distinguish from v1 */ + MNOTE_PENTAX2_TAG_BASE = 0x4000, + MNOTE_PENTAX2_TAG_MODE = 0x0001 + MNOTE_PENTAX2_TAG_BASE, + MNOTE_PENTAX2_TAG_PREVIEW_SIZE = 0x0002 + MNOTE_PENTAX2_TAG_BASE, + MNOTE_PENTAX2_TAG_PREVIEW_LENGTH = 0x0003 + MNOTE_PENTAX2_TAG_BASE, + MNOTE_PENTAX2_TAG_PREVIEW_START = 0x0004 + MNOTE_PENTAX2_TAG_BASE, + MNOTE_PENTAX2_TAG_MODEL_ID = 0x0005 + MNOTE_PENTAX2_TAG_BASE, + MNOTE_PENTAX2_TAG_DATE = 0x0006 + MNOTE_PENTAX2_TAG_BASE, + MNOTE_PENTAX2_TAG_TIME = 0x0007 + MNOTE_PENTAX2_TAG_BASE, + MNOTE_PENTAX2_TAG_QUALITY = 0x0008 + MNOTE_PENTAX2_TAG_BASE, + MNOTE_PENTAX2_TAG_IMAGE_SIZE = 0x0009 + MNOTE_PENTAX2_TAG_BASE, + MNOTE_PENTAX2_TAG_PICTURE_MODE = 0x000b + MNOTE_PENTAX2_TAG_BASE, + MNOTE_PENTAX2_TAG_FLASH_MODE = 0x000c + MNOTE_PENTAX2_TAG_BASE, + MNOTE_PENTAX2_TAG_FOCUS_MODE = 0x000d + MNOTE_PENTAX2_TAG_BASE, + MNOTE_PENTAX2_TAG_AFPOINT_SELECTED = 0x000e + MNOTE_PENTAX2_TAG_BASE, + MNOTE_PENTAX2_TAG_AUTO_AFPOINT = 0x000f + MNOTE_PENTAX2_TAG_BASE, + MNOTE_PENTAX2_TAG_FOCUS_POSITION = 0x0010 + MNOTE_PENTAX2_TAG_BASE, + MNOTE_PENTAX2_TAG_EXPOSURE_TIME = 0x0012 + MNOTE_PENTAX2_TAG_BASE, + MNOTE_PENTAX2_TAG_FNUMBER = 0x0013 + MNOTE_PENTAX2_TAG_BASE, + MNOTE_PENTAX2_TAG_ISO = 0x0014 + MNOTE_PENTAX2_TAG_BASE, + MNOTE_PENTAX2_TAG_EXPOSURE_COMPENSATION = 0x0016 + MNOTE_PENTAX2_TAG_BASE, + MNOTE_PENTAX2_TAG_METERING_MODE = 0x0017 + MNOTE_PENTAX2_TAG_BASE, + MNOTE_PENTAX2_TAG_AUTO_BRACKETING = 0x0018 + MNOTE_PENTAX2_TAG_BASE, + MNOTE_PENTAX2_TAG_WHITE_BALANCE = 0x0019 + MNOTE_PENTAX2_TAG_BASE, + MNOTE_PENTAX2_TAG_WHITE_BALANCE_MODE= 0x001a + MNOTE_PENTAX2_TAG_BASE, + MNOTE_PENTAX2_TAG_BLUE_BALANCE = 0x001b + MNOTE_PENTAX2_TAG_BASE, + MNOTE_PENTAX2_TAG_RED_BALANCE = 0x001c + MNOTE_PENTAX2_TAG_BASE, + MNOTE_PENTAX2_TAG_FOCAL_LENGTH = 0x001d + MNOTE_PENTAX2_TAG_BASE, + MNOTE_PENTAX2_TAG_DIGITAL_ZOOM = 0x001e + MNOTE_PENTAX2_TAG_BASE, + MNOTE_PENTAX2_TAG_SATURATION = 0x001f + MNOTE_PENTAX2_TAG_BASE, + MNOTE_PENTAX2_TAG_CONTRAST = 0x0020 + MNOTE_PENTAX2_TAG_BASE, + MNOTE_PENTAX2_TAG_SHARPNESS = 0x0021 + MNOTE_PENTAX2_TAG_BASE, + MNOTE_PENTAX2_TAG_WORLDTIME_LOCATION = 0x0022 + MNOTE_PENTAX2_TAG_BASE, + MNOTE_PENTAX2_TAG_HOMETOWN_CITY = 0x0023 + MNOTE_PENTAX2_TAG_BASE, + MNOTE_PENTAX2_TAG_DESTINATION_CITY = 0x0024 + MNOTE_PENTAX2_TAG_BASE, + MNOTE_PENTAX2_TAG_HOMETOWN_DST = 0x0025 + MNOTE_PENTAX2_TAG_BASE, + MNOTE_PENTAX2_TAG_DESTINATION_DST = 0x0026 + MNOTE_PENTAX2_TAG_BASE, + MNOTE_PENTAX2_TAG_FRAME_NUMBER = 0x0029 + MNOTE_PENTAX2_TAG_BASE, + MNOTE_PENTAX2_TAG_IMAGE_PROCESSING = 0x0032 + MNOTE_PENTAX2_TAG_BASE, + MNOTE_PENTAX2_TAG_PICTURE_MODE2 = 0x0033 + MNOTE_PENTAX2_TAG_BASE, + MNOTE_PENTAX2_TAG_DRIVE_MODE = 0x0034 + MNOTE_PENTAX2_TAG_BASE, + MNOTE_PENTAX2_TAG_COLOR_SPACE = 0x0037 + MNOTE_PENTAX2_TAG_BASE, + MNOTE_PENTAX2_TAG_IMAGE_AREA_OFFSET = 0x0038 + MNOTE_PENTAX2_TAG_BASE, + MNOTE_PENTAX2_TAG_RAW_IMAGE_SIZE = 0x0039 + MNOTE_PENTAX2_TAG_BASE, + MNOTE_PENTAX2_TAG_AFPOINTS_USED = 0x003c + MNOTE_PENTAX2_TAG_BASE, + MNOTE_PENTAX2_TAG_LENS_TYPE = 0x003f + MNOTE_PENTAX2_TAG_BASE, + MNOTE_PENTAX2_TAG_CAMERA_TEMPERATURE = 0x0047 + MNOTE_PENTAX2_TAG_BASE, + MNOTE_PENTAX2_TAG_NOISE_REDUCTION = 0x0049 + MNOTE_PENTAX2_TAG_BASE, + MNOTE_PENTAX2_TAG_FLASH_EXPOSURE_COMP = 0x004d + MNOTE_PENTAX2_TAG_BASE, + MNOTE_PENTAX2_TAG_IMAGE_TONE = 0x004f + MNOTE_PENTAX2_TAG_BASE, + MNOTE_PENTAX2_TAG_SHAKE_REDUCTION_INFO = 0x005c + MNOTE_PENTAX2_TAG_BASE, + MNOTE_PENTAX2_TAG_BLACK_POINT = 0x0200 + MNOTE_PENTAX2_TAG_BASE, + MNOTE_PENTAX2_TAG_WHITE_POINT = 0x0201 + MNOTE_PENTAX2_TAG_BASE, + MNOTE_PENTAX2_TAG_AE_INFO = 0x0206 + MNOTE_PENTAX2_TAG_BASE, + MNOTE_PENTAX2_TAG_LENS_INFO = 0x0207 + MNOTE_PENTAX2_TAG_BASE, + MNOTE_PENTAX2_TAG_FLASH_INFO = 0x0208 + MNOTE_PENTAX2_TAG_BASE, + MNOTE_PENTAX2_TAG_CAMERA_INFO = 0x0215 + MNOTE_PENTAX2_TAG_BASE, + MNOTE_PENTAX2_TAG_BATTERY_INFO = 0x0216 + MNOTE_PENTAX2_TAG_BASE, + MNOTE_PENTAX2_TAG_HOMETOWN_CITY_CODE = 0x1000 + MNOTE_PENTAX2_TAG_BASE, + MNOTE_PENTAX2_TAG_DESTINATION_CITY_CODE = 0x1001 + MNOTE_PENTAX2_TAG_BASE, + + /* Casio v2: some Casio v2 tags match Pentax v2 tags */ + MNOTE_CASIO2_TAG_BASE = MNOTE_PENTAX2_TAG_BASE, + MNOTE_CASIO2_TAG_PREVIEW_START = 0x2000 + MNOTE_CASIO2_TAG_BASE, + MNOTE_CASIO2_TAG_WHITE_BALANCE_BIAS = 0x2011 + MNOTE_CASIO2_TAG_BASE, + MNOTE_CASIO2_TAG_WHITE_BALANCE = 0x2012 + MNOTE_CASIO2_TAG_BASE, + MNOTE_CASIO2_TAG_OBJECT_DISTANCE = 0x2022 + MNOTE_CASIO2_TAG_BASE, + MNOTE_CASIO2_TAG_FLASH_DISTANCE = 0x2034 + MNOTE_CASIO2_TAG_BASE, + MNOTE_CASIO2_TAG_RECORD_MODE = 0x3000 + MNOTE_CASIO2_TAG_BASE, + MNOTE_CASIO2_TAG_SELF_TIMER = 0x3001 + MNOTE_CASIO2_TAG_BASE, + MNOTE_CASIO2_TAG_QUALITY = 0x3002 + MNOTE_CASIO2_TAG_BASE, + MNOTE_CASIO2_TAG_FOCUS_MODE = 0x3003 + MNOTE_CASIO2_TAG_BASE, + MNOTE_CASIO2_TAG_TIME_ZONE = 0x3006 + MNOTE_CASIO2_TAG_BASE, + MNOTE_CASIO2_TAG_BESTSHOT_MODE = 0x3007 + MNOTE_CASIO2_TAG_BASE, + MNOTE_CASIO2_TAG_CCS_ISO_SENSITIVITY = 0x3014 + MNOTE_CASIO2_TAG_BASE, + MNOTE_CASIO2_TAG_COLOR_MODE = 0x3015 + MNOTE_CASIO2_TAG_BASE, + MNOTE_CASIO2_TAG_ENHANCEMENT = 0x3016 + MNOTE_CASIO2_TAG_BASE, + MNOTE_CASIO2_TAG_FINER = 0x3017 + MNOTE_CASIO2_TAG_BASE +}; +typedef enum _MnotePentaxTag MnotePentaxTag; + +const char *mnote_pentax_tag_get_name (MnotePentaxTag tag); +const char *mnote_pentax_tag_get_title (MnotePentaxTag tag); +const char *mnote_pentax_tag_get_description (MnotePentaxTag tag); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __MNOTE_PENTAX_TAG_H__ */ |