/* -*- C++ -*-
 * Copyright 2019-2025 LibRaw LLC (info@libraw.org)
 *
 LibRaw is free software; you can redistribute it and/or modify
 it under the terms of the one of two licenses as you choose:

1. GNU LESSER GENERAL PUBLIC LICENSE version 2.1
   (See file LICENSE.LGPL provided in LibRaw distribution archive for details).

2. COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0
   (See file LICENSE.CDDL provided in LibRaw distribution archive for details).

 */

#include "../../internal/dcraw_defs.h"

void LibRaw::Kodak_KDC_WBtags(int wb, int wbi)
{
  int c;
  FORC3 icWBC[wb][c] = get4();
  icWBC[wb][3] = icWBC[wb][1];
  if (wbi == wb)
    FORC4 cam_mul[c] = float(icWBC[wb][c]);
  return;
}

void LibRaw::Kodak_DCR_WBtags(int wb, unsigned type, int wbi)
{
  float mul[3] = {1.0f, 1.0f, 1.0f}, num, mul2;
  int c;
  FORC3 mul[c] = (num = getrealf(type)) <= 0.001f ? 1.0f : num;
  icWBC[wb][1] = icWBC[wb][3] = int(mul[1]);
  mul2 = mul[1] * mul[1];
  icWBC[wb][0] = int(mul2 / mul[0]);
  icWBC[wb][2] = int(mul2 / mul[2]);
  if (wbi == wb)
    FORC4 cam_mul[c] = float(icWBC[wb][c]);
  return;
}

short LibRaw::KodakIllumMatrix(unsigned type, float *romm_camIllum)
{
  int c, j, romm_camTemp[9], romm_camScale[3];
  if (tagtypeIs(LIBRAW_EXIFTAG_TYPE_SRATIONAL))
  {
    for (j = 0; j < 9; j++)
      ((float *)romm_camIllum)[j] = getrealf(type);
    return 1;
  }
  else if (tagtypeIs(LIBRAW_EXIFTAG_TYPE_SLONG))
  {
    FORC3
    {
      romm_camScale[c] = 0;
      for (j = 0; j < 3; j++)
      {
        romm_camTemp[c * 3 + j] = get4();
        romm_camScale[c] += romm_camTemp[c * 3 + j];
      }
    }
    if ((romm_camScale[0] > 0x1fff) && (romm_camScale[1] > 0x1fff) &&
        (romm_camScale[2] > 0x1fff))
    {
      FORC3 for (j = 0; j < 3; j++)((float *)romm_camIllum)[c * 3 + j] =
          ((float)romm_camTemp[c * 3 + j]) / ((float)romm_camScale[c]);
      return 1;
    }
  }
  return 0;
}

