Remove commented out code.
[geeqie.git] / src / format_nikon.c
index 8cc2632..2b60ee5 100644 (file)
@@ -1,6 +1,7 @@
 /*
- *  GQView
- *  (C) 2005 John Ellis
+ * Geeqie
+ * (C) 2005 John Ellis
+ * Copyright (C) 2008 - 2012 The Geeqie Team
  *
  *  Authors:
  *    Raw NEF jpeg extraction based on nefextract.c by Joseph Heled,
@@ -15,6 +16,7 @@
 #  include "config.h"
 #endif
 
+#ifndef HAVE_EXIV2
 
 #include <stdio.h>
 #include <string.h>
@@ -24,6 +26,7 @@
 
 #include "intl.h"
 
+#include "main.h"
 #include "format_nikon.h"
 
 #include "exif.h"
  *-----------------------------------------------------------------------------
  */
 
-static guint tiff_table(unsigned char *data, const guint len, guint offset, ExifByteOrder byte_order,
-                       guint *image_offset, guint *jpeg_len);
+static guint nikon_tiff_table(guchar *data, const guint len, guint offset, ExifByteOrder bo,
+                             gint level,
+                             guint *image_offset, guint *jpeg_len);
 
 
-static void tiff_entry(unsigned char *data, const guint len, guint offset, ExifByteOrder byte_order,
-                      guint *image_offset, guint *image_length, guint *jpeg_start, guint *jpeg_len)
+static void nikon_tiff_entry(guchar *data, const guint len, guint offset, ExifByteOrder bo,
+                            gint level,
+                            guint *image_offset, guint *image_length, guint *jpeg_start, guint *jpeg_len)
 {
-       static gint size[] = { 1,1,1,2,4,8,1,1,2,4,8,4,8 };
        guint tag;
        guint type;
        guint count;
        guint segment;
+       guint seg_len;
 
-       tag = exif_byte_get_int16(data + offset, byte_order);
-       type = exif_byte_get_int16(data + offset + 2, byte_order);
-       count = exif_byte_get_int32(data + offset + 4, byte_order);
+       tag = exif_byte_get_int16(data + offset + EXIF_TIFD_OFFSET_TAG, bo);
+       type = exif_byte_get_int16(data + offset + EXIF_TIFD_OFFSET_FORMAT, bo);
+       count = exif_byte_get_int32(data + offset + EXIF_TIFD_OFFSET_COUNT, bo);
 
-       if (type > 12) return;
-       if (count * size[type] > 4)
+       /* so far, we only care about tags with type long */
+       if (type != EXIF_FORMAT_LONG_UNSIGNED && type != EXIF_FORMAT_LONG) return;
+
+       seg_len = ExifFormatList[type].size * count;
+       if (seg_len > 4)
                {
-               segment = exif_byte_get_int32(data + offset + 8, byte_order);
-               if (len < segment + count * size[type]) return;
+               segment = exif_byte_get_int32(data + offset + EXIF_TIFD_OFFSET_DATA, bo);
+               if (segment + seg_len > len) return;
                }
        else
                {
-               segment = offset + 8;
+               segment = offset + EXIF_TIFD_OFFSET_DATA;
                }
 
-       if (tag == 0x14a &&
-           type == EXIF_FORMAT_LONG_UNSIGNED)
+       if (tag == 0x14a)
                {
                /* sub IFD table */
-               gint i;
+               guint i;
 
                for (i = 0; i < count; i++)
                        {
                        guint subset;
 
-                       subset = exif_byte_get_int32(data + segment + i * 4, byte_order);
-                       tiff_table(data, len, subset, byte_order, image_offset, image_length);
+                       subset = exif_byte_get_int32(data + segment + i * 4, bo);
+                       nikon_tiff_table(data, len, subset, bo, level + 1, image_offset, image_length);
                        }
 
                }
        else if (tag == 0x201)
                {
                /* jpeg data start offset */
-               *jpeg_start = exif_byte_get_int32(data + segment, byte_order);
+               *jpeg_start = exif_byte_get_int32(data + segment, bo);
                }
        else if (tag == 0x202)
                {
                /* jpeg data length */
-               *jpeg_len = exif_byte_get_int32(data + segment, byte_order);
+               *jpeg_len = exif_byte_get_int32(data + segment, bo);
                }
 }
 
