Add libexif to deps/third_party.

BUG=none
TEST=none
Review URL: https://chromiumcodereview.appspot.com/10535156

git-svn-id: http://src.chromium.org/svn/trunk/deps/third_party/libexif@141967 4ff67af0-8c30-449e-8e8b-ad334ec8d88c
diff --git a/sources/AUTHORS b/sources/AUTHORS
new file mode 100644
index 0000000..127a5b4
--- /dev/null
+++ b/sources/AUTHORS
@@ -0,0 +1,4 @@
+Lutz Mueller <urc8@rz.uni-karlsruhe.de>
+Jan Patera <patera@users.sourceforge.net>
+Hans Ulrich Niedermann <gp@n-dimensional.de>
+Hubert Figuiere <hub@figuiere.net>
diff --git a/sources/COPYING b/sources/COPYING
new file mode 100644
index 0000000..602bfc9
--- /dev/null
+++ b/sources/COPYING
@@ -0,0 +1,504 @@
+		  GNU LESSER GENERAL PUBLIC LICENSE
+		       Version 2.1, February 1999
+
+ Copyright (C) 1991, 1999 Free Software Foundation, Inc.
+ 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the Lesser GPL.  It also counts
+ as the successor of the GNU Library Public License, version 2, hence
+ the version number 2.1.]
+
+			    Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+  This license, the Lesser General Public License, applies to some
+specially designated software packages--typically libraries--of the
+Free Software Foundation and other authors who decide to use it.  You
+can use it too, but we suggest you first think carefully about whether
+this license or the ordinary General Public License is the better
+strategy to use in any particular case, based on the explanations below.
+
+  When we speak of free software, we are referring to freedom of use,
+not price.  Our General Public Licenses are designed to make sure that
+you have the freedom to distribute copies of free software (and charge
+for this service if you wish); that you receive source code or can get
+it if you want it; that you can change the software and use pieces of
+it in new free programs; and that you are informed that you can do
+these things.
+
+  To protect your rights, we need to make restrictions that forbid
+distributors to deny you these rights or to ask you to surrender these
+rights.  These restrictions translate to certain responsibilities for
+you if you distribute copies of the library or if you modify it.
+
+  For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you.  You must make sure that they, too, receive or can get the source
+code.  If you link other code with the library, you must provide
+complete object files to the recipients, so that they can relink them
+with the library after making changes to the library and recompiling
+it.  And you must show them these terms so they know their rights.
+
+  We protect your rights with a two-step method: (1) we copyright the
+library, and (2) we offer you this license, which gives you legal
+permission to copy, distribute and/or modify the library.
+
+  To protect each distributor, we want to make it very clear that
+there is no warranty for the free library.  Also, if the library is
+modified by someone else and passed on, the recipients should know
+that what they have is not the original version, so that the original
+author's reputation will not be affected by problems that might be
+introduced by others.
+
+  Finally, software patents pose a constant threat to the existence of
+any free program.  We wish to make sure that a company cannot
+effectively restrict the users of a free program by obtaining a
+restrictive license from a patent holder.  Therefore, we insist that
+any patent license obtained for a version of the library must be
+consistent with the full freedom of use specified in this license.
+
+  Most GNU software, including some libraries, is covered by the
+ordinary GNU General Public License.  This license, the GNU Lesser
+General Public License, applies to certain designated libraries, and
+is quite different from the ordinary General Public License.  We use
+this license for certain libraries in order to permit linking those
+libraries into non-free programs.
+
+  When a program is linked with a library, whether statically or using
+a shared library, the combination of the two is legally speaking a
+combined work, a derivative of the original library.  The ordinary
+General Public License therefore permits such linking only if the
+entire combination fits its criteria of freedom.  The Lesser General
+Public License permits more lax criteria for linking other code with
+the library.
+
+  We call this license the "Lesser" General Public License because it
+does Less to protect the user's freedom than the ordinary General
+Public License.  It also provides other free software developers Less
+of an advantage over competing non-free programs.  These disadvantages
+are the reason we use the ordinary General Public License for many
+libraries.  However, the Lesser license provides advantages in certain
+special circumstances.
+
+  For example, on rare occasions, there may be a special need to
+encourage the widest possible use of a certain library, so that it becomes
+a de-facto standard.  To achieve this, non-free programs must be
+allowed to use the library.  A more frequent case is that a free
+library does the same job as widely used non-free libraries.  In this
+case, there is little to gain by limiting the free library to free
+software only, so we use the Lesser General Public License.
+
+  In other cases, permission to use a particular library in non-free
+programs enables a greater number of people to use a large body of
+free software.  For example, permission to use the GNU C Library in
+non-free programs enables many more people to use the whole GNU
+operating system, as well as its variant, the GNU/Linux operating
+system.
+
+  Although the Lesser General Public License is Less protective of the
+users' freedom, it does ensure that the user of a program that is
+linked with the Library has the freedom and the wherewithal to run
+that program using a modified version of the Library.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.  Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library".  The
+former contains code derived from the library, whereas the latter must
+be combined with the library in order to run.
+
+		  GNU LESSER GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License Agreement applies to any software library or other
+program which contains a notice placed by the copyright holder or
+other authorized party saying it may be distributed under the terms of
+this Lesser General Public License (also called "this License").
+Each licensee is addressed as "you".
+
+  A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+  The "Library", below, refers to any such software library or work
+which has been distributed under these terms.  A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language.  (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+  "Source code" for a work means the preferred form of the work for
+making modifications to it.  For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+  Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it).  Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+
+  1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+  You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+
+  2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) The modified work must itself be a software library.
+
+    b) You must cause the files modified to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    c) You must cause the whole of the work to be licensed at no
+    charge to all third parties under the terms of this License.
+
+    d) If a facility in the modified Library refers to a function or a
+    table of data to be supplied by an application program that uses
+    the facility, other than as an argument passed when the facility
+    is invoked, then you must make a good faith effort to ensure that,
+    in the event an application does not supply such function or
+    table, the facility still operates, and performs whatever part of
+    its purpose remains meaningful.
+
+    (For example, a function in a library to compute square roots has
+    a purpose that is entirely well-defined independent of the
+    application.  Therefore, Subsection 2d requires that any
+    application-supplied function or table used by this function must
+    be optional: if the application does not supply it, the square
+    root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library.  To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License.  (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.)  Do not make any other change in
+these notices.
+
+  Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+  This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+  4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+  If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library".  Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+  However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library".  The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+  When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library.  The
+threshold for this to be true is not precisely defined by law.
+
+  If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work.  (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+  Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+
+  6. As an exception to the Sections above, you may also combine or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+  You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License.  You must supply a copy of this License.  If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License.  Also, you must do one
+of these things:
+
+    a) Accompany the work with the complete corresponding
+    machine-readable source code for the Library including whatever
+    changes were used in the work (which must be distributed under
+    Sections 1 and 2 above); and, if the work is an executable linked
+    with the Library, with the complete machine-readable "work that
+    uses the Library", as object code and/or source code, so that the
+    user can modify the Library and then relink to produce a modified
+    executable containing the modified Library.  (It is understood
+    that the user who changes the contents of definitions files in the
+    Library will not necessarily be able to recompile the application
+    to use the modified definitions.)
+
+    b) Use a suitable shared library mechanism for linking with the
+    Library.  A suitable mechanism is one that (1) uses at run time a
+    copy of the library already present on the user's computer system,
+    rather than copying library functions into the executable, and (2)
+    will operate properly with a modified version of the library, if
+    the user installs one, as long as the modified version is
+    interface-compatible with the version that the work was made with.
+
+    c) Accompany the work with a written offer, valid for at
+    least three years, to give the same user the materials
+    specified in Subsection 6a, above, for a charge no more
+    than the cost of performing this distribution.
+
+    d) If distribution of the work is made by offering access to copy
+    from a designated place, offer equivalent access to copy the above
+    specified materials from the same place.
+
+    e) Verify that the user has already received a copy of these
+    materials or that you have already sent this user a copy.
+
+  For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it.  However, as a special exception,
+the materials to be distributed need not include anything that is
+normally distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+  It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system.  Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+
+  7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+    a) Accompany the combined library with a copy of the same work
+    based on the Library, uncombined with any other library
+    facilities.  This must be distributed under the terms of the
+    Sections above.
+
+    b) Give prominent notice with the combined library of the fact
+    that part of it is a work based on the Library, and explaining
+    where to find the accompanying uncombined form of the same work.
+
+  8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License.  Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License.  However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+  9. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Library or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+  10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties with
+this License.
+
+  11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded.  In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+  13. The Free Software Foundation may publish revised and/or new
+versions of the Lesser General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation.  If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+
+  14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission.  For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this.  Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+			    NO WARRANTY
+
+  15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU.  SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+  16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+		     END OF TERMS AND CONDITIONS
+
+           How to Apply These Terms to Your New Libraries
+
+  If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change.  You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+  To apply these terms, attach the following notices to the library.  It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the library's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    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
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the
+  library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+  <signature of Ty Coon>, 1 April 1990
+  Ty Coon, President of Vice
+
+That's all there is to it!
+
+
diff --git a/sources/README b/sources/README
new file mode 100644
index 0000000..f6a4e0f
--- /dev/null
+++ b/sources/README
@@ -0,0 +1,177 @@
+				    libexif
+				    -------
+
+DESCRIPTION
+-----------
+
+libexif is a library for parsing, editing, and saving EXIF data. It is
+intended to replace lots of redundant implementations in command-line
+utilities and programs with GUIs.
+
+
+FEATURES
+--------
+
+libexif supports parsing, editing and saving of EXIF data. In addition, it
+has gettext support. All EXIF tags described in EXIF standard 2.1 (and most
+from 2.2) are supported.  Many maker notes from Canon, Casio, Epson,
+Fuji, Nikon, Olympus, Pentax and Sanyo cameras are also supported.
+
+
+REQUIREMENTS
+------------
+
+libexif is written in plain C and does not require any additional library.
+GNU gettext will be used for language translation, if available.
+
+
+LIMITATIONS
+-----------
+
+libexif can only handle some maker notes, and even those not very well. More
+work needs to be done. Note that libmnote has been merged with libexif - it
+is no longer needed.
+
+
+USAGE
+-----
+
+We have documented the libexif API using doxygen and are making
+the results available at http://libexif.sourceforge.net/api/
+
+The short test programs in the test directory illustrates how to create
+valid EXIF data from scratch, how to save EXIF data and how to load EXIF
+data from data in memory. There are also a few simple example programs
+available in the contrib/examples/ directory.  Don't hesitate to contact
+us at <libexif-devel@lists.sourceforge.net> if you've got any questions
+on how to use libexif.
+
+To link to libexif into your own package, we recommend using the
+pkgconfig utility (cf. http://pkg-config.freedesktop.org/wiki/). For
+your convenience, libexif both provides libexif-uninstalled.pc and
+installs libexif.pc.
+
+
+FRONTENDS
+---------
+
+Right now, I know of the following frontends to libexif:
+ - exif:     A small command-line utility to show EXIF information in JPEG
+             files (http://www.sourceforge.net/projects/libexif).
+ - gexif:    A GTK+ frontend for editing EXIF data
+             (http://www.sourceforge.net/projects/libexif).
+ - gphoto2:  A command-line frontend to libgphoto2, a library to access a 
+             wide range of digital cameras (http://www.gphoto.org).
+ - gtkam:    A GTK+ frontend to libgphoto2 (http://www.topfrose.de).
+ - thirdeye: Digital photos organizer and driver for eComStation
+             (http://ecomstation.ru/thirdeye).
+ - digikam:  digital photo management application for KDE
+             (http://www.digikam.org/)
+
+If you would like to migrate your program to use libexif or add EXIF support
+to it, don't hesitate to contact the authors.
+
+
+LIBRARIES
+---------
+
+I know of the following libraries that use or have been inspired by libexif:
+ - libexif-gtk: library of widgets to help display EXIF tags in GTK
+   programs (part of the libexif project)
+ - pel: PHP-Code (http://pel.sourceforge.net)
+
+
+BUILDING
+--------
+
+It really depends on your environment what to do in order to get libexif
+to build. Building from the source tar ball usually involves the commands:
+
+  ./configure
+  make
+  sudo make install
+
+When building from source out of CVS, something like the following will be
+necessary:
+
+  gettextize
+  mv po/Makevars.template po/Makevars
+  aclocal -I auto-m4 -I m4m
+  autoheader
+  libtoolize --force
+  automake --add-missing
+  autoconf
+  ./configure
+  make
+
+Or, probably just:
+
+  autoreconf -i
+  ./configure
+  make
+
+Besides the standard arguments, configure takes several specific to libexif:
+
+  --disable-docs          To disable producing any documentation
+  --enable-internal-docs  Build internal code docs if Doxygen available
+  --enable-ship-binaries  To include Windows DLLs in 'make dist'
+
+Certain specialized applications can reduce the size of the libexif
+binary by setting one or both of the following macros in the CPPFLAGS
+environment variable at configure time.  Each one removes certain kinds of
+text strings and constants from the binary.  Applications which need
+to access specific, known EXIF tags and know in advance the meaning of
+their data have no need of those strings and can save considerable space
+by eliminating them.
+
+ -DNO_VERBOSE_TAG_STRINGS Names and descriptions of EXIF tags, debug messages,
+                          mandatory EXIF fields (disabling auto-tag-fixup)
+ -DNO_VERBOSE_TAG_DATA    Names of enumerated tag data contents
+
+
+INTERNATIONALIZATION
+--------------------
+
+The libexif translations are made by volunteers working on their own,
+either directly with the libexif project or through one of two translation
+coordination sites, the Translation Project
+<http://translationproject.org/domain/libexif.html> and Launchpad
+<https://translations.edge.launchpad.net/ubuntu/karmic/+source/libexif>.
+Any updates to language translations coordinated by the Translation Project
+must be made through their web site, but all other languages can be
+updated either through Launchpad (preferred) or by sending updates to
+the libexif developers mailing list directly.  As of this writing, the
+following languages must be updated through the Translation Project:
+cs da de es fr it ja nl pl sk sv vi
+
+If you are interested in translating libexif into a new language, we
+recommend that you join one of the above translation groups and take
+advantage of the systems they have built to help you.  A translation
+disclaimer is NOT required for libexif at the Translation Project; by making
+a translation, you agree implicitly to provide it under the same license
+terms as the rest of libexif (LGPL).
+
+
+AUTHORS
+-------
+
+libexif has originally been written by Curtis Galloway
+<curtisg@users.sourceforge.net>. Because of the original design not
+supporting editing and saving, Lutz Mueller <lutz@users.sourceforge.net>
+rewrote libexif from scratch.
+
+
+LINKS
+-----
+
+Some links you might want to check out if you are interested in further
+information about EXIF.
+
+ - http://drewnoakes.com/code/exif: metadata extraction framework in Java
+ - http://www.pima.net: This is where I got the exif standard from. Site is
+   down as of 2002/12/31.
+ - http://www.jeida.or.jp: Can't remember any more. Site is down as of
+   2002/12/31.
+ - http://www.exif.org: information about the EXIF standard.
+ - http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/index.html: Looks
+   like libexif in Perl. Seems to support a lot of MakerNotes.
diff --git a/sources/config.h b/sources/config.h
new file mode 100644
index 0000000..7857662
--- /dev/null
+++ b/sources/config.h
@@ -0,0 +1,360 @@
+#if defined(_WIN32)
+/* config.h.  Generated by configure.  */
+/* config.h.in.  Generated from configure.ac by autoheader.  */
+
+/* Define to 1 if translation of program messages to the user's native
+   language is requested. */
+/* #undef ENABLE_NLS 1 */
+
+/* The gettext domain we're using */
+/* #undef GETTEXT_PACKAGE "libexif-12" */
+
+/* Define locale directory. */
+/* #undef LOCALEDIR "UTF-8" */
+
+/* Define to 1 if we want to bind text domain and enable GETTEXT_PACKAGE and
+ * LOCALE_DIR */
+/* #undef BIND_TEXTDOMAIN 1 */
+
+/* Define if the GNU dcgettext() function is already present or preinstalled.
+   */
+/* #undef HAVE_DCGETTEXT 1 */
+
+/* Define to 1 if you have the <dlfcn.h> header file. */
+#define HAVE_DLFCN_H 1
+
+/* Define if the GNU gettext() function is already present or preinstalled. */
+#define HAVE_GETTEXT 1
+
+/* Define if you have the iconv() function. */
+#define HAVE_ICONV 1
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#define HAVE_INTTYPES_H 1
+
+/* Define to 1 if you have the <memory.h> header file. */
+#define HAVE_MEMORY_H 1
+
+/* Define to 1 if you have the <stdint.h> header file. */
+/* #undef HAVE_STDINT_H 1 */
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#define HAVE_STDLIB_H 1
+
+/* Define to 1 if you have the <strings.h> header file. */
+#define HAVE_STRINGS_H 1
+
+/* Define to 1 if you have the <string.h> header file. */
+#define HAVE_STRING_H 1
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#define HAVE_SYS_STAT_H 1
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#define HAVE_SYS_TYPES_H 1
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#define HAVE_UNISTD_H 1
+
+/* Define as const if the declaration of iconv() needs const. */
+#define ICONV_CONST
+
+/* Name of package */
+#define PACKAGE "libexif"
+
+/* Define to the address where bug reports for this package should be sent. */
+#define PACKAGE_BUGREPORT "libexif-devel@lists.sourceforge.net"
+
+/* Define to the full name of this package. */
+#define PACKAGE_NAME "EXIF library"
+
+/* Define to the full name and version of this package. */
+#define PACKAGE_STRING "EXIF library 0.6.20"
+
+/* Define to the one symbol short name of this package. */
+#define PACKAGE_TARNAME "libexif"
+
+/* Define to the version of this package. */
+#define PACKAGE_VERSION "0.6.20"
+
+/* Define to 1 if you have the ANSI C header files. */
+#define STDC_HEADERS 1
+
+/* Version number of package */
+#define VERSION "0.6.20"
+
+#elif !defined(__APPLE__)
+/* config.h.  Generated by configure.  */
+/* config.h.in.  Generated from configure.ac by autoheader.  */
+
+/* #define __cplusplus 1 */
+#define LOCALEDIR "UTF-8"
+
+/* Define to 1 if translation of program messages to the user's native
+   language is requested. */
+/* #undef ENABLE_NLS */
+
+/* The gettext domain we're using */
+/* #undef GETTEXT_PACKAGE "libexif-12" */
+
+/* Define locale directory. */
+/* #undef LOCALEDIR "UTF-8" */
+
+/* Define to 1 if we want to bind text domain and enable GETTEXT_PACKAGE and
+ * LOCALE_DIR */
+/* #undef BIND_TEXTDOMAIN 1 */
+
+/* Define if the GNU dcgettext() function is already present or preinstalled.
+   */
+#define HAVE_DCGETTEXT 1
+
+/* Define to 1 if you have the <dlfcn.h> header file. */
+#define HAVE_DLFCN_H 1
+
+/* Define if the GNU gettext() function is already present or preinstalled. */
+#define HAVE_GETTEXT 1
+
+/* Define if you have the iconv() function. */
+#define HAVE_ICONV 1
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#define HAVE_INTTYPES_H 1
+
+/* Define to 1 if you have the <memory.h> header file. */
+#define HAVE_MEMORY_H 1
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#define HAVE_STDINT_H 1
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#define HAVE_STDLIB_H 1
+
+/* Define to 1 if you have the <strings.h> header file. */
+#define HAVE_STRINGS_H 1
+
+/* Define to 1 if you have the <string.h> header file. */
+#define HAVE_STRING_H 1
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#define HAVE_SYS_STAT_H 1
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#define HAVE_SYS_TYPES_H 1
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#define HAVE_UNISTD_H 1
+
+/* Define as const if the declaration of iconv() needs const. */
+#define ICONV_CONST
+
+/* Name of package */
+#define PACKAGE "libexif"
+
+/* Define to the address where bug reports for this package should be sent. */
+#define PACKAGE_BUGREPORT "libexif-devel@lists.sourceforge.net"
+
+/* Define to the full name of this package. */
+#define PACKAGE_NAME "EXIF library"
+
+/* Define to the full name and version of this package. */
+#define PACKAGE_STRING "EXIF library 0.6.20"
+
+/* Define to the one symbol short name of this package. */
+#define PACKAGE_TARNAME "libexif"
+
+/* Define to the version of this package. */
+#define PACKAGE_VERSION "0.6.20"
+
+/* Define to 1 if you have the ANSI C header files. */
+#define STDC_HEADERS 1
+
+/* Version number of package */
+#define VERSION "0.6.20"
+
+/* Define to empty if `const' does not conform to ANSI C. */
+/* #undef const */
+#else  // defined(__APPLE__)
+
+// We need different definitions for the iPhone from desktop OS X,
+// we get the necessary #define from TargetConditionals.h
+#include <TargetConditionals.h>
+
+#if TARGET_OS_IPHONE
+
+/* config.h.  Generated from config.h.in by configure.  */
+/* config.h.in.  Generated from configure.ac by autoheader.  */
+
+/* Define to 1 if translation of program messages to the user's native
+   language is requested. */
+/* #undef ENABLE_NLS */
+
+/* The gettext domain we're using */
+/* #undef GETTEXT_PACKAGE "libexif-12" */
+
+/* Define locale directory. */
+/* #undef LOCALEDIR "UTF-8" */
+
+/* Define to 1 if we want to bind text domain and enable GETTEXT_PACKAGE and
+ * LOCALE_DIR */
+/* #undef BIND_TEXTDOMAIN 1 */
+
+/* Define if the GNU dcgettext() function is already present or preinstalled.
+   */
+/* #undef HAVE_DCGETTEXT */
+
+/* Define to 1 if you have the <dlfcn.h> header file. */
+#define HAVE_DLFCN_H 1
+
+/* Define if the GNU gettext() function is already present or preinstalled. */
+/* #undef HAVE_GETTEXT */
+
+/* Define if you have the iconv() function. */
+/* #undef HAVE_ICONV */
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#define HAVE_INTTYPES_H 1
+
+/* Define to 1 if you have the <memory.h> header file. */
+#define HAVE_MEMORY_H 1
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#define HAVE_STDINT_H 1
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#define HAVE_STDLIB_H 1
+
+/* Define to 1 if you have the <strings.h> header file. */
+#define HAVE_STRINGS_H 1
+
+/* Define to 1 if you have the <string.h> header file. */
+#define HAVE_STRING_H 1
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#define HAVE_SYS_STAT_H 1
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#define HAVE_SYS_TYPES_H 1
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#define HAVE_UNISTD_H 1
+
+/* Define as const if the declaration of iconv() needs const. */
+/* #undef ICONV_CONST */
+
+/* Name of package */
+#define PACKAGE "libexif"
+
+/* Define to the address where bug reports for this package should be sent. */
+#define PACKAGE_BUGREPORT "libexif-devel@lists.sourceforge.net"
+
+/* Define to the full name of this package. */
+#define PACKAGE_NAME "EXIF library"
+
+/* Define to the full name and version of this package. */
+#define PACKAGE_STRING "EXIF library 0.6.20"
+
+/* Define to the one symbol short name of this package. */
+#define PACKAGE_TARNAME "libexif"
+
+/* Define to the version of this package. */
+#define PACKAGE_VERSION "0.6.20"
+
+/* Define to 1 if you have the ANSI C header files. */
+#define STDC_HEADERS 1
+
+/* Version number of package */
+#define VERSION "0.6.20"
+
+/* Define to empty if `const' does not conform to ANSI C. */
+/* #undef const */
+#else  // !TARGET_OS_IPHONE
+
+/* config.h.  Generated from config.h.in by configure.  */
+/* config.h.in.  Generated from configure.ac by autoheader.  */
+
+/* Define to 1 if translation of program messages to the user's native
+   language is requested. */
+/* #undef ENABLE_NLS */
+
+/* The gettext domain we're using */
+/* #undef GETTEXT_PACKAGE "libexif-12" */
+
+/* Define locale directory. */
+/* #undef LOCALEDIR "UTF-8" */
+
+/* Define to 1 if we want to bind text domain and enable GETTEXT_PACKAGE and
+ * LOCALE_DIR */
+/* #undef BIND_TEXTDOMAIN 1 */
+
+/* Define if the GNU dcgettext() function is already present or preinstalled.
+   */
+/* #undef HAVE_DCGETTEXT */
+
+/* Define to 1 if you have the <dlfcn.h> header file. */
+#define HAVE_DLFCN_H 1
+
+/* Define if the GNU gettext() function is already present or preinstalled. */
+/* #undef HAVE_GETTEXT */
+
+/* Define if you have the iconv() function. */
+#define HAVE_ICONV 1
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#define HAVE_INTTYPES_H 1
+
+/* Define to 1 if you have the <memory.h> header file. */
+#define HAVE_MEMORY_H 1
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#define HAVE_STDINT_H 1
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#define HAVE_STDLIB_H 1
+
+/* Define to 1 if you have the <strings.h> header file. */
+#define HAVE_STRINGS_H 1
+
+/* Define to 1 if you have the <string.h> header file. */
+#define HAVE_STRING_H 1
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#define HAVE_SYS_STAT_H 1
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#define HAVE_SYS_TYPES_H 1
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#define HAVE_UNISTD_H 1
+
+/* Define as const if the declaration of iconv() needs const. */
+#define ICONV_CONST
+
+/* Name of package */
+#define PACKAGE "libexif"
+
+/* Define to the address where bug reports for this package should be sent. */
+#define PACKAGE_BUGREPORT "libexif-devel@lists.sourceforge.net"
+
+/* Define to the full name of this package. */
+#define PACKAGE_NAME "EXIF library"
+
+/* Define to the full name and version of this package. */
+#define PACKAGE_STRING "EXIF library 0.6.20"
+
+/* Define to the one symbol short name of this package. */
+#define PACKAGE_TARNAME "libexif"
+
+/* Define to the version of this package. */
+#define PACKAGE_VERSION "0.6.20"
+
+/* Define to 1 if you have the ANSI C header files. */
+#define STDC_HEADERS 1
+
+/* Version number of package */
+#define VERSION "0.6.20"
+
+/* Define to empty if `const' does not conform to ANSI C. */
+/* #undef const */
+#endif  // TARGET_OS_IPHONE
+
+#endif  // _WIN32
diff --git a/sources/libexif/_stdint.h b/sources/libexif/_stdint.h
new file mode 100644
index 0000000..0ecf836
--- /dev/null
+++ b/sources/libexif/_stdint.h
@@ -0,0 +1,15 @@
+/* This file is generated automatically by configure */
+#if defined(_WIN32)
+// Define C99 equivalent types.
+typedef signed char           int8_t;
+typedef signed short          int16_t;
+typedef signed int            int32_t;
+typedef signed long long      int64_t;
+typedef signed long long      ssize_t;
+typedef unsigned char         uint8_t;
+typedef unsigned short        uint16_t;
+typedef unsigned int          uint32_t;
+typedef unsigned long long    uint64_t;
+#else
+#include <stdint.h>
+#endif
diff --git a/sources/libexif/canon/exif-mnote-data-canon.c b/sources/libexif/canon/exif-mnote-data-canon.c
new file mode 100644
index 0000000..eb53598
--- /dev/null
+++ b/sources/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/sources/libexif/canon/exif-mnote-data-canon.h b/sources/libexif/canon/exif-mnote-data-canon.h
new file mode 100644
index 0000000..2a1cc87
--- /dev/null
+++ b/sources/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/sources/libexif/canon/mnote-canon-entry.c b/sources/libexif/canon/mnote-canon-entry.c
new file mode 100644
index 0000000..6e3be19
--- /dev/null
+++ b/sources/libexif/canon/mnote-canon-entry.c
@@ -0,0 +1,759 @@
+/* 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,  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, 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")},
+  {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/sources/libexif/canon/mnote-canon-entry.h b/sources/libexif/canon/mnote-canon-entry.h
new file mode 100644
index 0000000..a4d4499
--- /dev/null
+++ b/sources/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/sources/libexif/canon/mnote-canon-tag.c b/sources/libexif/canon/mnote-canon-tag.c
new file mode 100644
index 0000000..6ced674
--- /dev/null
+++ b/sources/libexif/canon/mnote-canon-tag.c
@@ -0,0 +1,205 @@
+/* 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;
+
+#if defined(BIND_TEXTDOMAIN)
+	bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR);
+#endif
+	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)
+				return "";
+#if defined(BIND_TEXTDOMAIN)
+                	bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR);
+#endif
+			return _(table[i].description);
+		}
+	return NULL;
+}
diff --git a/sources/libexif/canon/mnote-canon-tag.h b/sources/libexif/canon/mnote-canon-tag.h
new file mode 100644
index 0000000..0c7d9aa
--- /dev/null
+++ b/sources/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/sources/libexif/exif-byte-order.c b/sources/libexif/exif-byte-order.c
new file mode 100644
index 0000000..05164e0
--- /dev/null
+++ b/sources/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/sources/libexif/exif-byte-order.h b/sources/libexif/exif-byte-order.h
new file mode 100644
index 0000000..ab5c9ad
--- /dev/null
+++ b/sources/libexif/exif-byte-order.h
@@ -0,0 +1,46 @@
+/* exif-byte-order.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_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/sources/libexif/exif-content.c b/sources/libexif/exif-content.c
new file mode 100644
index 0000000..6d6c589
--- /dev/null
+++ b/sources/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/sources/libexif/exif-content.h b/sources/libexif/exif-content.h
new file mode 100644
index 0000000..d912ccf
--- /dev/null
+++ b/sources/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/sources/libexif/exif-data-type.h b/sources/libexif/exif-data-type.h
new file mode 100644
index 0000000..05d4f95
--- /dev/null
+++ b/sources/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/sources/libexif/exif-data.c b/sources/libexif/exif-data.c
new file mode 100644
index 0000000..80533b6
--- /dev/null
+++ b/sources/libexif/exif-data.c
@@ -0,0 +1,1266 @@
+/* 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_orig)
+{
+	unsigned int l;
+	ExifLong offset;
+	ExifShort n;
+	const unsigned char *d = d_orig;
+	unsigned int ds = ds_orig, len;
+
+	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 (1) {
+			while ((d[0] == 0xff) && ds) {
+				d++;
+				ds--;
+			}
+
+			/* JPEG_MARKER_SOI */
+			if (d[0] == JPEG_MARKER_SOI) {
+				d++;
+				ds--;
+				continue;
+			}
+
+			/* JPEG_MARKER_APP0 */
+			if (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 (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;
+		}
+		d++;
+		ds--;
+		if (ds < 2) {
+			LOG_TOO_SMALL;
+			return;
+		}
+		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.");
+
+	/* Byte order (offset 6, length 2) */
+	if (ds < 14)
+		return;
+	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);
+
+	/* 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 */
+	if (offset + 6 + 2 > ds) {
+		return;
+	}
+	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 - 6) {
+			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, ds);
+
+	/* 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/sources/libexif/exif-data.h b/sources/libexif/exif-data.h
new file mode 100644
index 0000000..1bcc4e5
--- /dev/null
+++ b/sources/libexif/exif-data.h
@@ -0,0 +1,264 @@
+/*! \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 has been set on this #ExifData,
+ * then the tags are fixed after loading.
+ *
+ * \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/sources/libexif/exif-entry.c b/sources/libexif/exif-entry.c
new file mode 100644
index 0000000..7f3ae55
--- /dev/null
+++ b/sources/libexif/exif-entry.c
@@ -0,0 +1,1712 @@
+/* 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.
+ * \pre The buffer at val is entirely cleared to 0. This guarantees that the
+ *      resulting string will be NUL terminated.
+ * \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;
+	char b[64];
+	unsigned int i;
+	const ExifByteOrder o = exif_data_get_byte_order (e->parent->parent);
+
+	if (!e->size)
+		return;
+	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);
+		maxlen -= strlen (val);
+		for (i = 1; i < e->components; i++) {
+			v_byte = e->data[i];
+			snprintf (b, sizeof (b), ", 0x%02x", v_byte);
+			strncat (val, b, maxlen);
+			maxlen -= strlen (b);
+			if ((signed)maxlen <= 0) break;
+		}
+		break;
+	case EXIF_FORMAT_SHORT:
+		v_short = exif_get_short (e->data, o);
+		snprintf (val, maxlen, "%u", v_short);
+		maxlen -= 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 (b, sizeof (b), ", %u", v_short);
+			strncat (val, b, maxlen);
+			maxlen -= strlen (b);
+			if ((signed)maxlen <= 0) break;
+		}
+		break;
+	case EXIF_FORMAT_SSHORT:
+		v_sshort = exif_get_sshort (e->data, o);
+		snprintf (val, maxlen, "%i", v_sshort);
+		maxlen -= 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 (b, sizeof (b), ", %i", v_sshort);
+			strncat (val, b, maxlen);
+			maxlen -= strlen (b);
+			if ((signed)maxlen <= 0) break;
+		}
+		break;
+	case EXIF_FORMAT_LONG:
+		v_long = exif_get_long (e->data, o);
+		snprintf (val, maxlen, "%lu", (unsigned long) v_long);
+		maxlen -= 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 (b, sizeof (b), ", %lu", (unsigned long) v_long);
+			strncat (val, b, maxlen);
+			maxlen -= strlen (b);
+			if ((signed)maxlen <= 0) break;
+		}
+		break;
+	case EXIF_FORMAT_SLONG:
+		v_slong = exif_get_slong (e->data, o);
+		snprintf (val, maxlen, "%li", (long) v_slong);
+		maxlen -= 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 (b, sizeof (b), ", %li", (long) v_slong);
+			strncat (val, b, maxlen);
+			maxlen -= strlen (b);
+			if ((signed)maxlen <= 0) break;
+		}
+		break;
+	case EXIF_FORMAT_ASCII:
+		strncpy (val, (char *) e->data, MIN (maxlen, e->size));
+		break;
+	case EXIF_FORMAT_RATIONAL:
+		for (i = 0; i < e->components; i++) {
+			if (i > 0) {
+				strncat (val, ", ", maxlen);
+				maxlen -= 2;
+			}
+			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 (b, sizeof (b), "%2.*f",
+					  decimals,
+					  (double) v_rat.numerator /
+					  (double) v_rat.denominator);
+			} else
+				snprintf (b, sizeof (b), "%lu/%lu",
+				  (unsigned long) v_rat.numerator,
+				  (unsigned long) v_rat.denominator);
+			strncat (val, b, maxlen);
+			maxlen -= strlen (b);
+			if ((signed) maxlen <= 0) break;
+		}
+		break;
+	case EXIF_FORMAT_SRATIONAL:
+		for (i = 0; i < e->components; i++) {
+			if (i > 0) {
+				strncat (val, ", ", maxlen);
+				maxlen -= 2;
+			}
+			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 (b, sizeof (b), "%2.*f",
+					  decimals,
+					  (double) v_srat.numerator /
+					  (double) v_srat.denominator);
+			} else
+				snprintf (b, sizeof (b), "%li/%li",
+				  (long) v_srat.numerator,
+				  (long) v_srat.denominator);
+			strncat (val, b, maxlen);
+			maxlen -= strlen (b);
+			if ((signed) maxlen <= 0) 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)));
+}
+
+#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;
+	const unsigned char *t;
+	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},
+		{""    , 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");
+	 */
+#if defined(BIND_TEXTDOMAIN)
+	bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR);
+#endif
+
+	/* make sure the returned string is zero terminated */
+	memset (val, 0, maxlen);
+	maxlen--;
+	memset (b, 0, sizeof (b));
+
+	/* We need the byte order */
+	if (!e || !e->parent || !e->parent->parent)
+		return val;
+	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 and seems to contain data.
+		 * Print as much as possible.
+		 */
+		exif_entry_log (e, EXIF_LOG_CODE_DEBUG,
+			_("Tag UserComment does not comply "
+			"with standard but contains data."));
+		for (; (i < e->size)  && (strlen (val) < maxlen - 1); i++) {
+			exif_entry_log (e, EXIF_LOG_CODE_DEBUG,
+				_("Byte at position %i: 0x%02x"), i, e->data[i]);
+			val[strlen (val)] =
+				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.
+		 */
+		if (e->size && e->data &&
+		    (strspn ((char *)e->data, " ") != strlen ((char *) e->data)))
+			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));
+		if (e->size && e->data) {
+			size_t ts;
+			t = e->data + strlen ((char *) e->data) + 1;
+			ts = e->data + e->size - t;
+			if ((ts > 0) && (strspn ((char *)t, " ") != ts))
+				strncat (val, (char *)t, MIN (maxlen - strlen (val), ts));
+		} else {
+			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:
+		/* Warning! The texts are converted from UTF16 to UTF8 */
+		/* FIXME: use iconv to convert into the locale encoding */
+		exif_convert_utf16_to_utf8(val, (unsigned short*)e->data, MIN(maxlen, e->size));
+		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/sources/libexif/exif-entry.h b/sources/libexif/exif-entry.h
new file mode 100644
index 0000000..1dcdc73
--- /dev/null
+++ b/sources/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/sources/libexif/exif-format.c b/sources/libexif/exif-format.c
new file mode 100644
index 0000000..08e4f0c
--- /dev/null
+++ b/sources/libexif/exif-format.c
@@ -0,0 +1,82 @@
+/* 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");
+	 */
+#if defined(BIND_TEXTDOMAIN)
+	bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR);
+#endif
+	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/sources/libexif/exif-format.h b/sources/libexif/exif-format.h
new file mode 100644
index 0000000..b7a79a4
--- /dev/null
+++ b/sources/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/sources/libexif/exif-ifd.c b/sources/libexif/exif-ifd.c
new file mode 100644
index 0000000..f0f8816
--- /dev/null
+++ b/sources/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/sources/libexif/exif-ifd.h b/sources/libexif/exif-ifd.h
new file mode 100644
index 0000000..26c4053
--- /dev/null
+++ b/sources/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/sources/libexif/exif-loader.c b/sources/libexif/exif-loader.c
new file mode 100644
index 0000000..317b86b
--- /dev/null
+++ b/sources/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/sources/libexif/exif-loader.h b/sources/libexif/exif-loader.h
new file mode 100644
index 0000000..62ee87c
--- /dev/null
+++ b/sources/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/sources/libexif/exif-log.c b/sources/libexif/exif-log.c
new file mode 100644
index 0000000..2db18e3
--- /dev/null
+++ b/sources/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/sources/libexif/exif-log.h b/sources/libexif/exif-log.h
new file mode 100644
index 0000000..9e71ad6
--- /dev/null
+++ b/sources/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/sources/libexif/exif-mem.c b/sources/libexif/exif-mem.c
new file mode 100644
index 0000000..86f8fc9
--- /dev/null
+++ b/sources/libexif/exif-mem.c
@@ -0,0 +1,119 @@
+ /* exif-mem.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 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 <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/sources/libexif/exif-mem.h b/sources/libexif/exif-mem.h
new file mode 100644
index 0000000..fd8f2fa
--- /dev/null
+++ b/sources/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/sources/libexif/exif-mnote-data-priv.h b/sources/libexif/exif-mnote-data-priv.h
new file mode 100644
index 0000000..7462c97
--- /dev/null
+++ b/sources/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/sources/libexif/exif-mnote-data.c b/sources/libexif/exif-mnote-data.c
new file mode 100644
index 0000000..248056e
--- /dev/null
+++ b/sources/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/sources/libexif/exif-mnote-data.h b/sources/libexif/exif-mnote-data.h
new file mode 100644
index 0000000..19e1de5
--- /dev/null
+++ b/sources/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/sources/libexif/exif-system.h b/sources/libexif/exif-system.h
new file mode 100644
index 0000000..81fa703
--- /dev/null
+++ b/sources/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/sources/libexif/exif-tag.c b/sources/libexif/exif-tag.c
new file mode 100644
index 0000000..433d6cc
--- /dev/null
+++ b/sources/libexif/exif-tag.c
@@ -0,0 +1,1184 @@
+/* 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 knots."), 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");
+	 */
+#if defined(BIND_TEXTDOMAIN)
+	bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR);
+#endif
+	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");
+	 */
+#if defined(BIND_TEXTDOMAIN)
+	bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR);
+#endif
+	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/sources/libexif/exif-tag.h b/sources/libexif/exif-tag.h
new file mode 100644
index 0000000..d8b8657
--- /dev/null
+++ b/sources/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/sources/libexif/exif-utils.c b/sources/libexif/exif-utils.c
new file mode 100644
index 0000000..22ee29f
--- /dev/null
+++ b/sources/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 > 2) {
+				*out++ = ((*in >> 12) & 0x0F) | 0xE0;
+				*out++ = ((*in >> 6) & 0x3F) | 0x80;
+				*out++ = (*in++ & 0x3F) | 0x80;
+				maxlen -= 3;
+			} else {
+				break;
+			}
+		}
+	}
+	*out = 0;
+}
diff --git a/sources/libexif/exif-utils.h b/sources/libexif/exif-utils.h
new file mode 100644
index 0000000..38d0f67
--- /dev/null
+++ b/sources/libexif/exif-utils.h
@@ -0,0 +1,195 @@
+/*! \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>
+#include "config.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/sources/libexif/fuji/exif-mnote-data-fuji.c b/sources/libexif/fuji/exif-mnote-data-fuji.c
new file mode 100644
index 0000000..9514654
--- /dev/null
+++ b/sources/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/sources/libexif/fuji/exif-mnote-data-fuji.h b/sources/libexif/fuji/exif-mnote-data-fuji.h
new file mode 100644
index 0000000..2a7cd3e
--- /dev/null
+++ b/sources/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/sources/libexif/fuji/mnote-fuji-entry.c b/sources/libexif/fuji/mnote-fuji-entry.c
new file mode 100644
index 0000000..0ca1634
--- /dev/null
+++ b/sources/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/sources/libexif/fuji/mnote-fuji-entry.h b/sources/libexif/fuji/mnote-fuji-entry.h
new file mode 100644
index 0000000..a8395c5
--- /dev/null
+++ b/sources/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/sources/libexif/fuji/mnote-fuji-tag.c b/sources/libexif/fuji/mnote-fuji-tag.c
new file mode 100644
index 0000000..4078037
--- /dev/null
+++ b/sources/libexif/fuji/mnote-fuji-tag.c
@@ -0,0 +1,109 @@
+/* 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;
+
+#if defined(BIND_TEXTDOMAIN)
+	bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR);
+#endif
+	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)
+				return "";
+#if defined(BIND_TEXTDOMAIN)
+			bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR);
+#endif
+			return _(table[i].description);
+		}
+	return NULL;
+}
diff --git a/sources/libexif/fuji/mnote-fuji-tag.h b/sources/libexif/fuji/mnote-fuji-tag.h
new file mode 100644
index 0000000..1d250e4
--- /dev/null
+++ b/sources/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/sources/libexif/i18n.h b/sources/libexif/i18n.h
new file mode 100644
index 0000000..dbfe258
--- /dev/null
+++ b/sources/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/sources/libexif/olympus/exif-mnote-data-olympus.c b/sources/libexif/olympus/exif-mnote-data-olympus.c
new file mode 100644
index 0000000..099671d
--- /dev/null
+++ b/sources/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/sources/libexif/olympus/exif-mnote-data-olympus.h b/sources/libexif/olympus/exif-mnote-data-olympus.h
new file mode 100644
index 0000000..d08b0f4
--- /dev/null
+++ b/sources/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/sources/libexif/olympus/mnote-olympus-entry.c b/sources/libexif/olympus/mnote-olympus-entry.c
new file mode 100644
index 0000000..9db5224
--- /dev/null
+++ b/sources/libexif/olympus/mnote-olympus-entry.c
@@ -0,0 +1,821 @@
+/* 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;                                                  \
+	}                                                               \
+}
+
+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);
+
+	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 = (double)vr.numerator / vr.denominator;
+		vr = exif_get_rational (entry->data+8, entry->order);
+		b = (double)vr.numerator / vr.denominator;
+		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) {
+			r = (double)vr.numerator / vr.denominator;
+			snprintf (v, maxlen, _("%2.2f meters"), r);
+		} else {
+			strncpy (v, _("No manual focus selection"), maxlen);
+		}
+		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 = (double)vr.numerator / vr.denominator;
+		b = (double)vr2.numerator / vr2.denominator;
+		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) {
+				strncpy (v, _("None"), maxlen);
+			} else {
+				r = (double)vr.numerator / vr.denominator;
+				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 = vr.numerator / vr.denominator;
+			vr = exif_get_rational (entry->data+8, entry->order);
+			b = vr.numerator / vr.denominator;
+			vr = exif_get_rational (entry->data+16, entry->order);
+			c = (double)vr.numerator / vr.denominator;
+			vr = exif_get_rational (entry->data+24, entry->order);
+			d = (double)vr.numerator / vr.denominator;
+			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 == 0) {
+			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 = (double)vr.numerator / vr.denominator;
+				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 = (double)vsr.numerator / vsr.denominator;
+				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/sources/libexif/olympus/mnote-olympus-entry.h b/sources/libexif/olympus/mnote-olympus-entry.h
new file mode 100644
index 0000000..f1b0a98
--- /dev/null
+++ b/sources/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/sources/libexif/olympus/mnote-olympus-tag.c b/sources/libexif/olympus/mnote-olympus-tag.c
new file mode 100644
index 0000000..af8ffef
--- /dev/null
+++ b/sources/libexif/olympus/mnote-olympus-tag.c
@@ -0,0 +1,234 @@
+/* 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;
+
+#if defined(BIND_TEXTDOMAIN)
+	bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR);
+#endif
+	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 "";
+#if defined(BIND_TEXTDOMAIN)
+			bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR);
+#endif
+			return _(table[i].description);
+		}
+	return NULL;
+}
diff --git a/sources/libexif/olympus/mnote-olympus-tag.h b/sources/libexif/olympus/mnote-olympus-tag.h
new file mode 100644
index 0000000..2c3de82
--- /dev/null
+++ b/sources/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/sources/libexif/pentax/exif-mnote-data-pentax.c b/sources/libexif/pentax/exif-mnote-data-pentax.c
new file mode 100644
index 0000000..757bb72
--- /dev/null
+++ b/sources/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/sources/libexif/pentax/exif-mnote-data-pentax.h b/sources/libexif/pentax/exif-mnote-data-pentax.h
new file mode 100644
index 0000000..da9f79a
--- /dev/null
+++ b/sources/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/sources/libexif/pentax/mnote-pentax-entry.c b/sources/libexif/pentax/mnote-pentax-entry.c
new file mode 100644
index 0000000..7e97c2c
--- /dev/null
+++ b/sources/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/sources/libexif/pentax/mnote-pentax-entry.h b/sources/libexif/pentax/mnote-pentax-entry.h
new file mode 100644
index 0000000..4547ec3
--- /dev/null
+++ b/sources/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/sources/libexif/pentax/mnote-pentax-tag.c b/sources/libexif/pentax/mnote-pentax-tag.c
new file mode 100644
index 0000000..b53390f
--- /dev/null
+++ b/sources/libexif/pentax/mnote-pentax-tag.c
@@ -0,0 +1,179 @@
+/* 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;
+
+#if defined(BIND_TEXTDOMAIN)
+	bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR);
+#endif
+	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 "";
+#if defined(BIND_TEXTDOMAIN)
+			bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR);
+#endif
+			return _(table[i].description);
+		}
+	return NULL;
+}
diff --git a/sources/libexif/pentax/mnote-pentax-tag.h b/sources/libexif/pentax/mnote-pentax-tag.h
new file mode 100644
index 0000000..51b2aec
--- /dev/null
+++ b/sources/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__ */
diff --git a/sources/test/test-integers.c b/sources/test/test-integers.c
new file mode 100644
index 0000000..6af7534
--- /dev/null
+++ b/sources/test/test-integers.c
@@ -0,0 +1,64 @@
+/** \file test-integers.c
+ * \brief Check assumptions about integer types (sizes, ranges).
+ *
+ * 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.
+ */
+
+
+#include "libexif/_stdint.h"
+#include <stdlib.h>
+#include <stdio.h>
+
+
+typedef enum {
+   EN_A,
+   EN_B,
+   EN_C,
+   EN_D,
+   EN_E,
+   EN_F
+} enum_t;
+
+
+#if defined(__GNUC__) && (__GNUC__ >= 4)
+# define CHECK(condition)					     \
+	if (!(condition)) {					     \
+		fprintf(stderr, "%s:%d: check failed: %s\n",	     \
+			__FILE__, __LINE__, #condition);	     \
+		errors++;					     \
+	}
+#else
+# define CHECK(condition)					     \
+	if (!(condition)) {					     \
+		abort();					     \
+	}
+#endif
+
+
+int main()
+{
+  unsigned int errors = 0;
+
+  /* libexif assumes unsigned ints are not smaller than 32bit in many places */
+  CHECK(sizeof(unsigned int) >= sizeof(uint32_t));
+
+  /* libexif assumes that enums fit into ints */
+  CHECK(sizeof(enum_t) <= sizeof(int));
+  
+  return (errors>0)?1:0;
+}
diff --git a/sources/test/test-mem.c b/sources/test/test-mem.c
new file mode 100644
index 0000000..d4459a9
--- /dev/null
+++ b/sources/test/test-mem.c
@@ -0,0 +1,67 @@
+/* test-mem.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-data.h>
+#include <libexif/exif-ifd.h>
+#include <libexif/exif-loader.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+
+int
+main ()
+{
+	ExifData *ed;
+	/* ExifEntry *e; */
+	unsigned char *eb, size[2];
+	unsigned int ebs;
+	ExifLoader *loader;
+	unsigned int i;
+
+	printf ("Creating EXIF data...\n");
+	ed = exif_data_new ();
+	exif_data_set_data_type (ed, EXIF_DATA_TYPE_UNCOMPRESSED_CHUNKY);
+
+	printf ("Fill EXIF data with all necessary entries to follow specs...\n");
+	exif_data_fix (ed);
+
+	exif_data_dump (ed);
+
+	printf ("Saving EXIF data to memory...\n");
+	exif_data_save_data (ed, &eb, &ebs);
+	exif_data_unref (ed);
+
+	printf ("Writing %i byte(s) EXIF data to loader...\n", ebs);
+	loader = exif_loader_new ();
+	size[0] = (unsigned char) ebs;
+	size[1] = (unsigned char) (ebs >> 8);
+	exif_loader_write (loader, size, 2);
+	for (i = 0; i < ebs && exif_loader_write (loader, eb + i, 1); i++);
+	printf ("Wrote %i byte(s).\n", i);
+	free (eb);
+	ed = exif_loader_get_data (loader);
+	exif_loader_unref (loader);
+	exif_data_dump (ed);
+	exif_data_unref (ed);
+
+	return 0;
+}
diff --git a/sources/test/test-mnote.c b/sources/test/test-mnote.c
new file mode 100644
index 0000000..3864065
--- /dev/null
+++ b/sources/test/test-mnote.c
@@ -0,0 +1,107 @@
+/* exif-mnote.c
+ *
+ * Copyright 2002 Lutz M\uffffller <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 <stdio.h>
+#include <stdlib.h>
+
+#include <libexif/exif-data.h>
+
+static int
+test_exif_data (ExifData *d)
+{
+	unsigned int i, c;
+	char v[1024], *p;
+	ExifMnoteData *md;
+
+	fprintf (stdout, "Byte order: %s\n",
+		exif_byte_order_get_name (exif_data_get_byte_order (d)));
+
+	fprintf (stdout, "Parsing maker note...\n");
+	md = exif_data_get_mnote_data (d);
+	if (!md) {
+		fprintf (stderr, "Could not parse maker note!\n");
+		exif_data_unref (d);
+		return 1;
+	}
+
+	fprintf (stdout, "Increasing ref-count...\n");
+	exif_mnote_data_ref (md);
+
+	fprintf (stdout, "Decreasing ref-count...\n");
+	exif_mnote_data_unref (md);
+
+	fprintf (stdout, "Counting entries...\n");
+	c = exif_mnote_data_count (md);
+	fprintf (stdout, "Found %i entries.\n", c);
+	for (i = 0; i < c; i++) {
+		fprintf (stdout, "Dumping entry number %i...\n", i);
+		fprintf (stdout, "  Name: '%s'\n",
+				exif_mnote_data_get_name (md, i));
+		fprintf (stdout, "  Title: '%s'\n",
+				exif_mnote_data_get_title (md, i));
+		fprintf (stdout, "  Description: '%s'\n",
+				exif_mnote_data_get_description (md, i));
+		p = exif_mnote_data_get_value (md, i, v, sizeof (v));
+		if (p) { fprintf (stdout, "  Value: '%s'\n", v); }
+	}
+
+	return 0;
+}
+
+int
+main (int argc, char **argv)
+{
+	ExifData *d;
+	unsigned int buf_size;
+	unsigned char *buf;
+	int r;
+
+	if (argc <= 1) {
+		fprintf (stderr, "You need to supply a filename!\n");
+		return 1;
+	}
+
+	fprintf (stdout, "Loading '%s'...\n", argv[1]);
+	d = exif_data_new_from_file (argv[1]);
+	if (!d) {
+		fprintf (stderr, "Could not load data from '%s'!\n", argv[1]);
+		return 1;
+	}
+	fprintf (stdout, "Loaded '%s'.\n", argv[1]);
+
+	fprintf (stdout, "######### Test 1 #########\n");
+	r = test_exif_data (d);
+	if (r) return r;
+
+	exif_data_save_data (d, &buf, &buf_size);
+	exif_data_unref (d);
+	d = exif_data_new_from_data (buf, buf_size);
+	free (buf);
+
+	fprintf (stdout, "######### Test 2 #########\n");
+	r = test_exif_data (d);
+	if (r) return r;
+
+	fprintf (stdout, "Test successful!\n");
+
+	return 1;
+}
diff --git a/sources/test/test-parse.c b/sources/test/test-parse.c
new file mode 100644
index 0000000..83889e6
--- /dev/null
+++ b/sources/test/test-parse.c
@@ -0,0 +1,122 @@
+/** \file test-parse.c
+ * \brief Completely parse all files given on the command line.
+ *
+ * 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.
+ *
+ */
+
+#include "libexif/exif-data.h"
+#include "libexif/exif-system.h"
+
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+
+/** Callback function handling an ExifEntry. */
+void content_foreach_func(ExifEntry *entry, void *callback_data);
+void content_foreach_func(ExifEntry *entry, void *UNUSED(callback_data))
+{
+  char buf[2000];
+  exif_entry_get_value(entry, buf, sizeof(buf));
+  printf("    Entry %p: %s (%s)\n"
+	 "      Size, Comps: %d, %d\n"
+	 "      Value: %s\n", 
+	 entry,
+	 exif_tag_get_name(entry->tag),
+	 exif_format_get_name(entry->format),
+	 entry->size,
+	 (int)(entry->components),
+	 exif_entry_get_value(entry, buf, sizeof(buf)));
+}
+
+
+/** Callback function handling an ExifContent (corresponds 1:1 to an IFD). */
+void data_foreach_func(ExifContent *content, void *callback_data);
+void data_foreach_func(ExifContent *content, void *callback_data)
+{
+  printf("  Content %p: ifd=%d\n", content, exif_content_get_ifd(content));
+  exif_content_foreach_entry(content, content_foreach_func, callback_data);
+}
+
+
+/** Run EXIF parsing test on the given file. */
+void test_parse(const char *filename, void *callback_data);
+void test_parse(const char *filename, void *callback_data)
+{
+  ExifData *d;
+  printf("File %s\n", filename);
+
+  d = exif_data_new_from_file(filename);
+  exif_data_foreach_content(d, data_foreach_func, callback_data);
+  exif_data_unref(d);
+}
+
+
+/** Callback function prototype for string parsing. */
+typedef void (*test_parse_func) (const char *filename, void *callback_data);
+
+
+/** Split string at whitespace and call callback with each substring. */
+void split_ws_string(const char *string, test_parse_func func, void *callback_data);
+void split_ws_string(const char *string, test_parse_func func, void *callback_data)
+{
+  const char *start = string;
+  const char *p = start;
+  for (;;) {
+    if (*p == ' ' || *p == '\t' || *p == '\n' || *p == '\r' || *p == '\0' ) {
+      size_t len = p-start;
+      if (len > 0) {
+	/* emulate strndup */
+	char *str = malloc(1+len);
+	if (str) {
+	  memcpy(str, start, len);
+	  str[len] = '\0';
+	  func(str, callback_data);
+	  free(str);
+	  start = p+1;
+	}
+      } else {
+	start = p+1;
+      }
+    }
+    if (*p == '\0') {
+      break;
+    }
+    p++;
+  }  
+}
+
+
+/** Main program. */
+int main(const int argc, const char *argv[])
+{
+  int i;
+  void *callback_data = NULL;
+
+  const char *envar = getenv("TEST_IMAGES");
+  if (envar) {
+    split_ws_string(envar, test_parse, callback_data);
+  }
+
+  for (i=1; i<argc; i++) {
+    test_parse(argv[i], callback_data);
+  }
+
+  return 0;
+}
diff --git a/sources/test/test-sorted.c b/sources/test/test-sorted.c
new file mode 100644
index 0000000..0d00317
--- /dev/null
+++ b/sources/test/test-sorted.c
@@ -0,0 +1,50 @@
+/* test-sorted.c
+ *
+ * This test ensures that the ExifTagTable[] array is stored in sorted
+ * order. If that were not so, then it a binary search of the array would
+ * not give correct results.
+ *
+ * Copyright 2009 Dan Fandrich <dan@coneharvesters.com>
+ *
+ * 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 <libexif/exif-tag.h>
+#include <stdio.h>
+
+int
+main (void)
+{
+	int rc = 0;
+	unsigned int i, num;
+	ExifTag last = 0, current;
+	num = exif_tag_table_count() - 1; /* last entry is a NULL terminator */
+	for (i=0; i < num; ++i) {
+		current = exif_tag_table_get_tag(i);
+		if (current < last) {
+			printf("Tag 0x%04x in ExifTagTable[] is out of order\n",
+				current);
+			rc = 1;
+		}
+		if (exif_tag_table_get_name(i) == NULL) {
+			printf("Tag 0x%04x has a NULL name\n", current);
+			rc = 1;
+		}
+		last = current;
+	}
+
+	return rc;
+}
diff --git a/sources/test/test-tagtable.c b/sources/test/test-tagtable.c
new file mode 100644
index 0000000..d4af368
--- /dev/null
+++ b/sources/test/test-tagtable.c
@@ -0,0 +1,220 @@
+/* test-tagtable.c
+ *
+ * Test various functions that involve the tag table.
+ *
+ * Copyright (c) 2009 Dan Fandrich <dan@coneharvesters.com>
+ *
+ * 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 <stdio.h>
+#include <string.h>
+
+#define VALIDATE(s) if (!(s)) {printf("Test %s FAILED\n", #s); fail=1;}
+
+#define TESTBLOCK(t) {int rc = (t); fail |= rc; \
+                      if (rc) printf("%s tests FAILED\n", #t);}
+
+/* Test exif_tag_get_support_level_in_ifd */
+static int support_level(void)
+{
+    int fail = 0;
+
+    /*
+     * The tag EXIF_TAG_PLANAR_CONFIGURATION support varies greatly between
+     * data types.
+     */
+    VALIDATE(exif_tag_get_support_level_in_ifd(EXIF_TAG_PLANAR_CONFIGURATION,
+               EXIF_IFD_0, EXIF_DATA_TYPE_UNCOMPRESSED_CHUNKY) == 
+             EXIF_SUPPORT_LEVEL_OPTIONAL)
+
+    VALIDATE(exif_tag_get_support_level_in_ifd(EXIF_TAG_PLANAR_CONFIGURATION,
+               EXIF_IFD_0, EXIF_DATA_TYPE_UNCOMPRESSED_PLANAR) == 
+             EXIF_SUPPORT_LEVEL_MANDATORY)
+
+    VALIDATE(exif_tag_get_support_level_in_ifd(EXIF_TAG_PLANAR_CONFIGURATION,
+               EXIF_IFD_0, EXIF_DATA_TYPE_UNCOMPRESSED_YCC) == 
+             EXIF_SUPPORT_LEVEL_OPTIONAL)
+
+    VALIDATE(exif_tag_get_support_level_in_ifd(EXIF_TAG_PLANAR_CONFIGURATION,
+               EXIF_IFD_0, EXIF_DATA_TYPE_COMPRESSED) == 
+             EXIF_SUPPORT_LEVEL_NOT_RECORDED)
+
+    VALIDATE(exif_tag_get_support_level_in_ifd(EXIF_TAG_PLANAR_CONFIGURATION,
+               EXIF_IFD_0, EXIF_DATA_TYPE_UNKNOWN) == 
+             EXIF_SUPPORT_LEVEL_UNKNOWN)
+
+    /*
+     * The tag EXIF_TAG_YCBCR_POSITIONING support varies greatly between
+     * IFDs
+     */
+    VALIDATE(exif_tag_get_support_level_in_ifd(EXIF_TAG_YCBCR_POSITIONING,
+               EXIF_IFD_0, EXIF_DATA_TYPE_COMPRESSED) == 
+             EXIF_SUPPORT_LEVEL_MANDATORY)
+
+    VALIDATE(exif_tag_get_support_level_in_ifd(EXIF_TAG_YCBCR_POSITIONING,
+               EXIF_IFD_1, EXIF_DATA_TYPE_COMPRESSED) == 
+             EXIF_SUPPORT_LEVEL_OPTIONAL)
+
+    VALIDATE(exif_tag_get_support_level_in_ifd(EXIF_TAG_YCBCR_POSITIONING,
+               EXIF_IFD_EXIF, EXIF_DATA_TYPE_COMPRESSED) == 
+             EXIF_SUPPORT_LEVEL_NOT_RECORDED)
+
+    VALIDATE(exif_tag_get_support_level_in_ifd(EXIF_TAG_YCBCR_POSITIONING,
+               EXIF_IFD_GPS, EXIF_DATA_TYPE_COMPRESSED) == 
+             EXIF_SUPPORT_LEVEL_NOT_RECORDED)
+
+    VALIDATE(exif_tag_get_support_level_in_ifd(EXIF_TAG_YCBCR_POSITIONING,
+               EXIF_IFD_INTEROPERABILITY, EXIF_DATA_TYPE_COMPRESSED) == 
+             EXIF_SUPPORT_LEVEL_NOT_RECORDED)
+
+
+    /*
+     * The tag EXIF_TAG_GPS_VERSION_ID has value 0 which should NOT be
+     * treated specially
+     */
+    VALIDATE(exif_tag_get_support_level_in_ifd(EXIF_TAG_GPS_VERSION_ID,
+               EXIF_IFD_GPS, EXIF_DATA_TYPE_COMPRESSED) == 
+             EXIF_SUPPORT_LEVEL_OPTIONAL)
+
+    VALIDATE(exif_tag_get_support_level_in_ifd(EXIF_TAG_GPS_VERSION_ID,
+               EXIF_IFD_GPS, EXIF_DATA_TYPE_UNKNOWN) == 
+             EXIF_SUPPORT_LEVEL_OPTIONAL)
+
+    VALIDATE(exif_tag_get_support_level_in_ifd(EXIF_TAG_GPS_VERSION_ID,
+               EXIF_IFD_0, EXIF_DATA_TYPE_COMPRESSED) == 
+             EXIF_SUPPORT_LEVEL_NOT_RECORDED)
+
+    VALIDATE(exif_tag_get_support_level_in_ifd(EXIF_TAG_GPS_VERSION_ID,
+               EXIF_IFD_0, EXIF_DATA_TYPE_UNKNOWN) == 
+             EXIF_SUPPORT_LEVEL_UNKNOWN)
+
+    /* The unused tag 0xffff should NOT be treated specially */
+    VALIDATE(exif_tag_get_support_level_in_ifd(0xffff,
+               EXIF_IFD_0, EXIF_DATA_TYPE_UNKNOWN) == 
+             EXIF_SUPPORT_LEVEL_UNKNOWN)
+
+    VALIDATE(exif_tag_get_support_level_in_ifd(0xffff,
+               EXIF_IFD_0, EXIF_DATA_TYPE_COMPRESSED) == 
+             EXIF_SUPPORT_LEVEL_NOT_RECORDED)
+
+    /*
+     * The tag EXIF_TAG_DOCUMENT_NAME isn't in the EXIF 2.2 standard but
+     * it exists in the tag table, which causes it to show up as unknown
+     * instead of not recorded.
+     */
+    VALIDATE(exif_tag_get_support_level_in_ifd(EXIF_TAG_DOCUMENT_NAME,
+               EXIF_IFD_0, EXIF_DATA_TYPE_UNKNOWN) == 
+             EXIF_SUPPORT_LEVEL_UNKNOWN)
+
+    VALIDATE(exif_tag_get_support_level_in_ifd(EXIF_TAG_DOCUMENT_NAME,
+               EXIF_IFD_1, EXIF_DATA_TYPE_UNCOMPRESSED_CHUNKY) == 
+             EXIF_SUPPORT_LEVEL_UNKNOWN)
+
+
+    /*
+     * The tag number for EXIF_TAG_INTEROPERABILITY_INDEX (1) exists in both
+     * IFD Interoperability and IFD GPS (as EXIF_TAG_GPS_LATITUDE_REF) so
+     * there are two entries in the table.
+     */
+    VALIDATE(exif_tag_get_support_level_in_ifd(EXIF_TAG_INTEROPERABILITY_INDEX,
+               EXIF_IFD_INTEROPERABILITY, EXIF_DATA_TYPE_COMPRESSED) == 
+             EXIF_SUPPORT_LEVEL_OPTIONAL)
+
+    VALIDATE(exif_tag_get_support_level_in_ifd(EXIF_TAG_INTEROPERABILITY_INDEX,
+               EXIF_IFD_INTEROPERABILITY, EXIF_DATA_TYPE_UNKNOWN) == 
+             EXIF_SUPPORT_LEVEL_OPTIONAL)
+
+    VALIDATE(exif_tag_get_support_level_in_ifd(EXIF_TAG_INTEROPERABILITY_INDEX,
+               EXIF_IFD_0, EXIF_DATA_TYPE_COMPRESSED) == 
+             EXIF_SUPPORT_LEVEL_NOT_RECORDED)
+
+    VALIDATE(exif_tag_get_support_level_in_ifd(EXIF_TAG_INTEROPERABILITY_INDEX,
+               EXIF_IFD_0, EXIF_DATA_TYPE_UNKNOWN) == 
+             EXIF_SUPPORT_LEVEL_UNKNOWN)
+
+    VALIDATE(exif_tag_get_support_level_in_ifd(EXIF_TAG_GPS_LATITUDE_REF,
+               EXIF_IFD_GPS, EXIF_DATA_TYPE_COMPRESSED) == 
+             EXIF_SUPPORT_LEVEL_OPTIONAL)
+
+    VALIDATE(exif_tag_get_support_level_in_ifd(EXIF_TAG_GPS_LATITUDE_REF,
+               EXIF_IFD_GPS, EXIF_DATA_TYPE_UNKNOWN) == 
+             EXIF_SUPPORT_LEVEL_OPTIONAL)
+
+    /* The result of an unknown IFD should always be unknown */
+    VALIDATE(exif_tag_get_support_level_in_ifd(EXIF_TAG_EXIF_VERSION,
+               EXIF_IFD_COUNT, EXIF_DATA_TYPE_UNKNOWN) == 
+             EXIF_SUPPORT_LEVEL_UNKNOWN)
+
+    VALIDATE(exif_tag_get_support_level_in_ifd(EXIF_TAG_EXIF_VERSION,
+               EXIF_IFD_COUNT, EXIF_DATA_TYPE_COMPRESSED) == 
+             EXIF_SUPPORT_LEVEL_UNKNOWN)
+
+    return fail;
+}
+
+/* Test exif_tag_get_name_in_ifd  */
+static int name(void)
+{
+    int fail = 0;
+
+    /*
+     * The tag EXIF_TAG_GPS_VERSION_ID has value 0 which should NOT be
+     * treated specially
+     */
+    VALIDATE(!strcmp(exif_tag_get_name_in_ifd(
+                        EXIF_TAG_GPS_VERSION_ID, EXIF_IFD_GPS), 
+                     "GPSVersionID"))
+
+    VALIDATE(exif_tag_get_name_in_ifd(
+                        EXIF_TAG_GPS_VERSION_ID, EXIF_IFD_0) == NULL)
+
+    /*
+     * The tag number for EXIF_TAG_INTEROPERABILITY_INDEX (1) exists in both
+     * IFD Interoperability and IFD GPS (as EXIF_TAG_GPS_LATITUDE_REF) so
+     * there are two entries in the table.
+     */
+    VALIDATE(!strcmp(exif_tag_get_name_in_ifd(
+                EXIF_TAG_INTEROPERABILITY_INDEX, EXIF_IFD_INTEROPERABILITY), 
+                     "InteroperabilityIndex"))
+
+    VALIDATE(!strcmp(exif_tag_get_name_in_ifd(
+                        EXIF_TAG_GPS_LATITUDE_REF, EXIF_IFD_GPS), 
+                     "GPSLatitudeRef"))
+
+    /* Tag that doesn't appear in an IFD produces a NULL */
+    VALIDATE(exif_tag_get_name_in_ifd(
+                        EXIF_TAG_EXIF_VERSION, EXIF_IFD_0) == NULL)
+
+    /* Invalid IFD produces a NULL */
+    VALIDATE(exif_tag_get_name_in_ifd(
+                        EXIF_TAG_EXIF_VERSION, EXIF_IFD_COUNT) == NULL)
+
+    return fail;
+}
+
+int
+main ()
+{
+    int fail = 0;
+
+    TESTBLOCK(support_level())
+    TESTBLOCK(name())
+
+    return fail;
+}
diff --git a/sources/test/test-value.c b/sources/test/test-value.c
new file mode 100644
index 0000000..715ce10
--- /dev/null
+++ b/sources/test/test-value.c
@@ -0,0 +1,61 @@
+/* test-value.c
+ *
+ * Copyright 2002 Lutz M\uffffller <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 <libexif/exif-utils.h>
+#include <libexif/exif-data.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+
+int
+main ()
+{
+	ExifData *d;
+	ExifEntry *e;
+	char v[1024];
+	ExifSRational r = {1., 20.};
+	unsigned int i;
+
+	d = exif_data_new ();
+	if (!d) {
+		printf ("Error running exif_data_new()\n");
+		exit(13);
+	}
+
+	e = exif_entry_new ();
+	if (!e) {
+		printf ("Error running exif_entry_new()\n");
+		exit(13);
+	}
+
+	exif_content_add_entry (d->ifd[EXIF_IFD_0], e);
+	exif_entry_initialize (e, EXIF_TAG_SHUTTER_SPEED_VALUE);
+	exif_set_srational (e->data, exif_data_get_byte_order (d), r);
+
+	for (i = 30; i > 0; i--) {
+		printf ("Length %2i: '%s'\n", i, 
+			exif_entry_get_value (e, v, i));
+	}
+
+	exif_entry_unref (e);
+	exif_data_unref (d);
+
+	return 0;
+}