/* Thanks to Alexey Danilchenko for wb as-shot parsing code */
void LibRaw::parse_kodak_ifd(INT64 base)
{
  unsigned entries, tag, type, len;
  INT64 save;
  int c, wbi = -1;

  static const int wbtag_kdc[] = {
      LIBRAW_WBI_Auto,        // 64037 / 0xfa25
      LIBRAW_WBI_Fluorescent, // 64040 / 0xfa28
      LIBRAW_WBI_Tungsten,    // 64039 / 0xfa27
      LIBRAW_WBI_Daylight,    // 64041 / 0xfa29
      -1,
      -1,
      LIBRAW_WBI_Shade // 64042 / 0xfa2a
  };

  static const int wbtag_dcr[] = {
      LIBRAW_WBI_Daylight,    // 2120 / 0x0848
      LIBRAW_WBI_Tungsten,    // 2121 / 0x0849
      LIBRAW_WBI_Fluorescent, // 2122 / 0x084a
      LIBRAW_WBI_Flash,       // 2123 / 0x084b
      LIBRAW_WBI_Custom,      // 2124 / 0x084c
      LIBRAW_WBI_Auto         // 2125 / 0x084d
  };

  //  int a_blck = 0;

  entries = get2();
  if (entries > 1024)
    return;
  INT64 fsize = ifp->size();
  while (entries--)
  {
    tiff_get(base, &tag, &type, &len, &save);
    INT64 savepos = ftell(ifp);
    if (len > 8 && len + savepos > 2 * fsize)
    {
      fseek(ifp, save, SEEK_SET); // Recover tiff-read position!!
      continue;
    }
    if (callbacks.exif_cb)
    {
      callbacks.exif_cb(callbacks.exifparser_data, tag | 0x20000, type, len,
                        order, ifp, base);
      fseek(ifp, savepos, SEEK_SET);
    }
    if (tag == 0x03eb) // 1003
      imgdata.sizes.raw_inset_crops[0].cleft = get2();
    else if (tag == 0x03ec) // 1004
      imgdata.sizes.raw_inset_crops[0].ctop = get2();
    else if (tag == 0x03ed) // 1005
      imgdata.sizes.raw_inset_crops[0].cwidth = get2();
    else if (tag == 0x03ee) // 1006
      imgdata.sizes.raw_inset_crops[0].cheight = get2();
    else if (tag == 0x03ef) // 1007
    {
      if (!strcmp(model, "EOS D2000C"))
        black = get2();
      else
        imKodak.BlackLevelTop = get2();
    }
    else if (tag == 0x03f0) // 1008
    {
      if (!strcmp(model, "EOS D2000C"))
      {
        if (black) // already set by tag 1007 (0x03ef)
          black = (black + get2()) / 2;
        else
          black = get2();
      }
      else
        imKodak.BlackLevelBottom = get2();
    }

    else if (tag == 0x03f1)
    { // 1009 Kodak TextualInfo
      if (len > 0)
      {
        char kti[1024];
        char *pkti;
        int nsym = MIN(len, 1023);
        fread(kti, 1, nsym, ifp);
        kti[nsym] = 0;
#ifdef LIBRAW_WIN32_CALLS
        pkti = strtok(kti, "\x0a");
#else
        char *last = 0;
        pkti = strtok_r(kti, "\x0a", &last);
#endif
        while (pkti != NULL)
        {
          c = 12;
          if (((int)strlen(pkti) > c) && (!strncasecmp(pkti, "Camera body:", c)))
          {
            while ((pkti[c] == ' ') && (c < (int)strlen(pkti)))
            {
              c++;
            }
            strcpy(ilm.body, pkti + c);
          }
          c = 5;
          if (((int)strlen(pkti) > c) && (!strncasecmp(pkti, "Lens:", c)))
          {
            ilm.CurFocal = float(atoi(pkti + c));
          }
          c = 9;
          if (((int)strlen(pkti) > c) && (!strncasecmp(pkti, "Aperture:", c)))
          {
            while (((pkti[c] == ' ') || (pkti[c] == 'f')) && (c < (int)strlen(pkti)))
            {
              c++;
            }
            ilm.CurAp = float(atof(pkti + c));
          }
          c = 10;
          if (((int)strlen(pkti) > c) && (!strncasecmp(pkti, "ISO Speed:", c)))
          {
            iso_speed = float(atoi(pkti + c));
          }
          c = 13;
          if (((int)strlen(pkti) > c) && (!strncasecmp(pkti, "Focal Length:", c)))
          {
            ilm.CurFocal = float(atoi(pkti + c));
          }
          c = 13;
          if (((int)strlen(pkti) > c) && (!strncasecmp(pkti, "Max Aperture:", c)))
          {
            while (((pkti[c] == ' ') || (pkti[c] == 'f')) && (c < (int)strlen(pkti)))
            {
              c++;
            }
            ilm.MaxAp4CurFocal = float(atof(pkti + c));
          }
          c = 13;
          if (((int)strlen(pkti) > c) && (!strncasecmp(pkti, "Min Aperture:", c)))
          {
            while (((pkti[c] == ' ') || (pkti[c] == 'f')) && (c < (int)strlen(pkti)))
            {
              c++;
            }
            ilm.MinAp4CurFocal = float(atof(pkti + c));
          }
#ifdef LIBRAW_WIN32_CALLS
          pkti = strtok(NULL, "\x0a");
#else
          pkti = strtok_r(NULL, "\x0a", &last);
#endif
        }
      }
    }

    else if (tag == 0x03f3) // 1011
      imCommon.FlashEC = getrealf(type);

    else if (tag == 0x03fc) // 1020
    {
      wbi = getint(type);
      if ((wbi >= 0) && (wbi < 6) && (wbi != -2))
        wbi = wbtag_dcr[wbi];
    }
    else if (tag == 0x03fd && len == 72) // 1021
    {                                    /* WB set in software */
      fseek(ifp, 40, SEEK_CUR);
      FORC3 cam_mul[c] = 2048.0f / fMAX(1.0f, get2());
      wbi = -2;
    }

    else if ((tag == 0x0406) && (len == 1)) // 1030
      imCommon.CameraTemperature = getrealf(type);
    else if ((tag == 0x0413) && (len == 1)) // 1043
      imCommon.SensorTemperature = getrealf(type);
    else if (tag == 0x0848) // 2120
      Kodak_DCR_WBtags(LIBRAW_WBI_Daylight, type, wbi);
    else if (tag == 0x0849) // 2121
      Kodak_DCR_WBtags(LIBRAW_WBI_Tungsten, type, wbi);
    else if (tag == 0x084a) // 2122
      Kodak_DCR_WBtags(LIBRAW_WBI_Fluorescent, type, wbi);
    else if (tag == 0x084b) // 2123
      Kodak_DCR_WBtags(LIBRAW_WBI_Flash, type, wbi);
    else if (tag == 0x084c) // 2124
      Kodak_DCR_WBtags(LIBRAW_WBI_Custom, type, wbi);
    else if (tag == 0x084d) // 2125
    {
      if (wbi == -1)
        wbi = LIBRAW_WBI_Auto;
      Kodak_DCR_WBtags(LIBRAW_WBI_Auto, type, wbi);
    }
    else if (tag == 0x089f) // 2207
      imKodak.ISOCalibrationGain = getrealf(type);
    else if (tag == 0x0903) // 2307
      imKodak.AnalogISO = iso_speed = getrealf(type);
    else if (tag == 0x090d) // 2317
      linear_table(len);
    else if (tag == 0x09ce) // 2510
      stmread(imgdata.shootinginfo.InternalBodySerial, len, ifp);
    else if (tag == 0x0e92) // 3730
    {
      imKodak.val018percent = get2();
      imgdata.color.linear_max[0] = imgdata.color.linear_max[1] =
          imgdata.color.linear_max[2] = imgdata.color.linear_max[3] =
              (int)(((float)imKodak.val018percent) / 18.0f * 170.0f);
    }
    else if (tag == 0x0e93) // 3731
      imgdata.color.linear_max[0] = imgdata.color.linear_max[1] =
          imgdata.color.linear_max[2] = imgdata.color.linear_max[3] =
              imKodak.val170percent = get2();
    else if (tag == 0x0e94) // 3732
      imKodak.val100percent = get2();
    /*
        else if (tag == 0x1784)    // 6020
          iso_speed = getint(type);
    */
    else if (tag == 0xfa00) // 64000
      stmread(imgdata.shootinginfo.BodySerial, len, ifp);
    else if (tag == 0xfa0d) // 64013
    {
      wbi = fgetc(ifp);
      if ((wbi >= 0) && (wbi < 7))
        wbi = wbtag_kdc[wbi];
    }
    else if (tag == 0xfa13) // 64019
      width = getint(type);
    else if (tag == 0xfa14) // 64020
      height = (getint(type) + 1) & -2;
    /*
          height = getint(type);

        else if (tag == 0xfa16)  // 64022
          raw_width = get2();
        else if (tag == 0xfa17)  // 64023
          raw_height = get2();
    */
    else if (tag == 0xfa18) // 64024
    {
      imKodak.offset_left = getint(LIBRAW_EXIFTAG_TYPE_SSHORT);
      if (type != LIBRAW_EXIFTAG_TYPE_SSHORT)
        imKodak.offset_left += 1;
    }
    else if (tag == 0xfa19) // 64025
    {
      imKodak.offset_top = getint(LIBRAW_EXIFTAG_TYPE_SSHORT);
      if (type != LIBRAW_EXIFTAG_TYPE_SSHORT)
        imKodak.offset_top += 1;
    }

    else if (tag == 0xfa25) // 64037
      Kodak_KDC_WBtags(LIBRAW_WBI_Auto, wbi);
    else if (tag == 0xfa27) // 64039
      Kodak_KDC_WBtags(LIBRAW_WBI_Tungsten, wbi);
    else if (tag == 0xfa28) // 64040
      Kodak_KDC_WBtags(LIBRAW_WBI_Fluorescent, wbi);
    else if (tag == 0xfa29) // 64041
      Kodak_KDC_WBtags(LIBRAW_WBI_Daylight, wbi);
    else if (tag == 0xfa2a) // 64042
      Kodak_KDC_WBtags(LIBRAW_WBI_Shade, wbi);

    else if (tag == 0xfa31) // 64049
      imgdata.sizes.raw_inset_crops[0].cwidth = get2();
    else if (tag == 0xfa32) // 64050
      imgdata.sizes.raw_inset_crops[0].cheight = get2();
    else if (tag == 0xfa3e) // 64062
      imgdata.sizes.raw_inset_crops[0].cleft = get2();
    else if (tag == 0xfa3f) // 64063
      imgdata.sizes.raw_inset_crops[0].ctop = get2();

    else if (((tag == 0x07e4) || (tag == 0xfb01)) &&
             (len == 9)) // 2020 or 64257
    {
      if (KodakIllumMatrix(type, (float *)imKodak.romm_camDaylight))
      {
        romm_coeff(imKodak.romm_camDaylight);
      }
    }
    else if (((tag == 0x07e5) || (tag == 0xfb02)) &&
             (len == 9)) // 2021 or 64258
      KodakIllumMatrix(type, (float *)imKodak.romm_camTungsten);
    else if (((tag == 0x07e6) || (tag == 0xfb03)) &&
             (len == 9)) // 2022 or 64259
      KodakIllumMatrix(type, (float *)imKodak.romm_camFluorescent);
    else if (((tag == 0x07e7) || (tag == 0xfb04)) &&
             (len == 9)) // 2023 or 64260
      KodakIllumMatrix(type, (float *)imKodak.romm_camFlash);
    else if (((tag == 0x07e8) || (tag == 0xfb05)) &&
             (len == 9)) // 2024 or 64261
      KodakIllumMatrix(type, (float *)imKodak.romm_camCustom);
    else if (((tag == 0x07e9) || (tag == 0xfb06)) &&
             (len == 9)) // 2025 or 64262
      KodakIllumMatrix(type, (float *)imKodak.romm_camAuto);

    fseek(ifp, save, SEEK_SET);
  }
}