-static guint tiff_table(unsigned char *data, const guint len, guint offset, ExifByteOrder byte_order,
-                       guint *image_offset, guint *image_length)
+static guint nikon_tiff_table(guchar *data, const guint len, guint offset, ExifByteOrder bo,
+                             gint level,
+                             guint *image_offset, guint *image_length)
 {
        guint count;
        guint i;
        guint jpeg_start = 0;
        guint jpeg_len = 0;
 
-       if (len < offset + 2) return FALSE;
+       /* limit damage from infinite loops */
+       if (level > EXIF_TIFF_MAX_LEVELS) return 0;
 
-       count = exif_byte_get_int16((unsigned char *)data + offset, byte_order);
+       if (len < offset + 2) return FALSE;
 
-       if (len < offset + count * 12 + 4) return 0;
+       count = exif_byte_get_int16(data + offset, bo);
        offset += 2;
+       if (len < offset + count * EXIF_TIFD_SIZE + 4) return 0;
 
        for (i = 0; i < count; i++)
                {
-               tiff_entry(data, len, offset + i * 12, byte_order,
-                          image_offset, image_length, &jpeg_start, &jpeg_len);
+               nikon_tiff_entry(data, len, offset + i * EXIF_TIFD_SIZE, bo, level,
+                                image_offset, image_length, &jpeg_start, &jpeg_len);
                }
 
        if (jpeg_start > 0 &&
@@ -118,87 +128,25 @@ static guint tiff_table(unsigned char *data, const guint len, guint offset, Exif
                *image_length = jpeg_len;
                }
 
-       return exif_byte_get_int32((unsigned char *)data + offset + count * 12, byte_order);
-}
-
-/*
- * Walk the first TIFF IFD table and check for existence of a "make" tag (0x10f) that
- * identifies NIKON CORPORATION, so that we can abort quickly if it is not a raw NEF.
- */
-static gint tiff_nikon_verify(unsigned char *data, const guint len, guint offset, ExifByteOrder byte_order)
-{
-       guint nb_entries;
-       guint i;
-
-       if (len < offset + 2) return FALSE;
-
-       nb_entries = exif_byte_get_int16(data + offset, byte_order);
-       offset += 2;
-       if (len < offset + nb_entries * 12 + 4) return FALSE;
-
-       for (i = 0; i < nb_entries; i++)
-               {
-               guint segment;
-
-               segment = offset + i * 12;
-               if (exif_byte_get_int16(data + segment, byte_order) == 0x10f &&
-                   exif_byte_get_int16(data + segment + 2, byte_order) == EXIF_FORMAT_STRING)
-                       {
-                       guint count;
-                       guint make_text;
-
-                       count = exif_byte_get_int32(data + segment + 4, byte_order);
-                       make_text = exif_byte_get_int32(data + segment + 8, byte_order);
-
-                       if (count >= 17 &&
-                           memcmp(data + make_text, "NIKON CORPORATION", 17) == 0)
-                               {
-                               return TRUE;
-                               }
-
-                       return FALSE;
-                       }
-               }
-
-       return FALSE;
+       return exif_byte_get_int32(data + offset + count * EXIF_TIFD_SIZE, bo);
 }
 
-gint format_nikon_raw(const void *data, const guint len,
-                     guint *image_offset, guint *exif_offset)
+gboolean format_nikon_raw(guchar *data, const guint len,
+                         guint *image_offset, guint *exif_offset)
 {
        guint i_off = 0;
        guint i_len = 0;
-       ExifByteOrder byte_order;
+       ExifByteOrder bo;
        guint offset;
+       gint level;
 
-       if (len < 8) return FALSE;
+       if (!exif_tiff_directory_offset(data, len, &offset, &bo)) return FALSE;
 
-       if (memcmp(data, "II", 2) == 0)
-               {
-               byte_order = EXIF_BYTE_ORDER_INTEL;
-               }
-       else if (memcmp(data, "MM", 2) == 0)
+       level = 0;
+       while (offset && level < EXIF_TIFF_MAX_LEVELS)
                {
-               byte_order = EXIF_BYTE_ORDER_MOTOROLA;
-               }
-       else
-               {
-               return FALSE;
-               }
-
-       if (exif_byte_get_int16((unsigned char *)data + 2, byte_order) != 0x002A)
-               {
-               return FALSE;
-               }
-
-       offset = exif_byte_get_int32((unsigned char *)data + 4, byte_order);
-       if (!tiff_nikon_verify((unsigned char *)data, len, offset, byte_order)) return FALSE;
-
-       while (offset != 0)
-               {
-               guint next_offset = 0;
-               tiff_table((unsigned char *)data, len, offset, byte_order, &i_off, &i_len);
-               offset = next_offset;
+               offset = nikon_tiff_table(data, len, offset, bo, 0, &i_off, &i_len);
+               level++;
                }
 
        if (i_off != 0)
@@ -273,27 +221,18 @@ static ExifTextList NikonTagConverter[]= {
        EXIF_TEXT_LIST_END
 };
 
-#if 0
-static ExifTextList NikonTag[]= {
-       { ,     "" },
-       { ,     "" },
-       EXIF_TEXT_LIST_END
-};
-#endif
-
 static ExifMarker NikonExifMarkersList1[] = {
-{ 0x0002, EXIF_FORMAT_STRING, 6,               "MkN.Nikon.unknown",    NULL,           NULL },
-{ 0x0003, EXIF_FORMAT_SHORT_UNSIGNED, 1,       "MkN.Nikon.Quality",    "Quality",      NikonTagQuality },
-{ 0x0004, EXIF_FORMAT_SHORT_UNSIGNED, 1,       "MkN.Nikon.ColorMode",  "Color mode",   NikonTagColorMode },
-{ 0x0005, EXIF_FORMAT_SHORT_UNSIGNED, 1,       "MkN.Nikon.ImageAdjustment",
+{ 0x0002, EXIF_FORMAT_STRING, 6,               "Nikon.unknown",        NULL,           NULL },
+{ 0x0003, EXIF_FORMAT_SHORT_UNSIGNED, 1,       "Nikon.Quality",        "Quality",      NikonTagQuality },
+{ 0x0004, EXIF_FORMAT_SHORT_UNSIGNED, 1,       "Nikon.ColorMode",      "Color mode",   NikonTagColorMode },
+{ 0x0005, EXIF_FORMAT_SHORT_UNSIGNED, 1,       "Nikon.ImageAdjustment",
                                                                "Image adjustment",     NikonTagImgAdjust },
-{ 0x0006, EXIF_FORMAT_SHORT_UNSIGNED, 1,       "MkN.Nikon.ISOSensitivity",
+{ 0x0006, EXIF_FORMAT_SHORT_UNSIGNED, 1,       "Nikon.ISOSensitivity",
                                                                "ISO sensitivity",      NikonTagISOSensitivity },
-{ 0x0007, EXIF_FORMAT_SHORT_UNSIGNED, 1,       "MkN.Nikon.WhiteBalance",
-                                                               "White balance",        NikonTagWhiteBalance },
-{ 0x0008, EXIF_FORMAT_RATIONAL_UNSIGNED, 1,    "MkN.Nikon.Focus",      "Focus",        NULL },
-{ 0x000a, EXIF_FORMAT_RATIONAL_UNSIGNED, 1,    "MkN.Nikon.DigitalZoom","Digital zoom", NULL },
-{ 0x000b, EXIF_FORMAT_SHORT_UNSIGNED, 1,       "MkN.Nikon.Converter",  "Converter",    NikonTagConverter },
+{ 0x0007, EXIF_FORMAT_SHORT_UNSIGNED, 1,       "Nikon.WhiteBalance",   "White balance",NikonTagWhiteBalance },
+{ 0x0008, EXIF_FORMAT_RATIONAL_UNSIGNED, 1,    "Nikon.Focus",          "Focus",        NULL },
+{ 0x000a, EXIF_FORMAT_RATIONAL_UNSIGNED, 1,    "Nikon.DigitalZoom",    "Digital zoom", NULL },
+{ 0x000b, EXIF_FORMAT_SHORT_UNSIGNED, 1,       "Nikon.Converter",      "Converter",    NikonTagConverter },
 EXIF_MARKER_LIST_END
 };
 
@@ -318,117 +257,175 @@ static ExifTextList NikonTag2FlashComp[]= {
        EXIF_TEXT_LIST_END
 };
 
+static ExifTextList NikonTag2LensType[]= {
+       { 0,    "AF non D" },
+       { 1,    "manual" },
+       { 2,    "AF-D or AF-s" },
+       { 6,    "AF-D G" },
+       { 10,   "AF-D VR" },
+       EXIF_TEXT_LIST_END
+};
+
 static ExifTextList NikonTag2FlashUsed[]= {
        { 0,    "no" },
+       { 4,    "unit unknown" },
+       { 7,    "external" },
        { 9,    "yes" },
        EXIF_TEXT_LIST_END
 };
 
-#if 0
-static ExifTextList NikonTagi2Saturation[]= {
-       { -3,   "black and white" },
-       { -2,   "-2" },
-       { -1,   "-1" },
-       { 0,    "normal" },
-       { 1,    "+1" },
-       { 2,    "+2" },
-       EXIF_TEXT_LIST_END
-};
-#endif
 
 static ExifMarker NikonExifMarkersList2[] = {
-{ 0x0002, EXIF_FORMAT_SHORT_UNSIGNED, 2,       "MkN.Nikon.ISOSpeed",   "ISO speed",    NULL },
-{ 0x0003, EXIF_FORMAT_STRING, -1,              "MkN.Nikon.ColorMode",  "Color mode",   NULL },
-{ 0x0004, EXIF_FORMAT_STRING, -1,              "MkN.Nikon.Quality",    "Quality",      NULL },
-{ 0x0005, EXIF_FORMAT_STRING, -1,              "MkN.Nikon.WhiteBalance",
-                                                               "White balance",        NULL },
-{ 0x0006, EXIF_FORMAT_STRING, -1,              "MkN.Nikon.Sharpening", "Sharpening",   NULL },
-{ 0x0007, EXIF_FORMAT_STRING, -1,              "MkN.Nikon.FocusMode",  "Focus mode",   NULL },
-{ 0x0008, EXIF_FORMAT_STRING, -1,              "MkN.Nikon.FlashSetting",
-                                                               "Flash setting",        NULL },
-{ 0x0009, EXIF_FORMAT_STRING, -1,              "MkN.Nikon.AutoFlashMode","Auto flash mode",NULL },
-{ 0x000b, EXIF_FORMAT_SHORT, 1,                        "MkN.Nikon.WhiteBalanceBias",
+{ 0x0002, EXIF_FORMAT_SHORT_UNSIGNED, 2,       "Nikon.ISOSpeed",       "ISO speed",    NULL },
+{ 0x0003, EXIF_FORMAT_STRING, -1,              "Nikon.ColorMode",      "Color mode",   NULL },
+{ 0x0004, EXIF_FORMAT_STRING, -1,              "Nikon.Quality",        "Quality",      NULL },
+{ 0x0005, EXIF_FORMAT_STRING, -1,              "Nikon.WhiteBalance",   "White balance",NULL },
+{ 0x0006, EXIF_FORMAT_STRING, -1,              "Nikon.Sharpening",     "Sharpening",   NULL },
+{ 0x0007, EXIF_FORMAT_STRING, -1,              "Nikon.FocusMode",      "Focus mode",   NULL },
+{ 0x0008, EXIF_FORMAT_STRING, -1,              "Nikon.FlashSetting",   "Flash setting",NULL },
+{ 0x0009, EXIF_FORMAT_STRING, -1,              "Nikon.AutoFlashMode","Auto flash mode",NULL },
+{ 0x000b, EXIF_FORMAT_SHORT, 1,                        "Nikon.WhiteBalanceBias",
                                                        "White balance bias value",     NULL },
-/* { 0x000c, EXIF_FORMAT_SHORT_UNSIGNED, 1,    "MkN.Nikon.WhiteBalanceCoeff",
-                                               "White balance red/blue coefficents",   NULL }, */
-/* { 0x000f, EXIF_FORMAT_STRING, -1,           "MkN.Nikon.ISOSelect",  "ISO selection",NULL }, */
-{ 0x0012, EXIF_FORMAT_UNDEFINED, 4,            "MkN.Nikon.FlashCompensation",
+/* { 0x000c, EXIF_FORMAT_SHORT_UNSIGNED, 1,    "Nikon.WhiteBalanceRB",
+                                               "White balance red/blue coefficients",  NULL }, */
+/* { 0x000f, EXIF_FORMAT_STRING, -1,           "Nikon.ISOSelect",      "ISO selection",NULL }, */
+{ 0x0012, EXIF_FORMAT_UNDEFINED, 4,            "Nikon.FlashCompensation",
                                                                "Flash compensation",   NikonTag2FlashComp },
-{ 0x0013, EXIF_FORMAT_SHORT_UNSIGNED, 2,       "MkN.Nikon.ISOSpeedRequest",
+{ 0x0013, EXIF_FORMAT_SHORT_UNSIGNED, 2,       "Nikon.ISOSpeedRequest",
                                                                "ISO speed requested",  NULL },
-{ 0x0016, EXIF_FORMAT_SHORT_UNSIGNED, 4,       "MkN.Nikon.CornerCoord",
+{ 0x0016, EXIF_FORMAT_SHORT_UNSIGNED, 4,       "Nikon.CornerCoord",
                                                                "Corner coordinates",   NULL },
-{ 0x0018, EXIF_FORMAT_UNDEFINED, 4,            "MkN.Nikon.FlashBracketCompensation",
+{ 0x0018, EXIF_FORMAT_UNDEFINED, 4,            "Nikon.FlashBracketCompensation",
                                                        "Flash bracket compensation",   NikonTag2FlashComp },
-{ 0x0019, EXIF_FORMAT_RATIONAL, 1,             "MkN.Nikon.AEBracketCompensation",
+{ 0x0019, EXIF_FORMAT_RATIONAL, 1,             "Nikon.AEBracketCompensation",
                                                        "AE bracket compensation",      NULL },
-{ 0x0080, EXIF_FORMAT_STRING, -1,              "MkN.Nikon.ImageAdjustment",
+{ 0x0080, EXIF_FORMAT_STRING, -1,              "Nikon.ImageAdjustment",
                                                                "Image adjustment",     NULL },
-{ 0x0081, EXIF_FORMAT_STRING, -1,              "MkN.Nikon.Contrast",   "Contrast",     NULL },
-{ 0x0082, EXIF_FORMAT_STRING, -1,              "MkN.Nikon.AuxLens","Aux lens adapter", NULL },
-{ 0x0083, EXIF_FORMAT_BYTE_UNSIGNED, -1,       "MkN.Nikon.LensType",   "Lens type",    NULL },
-{ 0x0084, EXIF_FORMAT_RATIONAL_UNSIGNED, -1,   "MkN.Nikon.LensFocalLength",
+{ 0x0081, EXIF_FORMAT_STRING, -1,              "Nikon.Contrast",       "Contrast",     NULL },
+{ 0x0082, EXIF_FORMAT_STRING, -1,              "Nikon.AuxLens", "Aux lens adapter",    NULL },
+{ 0x0083, EXIF_FORMAT_BYTE_UNSIGNED, -1,       "Nikon.LensType",       "Lens type",    NikonTag2LensType },
+{ 0x0084, EXIF_FORMAT_RATIONAL_UNSIGNED, -1,   "Nikon.LensFocalLength",
                                                        "Lens min/max focal length and aperture", NULL },
-{ 0x0085, EXIF_FORMAT_SHORT_UNSIGNED, 1,       "MkN.Nikon.ManualFocusDistance",
+{ 0x0085, EXIF_FORMAT_SHORT_UNSIGNED, 1,       "Nikon.ManualFocusDistance",
                                                        "Manual focus distance",        NULL },
-{ 0x0086, EXIF_FORMAT_SHORT_UNSIGNED, 1,       "MkN.Nikon.DigitalZoomFactor",
-                                                       "Digital zoom facotr",          NULL },
-{ 0x0087, EXIF_FORMAT_BYTE_UNSIGNED, 1,                "MkN.Nikon.FlashUsed",  "Flash used",   NikonTag2FlashUsed },
-{ 0x0088, EXIF_FORMAT_UNDEFINED, -1,           "MkN.Nikon.AutoFocusArea", NULL,        NULL },
-/* { 0x0089, EXIF_FORMAT_SHORT_UNSIGNED, -1,   "MkN.Nikon.Bracket/ShootingMode", NULL, NULL }, */
-{ 0x008d, EXIF_FORMAT_STRING, -1,              "MkN.Nikon.ColorMode",  "Color mode",   NULL },
-{ 0x008f, EXIF_FORMAT_SHORT_UNSIGNED, 1,       "MkN.Nikon.SceneMode",  NULL,           NULL },
-{ 0x0090, EXIF_FORMAT_STRING, -1,              "MkN.Nikon.LightingType", "Lighting type", NULL },
-{ 0x0092, EXIF_FORMAT_SHORT, 1,                        "MkN.Nikon.HueAdjust",  "Hue adjustment", NULL },
-/* { 0x0094, EXIF_FORMAT_SHORT_UNSIGNED, 1,    "MkN.Nikon.Saturation", "Saturation",   NikonTag2Saturation }, */
-{ 0x0095, EXIF_FORMAT_STRING, -1,              "MkN.Nikon.NoiseReduction", "Noise reduction", NULL },
-{ 0x00a7, EXIF_FORMAT_LONG_UNSIGNED, 1,                "MkN.Nikon.ShutterCount", "Shutter release count", NULL },
-{ 0x00a9, EXIF_FORMAT_STRING, -1,              "MkN.Nikon.ImageOptimization", "Image optimization", NULL },
-{ 0x00aa, EXIF_FORMAT_STRING, -1,              "MkN.Nikon.Saturation", "Saturation",   NULL },
-{ 0x00ab, EXIF_FORMAT_STRING, -1,              "MkN.Nikon.DigitalVariProg", "Digital Vari-program", NULL },
+{ 0x0086, EXIF_FORMAT_RATIONAL, 1,             "Nikon.DigitalZoomFactor",
+                                                       "Digital zoom factor",          NULL },
+{ 0x0087, EXIF_FORMAT_BYTE_UNSIGNED, 1,                "Nikon.FlashUsed",      "Flash used",   NikonTag2FlashUsed },
+{ 0x0088, EXIF_FORMAT_UNDEFINED, 4,            "Nikon.AutoFocusArea","Auto focus area",NULL },
+/* { 0x0089, EXIF_FORMAT_SHORT_UNSIGNED, -1,   "Nikon.Bracket/ShootingMode", NULL,     NULL }, */
+{ 0x008d, EXIF_FORMAT_STRING, -1,              "Nikon.ColorMode",      "Color mode",   NULL },
+{ 0x008f, EXIF_FORMAT_SHORT_UNSIGNED, 1,       "Nikon.SceneMode",      "Scene mode",   NULL },
+{ 0x0090, EXIF_FORMAT_STRING, -1,              "Nikon.LightingType",   "Lighting type",NULL },
+{ 0x0092, EXIF_FORMAT_SHORT, 1,                        "Nikon.HueAdjust",      "Hue adjustment",NULL },
+/* { 0x0094, EXIF_FORMAT_SHORT_UNSIGNED, 1,    "Nikon.Saturation",     "Saturation",   NikonTag2Saturation }, */
+{ 0x0095, EXIF_FORMAT_STRING, -1,              "Nikon.NoiseReduction", "Noise reduction", NULL },
+{ 0x00a7, EXIF_FORMAT_LONG_UNSIGNED, 1,                "Nikon.ShutterCount", "Shutter release count", NULL },
+{ 0x00a9, EXIF_FORMAT_STRING, -1,              "Nikon.ImageOptimization", "Image optimization", NULL },
+{ 0x00aa, EXIF_FORMAT_STRING, -1,              "Nikon.Saturation", "Saturation",       NULL },
+{ 0x00ab, EXIF_FORMAT_STRING, -1,              "Nikon.DigitalVariProg", "Digital Vari-program", NULL },
 EXIF_MARKER_LIST_END
 };
 
+static ExifTextList NikonAFPoint[]= {
+       { 0,    "center" },
+       { 1,    "top" },
+       { 2,    "bottom" },
+       { 3,    "left" },
+       { 4,    "right" },
+       EXIF_TEXT_LIST_END
+};
+
 
-gint format_nikon_makernote(ExifData *exif, unsigned char *tiff, guint offset,
-                           guint size, ExifByteOrder byte_order)
+gboolean format_nikon_makernote(ExifData *exif, guchar *tiff, guint offset,
+                               guint size, ExifByteOrder bo)
 {
-       unsigned char *data;
+       guchar *data;
+       ExifItem *item;
 
        if (offset + 8 + 4 >= size) return FALSE;
 
        data = tiff + offset;
+
+       /* Nikon tag format 1 */
        if (memcmp(data, "Nikon\x00\x01\x00", 8) == 0)
                {
                if (exif_parse_IFD_table(exif, tiff, offset + 8, size,
-                                        byte_order, NikonExifMarkersList1) != 0)
+                                        bo, 0, NikonExifMarkersList1) != 0)
                        {
                        return FALSE;
                        }
                return TRUE;
                }
 
+       /* Nikon tag format 2 uses Embedded tiff header */
        if (memcmp(data, "Nikon\x00\x02\x00\x00\x00", 10) == 0 ||
            memcmp(data, "Nikon\x00\x02\x10\x00\x00", 10) == 0)
                {
                guint tiff_header;
 
                tiff_header = offset + 10;
-               if (exif_parse_TIFF(exif, tiff + tiff_header, size - tiff_header,
+               if (exif_tiff_parse(exif, tiff + tiff_header, size - tiff_header,
                    NikonExifMarkersList2) != 0)
                        {
                        return FALSE;
                        }
-               return TRUE;
                }
-
-       /* fixme: support E990 and D1 */
-       if (exif_parse_IFD_table(exif, tiff, offset, size,
-                                byte_order, NikonExifMarkersList2) != 0)
+       /* Nikon tag format 3 uses format 2 tags without "Nikon" and tiff header */
+       else if (exif_parse_IFD_table(exif, tiff, offset, size,
+                                     bo, 0, NikonExifMarkersList2) != 0)
                {
                return FALSE;
                }
 
-       return FALSE;
+       item = exif_get_item(exif, "Nikon.AutoFocusArea");
+       if (item && item->data_len == 4 * sizeof(guchar))
+               {
+               static ExifMarker marker = { 0x0088, EXIF_FORMAT_STRING, -1,
+                                            "Nikon.AutoFocusPoint", "Auto focus point", NULL };
+               guchar *array = item->data;
+               gchar *text;
+               gint l;
+
+               text = exif_text_list_find_value(NikonAFPoint, (gint)array[1]);
+               l = strlen(text) + 1;
+
+               item = exif_item_new(marker.format, marker.tag, l, &marker);
+               memcpy(item->data, text, l);
+
+               g_free(text);
+
+               exif->items = g_list_prepend(exif->items, item);
+               }
+
+       item = exif_get_item(exif, "Nikon.ISOSpeed");
+       if (item && item->data_len == 2 * 2)
+               {
+               static ExifMarker marker = { 0x0002, EXIF_FORMAT_SHORT_UNSIGNED, 1,
+                                            "ISOSpeedRatings", "ISO speed", NULL };
+               ExifItem *shadow;
+
+               shadow = exif_item_new(marker.format, marker.tag, 1, &marker);
+               memcpy(shadow->data, item->data + 2, 2);
+
+               exif->items = g_list_prepend(exif->items, shadow);
+               }
+
+       item = exif_get_item(exif, "Nikon.WhiteBalance");
+       if (item && item->format == EXIF_FORMAT_STRING)
+               {
+               static ExifMarker marker = { 0x0005, EXIF_FORMAT_STRING, -1,
+                                            "LightSource", "Light source", NULL };
+               ExifItem *shadow;
+
+               shadow = exif_item_new(marker.format, marker.tag, item->data_len, &marker);
+               memcpy(shadow->data, item->data, item->data_len);
+
+               exif->items = g_list_prepend(exif->items, shadow);
+               }
+
+       return TRUE;
 }
 
+#endif
+/* not HAVE_EXIV2 */
+/* vim: set shiftwidth=8 softtabstop=0 cindent cinoptions={1s: */