Commit message: Secunia SA75000 advisory: several buffer overruns
CVE: CVE-2017-6887
CWE: CWE-476
Vulnerability description: A boundary error within the "parse_tiff_ifd()" function (internal/dcraw_common.cpp) in LibRaw versions before 0.18.2 can be exploited to cause a memory corruption via e.g. a specially crafted KDC file with model set to "DSLR-A100" and containing multiple sequences of 0x100 and 0x14A TAGs.

Project: LibRaw
File: dcraw.c

void CLASS parse_makernote(int base, int uptag)
{
  unsigned offset = 0, entries, tag, type, len, save, c;
  unsigned ver97 = 0, serial = 0, i, wbi = 0, wb[4] = {0, 0, 0, 0};
  uchar buf97[324], ci, cj, ck;
  short morder, sorder = order;
  char buf[10];
  unsigned SamsungKey[11];
  uchar NikonKey;

#ifdef LIBRAW_LIBRARY_BUILD
  unsigned custom_serial = 0;
  unsigned NikonLensDataVersion = 0;
  unsigned lenNikonLensData = 0;

  unsigned NikonFlashInfoVersion = 0;

  uchar *CanonCameraInfo;
  unsigned lenCanonCameraInfo = 0;

  uchar *table_buf;
  uchar *table_buf_0x9050;
  ushort table_buf_0x9050_present = 0;
  uchar *table_buf_0x940c;
  ushort table_buf_0x940c_present = 0;

  INT64 fsize = ifp->size();
#endif
  /*
     The MakerNote might have its own TIFF header (possibly with
     its own byte-order!), or it might just be a table.
   */
  if (!strncmp(make, "Nokia", 5))
    return;
  fread(buf, 1, 10, ifp);
  if (!strncmp(buf, "KDK", 3) || /* these aren't TIFF tables */
      !strncmp(buf, "VER", 3) || !strncmp(buf, "IIII", 4) || !strncmp(buf, "MMMM", 4))
    return;
  if (!strncmp(buf, "KC", 2) || /* Konica KD-400Z, KD-510Z */
      !strncmp(buf, "MLY", 3))
  { /* Minolta DiMAGE G series */
    order = 0x4d4d;
    while ((i = ftell(ifp)) < data_offset && i < 16384)
    {
      wb[0] = wb[2];
      wb[2] = wb[1];
      wb[1] = wb[3];
      wb[3] = get2();
      if (wb[1] == 256 && wb[3] == 256 && wb[0] > 256 && wb[0] < 640 && wb[2] > 256 && wb[2] < 640)
        FORC4 cam_mul[c] = wb[c];
    }
    goto quit;
  }
  if (!strcmp(buf, "Nikon"))
  {
    base = ftell(ifp);
    order = get2();
    if (get2() != 42)
      goto quit;
    offset = get4();
    fseek(ifp, offset - 8, SEEK_CUR);
  }
  else if (!strcmp(buf, "OLYMPUS") || !strcmp(buf, "PENTAX "))
  {
    base = ftell(ifp) - 10;
    fseek(ifp, -2, SEEK_CUR);
    order = get2();
    if (buf[0] == 'O')
      get2();
  }
  else if (!strncmp(buf, "SONY", 4) || !strcmp(buf, "Panasonic"))
  {
    goto nf;
  }
  else if (!strncmp(buf, "FUJIFILM", 8))
  {
    base = ftell(ifp) - 10;
  nf:
    order = 0x4949;
    fseek(ifp, 2, SEEK_CUR);
  }
  else if (!strcmp(buf, "OLYMP") || !strcmp(buf, "LEICA") || !strcmp(buf, "Ricoh") || !strcmp(buf, "EPSON"))
    fseek(ifp, -2, SEEK_CUR);
  else if (!strcmp(buf, "AOC") || !strcmp(buf, "QVC"))
    fseek(ifp, -4, SEEK_CUR);
  else
  {
    fseek(ifp, -10, SEEK_CUR);
    if (!strncmp(make, "SAMSUNG", 7))
      base = ftell(ifp);
  }

  // adjust pos & base for Leica M8/M9/M Mono tags and dir in tag 0x3400
  if (!strncasecmp(make, "LEICA", 5))
  {
    if (!strncmp(model, "M8", 2) || !strncasecmp(model, "Leica M8", 8) || !strncasecmp(model, "LEICA X", 7))
    {
      base = ftell(ifp) - 8;
    }
    else if (!strncasecmp(model, "LEICA M (Typ 240)", 17))
    {
      base = 0;
    }
    else if (!strncmp(model, "M9", 2) || !strncasecmp(model, "Leica M9", 8) || !strncasecmp(model, "M Monochrom", 11) ||
             !strncasecmp(model, "Leica M Monochrom", 11))
    {
      if (!uptag)
      {
        base = ftell(ifp) - 10;
        fseek(ifp, 8, SEEK_CUR);
      }
      else if (uptag == 0x3400)
      {
        fseek(ifp, 10, SEEK_CUR);
        base += 10;
      }
    }
    else if (!strncasecmp(model, "LEICA T", 7))
    {
      base = ftell(ifp) - 8;
#ifdef LIBRAW_LIBRARY_BUILD
      imgdata.lens.makernotes.CameraMount = LIBRAW_MOUNT_Leica_T;
#endif
    }
#ifdef LIBRAW_LIBRARY_BUILD
    else if (!strncasecmp(model, "LEICA SL", 8))
    {
      imgdata.lens.makernotes.CameraMount = LIBRAW_MOUNT_Leica_SL;
      imgdata.lens.makernotes.CameraFormat = LIBRAW_FORMAT_FF;
    }
#endif
  }

  entries = get2();
  if (entries > 1000)
    return;
  morder = order;

  while (entries--)
  {
    order = morder;
    tiff_get(base, &tag, &type, &len, &save);
    tag |= uptag << 16;

#ifdef LIBRAW_LIBRARY_BUILD
    INT64 _pos = ftell(ifp);
    if (len > 8 && _pos + len > 2 * fsize)
      continue;
    if (!strncmp(make, "Canon", 5))
    {
      if (tag == 0x000d && len < 256000) // camera info
      {
        CanonCameraInfo = (uchar *)malloc(len);
        fread(CanonCameraInfo, len, 1, ifp);
        lenCanonCameraInfo = len;
      }

      else if (tag == 0x10) // Canon ModelID
      {
        unique_id = get4();
        if (unique_id == 0x03740000)
          unique_id = 0x80000374; // M3
        if (unique_id == 0x03840000)
          unique_id = 0x80000384; // M10
        if (unique_id == 0x03940000)
          unique_id = 0x80000394; // M5
        setCanonBodyFeatures(unique_id);
        if (lenCanonCameraInfo)
        {
          processCanonCameraInfo(unique_id, CanonCameraInfo, lenCanonCameraInfo);
          free(CanonCameraInfo);
          CanonCameraInfo = 0;
          lenCanonCameraInfo = 0;
        }
      }

      else
        parseCanonMakernotes(tag, type, len);
    }

    else if (!strncmp(make, "FUJI", 4))
    {
      if (tag == 0x0010)
      {
        char FujiSerial[sizeof(imgdata.shootinginfo.InternalBodySerial)];
        char *words[4];
        char yy[2], mm[3], dd[3], ystr[16], ynum[16];
        int year, nwords, ynum_len;
        unsigned c;
        stmread(FujiSerial, len, ifp);
        nwords = getwords(FujiSerial, words, 4, sizeof(imgdata.shootinginfo.InternalBodySerial));
        for (int i = 0; i < nwords; i++)
        {
          mm[2] = dd[2] = 0;
          if (strnlen(words[i], sizeof(imgdata.shootinginfo.InternalBodySerial) - 1) < 18)
            if (i == 0)
              strncpy(imgdata.shootinginfo.InternalBodySerial, words[0],
                      sizeof(imgdata.shootinginfo.InternalBodySerial) - 1);
            else
            {
              char tbuf[sizeof(imgdata.shootinginfo.InternalBodySerial)];
              snprintf(tbuf, sizeof(tbuf), "%s %s", imgdata.shootinginfo.InternalBodySerial, words[i]);
              strncpy(imgdata.shootinginfo.InternalBodySerial, tbuf,
                      sizeof(imgdata.shootinginfo.InternalBodySerial) - 1);
            }
          else
          {
            strncpy(dd, words[i] + strnlen(words[i], sizeof(imgdata.shootinginfo.InternalBodySerial) - 1) - 14, 2);
            strncpy(mm, words[i] + strnlen(words[i], sizeof(imgdata.shootinginfo.InternalBodySerial) - 1) - 16, 2);
            strncpy(yy, words[i] + strnlen(words[i], sizeof(imgdata.shootinginfo.InternalBodySerial) - 1) - 18, 2);
            year = (yy[0] - '0') * 10 + (yy[1] - '0');
            if (year < 70)
              year += 2000;
            else
              year += 1900;

            ynum_len = (int)strnlen(words[i], sizeof(imgdata.shootinginfo.InternalBodySerial) - 1) - 18;
            strncpy(ynum, words[i], ynum_len);
            ynum[ynum_len] = 0;
            for (int j = 0; ynum[j] && ynum[j + 1] && sscanf(ynum + j, "%2x", &c); j += 2)
              ystr[j / 2] = c;
            ystr[ynum_len / 2 + 1] = 0;
            strcpy(model2, ystr);

            if (i == 0)
            {
              char tbuf[sizeof(imgdata.shootinginfo.InternalBodySerial)];

              if (nwords == 1)
                snprintf(tbuf, sizeof(tbuf), "%s %s %d:%s:%s",
                         words[0] + strnlen(words[0], sizeof(imgdata.shootinginfo.InternalBodySerial) - 1) - 12, ystr,
                         year, mm, dd);

              else
                snprintf(tbuf, sizeof(tbuf), "%s %d:%s:%s %s", ystr, year, mm, dd,
                         words[0] + strnlen(words[0], sizeof(imgdata.shootinginfo.InternalBodySerial) - 1) - 12);

              strncpy(imgdata.shootinginfo.InternalBodySerial, tbuf,
                      sizeof(imgdata.shootinginfo.InternalBodySerial) - 1);
            }
            else
            {
              char tbuf[sizeof(imgdata.shootinginfo.InternalBodySerial)];
              snprintf(tbuf, sizeof(tbuf), "%s %s %d:%s:%s %s", imgdata.shootinginfo.InternalBodySerial, ystr, year, mm,
                       dd, words[i] + strnlen(words[i], sizeof(imgdata.shootinginfo.InternalBodySerial) - 1) - 12);
              strncpy(imgdata.shootinginfo.InternalBodySerial, tbuf,
                      sizeof(imgdata.shootinginfo.InternalBodySerial) - 1);
            }
          }
        }
      }
      else
        parseFujiMakernotes(tag, type);
    }

    else if (!strncasecmp(make, "LEICA", 5))
    {
      if (((tag == 0x035e) || (tag == 0x035f)) && (type == 10) && (len == 9))
      {
        int ind = tag == 0x035e ? 0 : 1;
        for (int j = 0; j < 3; j++)
          FORCC imgdata.color.dng_color[ind].forwardmatrix[j][c] = getreal(type);
      }

      if ((tag == 0x0303) && (type != 4))
      {
        stmread(imgdata.lens.makernotes.Lens, len, ifp);
      }

      if ((tag == 0x3405) || (tag == 0x0310) || (tag == 0x34003405))
      {
        imgdata.lens.makernotes.LensID = get4();
        imgdata.lens.makernotes.LensID =
            ((imgdata.lens.makernotes.LensID >> 2) << 8) | (imgdata.lens.makernotes.LensID & 0x3);
        if (imgdata.lens.makernotes.LensID != -1)
        {
          if ((model[0] == 'M') || !strncasecmp(model, "LEICA M", 7))
          {
            imgdata.lens.makernotes.CameraMount = LIBRAW_MOUNT_Leica_M;
            if (imgdata.lens.makernotes.LensID)
              imgdata.lens.makernotes.LensMount = LIBRAW_MOUNT_Leica_M;
          }
          else if ((model[0] == 'S') || !strncasecmp(model, "LEICA S", 7))
          {
            imgdata.lens.makernotes.CameraMount = LIBRAW_MOUNT_Leica_S;
            if (imgdata.lens.makernotes.Lens[0])
              imgdata.lens.makernotes.LensMount = LIBRAW_MOUNT_Leica_S;
          }
        }
      }

      else if (((tag == 0x0313) || (tag == 0x34003406)) && (fabs(imgdata.lens.makernotes.CurAp) < 0.17f) &&
               ((type == 10) || (type == 5)))
      {
        imgdata.lens.makernotes.CurAp = getreal(type);
        if (imgdata.lens.makernotes.CurAp > 126.3)
          imgdata.lens.makernotes.CurAp = 0.0f;
      }

      else if (tag == 0x3400)
      {
        parse_makernote(base, 0x3400);
      }
    }

    else if (!strncmp(make, "NIKON", 5))
    {
      if (tag == 0x000a)
      {
        imgdata.lens.makernotes.LensMount = LIBRAW_MOUNT_FixedLens;
        imgdata.lens.makernotes.CameraMount = LIBRAW_MOUNT_FixedLens;
      }
      else if (tag == 0x0012)
      {
        char a, b, c;
        a = fgetc(ifp);
        b = fgetc(ifp);
        c = fgetc(ifp);
        if (c)
          imgdata.other.FlashEC = (float)(a * b) / (float)c;
      }
      else if (tag == 0x0082) // lens attachment
      {
        stmread(imgdata.lens.makernotes.Attachment, len, ifp);
      }
      else if (tag == 0x0083) // lens type
      {
        imgdata.lens.nikon.NikonLensType = fgetc(ifp);
      }
      else if (tag == 0x0084) // lens
      {
        imgdata.lens.makernotes.MinFocal = getreal(type);
        imgdata.lens.makernotes.MaxFocal = getreal(type);
        imgdata.lens.makernotes.MaxAp4MinFocal = getreal(type);
        imgdata.lens.makernotes.MaxAp4MaxFocal = getreal(type);
      }
      else if (tag == 0x008b) // lens f-stops
      {
        uchar a, b, c;
        a = fgetc(ifp);
        b = fgetc(ifp);
        c = fgetc(ifp);
        if (c)
        {
          imgdata.lens.nikon.NikonLensFStops = a * b * (12 / c);
          imgdata.lens.makernotes.LensFStops = (float)imgdata.lens.nikon.NikonLensFStops / 12.0f;
        }
      }
      else if (tag == 0x0093)
      {
        i = get2();
        if ((i == 7) || (i == 9))
        {
          imgdata.lens.makernotes.LensMount = LIBRAW_MOUNT_FixedLens;
          imgdata.lens.makernotes.CameraMount = LIBRAW_MOUNT_FixedLens;
        }
      }
      else if (tag == 0x0098) // contains lens data
      {
        for (i = 0; i < 4; i++)
        {
          NikonLensDataVersion = NikonLensDataVersion * 10 + fgetc(ifp) - '0';
        }
        switch (NikonLensDataVersion)
        {
        case 100:
          lenNikonLensData = 9;
          break;
        case 101:
        case 201: // encrypted, starting from v.201
        case 202:
        case 203:
          lenNikonLensData = 15;
          break;
        case 204:
          lenNikonLensData = 16;
          break;
        case 400:
          lenNikonLensData = 459;
          break;
        case 401:
          lenNikonLensData = 590;
          break;
        case 402:
          lenNikonLensData = 509;
          break;
        case 403:
          lenNikonLensData = 879;
          break;
        }
        if (lenNikonLensData > 0)
        {
          table_buf = (uchar *)malloc(lenNikonLensData);
          fread(table_buf, lenNikonLensData, 1, ifp);
          if ((NikonLensDataVersion < 201) && lenNikonLensData)
          {
            processNikonLensData(table_buf, lenNikonLensData);
            free(table_buf);
            lenNikonLensData = 0;
          }
        }
      }
      else if (tag == 0x00a0)
      {
        stmread(imgdata.shootinginfo.BodySerial, len, ifp);
      }
      else if (tag == 0x00a8) // contains flash data
      {
        for (i = 0; i < 4; i++)
        {
          NikonFlashInfoVersion = NikonFlashInfoVersion * 10 + fgetc(ifp) - '0';
        }
      }
    }

    else if (!strncmp(make, "OLYMPUS", 7))
    {
      switch (tag)
      {
      case 0x0404:
      case 0x101a:
      case 0x20100101:
        if (!imgdata.shootinginfo.BodySerial[0])
          stmread(imgdata.shootinginfo.BodySerial, len, ifp);
        break;
      case 0x20100102:
        if (!imgdata.shootinginfo.InternalBodySerial[0])
          stmread(imgdata.shootinginfo.InternalBodySerial, len, ifp);
        break;
      case 0x0207:
      case 0x20100100:
      {
        uchar sOlyID[8];
        unsigned long long OlyID;
        fread(sOlyID, MIN(len, 7), 1, ifp);
        sOlyID[7] = 0;
        OlyID = sOlyID[0];
        i = 1;
        while (i < 7 && sOlyID[i])
        {
          OlyID = OlyID << 8 | sOlyID[i];
          i++;
        }
        setOlympusBodyFeatures(OlyID);
      }
      break;
      case 0x1002:
        imgdata.lens.makernotes.CurAp = powf64(2.0f, getreal(type) / 2);
        break;
      case 0x20401112:
        imgdata.makernotes.olympus.OlympusCropID = get2();
        break;
      case 0x20401113:
        FORC4 imgdata.makernotes.olympus.OlympusFrame[c] = get2();
        break;
      case 0x20100201:
      {
        unsigned long long oly_lensid[3];
        oly_lensid[0] = fgetc(ifp);
        fgetc(ifp);
        oly_lensid[1] = fgetc(ifp);
        oly_lensid[2] = fgetc(ifp);
        imgdata.lens.makernotes.LensID = (oly_lensid[0] << 16) | (oly_lensid[1] << 8) | oly_lensid[2];
      }
        imgdata.lens.makernotes.LensMount = LIBRAW_MOUNT_FT;
        imgdata.lens.makernotes.LensFormat = LIBRAW_FORMAT_FT;
        if (((imgdata.lens.makernotes.LensID < 0x20000) || (imgdata.lens.makernotes.LensID > 0x4ffff)) &&
            (imgdata.lens.makernotes.LensID & 0x10))
        {
          imgdata.lens.makernotes.LensMount = LIBRAW_MOUNT_mFT;
        }
        break;
      case 0x20100202:
        stmread(imgdata.lens.LensSerial, len, ifp);
        break;
      case 0x20100203:
        stmread(imgdata.lens.makernotes.Lens, len, ifp);
        break;
      case 0x20100205:
        imgdata.lens.makernotes.MaxAp4MinFocal = powf64(sqrt(2.0f), get2() / 256.0f);
        break;
      case 0x20100206:
        imgdata.lens.makernotes.MaxAp4MaxFocal = powf64(sqrt(2.0f), get2() / 256.0f);
        break;
      case 0x20100207:
        imgdata.lens.makernotes.MinFocal = (float)get2();
        break;
      case 0x20100208:
        imgdata.lens.makernotes.MaxFocal = (float)get2();
        if (imgdata.lens.makernotes.MaxFocal > 1000.0f)
          imgdata.lens.makernotes.MaxFocal = imgdata.lens.makernotes.MinFocal;
        break;
      case 0x2010020a:
        imgdata.lens.makernotes.MaxAp4CurFocal = powf64(sqrt(2.0f), get2() / 256.0f);
        break;
      case 0x20100301:
        imgdata.lens.makernotes.TeleconverterID = fgetc(ifp) << 8;
        fgetc(ifp);
        imgdata.lens.makernotes.TeleconverterID = imgdata.lens.makernotes.TeleconverterID | fgetc(ifp);
        break;
      case 0x20100303:
        stmread(imgdata.lens.makernotes.Teleconverter, len, ifp);
        break;
      case 0x20100403:
        stmread(imgdata.lens.makernotes.Attachment, len, ifp);
        break;
      }
    }

    else if ((!strncmp(make, "PENTAX", 6) || !strncmp(make, "RICOH", 5)) && !strncmp(model, "GR", 2))
    {
      if (tag == 0x0005)
      {
        char buffer[17];
        int count = 0;
        fread(buffer, 16, 1, ifp);
        buffer[16] = 0;
        for (int i = 0; i < 16; i++)
        {
          //    	        sprintf(imgdata.shootinginfo.InternalBodySerial+2*i, "%02x", buffer[i]);
          if ((isspace(buffer[i])) || (buffer[i] == 0x2D) || (isalnum(buffer[i])))
            count++;
        }
        if (count == 16)
        {
          sprintf(imgdata.shootinginfo.BodySerial, "%8s", buffer + 8);
          buffer[8] = 0;
          sprintf(imgdata.shootinginfo.InternalBodySerial, "%8s", buffer);
        }
        else
        {
          sprintf(imgdata.shootinginfo.BodySerial, "%02x%02x%02x%02x", buffer[4], buffer[5], buffer[6], buffer[7]);
          sprintf(imgdata.shootinginfo.InternalBodySerial, "%02x%02x%02x%02x", buffer[8], buffer[9], buffer[10],
                  buffer[11]);
        }
      }
      else if ((tag == 0x1001) && (type == 3))
      {
        imgdata.lens.makernotes.CameraMount = LIBRAW_MOUNT_FixedLens;
        imgdata.lens.makernotes.LensMount = LIBRAW_MOUNT_FixedLens;
        imgdata.lens.makernotes.CameraFormat = LIBRAW_FORMAT_APSC;
        imgdata.lens.makernotes.LensID = -1;
        imgdata.lens.makernotes.FocalType = 1;
      }

      else if ((tag == 0x100b) && (type == 10))
      {
        imgdata.other.FlashEC = getreal(type);
      }

      else if ((tag == 0x1017) && (get2() == 2))
      {
        strcpy(imgdata.lens.makernotes.Attachment, "Wide-Angle Adapter");
      }
      else if (tag == 0x1500)
      {
        imgdata.lens.makernotes.CurFocal = getreal(type);
      }
    }

    else if (!strncmp(make, "RICOH", 5) && strncmp(model, "PENTAX", 6))
    {
      if ((tag == 0x0005) && !strncmp(model, "GXR", 3))
      {
        char buffer[9];
        buffer[8] = 0;
        fread(buffer, 8, 1, ifp);
        sprintf(imgdata.shootinginfo.InternalBodySerial, "%8s", buffer);
      }

      else if ((tag == 0x100b) && (type == 10))
      {
        imgdata.other.FlashEC = getreal(type);
      }

      else if ((tag == 0x1017) && (get2() == 2))
      {
        strcpy(imgdata.lens.makernotes.Attachment, "Wide-Angle Adapter");
      }

      else if (tag == 0x1500)
      {
        imgdata.lens.makernotes.CurFocal = getreal(type);
      }

      else if ((tag == 0x2001) && !strncmp(model, "GXR", 3))
      {
        short ntags, cur_tag;
        fseek(ifp, 20, SEEK_CUR);
        ntags = get2();
        cur_tag = get2();
        while (cur_tag != 0x002c)
        {
          fseek(ifp, 10, SEEK_CUR);
          cur_tag = get2();
        }
        fseek(ifp, 6, SEEK_CUR);
        fseek(ifp, get4() + 20, SEEK_SET);
        stread(imgdata.shootinginfo.BodySerial, 12, ifp);
        get2();
        imgdata.lens.makernotes.LensID = getc(ifp) - '0';
        switch (imgdata.lens.makernotes.LensID)
        {
        case 1:
        case 2:
        case 3:
        case 5:
        case 6:
          imgdata.lens.makernotes.CameraMount = LIBRAW_MOUNT_FixedLens;
          imgdata.lens.makernotes.LensMount = LIBRAW_MOUNT_RicohModule;
          break;
        case 8:
          imgdata.lens.makernotes.CameraMount = LIBRAW_MOUNT_Leica_M;
          imgdata.lens.makernotes.CameraFormat = LIBRAW_FORMAT_APSC;
          imgdata.lens.makernotes.LensID = -1;
          break;
        default:
          imgdata.lens.makernotes.LensID = -1;
        }
        fseek(ifp, 17, SEEK_CUR);
        stread(imgdata.lens.LensSerial, 12, ifp);
      }
    }

    else if ((!strncmp(make, "PENTAX", 6) || !strncmp(model, "PENTAX", 6) ||
              (!strncmp(make, "SAMSUNG", 7) && dng_version)) &&
             strncmp(model, "GR", 2))
    {
      if (tag == 0x0005)
      {
        unique_id = get4();
        setPentaxBodyFeatures(unique_id);
      }
      else if (tag == 0x0013)
      {
        imgdata.lens.makernotes.CurAp = (float)get2() / 10.0f;
      }
      else if (tag == 0x0014)
      {
        PentaxISO(get2());
      }
      else if (tag == 0x001d)
      {
        imgdata.lens.makernotes.CurFocal = (float)get4() / 100.0f;
      }
      else if (tag == 0x003f)
      {
        imgdata.lens.makernotes.LensID = fgetc(ifp) << 8 | fgetc(ifp);
      }
      else if (tag == 0x004d)
      {
        if (type == 9)
          imgdata.other.FlashEC = getreal(type) / 256.0f;
        else
          imgdata.other.FlashEC = (float)((signed short)fgetc(ifp)) / 6.0f;
      }
      else if (tag == 0x007e)
      {
        imgdata.color.linear_max[0] = imgdata.color.linear_max[1] = imgdata.color.linear_max[2] =
            imgdata.color.linear_max[3] = (long)(-1) * get4();
      }
      else if (tag == 0x0207)
      {
        if (len < 65535) // Safety belt
          PentaxLensInfo(imgdata.lens.makernotes.CamID, len);
      }
      else if (tag == 0x020d)
      {
        FORC4 imgdata.color.WB_Coeffs[LIBRAW_WBI_Daylight][c ^ (c >> 1)] = get2();
      }
      else if (tag == 0x020e)
      {
        FORC4 imgdata.color.WB_Coeffs[LIBRAW_WBI_Shade][c ^ (c >> 1)] = get2();
      }
      else if (tag == 0x020f)
      {
        FORC4 imgdata.color.WB_Coeffs[LIBRAW_WBI_Cloudy][c ^ (c >> 1)] = get2();
      }
      else if (tag == 0x0210)
      {
        FORC4 imgdata.color.WB_Coeffs[LIBRAW_WBI_Tungsten][c ^ (c >> 1)] = get2();
      }
      else if (tag == 0x0211)
      {
        FORC4 imgdata.color.WB_Coeffs[LIBRAW_WBI_FL_D][c ^ (c >> 1)] = get2();
      }
      else if (tag == 0x0212)
      {
        FORC4 imgdata.color.WB_Coeffs[LIBRAW_WBI_FL_N][c ^ (c >> 1)] = get2();
      }
      else if (tag == 0x0213)
      {
        FORC4 imgdata.color.WB_Coeffs[LIBRAW_WBI_FL_W][c ^ (c >> 1)] = get2();
      }
      else if (tag == 0x0214)
      {
        FORC4 imgdata.color.WB_Coeffs[LIBRAW_WBI_Flash][c ^ (c >> 1)] = get2();
      }
      else if (tag == 0x0221)
      {
        int nWB = get2();
        if (nWB <= sizeof(imgdata.color.WBCT_Coeffs) / sizeof(imgdata.color.WBCT_Coeffs[0]))
          for (int i = 0; i < nWB; i++)
          {
            imgdata.color.WBCT_Coeffs[i][0] = (unsigned)0xcfc6 - get2();
            fseek(ifp, 2, SEEK_CUR);
            imgdata.color.WBCT_Coeffs[i][1] = get2();
            imgdata.color.WBCT_Coeffs[i][2] = imgdata.color.WBCT_Coeffs[i][4] = 0x2000;
            imgdata.color.WBCT_Coeffs[i][3] = get2();
          }
      }
      else if (tag == 0x0215)
      {
        fseek(ifp, 16, SEEK_CUR);
        sprintf(imgdata.shootinginfo.InternalBodySerial, "%d", get4());
      }
      else if (tag == 0x0229)
      {
        stmread(imgdata.shootinginfo.BodySerial, len, ifp);
      }
      else if (tag == 0x022d)
      {
        fseek(ifp, 2, SEEK_CUR);
        FORC4 imgdata.color.WB_Coeffs[LIBRAW_WBI_Daylight][c ^ (c >> 1)] = get2();
        getc(ifp);
        FORC4 imgdata.color.WB_Coeffs[LIBRAW_WBI_Shade][c ^ (c >> 1)] = get2();
        getc(ifp);
        FORC4 imgdata.color.WB_Coeffs[LIBRAW_WBI_Cloudy][c ^ (c >> 1)] = get2();
        getc(ifp);
        FORC4 imgdata.color.WB_Coeffs[LIBRAW_WBI_Tungsten][c ^ (c >> 1)] = get2();
        getc(ifp);
        FORC4 imgdata.color.WB_Coeffs[LIBRAW_WBI_FL_D][c ^ (c >> 1)] = get2();
        getc(ifp);
        FORC4 imgdata.color.WB_Coeffs[LIBRAW_WBI_FL_N][c ^ (c >> 1)] = get2();
        getc(ifp);
        FORC4 imgdata.color.WB_Coeffs[LIBRAW_WBI_FL_W][c ^ (c >> 1)] = get2();
        getc(ifp);
        FORC4 imgdata.color.WB_Coeffs[LIBRAW_WBI_Flash][c ^ (c >> 1)] = get2();
        getc(ifp);
        FORC4 imgdata.color.WB_Coeffs[LIBRAW_WBI_FL_L][c ^ (c >> 1)] = get2();
      }
      else if (tag == 0x0239) // Q-series lens info (LensInfoQ)
      {
        char LensInfo[20];
        fseek(ifp, 2, SEEK_CUR);
        stread(imgdata.lens.makernotes.Lens, 30, ifp);
        strcat(imgdata.lens.makernotes.Lens, " ");
        stread(LensInfo, 20, ifp);
        strcat(imgdata.lens.makernotes.Lens, LensInfo);
      }
    }

    else if (!strncmp(make, "SAMSUNG", 7))
    {
      if (tag == 0x0002)
      {
        if (get4() == 0x2000)
        {
          imgdata.lens.makernotes.CameraMount = LIBRAW_MOUNT_Samsung_NX;
        }
        else if (!strncmp(model, "NX mini", 7))
        {
          imgdata.lens.makernotes.CameraMount = LIBRAW_MOUNT_Samsung_NX_M;
        }
        else
        {
          imgdata.lens.makernotes.CameraMount = LIBRAW_MOUNT_FixedLens;
          imgdata.lens.makernotes.LensMount = LIBRAW_MOUNT_FixedLens;
        }
      }
      else if (tag == 0x0003)
      {
        unique_id = imgdata.lens.makernotes.CamID = get4();
      }
      else if (tag == 0xa002)
      {
        stmread(imgdata.shootinginfo.BodySerial, len, ifp);
      }
      else if (tag == 0xa003)
      {
        imgdata.lens.makernotes.LensID = get2();
        if (imgdata.lens.makernotes.LensID)
          imgdata.lens.makernotes.LensMount = LIBRAW_MOUNT_Samsung_NX;
      }
      else if (tag == 0xa005)
      {
        stmread(imgdata.lens.InternalLensSerial, len, ifp);
      }
      else if (tag == 0xa019)
      {
        imgdata.lens.makernotes.CurAp = getreal(type);
      }
      else if (tag == 0xa01a)
      {
        imgdata.lens.makernotes.FocalLengthIn35mmFormat = get4() / 10.0f;
        if (imgdata.lens.makernotes.FocalLengthIn35mmFormat < 10.0f)
          imgdata.lens.makernotes.FocalLengthIn35mmFormat *= 10.0f;
      }
    }

    else if (!strncasecmp(make, "SONY", 4) || !strncasecmp(make, "Konica", 6) || !strncasecmp(make, "Minolta", 7) ||
             (!strncasecmp(make, "Hasselblad", 10) &&
              (!strncasecmp(model, "Stellar", 7) || !strncasecmp(model, "Lunar", 5) ||
               !strncasecmp(model, "Lusso", 5) || !strncasecmp(model, "HV", 2))))
    {
      ushort lid;
      if (tag == 0xb001) // Sony ModelID
      {
        unique_id = get2();
        setSonyBodyFeatures(unique_id);
        if (table_buf_0x9050_present)
        {
          process_Sony_0x9050(table_buf_0x9050, unique_id);
          free(table_buf_0x9050);
          table_buf_0x9050_present = 0;
        }
        if (table_buf_0x940c_present)
        {
          if (imgdata.lens.makernotes.CameraMount == LIBRAW_MOUNT_Sony_E)
          {
            process_Sony_0x940c(table_buf_0x940c);
          }
          free(table_buf_0x940c);
          table_buf_0x940c_present = 0;
        }
      }

      else if ((tag == 0x0010) && // CameraInfo
               strncasecmp(model, "DSLR-A100", 9) && strncasecmp(model, "NEX-5C", 6) && !strncasecmp(make, "SONY", 4) &&
               ((len == 368) ||  // a700
                (len == 5478) || // a850, a900
                (len == 5506) || // a200, a300, a350
                (len == 6118) || // a230, a290, a330, a380, a390
                                 // a450, a500, a550, a560, a580
                                 // a33, a35, a55
                                 // NEX3, NEX5, NEX5C, NEXC3, VG10E
                (len == 15360)))
      {
        table_buf = (uchar *)malloc(len);
        fread(table_buf, len, 1, ifp);
        if (memcmp(table_buf, "\xff\xff\xff\xff\xff\xff\xff\xff", 8) &&
            memcmp(table_buf, "\x00\x00\x00\x00\x00\x00\x00\x00", 8))
        {
          switch (len)
          {
          case 368:
          case 5478:
            // a700, a850, a900: CameraInfo
            if (table_buf[0] | table_buf[3])
              imgdata.lens.makernotes.MinFocal = bcd2dec(table_buf[0]) * 100 + bcd2dec(table_buf[3]);
            if (table_buf[2] | table_buf[5])
              imgdata.lens.makernotes.MaxFocal = bcd2dec(table_buf[2]) * 100 + bcd2dec(table_buf[5]);
            if (table_buf[4])
              imgdata.lens.makernotes.MaxAp4MinFocal = bcd2dec(table_buf[4]) / 10.0f;
            if (table_buf[4])
              imgdata.lens.makernotes.MaxAp4MaxFocal = bcd2dec(table_buf[7]) / 10.0f;
            parseSonyLensFeatures(table_buf[1], table_buf[6]);
            break;
          default:
            // CameraInfo2 & 3
            if (table_buf[1] | table_buf[2])
              imgdata.lens.makernotes.MinFocal = bcd2dec(table_buf[1]) * 100 + bcd2dec(table_buf[2]);
            if (table_buf[3] | table_buf[4])
              imgdata.lens.makernotes.MaxFocal = bcd2dec(table_buf[3]) * 100 + bcd2dec(table_buf[4]);
            if (table_buf[5])
              imgdata.lens.makernotes.MaxAp4MinFocal = bcd2dec(table_buf[5]) / 10.0f;
            if (table_buf[6])
              imgdata.lens.makernotes.MaxAp4MaxFocal = bcd2dec(table_buf[6]) / 10.0f;
            parseSonyLensFeatures(table_buf[0], table_buf[7]);
          }
        }
        free(table_buf);
      }

      else if ((tag == 0x0020) && // WBInfoA100, needs 0xb028 processing
               !strncasecmp(model, "DSLR-A100", 9))
      {
        fseek(ifp, 0x49dc, SEEK_CUR);
        stmread(imgdata.shootinginfo.InternalBodySerial, 12, ifp);
      }

      else if (tag == 0x0104)
      {
        imgdata.other.FlashEC = getreal(type);
      }

      else if (tag == 0x0105) // Teleconverter
      {
        imgdata.lens.makernotes.TeleconverterID = get2();
      }

      else if (tag == 0x0114 && len < 256000) // CameraSettings
      {
        table_buf = (uchar *)malloc(len);
        fread(table_buf, len, 1, ifp);
        switch (len)
        {
        case 280:
        case 364:
        case 332:
          // CameraSettings and CameraSettings2 are big endian
          if (table_buf[2] | table_buf[3])
          {
            lid = (((ushort)table_buf[2]) << 8) | ((ushort)table_buf[3]);
            imgdata.lens.makernotes.CurAp = powf64(2.0f, ((float)lid / 8.0f - 1.0f) / 2.0f);
          }
          break;
        case 1536:
        case 2048:
          // CameraSettings3 are little endian
          parseSonyLensType2(table_buf[1016], table_buf[1015]);
          if (imgdata.lens.makernotes.LensMount != LIBRAW_MOUNT_Canon_EF)
          {
            switch (table_buf[153])
            {
            case 16:
              imgdata.lens.makernotes.LensMount = LIBRAW_MOUNT_Minolta_A;
              break;
            case 17:
              imgdata.lens.makernotes.LensMount = LIBRAW_MOUNT_Sony_E;
              break;
            }
          }
          break;
        }
        free(table_buf);
      }

      else if (tag == 0x9050 && len < 256000) // little endian
      {
        table_buf_0x9050 = (uchar *)malloc(len);
        table_buf_0x9050_present = 1;
        fread(table_buf_0x9050, len, 1, ifp);

        if (imgdata.lens.makernotes.CamID)
        {
          process_Sony_0x9050(table_buf_0x9050, imgdata.lens.makernotes.CamID);
          free(table_buf_0x9050);
          table_buf_0x9050_present = 0;
        }
      }

      else if (tag == 0x940c && len < 256000)
      {
        table_buf_0x940c = (uchar *)malloc(len);
        table_buf_0x940c_present = 1;
        fread(table_buf_0x940c, len, 1, ifp);
        if ((imgdata.lens.makernotes.CamID) && (imgdata.lens.makernotes.CameraMount == LIBRAW_MOUNT_Sony_E))
        {
          process_Sony_0x940c(table_buf_0x940c);
          free(table_buf_0x940c);
          table_buf_0x940c_present = 0;
        }
      }

      else if (((tag == 0xb027) || (tag == 0x010c)) && (imgdata.lens.makernotes.LensID == -1))
      {
        imgdata.lens.makernotes.LensID = get4();
        if ((imgdata.lens.makernotes.LensID > 0x4900) && (imgdata.lens.makernotes.LensID <= 0x5900))
        {
          imgdata.lens.makernotes.AdapterID = 0x4900;
          imgdata.lens.makernotes.LensID -= imgdata.lens.makernotes.AdapterID;
          imgdata.lens.makernotes.LensMount = LIBRAW_MOUNT_Sigma_X3F;
          strcpy(imgdata.lens.makernotes.Adapter, "MC-11");
        }

        else if ((imgdata.lens.makernotes.LensID > 0xEF00) && (imgdata.lens.makernotes.LensID < 0xFFFF) &&
                 (imgdata.lens.makernotes.LensID != 0xFF00))
        {
          imgdata.lens.makernotes.AdapterID = 0xEF00;
          imgdata.lens.makernotes.LensID -= imgdata.lens.makernotes.AdapterID;
          imgdata.lens.makernotes.LensMount = LIBRAW_MOUNT_Canon_EF;
        }
        if (tag == 0x010c)
          imgdata.lens.makernotes.CameraMount = LIBRAW_MOUNT_Minolta_A;
      }

      else if (tag == 0xb02a && len < 256000) // Sony LensSpec
      {
        table_buf = (uchar *)malloc(len);
        fread(table_buf, len, 1, ifp);
        if (table_buf[1] | table_buf[2])
          imgdata.lens.makernotes.MinFocal = bcd2dec(table_buf[1]) * 100 + bcd2dec(table_buf[2]);
        if (table_buf[3] | table_buf[4])
          imgdata.lens.makernotes.MaxFocal = bcd2dec(table_buf[3]) * 100 + bcd2dec(table_buf[4]);
        if (table_buf[5])
          imgdata.lens.makernotes.MaxAp4MinFocal = bcd2dec(table_buf[5]) / 10.0f;
        if (table_buf[6])
          imgdata.lens.makernotes.MaxAp4MaxFocal = bcd2dec(table_buf[6]) / 10.0f;
        parseSonyLensFeatures(table_buf[0], table_buf[7]);
        free(table_buf);
      }
    }

    fseek(ifp, _pos, SEEK_SET);
#endif

    if (tag == 2 && strstr(make, "NIKON") && !iso_speed)
      iso_speed = (get2(), get2());
    if (tag == 37 && strstr(make, "NIKON") && (!iso_speed || iso_speed == 65535))
    {
      unsigned char cc;
      fread(&cc, 1, 1, ifp);
      iso_speed = int(100.0 * powf64(2.0f, float(cc) / 12.0 - 5.0));
    }
    if (tag == 4 && len > 26 && len < 35)
    {
      if ((i = (get4(), get2())) != 0x7fff && (!iso_speed || iso_speed == 65535))
        iso_speed = 50 * powf64(2.0, i / 32.0 - 4);
#ifdef LIBRAW_LIBRARY_BUILD
      get4();
#else
      if ((i = (get2(), get2())) != 0x7fff && !aperture)
        aperture = powf64(2.0, i / 64.0);
#endif
      if ((i = get2()) != 0xffff && !shutter)
        shutter = powf64(2.0, (short)i / -32.0);
      wbi = (get2(), get2());
      shot_order = (get2(), get2());
    }
    if ((tag == 4 || tag == 0x114) && !strncmp(make, "KONICA", 6))
    {
      fseek(ifp, tag == 4 ? 140 : 160, SEEK_CUR);
      switch (get2())
      {
      case 72:
        flip = 0;
        break;
      case 76:
        flip = 6;
        break;
      case 82:
        flip = 5;
        break;
      }
    }
    if (tag == 7 && type == 2 && len > 20)
      fgets(model2, 64, ifp);
    if (tag == 8 && type == 4)
      shot_order = get4();
    if (tag == 9 && !strncmp(make, "Canon", 5))
      fread(artist, 64, 1, ifp);
    if (tag == 0xc && len == 4)
      FORC3 cam_mul[(c << 1 | c >> 1) & 3] = getreal(type);
    if (tag == 0xd && type == 7 && get2() == 0xaaaa)
    {
#if 0 /* Canon rotation data is handled by EXIF.Orientation */
      for (c = i = 2; (ushort)c != 0xbbbb && i < len; i++)
        c = c << 8 | fgetc(ifp);
      while ((i += 4) < len - 5)
        if (get4() == 257 && (i = len) && (c = (get4(), fgetc(ifp))) < 3)
          flip = "065"[c] - '0';
#endif
    }

#ifndef LIBRAW_LIBRARY_BUILD
    if (tag == 0x10 && type == 4)
      unique_id = get4();
#endif

#ifdef LIBRAW_LIBRARY_BUILD
    INT64 _pos2 = ftell(ifp);
    if (!strncasecmp(make, "Olympus", 7))
    {
      short nWB, tWB;
      if ((tag == 0x20300108) || (tag == 0x20310109))
        imgdata.makernotes.olympus.ColorSpace = get2();

      if ((tag == 0x20400102) && (len == 2) && (!strncasecmp(model, "E-410", 5) || !strncasecmp(model, "E-510", 5)))
      {
        int i;
        for (i = 0; i < 64; i++)
          imgdata.color.WBCT_Coeffs[i][2] = imgdata.color.WBCT_Coeffs[i][4] = imgdata.color.WB_Coeffs[i][1] =
              imgdata.color.WB_Coeffs[i][3] = 0x100;
        for (i = 64; i < 256; i++)
          imgdata.color.WB_Coeffs[i][1] = imgdata.color.WB_Coeffs[i][3] = 0x100;
      }
      if ((tag >= 0x20400102) && (tag <= 0x2040010d))
      {
        ushort CT;
        nWB = tag - 0x20400102;
        switch (nWB)
        {
        case 0:
          CT = 3000;
          tWB = LIBRAW_WBI_Tungsten;
          break;
        case 1:
          CT = 3300;
          tWB = 0x100;
          break;
        case 2:
          CT = 3600;
          tWB = 0x100;
          break;
        case 3:
          CT = 3900;
          tWB = 0x100;
          break;
        case 4:
          CT = 4000;
          tWB = LIBRAW_WBI_FL_W;
          break;
        case 5:
          CT = 4300;
          tWB = 0x100;
          break;
        case 6:
          CT = 4500;
          tWB = LIBRAW_WBI_FL_D;
          break;
        case 7:
          CT = 4800;
          tWB = 0x100;
          break;
        case 8:
          CT = 5300;
          tWB = LIBRAW_WBI_FineWeather;
          break;
        case 9:
          CT = 6000;
          tWB = LIBRAW_WBI_Cloudy;
          break;
        case 10:
          CT = 6600;
          tWB = LIBRAW_WBI_FL_N;
          break;
        case 11:
          CT = 7500;
          tWB = LIBRAW_WBI_Shade;
          break;
        default:
          CT = 0;
          tWB = 0x100;
        }
        if (CT)
        {
          imgdata.color.WBCT_Coeffs[nWB][0] = CT;
          imgdata.color.WBCT_Coeffs[nWB][1] = get2();
          imgdata.color.WBCT_Coeffs[nWB][3] = get2();
          if (len == 4)
          {
            imgdata.color.WBCT_Coeffs[nWB][2] = get2();
            imgdata.color.WBCT_Coeffs[nWB][4] = get2();
          }
        }
        if (tWB != 0x100)
          FORC4 imgdata.color.WB_Coeffs[tWB][c] = imgdata.color.WBCT_Coeffs[nWB][c + 1];
      }
      if ((tag >= 0x20400113) && (tag <= 0x2040011e))
      {
        nWB = tag - 0x20400113;
        imgdata.color.WBCT_Coeffs[nWB][2] = imgdata.color.WBCT_Coeffs[nWB][4] = get2();
        switch (nWB)
        {
        case 0:
          tWB = LIBRAW_WBI_Tungsten;
          break;
        case 4:
          tWB = LIBRAW_WBI_FL_W;
          break;
        case 6:
          tWB = LIBRAW_WBI_FL_D;
          break;
        case 8:
          tWB = LIBRAW_WBI_FineWeather;
          break;
        case 9:
          tWB = LIBRAW_WBI_Cloudy;
          break;
        case 10:
          tWB = LIBRAW_WBI_FL_N;
          break;
        case 11:
          tWB = LIBRAW_WBI_Shade;
          break;
        default:
          tWB = 0x100;
        }
        if (tWB != 0x100)
          imgdata.color.WB_Coeffs[tWB][1] = imgdata.color.WB_Coeffs[tWB][3] = imgdata.color.WBCT_Coeffs[nWB][2];
      }

      if (tag == 0x20400121)
      {
        imgdata.color.WB_Coeffs[LIBRAW_WBI_Flash][0] = get2();
        imgdata.color.WB_Coeffs[LIBRAW_WBI_Flash][2] = get2();
        if (len == 4)
        {
          imgdata.color.WB_Coeffs[LIBRAW_WBI_Flash][1] = get2();
          imgdata.color.WB_Coeffs[LIBRAW_WBI_Flash][3] = get2();
        }
      }
      if (tag == 0x2040011f)
      {
        imgdata.color.WB_Coeffs[LIBRAW_WBI_Flash][1] = imgdata.color.WB_Coeffs[LIBRAW_WBI_Flash][3] = get2();
      }
      if (tag == 0x30000120)
      {
        imgdata.color.WB_Coeffs[LIBRAW_WBI_Shade][0] = get2();
        imgdata.color.WB_Coeffs[LIBRAW_WBI_Shade][2] = get2();
        if (len == 2)
        {
          for (int i = 0; i < 256; i++)
            imgdata.color.WB_Coeffs[i][1] = imgdata.color.WB_Coeffs[i][3] = 0x100;
        }
      }
      if (tag == 0x30000121)
      {
        imgdata.color.WB_Coeffs[LIBRAW_WBI_Cloudy][0] = get2();
        imgdata.color.WB_Coeffs[LIBRAW_WBI_Cloudy][2] = get2();
      }
      if (tag == 0x30000122)
      {
        imgdata.color.WB_Coeffs[LIBRAW_WBI_FineWeather][0] = get2();
        imgdata.color.WB_Coeffs[LIBRAW_WBI_FineWeather][2] = get2();
      }
      if (tag == 0x30000123)
      {
        imgdata.color.WB_Coeffs[LIBRAW_WBI_Tungsten][0] = get2();
        imgdata.color.WB_Coeffs[LIBRAW_WBI_Tungsten][2] = get2();
      }
      if (tag == 0x30000124)
      {
        imgdata.color.WB_Coeffs[LIBRAW_WBI_Sunset][0] = get2();
        imgdata.color.WB_Coeffs[LIBRAW_WBI_Sunset][2] = get2();
      }
      if (tag == 0x30000130)
      {
        imgdata.color.WB_Coeffs[LIBRAW_WBI_FL_D][0] = get2();
        imgdata.color.WB_Coeffs[LIBRAW_WBI_FL_D][2] = get2();
      }
      if (tag == 0x30000131)
      {
        imgdata.color.WB_Coeffs[LIBRAW_WBI_FL_N][0] = get2();
        imgdata.color.WB_Coeffs[LIBRAW_WBI_FL_N][2] = get2();
      }
      if (tag == 0x30000132)
      {
        imgdata.color.WB_Coeffs[LIBRAW_WBI_FL_W][0] = get2();
        imgdata.color.WB_Coeffs[LIBRAW_WBI_FL_W][2] = get2();
      }
      if (tag == 0x30000133)
      {
        imgdata.color.WB_Coeffs[LIBRAW_WBI_FL_WW][0] = get2();
        imgdata.color.WB_Coeffs[LIBRAW_WBI_FL_WW][2] = get2();
      }

      if ((tag == 0x20400805) && (len == 2))
      {
        imgdata.makernotes.olympus.OlympusSensorCalibration[0] = getreal(type);
        imgdata.makernotes.olympus.OlympusSensorCalibration[1] = getreal(type);
        FORC4 imgdata.color.linear_max[c] = imgdata.makernotes.olympus.OlympusSensorCalibration[0];
      }
      if (tag == 0x20200401)
      {
        imgdata.other.FlashEC = getreal(type);
      }
    }
    fseek(ifp, _pos2, SEEK_SET);

#endif
    if (tag == 0x11 && is_raw && !strncmp(make, "NIKON", 5))
    {
      fseek(ifp, get4() + base, SEEK_SET);
      parse_tiff_ifd(base);
    }
    if (tag == 0x14 && type == 7)
    {
      if (len == 2560)
      {
        fseek(ifp, 1248, SEEK_CUR);
        goto get2_256;
      }
      fread(buf, 1, 10, ifp);
      if (!strncmp(buf, "NRW ", 4))
      {
        fseek(ifp, strcmp(buf + 4, "0100") ? 46 : 1546, SEEK_CUR);
        cam_mul[0] = get4() << 2;
        cam_mul[1] = get4() + get4();
        cam_mul[2] = get4() << 2;
      }
    }
    if (tag == 0x15 && type == 2 && is_raw)
      fread(model, 64, 1, ifp);
    if (strstr(make, "PENTAX"))
    {
      if (tag == 0x1b)
        tag = 0x1018;
      if (tag == 0x1c)
        tag = 0x1017;
    }
    if (tag == 0x1d)
    {
      while ((c = fgetc(ifp)) && c != EOF)
#ifdef LIBRAW_LIBRARY_BUILD
      {
        if ((!custom_serial) && (!isdigit(c)))
        {
          if ((strbuflen(model) == 3) && (!strcmp(model, "D50")))
          {
            custom_serial = 34;
          }
          else
          {
            custom_serial = 96;
          }
        }
#endif
        serial = serial * 10 + (isdigit(c) ? c - '0' : c % 10);
#ifdef LIBRAW_LIBRARY_BUILD
      }
      if (!imgdata.shootinginfo.BodySerial[0])
        sprintf(imgdata.shootinginfo.BodySerial, "%d", serial);
#endif
    }
    if (tag == 0x29 && type == 1)
    { // Canon PowerShot G9
      c = wbi < 18 ? "012347800000005896"[wbi] - '0' : 0;
      fseek(ifp, 8 + c * 32, SEEK_CUR);
      FORC4 cam_mul[c ^ (c >> 1) ^ 1] = get4();
    }
#ifndef LIBRAW_LIBRARY_BUILD
    if (tag == 0x3d && type == 3 && len == 4)
      FORC4 cblack[c ^ c >> 1] = get2() >> (14 - tiff_bps);
#endif
    if (tag == 0x81 && type == 4)
    {
      data_offset = get4();
      fseek(ifp, data_offset + 41, SEEK_SET);
      raw_height = get2() * 2;
      raw_width = get2();
      filters = 0x61616161;
    }
    if ((tag == 0x81 && type == 7) || (tag == 0x100 && type == 7) || (tag == 0x280 && type == 1))
    {
      thumb_offset = ftell(ifp);
      thumb_length = len;
    }
    if (tag == 0x88 && type == 4 && (thumb_offset = get4()))
      thumb_offset += base;
    if (tag == 0x89 && type == 4)
      thumb_length = get4();
    if (tag == 0x8c || tag == 0x96)
      meta_offset = ftell(ifp);
    if (tag == 0x97)
    {
      for (i = 0; i < 4; i++)
        ver97 = ver97 * 10 + fgetc(ifp) - '0';
      switch (ver97)
      {
      case 100:
        fseek(ifp, 68, SEEK_CUR);
        FORC4 cam_mul[(c >> 1) | ((c & 1) << 1)] = get2();
        break;
      case 102:
        fseek(ifp, 6, SEEK_CUR);
        FORC4 cam_mul[c ^ (c >> 1)] = get2();
        break;
      case 103:
        fseek(ifp, 16, SEEK_CUR);
        FORC4 cam_mul[c] = get2();
      }
      if (ver97 >= 200)
      {
        if (ver97 != 205)
          fseek(ifp, 280, SEEK_CUR);
        fread(buf97, 324, 1, ifp);
      }
    }
    if (tag == 0xa1 && type == 7)
    {
      order = 0x4949;
      fseek(ifp, 140, SEEK_CUR);
      FORC3 cam_mul[c] = get4();
    }
    if (tag == 0xa4 && type == 3)
    {
      fseek(ifp, wbi * 48, SEEK_CUR);
      FORC3 cam_mul[c] = get2();
    }

    if (tag == 0xa7)
    { // shutter count
      NikonKey = fgetc(ifp) ^ fgetc(ifp) ^ fgetc(ifp) ^ fgetc(ifp);
      if ((unsigned)(ver97 - 200) < 17)
      {
        ci = xlat[0][serial & 0xff];
        cj = xlat[1][NikonKey];
        ck = 0x60;
        for (i = 0; i < 324; i++)
          buf97[i] ^= (cj += ci * ck++);
        i = "66666>666;6A;:;55"[ver97 - 200] - '0';
        FORC4 cam_mul[c ^ (c >> 1) ^ (i & 1)] = sget2(buf97 + (i & -2) + c * 2);
      }
#ifdef LIBRAW_LIBRARY_BUILD
      if ((NikonLensDataVersion > 200) && lenNikonLensData)
      {
        if (custom_serial)
        {
          ci = xlat[0][custom_serial];
        }
        else
        {
          ci = xlat[0][serial & 0xff];
        }
        cj = xlat[1][NikonKey];
        ck = 0x60;
        for (i = 0; i < lenNikonLensData; i++)
          table_buf[i] ^= (cj += ci * ck++);
        processNikonLensData(table_buf, lenNikonLensData);
        lenNikonLensData = 0;
        free(table_buf);
      }
      if (ver97 == 601) // Coolpix A
      {
        imgdata.lens.makernotes.LensMount = LIBRAW_MOUNT_FixedLens;
        imgdata.lens.makernotes.CameraMount = LIBRAW_MOUNT_FixedLens;
      }
#endif
    }

    if (tag == 0xb001 && type == 3) // Sony ModelID
    {
      unique_id = get2();
    }
    if (tag == 0x200 && len == 3)
      shot_order = (get4(), get4());
    if (tag == 0x200 && len == 4)
      FORC4 cblack[c ^ c >> 1] = get2();
    if (tag == 0x201 && len == 4)
      FORC4 cam_mul[c ^ (c >> 1)] = get2();
    if (tag == 0x220 && type == 7)
      meta_offset = ftell(ifp);
    if (tag == 0x401 && type == 4 && len == 4)
      FORC4 cblack[c ^ c >> 1] = get4();
#ifdef LIBRAW_LIBRARY_BUILD
    // not corrected for file bitcount, to be patched in open_datastream
    if (tag == 0x03d && strstr(make, "NIKON") && len == 4)
    {
      FORC4 cblack[c ^ c >> 1] = get2();
      i = cblack[3];
      FORC3 if (i > cblack[c]) i = cblack[c];
      FORC4 cblack[c] -= i;
      black += i;
    }
#endif
    if (tag == 0xe01)
    { /* Nikon Capture Note */
#ifdef LIBRAW_LIBRARY_BUILD
      int loopc = 0;
#endif
      order = 0x4949;
      fseek(ifp, 22, SEEK_CUR);
      for (offset = 22; offset + 22 < len; offset += 22 + i)
      {
#ifdef LIBRAW_LIBRARY_BUILD
        if (loopc++ > 1024)
          throw LIBRAW_EXCEPTION_IO_CORRUPT;
#endif
        tag = get4();
        fseek(ifp, 14, SEEK_CUR);
        i = get4() - 4;
        if (tag == 0x76a43207)
          flip = get2();
        else
          fseek(ifp, i, SEEK_CUR);
      }
    }
    if (tag == 0xe80 && len == 256 && type == 7)
    {
      fseek(ifp, 48, SEEK_CUR);
      cam_mul[0] = get2() * 508 * 1.078 / 0x10000;
      cam_mul[2] = get2() * 382 * 1.173 / 0x10000;
    }
    if (tag == 0xf00 && type == 7)
    {
      if (len == 614)
        fseek(ifp, 176, SEEK_CUR);
      else if (len == 734 || len == 1502)
        fseek(ifp, 148, SEEK_CUR);
      else
        goto next;
      goto get2_256;
    }
    if ((tag == 0x1011 && len == 9) || tag == 0x20400200)
      for (i = 0; i < 3; i++)
      {
#ifdef LIBRAW_LIBRARY_BUILD
        if (!imgdata.makernotes.olympus.ColorSpace)
        {
          FORC3 cmatrix[i][c] = ((short)get2()) / 256.0;
        }
        else
        {
          FORC3 imgdata.color.ccm[i][c] = ((short)get2()) / 256.0;
        }
#else
        FORC3 cmatrix[i][c] = ((short)get2()) / 256.0;
#endif
      }
    if ((tag == 0x1012 || tag == 0x20400600) && len == 4)
      FORC4 cblack[c ^ c >> 1] = get2();
    if (tag == 0x1017 || tag == 0x20400100)
      cam_mul[0] = get2() / 256.0;
    if (tag == 0x1018 || tag == 0x20400100)
      cam_mul[2] = get2() / 256.0;
    if (tag == 0x2011 && len == 2)
    {
    get2_256:
      order = 0x4d4d;
      cam_mul[0] = get2() / 256.0;
      cam_mul[2] = get2() / 256.0;
    }
    if ((tag | 0x70) == 0x2070 && (type == 4 || type == 13))
      fseek(ifp, get4() + base, SEEK_SET);
#ifdef LIBRAW_LIBRARY_BUILD
    // IB start
    if (tag == 0x2010)
    {
      INT64 _pos3 = ftell(ifp);
      parse_makernote(base, 0x2010);
      fseek(ifp, _pos3, SEEK_SET);
    }

    if (((tag == 0x2020) || (tag == 0x3000) || (tag == 0x2030) || (tag == 0x2031)) && ((type == 7) || (type == 13)) &&
        !strncasecmp(make, "Olympus", 7))
    {
      INT64 _pos3 = ftell(ifp);
      parse_makernote(base, tag);
      fseek(ifp, _pos3, SEEK_SET);
    }
// IB end
#endif
    if ((tag == 0x2020) && ((type == 7) || (type == 13)) && !strncmp(buf, "OLYMP", 5))
      parse_thumb_note(base, 257, 258);
    if (tag == 0x2040)
      parse_makernote(base, 0x2040);
    if (tag == 0xb028)
    {
      fseek(ifp, get4() + base, SEEK_SET);
      parse_thumb_note(base, 136, 137);
    }
    if (tag == 0x4001 && len > 500 && len < 100000)
    {
      i = len == 582 ? 50 : len == 653 ? 68 : len == 5120 ? 142 : 126;
      fseek(ifp, i, SEEK_CUR);
      FORC4 cam_mul[c ^ (c >> 1)] = get2();
      for (i += 18; i <= len; i += 10)
      {
        get2();
        FORC4 sraw_mul[c ^ (c >> 1)] = get2();
        if (sraw_mul[1] == 1170)
          break;
      }
    }
    if (!strncasecmp(make, "Samsung", 7))
    {
      if (tag == 0xa020) // get the full Samsung encryption key
        for (i = 0; i < 11; i++)
          SamsungKey[i] = get4();
      if (tag == 0xa021) // get and decode Samsung cam_mul array
        FORC4 cam_mul[c ^ (c >> 1)] = get4() - SamsungKey[c];
#ifdef LIBRAW_LIBRARY_BUILD
      if (tag == 0xa023)
      {
        imgdata.color.WB_Coeffs[LIBRAW_WBI_Ill_A][0] = get4() - SamsungKey[8];
        imgdata.color.WB_Coeffs[LIBRAW_WBI_Ill_A][1] = get4() - SamsungKey[9];
        imgdata.color.WB_Coeffs[LIBRAW_WBI_Ill_A][3] = get4() - SamsungKey[10];
        imgdata.color.WB_Coeffs[LIBRAW_WBI_Ill_A][2] = get4() - SamsungKey[0];
        if (imgdata.color.WB_Coeffs[LIBRAW_WBI_Ill_A][0] < (imgdata.color.WB_Coeffs[LIBRAW_WBI_Ill_A][1] >> 1))
        {
          imgdata.color.WB_Coeffs[LIBRAW_WBI_Ill_A][1] = imgdata.color.WB_Coeffs[LIBRAW_WBI_Ill_A][1] >> 4;
          imgdata.color.WB_Coeffs[LIBRAW_WBI_Ill_A][3] = imgdata.color.WB_Coeffs[LIBRAW_WBI_Ill_A][3] >> 4;
        }
      }
      if (tag == 0xa024)
      {
        FORC4 imgdata.color.WB_Coeffs[LIBRAW_WBI_D65][c ^ (c >> 1)] = get4() - SamsungKey[c + 1];
        if (imgdata.color.WB_Coeffs[LIBRAW_WBI_D65][0] < (imgdata.color.WB_Coeffs[LIBRAW_WBI_D65][1] >> 1))
        {
          imgdata.color.WB_Coeffs[LIBRAW_WBI_D65][1] = imgdata.color.WB_Coeffs[LIBRAW_WBI_D65][1] >> 4;
          imgdata.color.WB_Coeffs[LIBRAW_WBI_D65][3] = imgdata.color.WB_Coeffs[LIBRAW_WBI_D65][3] >> 4;
        }
      }
      if (tag == 0xa025)
        imgdata.color.linear_max[0] = imgdata.color.linear_max[1] = imgdata.color.linear_max[2] =
            imgdata.color.linear_max[3] = get4() - SamsungKey[0];
      if (tag == 0xa030 && len == 9)
        for (i = 0; i < 3; i++)
          FORC3 imgdata.color.ccm[i][c] = (float)((short)((get4() + SamsungKey[i * 3 + c]))) / 256.0;
#endif
      if (tag == 0xa031 && len == 9) // get and decode Samsung color matrix
        for (i = 0; i < 3; i++)
          FORC3 cmatrix[i][c] = (float)((short)((get4() + SamsungKey[i * 3 + c]))) / 256.0;

      if (tag == 0xa028)
        FORC4 cblack[c ^ (c >> 1)] = get4() - SamsungKey[c];
    }
    else
    {
      // Somebody else use 0xa021 and 0xa028?
      if (tag == 0xa021)
        FORC4 cam_mul[c ^ (c >> 1)] = get4();
      if (tag == 0xa028)
        FORC4 cam_mul[c ^ (c >> 1)] -= get4();
    }
    if (tag == 0x4021 && get4() && get4())
      FORC4 cam_mul[c] = 1024;
  next:
    fseek(ifp, save, SEEK_SET);
  }
quit:
  order = sorder;
}

Project: LibRaw
File: dcraw.c

void CLASS parse_makernote_0xc634(int base, int uptag, unsigned dng_writer)
{
  unsigned ver97 = 0, offset = 0, entries, tag, type, len, save, c;
  unsigned i;

  uchar NikonKey, ci, cj, ck;
  unsigned serial = 0;
  unsigned custom_serial = 0;
  unsigned NikonLensDataVersion = 0;
  unsigned lenNikonLensData = 0;
  unsigned NikonFlashInfoVersion = 0;

  uchar *CanonCameraInfo;
  unsigned lenCanonCameraInfo = 0;

  uchar *table_buf;
  uchar *table_buf_0x9050;
  ushort table_buf_0x9050_present = 0;
  uchar *table_buf_0x940c;
  ushort table_buf_0x940c_present = 0;

  short morder, sorder = order;
  char buf[10];
  INT64 fsize = ifp->size();

  fread(buf, 1, 10, ifp);
  if (!strcmp(buf, "Nikon"))
  {
    base = ftell(ifp);
    order = get2();
    if (get2() != 42)
      goto quit;
    offset = get4();
    fseek(ifp, offset - 8, SEEK_CUR);
  }
  else if (!strcmp(buf, "OLYMPUS") || !strcmp(buf, "PENTAX ") ||
           (!strncmp(make, "SAMSUNG", 7) && (dng_writer == CameraDNG)))
  {
    base = ftell(ifp) - 10;
    fseek(ifp, -2, SEEK_CUR);
    order = get2();
    if (buf[0] == 'O')
      get2();
  }
  else if (!strncmp(buf, "SONY", 4) || !strcmp(buf, "Panasonic"))
  {
    goto nf;
  }
  else if (!strncmp(buf, "FUJIFILM", 8))
  {
    base = ftell(ifp) - 10;
  nf:
    order = 0x4949;
    fseek(ifp, 2, SEEK_CUR);
  }
  else if (!strcmp(buf, "OLYMP") || !strcmp(buf, "LEICA") || !strcmp(buf, "Ricoh") || !strcmp(buf, "EPSON"))
    fseek(ifp, -2, SEEK_CUR);
  else if (!strcmp(buf, "AOC") || !strcmp(buf, "QVC"))
    fseek(ifp, -4, SEEK_CUR);
  else
  {
    fseek(ifp, -10, SEEK_CUR);
    if ((!strncmp(make, "SAMSUNG", 7) && (dng_writer == AdobeDNG)))
      base = ftell(ifp);
  }

  entries = get2();
  if (entries > 1000)
    return;
  morder = order;

  while (entries--)
  {
    order = morder;
    tiff_get(base, &tag, &type, &len, &save);
    INT64 pos = ifp->tell();
    if (len > 8 && pos + len > 2 * fsize)
      continue;
    tag |= uptag << 16;
    if (len > 100 * 1024 * 1024)
      goto next; // 100Mb tag? No!

    if (!strncmp(make, "Canon", 5))
    {
      if (tag == 0x000d && len < 256000) // camera info
      {
        CanonCameraInfo = (uchar *)malloc(len);
        fread(CanonCameraInfo, len, 1, ifp);
        lenCanonCameraInfo = len;
      }

      else if (tag == 0x10) // Canon ModelID
      {
        unique_id = get4();
        if (unique_id == 0x03740000)
          unique_id = 0x80000374; // M3
        if (unique_id == 0x03840000)
          unique_id = 0x80000384; // M10
        if (unique_id == 0x03940000)
          unique_id = 0x80000394; // M5
        setCanonBodyFeatures(unique_id);
        if (lenCanonCameraInfo)
        {
          processCanonCameraInfo(unique_id, CanonCameraInfo, lenCanonCameraInfo);
          free(CanonCameraInfo);
          CanonCameraInfo = 0;
          lenCanonCameraInfo = 0;
        }
      }

      else
        parseCanonMakernotes(tag, type, len);
    }

    else if (!strncmp(make, "FUJI", 4))
      parseFujiMakernotes(tag, type);

    else if (!strncasecmp(make, "LEICA", 5))
    {
      if (((tag == 0x035e) || (tag == 0x035f)) && (type == 10) && (len == 9))
      {
        int ind = tag == 0x035e ? 0 : 1;
        for (int j = 0; j < 3; j++)
          FORCC imgdata.color.dng_color[ind].forwardmatrix[j][c] = getreal(type);
      }
      if ((tag == 0x0303) && (type != 4))
      {
        stmread(imgdata.lens.makernotes.Lens, len, ifp);
      }

      if ((tag == 0x3405) || (tag == 0x0310) || (tag == 0x34003405))
      {
        imgdata.lens.makernotes.LensID = get4();
        imgdata.lens.makernotes.LensID =
            ((imgdata.lens.makernotes.LensID >> 2) << 8) | (imgdata.lens.makernotes.LensID & 0x3);
        if (imgdata.lens.makernotes.LensID != -1)
        {
          if ((model[0] == 'M') || !strncasecmp(model, "LEICA M", 7))
          {
            imgdata.lens.makernotes.CameraMount = LIBRAW_MOUNT_Leica_M;
            if (imgdata.lens.makernotes.LensID)
              imgdata.lens.makernotes.LensMount = LIBRAW_MOUNT_Leica_M;
          }
          else if ((model[0] == 'S') || !strncasecmp(model, "LEICA S", 7))
          {
            imgdata.lens.makernotes.CameraMount = LIBRAW_MOUNT_Leica_S;
            if (imgdata.lens.makernotes.Lens[0])
              imgdata.lens.makernotes.LensMount = LIBRAW_MOUNT_Leica_S;
          }
        }
      }

      else if (((tag == 0x0313) || (tag == 0x34003406)) && (fabs(imgdata.lens.makernotes.CurAp) < 0.17f) &&
               ((type == 10) || (type == 5)))
      {
        imgdata.lens.makernotes.CurAp = getreal(type);
        if (imgdata.lens.makernotes.CurAp > 126.3)
          imgdata.lens.makernotes.CurAp = 0.0f;
      }

      else if (tag == 0x3400)
      {
        parse_makernote(base, 0x3400);
      }
    }

    else if (!strncmp(make, "NIKON", 5))
    {
      if (tag == 0x1d) // serial number
        while ((c = fgetc(ifp)) && c != EOF)
        {
          if ((!custom_serial) && (!isdigit(c)))
          {
            if ((strbuflen(model) == 3) && (!strcmp(model, "D50")))
            {
              custom_serial = 34;
            }
            else
            {
              custom_serial = 96;
            }
          }
          serial = serial * 10 + (isdigit(c) ? c - '0' : c % 10);
        }
      else if (tag == 0x000a)
      {
        imgdata.lens.makernotes.LensMount = LIBRAW_MOUNT_FixedLens;
        imgdata.lens.makernotes.CameraMount = LIBRAW_MOUNT_FixedLens;
      }
      else if (tag == 0x0082) // lens attachment
      {
        stmread(imgdata.lens.makernotes.Attachment, len, ifp);
      }
      else if (tag == 0x0083) // lens type
      {
        imgdata.lens.nikon.NikonLensType = fgetc(ifp);
      }
      else if (tag == 0x0084) // lens
      {
        imgdata.lens.makernotes.MinFocal = getreal(type);
        imgdata.lens.makernotes.MaxFocal = getreal(type);
        imgdata.lens.makernotes.MaxAp4MinFocal = getreal(type);
        imgdata.lens.makernotes.MaxAp4MaxFocal = getreal(type);
      }
      else if (tag == 0x008b) // lens f-stops
      {
        uchar a, b, c;
        a = fgetc(ifp);
        b = fgetc(ifp);
        c = fgetc(ifp);
        if (c)
        {
          imgdata.lens.nikon.NikonLensFStops = a * b * (12 / c);
          imgdata.lens.makernotes.LensFStops = (float)imgdata.lens.nikon.NikonLensFStops / 12.0f;
        }
      }
      else if (tag == 0x0093)
      {
        i = get2();
        if ((i == 7) || (i == 9))
        {
          imgdata.lens.makernotes.LensMount = LIBRAW_MOUNT_FixedLens;
          imgdata.lens.makernotes.CameraMount = LIBRAW_MOUNT_FixedLens;
        }
      }
      else if (tag == 0x0097)
      {
        for (i = 0; i < 4; i++)
          ver97 = ver97 * 10 + fgetc(ifp) - '0';
        if (ver97 == 601) // Coolpix A
        {
          imgdata.lens.makernotes.LensMount = LIBRAW_MOUNT_FixedLens;
          imgdata.lens.makernotes.CameraMount = LIBRAW_MOUNT_FixedLens;
        }
      }
      else if (tag == 0x0098) // contains lens data
      {
        for (i = 0; i < 4; i++)
        {
          NikonLensDataVersion = NikonLensDataVersion * 10 + fgetc(ifp) - '0';
        }
        switch (NikonLensDataVersion)
        {
        case 100:
          lenNikonLensData = 9;
          break;
        case 101:
        case 201: // encrypted, starting from v.201
        case 202:
        case 203:
          lenNikonLensData = 15;
          break;
        case 204:
          lenNikonLensData = 16;
          break;
        case 400:
          lenNikonLensData = 459;
          break;
        case 401:
          lenNikonLensData = 590;
          break;
        case 402:
          lenNikonLensData = 509;
          break;
        case 403:
          lenNikonLensData = 879;
          break;
        }
        if (lenNikonLensData)
        {
          table_buf = (uchar *)malloc(lenNikonLensData);
          fread(table_buf, lenNikonLensData, 1, ifp);
          if ((NikonLensDataVersion < 201) && lenNikonLensData)
          {
            processNikonLensData(table_buf, lenNikonLensData);
            free(table_buf);
            lenNikonLensData = 0;
          }
        }
      }

      else if (tag == 0xa7) // shutter count
      {
        NikonKey = fgetc(ifp) ^ fgetc(ifp) ^ fgetc(ifp) ^ fgetc(ifp);
        if ((NikonLensDataVersion > 200) && lenNikonLensData)
        {
          if (custom_serial)
          {
            ci = xlat[0][custom_serial];
          }
          else
          {
            ci = xlat[0][serial & 0xff];
          }
          cj = xlat[1][NikonKey];
          ck = 0x60;
          for (i = 0; i < lenNikonLensData; i++)
            table_buf[i] ^= (cj += ci * ck++);
          processNikonLensData(table_buf, lenNikonLensData);
          lenNikonLensData = 0;
          free(table_buf);
        }
      }
      else if (tag == 0x00a8) // contains flash data
      {
        for (i = 0; i < 4; i++)
        {
          NikonFlashInfoVersion = NikonFlashInfoVersion * 10 + fgetc(ifp) - '0';
        }
      }

      else if (tag == 37 && (!iso_speed || iso_speed == 65535))
      {
        unsigned char cc;
        fread(&cc, 1, 1, ifp);
        iso_speed = (int)(100.0 * powf64(2.0, (double)(cc) / 12.0 - 5.0));
        break;
      }
    }

    else if (!strncmp(make, "OLYMPUS", 7))
    {
      int SubDirOffsetValid = strncmp(model, "E-300", 5) && strncmp(model, "E-330", 5) && strncmp(model, "E-400", 5) &&
                              strncmp(model, "E-500", 5) && strncmp(model, "E-1", 3);

      if ((tag == 0x2010) || (tag == 0x2020))
      {
        fseek(ifp, save - 4, SEEK_SET);
        fseek(ifp, base + get4(), SEEK_SET);
        parse_makernote_0xc634(base, tag, dng_writer);
      }
      if (!SubDirOffsetValid && ((len > 4) || (((type == 3) || (type == 8)) && (len > 2)) ||
                                 (((type == 4) || (type == 9)) && (len > 1)) || (type == 5) || (type > 9)))
        goto skip_Oly_broken_tags;

      switch (tag)
      {
      case 0x0207:
      case 0x20100100:
      {
        uchar sOlyID[8];
        unsigned long long OlyID;
        fread(sOlyID, MIN(len, 7), 1, ifp);
        sOlyID[7] = 0;
        OlyID = sOlyID[0];
        i = 1;
        while (i < 7 && sOlyID[i])
        {
          OlyID = OlyID << 8 | sOlyID[i];
          i++;
        }
        setOlympusBodyFeatures(OlyID);
      }
      break;
      case 0x1002:
        imgdata.lens.makernotes.CurAp = powf64(2.0f, getreal(type) / 2);
        break;
      case 0x20100102:
        stmread(imgdata.shootinginfo.InternalBodySerial, len, ifp);
        break;
      case 0x20100201:
        imgdata.lens.makernotes.LensID = (unsigned long long)fgetc(ifp) << 16 |
                                         (unsigned long long)(fgetc(ifp), fgetc(ifp)) << 8 |
                                         (unsigned long long)fgetc(ifp);
        imgdata.lens.makernotes.LensMount = LIBRAW_MOUNT_FT;
        imgdata.lens.makernotes.LensFormat = LIBRAW_FORMAT_FT;
        if (((imgdata.lens.makernotes.LensID < 0x20000) || (imgdata.lens.makernotes.LensID > 0x4ffff)) &&
            (imgdata.lens.makernotes.LensID & 0x10))
        {
          imgdata.lens.makernotes.LensMount = LIBRAW_MOUNT_mFT;
        }
        break;
      case 0x20100202:
        if ((!imgdata.lens.LensSerial[0]))
          stmread(imgdata.lens.LensSerial, len, ifp);
        break;
      case 0x20100203:
        stmread(imgdata.lens.makernotes.Lens, len, ifp);
        break;
      case 0x20100205:
        imgdata.lens.makernotes.MaxAp4MinFocal = powf64(sqrt(2.0f), get2() / 256.0f);
        break;
      case 0x20100206:
        imgdata.lens.makernotes.MaxAp4MaxFocal = powf64(sqrt(2.0f), get2() / 256.0f);
        break;
      case 0x20100207:
        imgdata.lens.makernotes.MinFocal = (float)get2();
        break;
      case 0x20100208:
        imgdata.lens.makernotes.MaxFocal = (float)get2();
        if (imgdata.lens.makernotes.MaxFocal > 1000.0f)
          imgdata.lens.makernotes.MaxFocal = imgdata.lens.makernotes.MinFocal;
        break;
      case 0x2010020a:
        imgdata.lens.makernotes.MaxAp4CurFocal = powf64(sqrt(2.0f), get2() / 256.0f);
        break;
      case 0x20100301:
        imgdata.lens.makernotes.TeleconverterID = fgetc(ifp) << 8;
        fgetc(ifp);
        imgdata.lens.makernotes.TeleconverterID = imgdata.lens.makernotes.TeleconverterID | fgetc(ifp);
        break;
      case 0x20100303:
        stmread(imgdata.lens.makernotes.Teleconverter, len, ifp);
        break;
      case 0x20100403:
        stmread(imgdata.lens.makernotes.Attachment, len, ifp);
        break;
      case 0x20200401:
        imgdata.other.FlashEC = getreal(type);
        break;
      }
    skip_Oly_broken_tags:;
    }

    else if (!strncmp(make, "PENTAX", 6) || !strncmp(model, "PENTAX", 6) ||
             (!strncmp(make, "SAMSUNG", 7) && (dng_writer == CameraDNG)))
    {
      if (tag == 0x0005)
      {
        unique_id = get4();
        setPentaxBodyFeatures(unique_id);
      }
      else if (tag == 0x0013)
      {
        imgdata.lens.makernotes.CurAp = (float)get2() / 10.0f;
      }
      else if (tag == 0x0014)
      {
        PentaxISO(get2());
      }
      else if (tag == 0x001d)
      {
        imgdata.lens.makernotes.CurFocal = (float)get4() / 100.0f;
      }
      else if (tag == 0x003f)
      {
        imgdata.lens.makernotes.LensID = fgetc(ifp) << 8 | fgetc(ifp);
      }
      else if (tag == 0x004d)
      {
        if (type == 9)
          imgdata.other.FlashEC = getreal(type) / 256.0f;
        else
          imgdata.other.FlashEC = (float)((signed short)fgetc(ifp)) / 6.0f;
      }
      else if (tag == 0x007e)
      {
        imgdata.color.linear_max[0] = imgdata.color.linear_max[1] = imgdata.color.linear_max[2] =
            imgdata.color.linear_max[3] = (long)(-1) * get4();
      }
      else if (tag == 0x0207)
      {
        if (len < 65535) // Safety belt
          PentaxLensInfo(imgdata.lens.makernotes.CamID, len);
      }
      else if (tag == 0x020d)
      {
        FORC4 imgdata.color.WB_Coeffs[LIBRAW_WBI_Daylight][c ^ (c >> 1)] = get2();
      }
      else if (tag == 0x020e)
      {
        FORC4 imgdata.color.WB_Coeffs[LIBRAW_WBI_Shade][c ^ (c >> 1)] = get2();
      }
      else if (tag == 0x020f)
      {
        FORC4 imgdata.color.WB_Coeffs[LIBRAW_WBI_Cloudy][c ^ (c >> 1)] = get2();
      }
      else if (tag == 0x0210)
      {
        FORC4 imgdata.color.WB_Coeffs[LIBRAW_WBI_Tungsten][c ^ (c >> 1)] = get2();
      }
      else if (tag == 0x0211)
      {
        FORC4 imgdata.color.WB_Coeffs[LIBRAW_WBI_FL_D][c ^ (c >> 1)] = get2();
      }
      else if (tag == 0x0212)
      {
        FORC4 imgdata.color.WB_Coeffs[LIBRAW_WBI_FL_N][c ^ (c >> 1)] = get2();
      }
      else if (tag == 0x0213)
      {
        FORC4 imgdata.color.WB_Coeffs[LIBRAW_WBI_FL_W][c ^ (c >> 1)] = get2();
      }
      else if (tag == 0x0214)
      {
        FORC4 imgdata.color.WB_Coeffs[LIBRAW_WBI_Flash][c ^ (c >> 1)] = get2();
      }
      else if (tag == 0x0221)
      {
        int nWB = get2();
        if (nWB <= sizeof(imgdata.color.WBCT_Coeffs) / sizeof(imgdata.color.WBCT_Coeffs[0]))
          for (int i = 0; i < nWB; i++)
          {
            imgdata.color.WBCT_Coeffs[i][0] = (unsigned)0xcfc6 - get2();
            fseek(ifp, 2, SEEK_CUR);
            imgdata.color.WBCT_Coeffs[i][1] = get2();
            imgdata.color.WBCT_Coeffs[i][2] = imgdata.color.WBCT_Coeffs[i][4] = 0x2000;
            imgdata.color.WBCT_Coeffs[i][3] = get2();
          }
      }
      else if (tag == 0x0215)
      {
        fseek(ifp, 16, SEEK_CUR);
        sprintf(imgdata.shootinginfo.InternalBodySerial, "%d", get4());
      }
      else if (tag == 0x0229)
      {
        stmread(imgdata.shootinginfo.BodySerial, len, ifp);
      }
      else if (tag == 0x022d)
      {
        fseek(ifp, 2, SEEK_CUR);
        FORC4 imgdata.color.WB_Coeffs[LIBRAW_WBI_Daylight][c ^ (c >> 1)] = get2();
        getc(ifp);
        FORC4 imgdata.color.WB_Coeffs[LIBRAW_WBI_Shade][c ^ (c >> 1)] = get2();
        getc(ifp);
        FORC4 imgdata.color.WB_Coeffs[LIBRAW_WBI_Cloudy][c ^ (c >> 1)] = get2();
        getc(ifp);
        FORC4 imgdata.color.WB_Coeffs[LIBRAW_WBI_Tungsten][c ^ (c >> 1)] = get2();
        getc(ifp);
        FORC4 imgdata.color.WB_Coeffs[LIBRAW_WBI_FL_D][c ^ (c >> 1)] = get2();
        getc(ifp);
        FORC4 imgdata.color.WB_Coeffs[LIBRAW_WBI_FL_N][c ^ (c >> 1)] = get2();
        getc(ifp);
        FORC4 imgdata.color.WB_Coeffs[LIBRAW_WBI_FL_W][c ^ (c >> 1)] = get2();
        getc(ifp);
        FORC4 imgdata.color.WB_Coeffs[LIBRAW_WBI_Flash][c ^ (c >> 1)] = get2();
        getc(ifp);
        FORC4 imgdata.color.WB_Coeffs[LIBRAW_WBI_FL_L][c ^ (c >> 1)] = get2();
      }
      else if (tag == 0x0239) // Q-series lens info (LensInfoQ)
      {
        char LensInfo[20];
        fseek(ifp, 12, SEEK_CUR);
        stread(imgdata.lens.makernotes.Lens, 30, ifp);
        strcat(imgdata.lens.makernotes.Lens, " ");
        stread(LensInfo, 20, ifp);
        strcat(imgdata.lens.makernotes.Lens, LensInfo);
      }
    }

    else if (!strncmp(make, "SAMSUNG", 7) && (dng_writer == AdobeDNG))
    {
      if (tag == 0x0002)
      {
        if (get4() == 0x2000)
        {
          imgdata.lens.makernotes.CameraMount = LIBRAW_MOUNT_Samsung_NX;
        }
        else if (!strncmp(model, "NX mini", 7))
        {
          imgdata.lens.makernotes.CameraMount = LIBRAW_MOUNT_Samsung_NX_M;
        }
        else
        {
          imgdata.lens.makernotes.CameraMount = LIBRAW_MOUNT_FixedLens;
          imgdata.lens.makernotes.LensMount = LIBRAW_MOUNT_FixedLens;
        }
      }
      else if (tag == 0x0003)
      {
        imgdata.lens.makernotes.CamID = unique_id = get4();
      }
      else if (tag == 0xa003)
      {
        imgdata.lens.makernotes.LensID = get2();
        if (imgdata.lens.makernotes.LensID)
          imgdata.lens.makernotes.LensMount = LIBRAW_MOUNT_Samsung_NX;
      }
      else if (tag == 0xa005)
      {
        stmread(imgdata.lens.InternalLensSerial, len, ifp);
      }
      else if (tag == 0xa019)
      {
        imgdata.lens.makernotes.CurAp = getreal(type);
      }
      else if (tag == 0xa01a)
      {
        imgdata.lens.makernotes.FocalLengthIn35mmFormat = get4() / 10.0f;
        if (imgdata.lens.makernotes.FocalLengthIn35mmFormat < 10.0f)
          imgdata.lens.makernotes.FocalLengthIn35mmFormat *= 10.0f;
      }
    }

    else if (!strncasecmp(make, "SONY", 4) || !strncasecmp(make, "Konica", 6) || !strncasecmp(make, "Minolta", 7) ||
             (!strncasecmp(make, "Hasselblad", 10) &&
              (!strncasecmp(model, "Stellar", 7) || !strncasecmp(model, "Lunar", 5) ||
               !strncasecmp(model, "Lusso", 5) || !strncasecmp(model, "HV", 2))))
    {
      ushort lid;

      if (tag == 0xb001) // Sony ModelID
      {
        unique_id = get2();
        setSonyBodyFeatures(unique_id);
        if (table_buf_0x9050_present)
        {
          process_Sony_0x9050(table_buf_0x9050, unique_id);
          free(table_buf_0x9050);
          table_buf_0x9050_present = 0;
        }
        if (table_buf_0x940c_present)
        {
          if (imgdata.lens.makernotes.CameraMount == LIBRAW_MOUNT_Sony_E)
          {
            process_Sony_0x940c(table_buf_0x940c);
          }
          free(table_buf_0x940c);
          table_buf_0x940c_present = 0;
        }
      }
      else if ((tag == 0x0010) && // CameraInfo
               strncasecmp(model, "DSLR-A100", 9) && strncasecmp(model, "NEX-5C", 6) && !strncasecmp(make, "SONY", 4) &&
               ((len == 368) ||  // a700
                (len == 5478) || // a850, a900
                (len == 5506) || // a200, a300, a350
                (len == 6118) || // a230, a290, a330, a380, a390

                // a450, a500, a550, a560, a580
                // a33, a35, a55
                // NEX3, NEX5, NEX5C, NEXC3, VG10E
                (len == 15360)))
      {
        table_buf = (uchar *)malloc(len);
        fread(table_buf, len, 1, ifp);
        if (memcmp(table_buf, "\xff\xff\xff\xff\xff\xff\xff\xff", 8) &&
            memcmp(table_buf, "\x00\x00\x00\x00\x00\x00\x00\x00", 8))
        {
          switch (len)
          {
          case 368:
          case 5478:
            // a700, a850, a900: CameraInfo
            if (saneSonyCameraInfo(table_buf[0], table_buf[3], table_buf[2], table_buf[5], table_buf[4], table_buf[7]))
            {
              if (table_buf[0] | table_buf[3])
                imgdata.lens.makernotes.MinFocal = bcd2dec(table_buf[0]) * 100 + bcd2dec(table_buf[3]);
              if (table_buf[2] | table_buf[5])
                imgdata.lens.makernotes.MaxFocal = bcd2dec(table_buf[2]) * 100 + bcd2dec(table_buf[5]);
              if (table_buf[4])
                imgdata.lens.makernotes.MaxAp4MinFocal = bcd2dec(table_buf[4]) / 10.0f;
              if (table_buf[4])
                imgdata.lens.makernotes.MaxAp4MaxFocal = bcd2dec(table_buf[7]) / 10.0f;
              parseSonyLensFeatures(table_buf[1], table_buf[6]);
            }
            break;
          default:
            // CameraInfo2 & 3
            if (saneSonyCameraInfo(table_buf[1], table_buf[2], table_buf[3], table_buf[4], table_buf[5], table_buf[6]))
            {
              if (table_buf[1] | table_buf[2])
                imgdata.lens.makernotes.MinFocal = bcd2dec(table_buf[1]) * 100 + bcd2dec(table_buf[2]);
              if (table_buf[3] | table_buf[4])
                imgdata.lens.makernotes.MaxFocal = bcd2dec(table_buf[3]) * 100 + bcd2dec(table_buf[4]);
              if (table_buf[5])
                imgdata.lens.makernotes.MaxAp4MinFocal = bcd2dec(table_buf[5]) / 10.0f;
              if (table_buf[6])
                imgdata.lens.makernotes.MaxAp4MaxFocal = bcd2dec(table_buf[6]) / 10.0f;
              parseSonyLensFeatures(table_buf[0], table_buf[7]);
            }
          }
        }
        free(table_buf);
      }

      else if (tag == 0x0104)
      {
        imgdata.other.FlashEC = getreal(type);
      }

      else if (tag == 0x0105) // Teleconverter
      {
        imgdata.lens.makernotes.TeleconverterID = get2();
      }

      else if (tag == 0x0114 && len < 65535) // CameraSettings
      {
        table_buf = (uchar *)malloc(len);
        fread(table_buf, len, 1, ifp);
        switch (len)
        {
        case 280:
        case 364:
        case 332:
          // CameraSettings and CameraSettings2 are big endian
          if (table_buf[2] | table_buf[3])
          {
            lid = (((ushort)table_buf[2]) << 8) | ((ushort)table_buf[3]);
            imgdata.lens.makernotes.CurAp = powf64(2.0f, ((float)lid / 8.0f - 1.0f) / 2.0f);
          }
          break;
        case 1536:
        case 2048:
          // CameraSettings3 are little endian
          parseSonyLensType2(table_buf[1016], table_buf[1015]);
          if (imgdata.lens.makernotes.LensMount != LIBRAW_MOUNT_Canon_EF)
          {
            switch (table_buf[153])
            {
            case 16:
              imgdata.lens.makernotes.LensMount = LIBRAW_MOUNT_Minolta_A;
              break;
            case 17:
              imgdata.lens.makernotes.LensMount = LIBRAW_MOUNT_Sony_E;
              break;
            }
          }
          break;
        }
        free(table_buf);
      }

      else if (tag == 0x9050 && len < 256000) // little endian
      {
        table_buf_0x9050 = (uchar *)malloc(len);
        table_buf_0x9050_present = 1;
        fread(table_buf_0x9050, len, 1, ifp);

        if (imgdata.lens.makernotes.CamID)
        {
          process_Sony_0x9050(table_buf_0x9050, imgdata.lens.makernotes.CamID);
          free(table_buf_0x9050);
          table_buf_0x9050_present = 0;
        }
      }

      else if (tag == 0x940c && len < 256000)
      {
        table_buf_0x940c = (uchar *)malloc(len);
        table_buf_0x940c_present = 1;
        fread(table_buf_0x940c, len, 1, ifp);
        if ((imgdata.lens.makernotes.CamID) && (imgdata.lens.makernotes.CameraMount == LIBRAW_MOUNT_Sony_E))
        {
          process_Sony_0x940c(table_buf_0x940c);
          free(table_buf_0x940c);
          table_buf_0x940c_present = 0;
        }
      }

      else if (((tag == 0xb027) || (tag == 0x010c)) && (imgdata.lens.makernotes.LensID == -1))
      {
        imgdata.lens.makernotes.LensID = get4();
        if ((imgdata.lens.makernotes.LensID > 0x4900) && (imgdata.lens.makernotes.LensID <= 0x5900))
        {
          imgdata.lens.makernotes.AdapterID = 0x4900;
          imgdata.lens.makernotes.LensID -= imgdata.lens.makernotes.AdapterID;
          imgdata.lens.makernotes.LensMount = LIBRAW_MOUNT_Sigma_X3F;
          strcpy(imgdata.lens.makernotes.Adapter, "MC-11");
        }

        else if ((imgdata.lens.makernotes.LensID > 0xEF00) && (imgdata.lens.makernotes.LensID < 0xFFFF) &&
                 (imgdata.lens.makernotes.LensID != 0xFF00))
        {
          imgdata.lens.makernotes.AdapterID = 0xEF00;
          imgdata.lens.makernotes.LensID -= imgdata.lens.makernotes.AdapterID;
          imgdata.lens.makernotes.LensMount = LIBRAW_MOUNT_Canon_EF;
        }
        if (tag == 0x010c)
          imgdata.lens.makernotes.CameraMount = LIBRAW_MOUNT_Minolta_A;
      }

      else if (tag == 0xb02a && len < 256000) // Sony LensSpec
      {
        table_buf = (uchar *)malloc(len);
        fread(table_buf, len, 1, ifp);
        if (saneSonyCameraInfo(table_buf[1], table_buf[2], table_buf[3], table_buf[4], table_buf[5], table_buf[6]))
        {
          if (table_buf[1] | table_buf[2])
            imgdata.lens.makernotes.MinFocal = bcd2dec(table_buf[1]) * 100 + bcd2dec(table_buf[2]);
          if (table_buf[3] | table_buf[4])
            imgdata.lens.makernotes.MaxFocal = bcd2dec(table_buf[3]) * 100 + bcd2dec(table_buf[4]);
          if (table_buf[5])
            imgdata.lens.makernotes.MaxAp4MinFocal = bcd2dec(table_buf[5]) / 10.0f;
          if (table_buf[6])
            imgdata.lens.makernotes.MaxAp4MaxFocal = bcd2dec(table_buf[6]) / 10.0f;
          parseSonyLensFeatures(table_buf[0], table_buf[7]);
        }
        free(table_buf);
      }
    }
  next:
    fseek(ifp, save, SEEK_SET);
  }
quit:
  order = sorder;
}

Project: LibRaw
File: dcraw.c

void CLASS parse_foveon()
{
  int entries, img = 0, off, len, tag, save, i, wide, high, pent, poff[256][2];
  char name[64], value[64];
  order = 0x4949; /* Little-endian */
  fseek(ifp, 36, SEEK_SET);
  flip = get4();
  fseek(ifp, -4, SEEK_END);
  fseek(ifp, get4(), SEEK_SET);
  if (get4() != 0x64434553)
    return; /* SECd */
  entries = (get4(), get4());
  while (entries--)
  {
    off = get4();
    len = get4();
    tag = get4();
    save = ftell(ifp);
    fseek(ifp, off, SEEK_SET);
    if (get4() != (0x20434553 | (tag << 24)))
      return;
    switch (tag)
    {
    case 0x47414d49: /* IMAG */
    case 0x32414d49: /* IMA2 */
      fseek(ifp, 8, SEEK_CUR);
      pent = get4();
      wide = get4();
      high = get4();
      if (wide > raw_width && high > raw_height)
      {
        switch (pent)
        {
        case 5:
          load_flags = 1;
        case 6:
          load_raw = &CLASS foveon_sd_load_raw;
          break;
        case 30:
          load_raw = &CLASS foveon_dp_load_raw;
          break;
        default:
          load_raw = 0;
        }
        raw_width = wide;
        raw_height = high;
        data_offset = off + 28;
        is_foveon = 1;
      }
      fseek(ifp, off + 28, SEEK_SET);
      if (fgetc(ifp) == 0xff && fgetc(ifp) == 0xd8 && thumb_length < len - 28)
      {
        thumb_offset = off + 28;
        thumb_length = len - 28;
        write_thumb = &CLASS jpeg_thumb;
      }
      if (++img == 2 && !thumb_length)
      {
        thumb_offset = off + 24;
        thumb_width = wide;
        thumb_height = high;
        write_thumb = &CLASS foveon_thumb;
      }
      break;
    case 0x464d4143: /* CAMF */
      meta_offset = off + 8;
      meta_length = len - 28;
      break;
    case 0x504f5250: /* PROP */
      pent = (get4(), get4());
      fseek(ifp, 12, SEEK_CUR);
      off += pent * 8 + 24;
      if ((unsigned)pent > 256)
        pent = 256;
      for (i = 0; i < pent * 2; i++)
        ((int *)poff)[i] = off + get4() * 2;
      for (i = 0; i < pent; i++)
      {
        foveon_gets(poff[i][0], name, 64);
        foveon_gets(poff[i][1], value, 64);
        if (!strcmp(name, "ISO"))
          iso_speed = atoi(value);
        if (!strcmp(name, "CAMMANUF"))
          strcpy(make, value);
        if (!strcmp(name, "CAMMODEL"))
          strcpy(model, value);
        if (!strcmp(name, "WB_DESC"))
          strcpy(model2, value);
        if (!strcmp(name, "TIME"))
          timestamp = atoi(value);
        if (!strcmp(name, "EXPTIME"))
          shutter = atoi(value) / 1000000.0;
        if (!strcmp(name, "APERTURE"))
          aperture = atof(value);
        if (!strcmp(name, "FLENGTH"))
          focal_len = atof(value);
#ifdef LIBRAW_LIBRARY_BUILD
        if (!strcmp(name, "CAMSERIAL"))
          strcpy(imgdata.shootinginfo.BodySerial, value);
        if (!strcmp(name, "FLEQ35MM"))
          imgdata.lens.makernotes.FocalLengthIn35mmFormat = atof(value);
        if (!strcmp(name, "LENSARANGE"))
        {
          char *sp;
          imgdata.lens.makernotes.MaxAp4CurFocal = imgdata.lens.makernotes.MinAp4CurFocal = atof(value);
          sp = strrchr(value, ' ');
          if (sp)
          {
            imgdata.lens.makernotes.MinAp4CurFocal = atof(sp);
            if (imgdata.lens.makernotes.MaxAp4CurFocal > imgdata.lens.makernotes.MinAp4CurFocal)
              my_swap(float, imgdata.lens.makernotes.MaxAp4CurFocal, imgdata.lens.makernotes.MinAp4CurFocal);
          }
        }
        if (!strcmp(name, "LENSFRANGE"))
        {
          char *sp;
          imgdata.lens.makernotes.MinFocal = imgdata.lens.makernotes.MaxFocal = atof(value);
          sp = strrchr(value, ' ');
          if (sp)
          {
            imgdata.lens.makernotes.MaxFocal = atof(sp);
            if ((imgdata.lens.makernotes.MaxFocal + 0.17f) < imgdata.lens.makernotes.MinFocal)
              my_swap(float, imgdata.lens.makernotes.MaxFocal, imgdata.lens.makernotes.MinFocal);
          }
        }
        if (!strcmp(name, "LENSMODEL"))
        {
          char *sp;
          imgdata.lens.makernotes.LensID = strtol(value, &sp, 16); // atoi(value);
          if (imgdata.lens.makernotes.LensID)
            imgdata.lens.makernotes.LensMount = Sigma_X3F;
        }
      }
#endif
    }
#ifdef LOCALTIME
    timestamp = mktime(gmtime(&timestamp));
#endif
  }
  fseek(ifp, save, SEEK_SET);
}

Project: LibRaw
File: dcraw.c

void CLASS apply_tiff()
{
  int max_samp = 0, ties = 0, raw = -1, thm = -1, i;
  unsigned long long ns, os;
  struct jhead jh;

  thumb_misc = 16;
  if (thumb_offset)
  {
    fseek(ifp, thumb_offset, SEEK_SET);
    if (ljpeg_start(&jh, 1))
    {
      if ((unsigned)jh.bits < 17 && (unsigned)jh.wide < 0x10000 && (unsigned)jh.high < 0x10000)
      {
        thumb_misc = jh.bits;
        thumb_width = jh.wide;
        thumb_height = jh.high;
      }
    }
  }
  for (i = tiff_nifds; i--;)
  {
    if (tiff_ifd[i].t_shutter)
      shutter = tiff_ifd[i].t_shutter;
    tiff_ifd[i].t_shutter = shutter;
  }
  for (i = 0; i < tiff_nifds; i++)
  {
    if (max_samp < tiff_ifd[i].samples)
      max_samp = tiff_ifd[i].samples;
    if (max_samp > 3)
      max_samp = 3;
    os = raw_width * raw_height;
    ns = tiff_ifd[i].t_width * tiff_ifd[i].t_height;
    if (tiff_bps)
    {
      os *= tiff_bps;
      ns *= tiff_ifd[i].bps;
    }
    if ((tiff_ifd[i].comp != 6 || tiff_ifd[i].samples != 3) &&
        unsigned(tiff_ifd[i].t_width | tiff_ifd[i].t_height) < 0x10000 && (unsigned)tiff_ifd[i].bps < 33 &&
        (unsigned)tiff_ifd[i].samples < 13 && ns && ((ns > os && (ties = 1)) || (ns == os && shot_select == ties++)))
    {
      raw_width = tiff_ifd[i].t_width;
      raw_height = tiff_ifd[i].t_height;
      tiff_bps = tiff_ifd[i].bps;
      tiff_compress = tiff_ifd[i].comp;
      data_offset = tiff_ifd[i].offset;
#ifdef LIBRAW_LIBRARY_BUILD
      data_size = tiff_ifd[i].bytes;
#endif
      tiff_flip = tiff_ifd[i].t_flip;
      tiff_samples = tiff_ifd[i].samples;
      tile_width = tiff_ifd[i].t_tile_width;
      tile_length = tiff_ifd[i].t_tile_length;
      shutter = tiff_ifd[i].t_shutter;
      raw = i;
    }
  }
  if (is_raw == 1 && ties)
    is_raw = ties;
  if (!tile_width)
    tile_width = INT_MAX;
  if (!tile_length)
    tile_length = INT_MAX;
  for (i = tiff_nifds; i--;)
    if (tiff_ifd[i].t_flip)
      tiff_flip = tiff_ifd[i].t_flip;
  if (raw >= 0 && !load_raw)
    switch (tiff_compress)
    {
    case 32767:
      if (tiff_ifd[raw].bytes == raw_width * raw_height)
      {
        tiff_bps = 12;
        load_raw = &CLASS sony_arw2_load_raw;
        break;
      }
      if (!strncasecmp(make, "Sony", 4) && tiff_ifd[raw].bytes == raw_width * raw_height * 2)
      {
        tiff_bps = 14;
        load_raw = &CLASS unpacked_load_raw;
        break;
      }
      if (tiff_ifd[raw].bytes * 8 != raw_width * raw_height * tiff_bps)
      {
        raw_height += 8;
        load_raw = &CLASS sony_arw_load_raw;
        break;
      }
      load_flags = 79;
    case 32769:
      load_flags++;
    case 32770:
    case 32773:
      goto slr;
    case 0:
    case 1:
#ifdef LIBRAW_LIBRARY_BUILD
      // Sony 14-bit uncompressed
      if (!strncasecmp(make, "Sony", 4) && tiff_ifd[raw].bytes == raw_width * raw_height * 2)
      {
        tiff_bps = 14;
        load_raw = &CLASS unpacked_load_raw;
        break;
      }
      if (!strncasecmp(make, "Nikon", 5) && !strncmp(software, "Nikon Scan", 10))
      {
        load_raw = &CLASS nikon_coolscan_load_raw;
        raw_color = 1;
        filters = 0;
        break;
      }
#endif
      if (!strncmp(make, "OLYMPUS", 7) && tiff_ifd[raw].bytes * 2 == raw_width * raw_height * 3)
        load_flags = 24;
      if (tiff_ifd[raw].bytes * 5 == raw_width * raw_height * 8)
      {
        load_flags = 81;
        tiff_bps = 12;
      }
    slr:
      switch (tiff_bps)
      {
      case 8:
        load_raw = &CLASS eight_bit_load_raw;
        break;
      case 12:
        if (tiff_ifd[raw].phint == 2)
          load_flags = 6;
        load_raw = &CLASS packed_load_raw;
        break;
      case 14:
        load_flags = 0;
      case 16:
        load_raw = &CLASS unpacked_load_raw;
        if (!strncmp(make, "OLYMPUS", 7) && tiff_ifd[raw].bytes * 7 > raw_width * raw_height)
          load_raw = &CLASS olympus_load_raw;
      }
      break;
    case 6:
    case 7:
    case 99:
      load_raw = &CLASS lossless_jpeg_load_raw;
      break;
    case 262:
      load_raw = &CLASS kodak_262_load_raw;
      break;
    case 34713:
      if ((raw_width + 9) / 10 * 16 * raw_height == tiff_ifd[raw].bytes)
      {
        load_raw = &CLASS packed_load_raw;
        load_flags = 1;
      }
      else if (raw_width * raw_height * 3 == tiff_ifd[raw].bytes * 2)
      {
        load_raw = &CLASS packed_load_raw;
        if (model[0] == 'N')
          load_flags = 80;
      }
      else if (raw_width * raw_height * 3 == tiff_ifd[raw].bytes)
      {
        load_raw = &CLASS nikon_yuv_load_raw;
        gamma_curve(1 / 2.4, 12.92, 1, 4095);
        memset(cblack, 0, sizeof cblack);
        filters = 0;
      }
      else if (raw_width * raw_height * 2 == tiff_ifd[raw].bytes)
      {
        load_raw = &CLASS unpacked_load_raw;
        load_flags = 4;
        order = 0x4d4d;
      }
      else
#ifdef LIBRAW_LIBRARY_BUILD
          if (raw_width * raw_height * 3 == tiff_ifd[raw].bytes * 2)
      {
        load_raw = &CLASS packed_load_raw;
        load_flags = 80;
      }
      else if (tiff_ifd[raw].rows_per_strip && tiff_ifd[raw].strip_offsets_count &&
               tiff_ifd[raw].strip_offsets_count == tiff_ifd[raw].strip_byte_counts_count)
      {
        int fit = 1;
        for (int i = 0; i < tiff_ifd[raw].strip_byte_counts_count - 1; i++) // all but last
          if (tiff_ifd[raw].strip_byte_counts[i] * 2 != tiff_ifd[raw].rows_per_strip * raw_width * 3)
          {
            fit = 0;
            break;
          }
        if (fit)
          load_raw = &CLASS nikon_load_striped_packed_raw;
        else
          load_raw = &CLASS nikon_load_raw; // fallback
      }
      else
#endif
        load_raw = &CLASS nikon_load_raw;
      break;
    case 65535:
      load_raw = &CLASS pentax_load_raw;
      break;
    case 65000:
      switch (tiff_ifd[raw].phint)
      {
      case 2:
        load_raw = &CLASS kodak_rgb_load_raw;
        filters = 0;
        break;
      case 6:
        load_raw = &CLASS kodak_ycbcr_load_raw;
        filters = 0;
        break;
      case 32803:
        load_raw = &CLASS kodak_65000_load_raw;
      }
    case 32867:
    case 34892:
      break;
#ifdef LIBRAW_LIBRARY_BUILD
    case 8:
      break;
#endif
    default:
      is_raw = 0;
    }
  if (!dng_version)
    if (((tiff_samples == 3 && tiff_ifd[raw].bytes && tiff_bps != 14 && (tiff_compress & -16) != 32768) ||
         (tiff_bps == 8 && strncmp(make, "Phase", 5) && !strcasestr(make, "Kodak") && !strstr(model2, "DEBUG RAW"))) &&
        strncmp(software, "Nikon Scan", 10))
      is_raw = 0;
  for (i = 0; i < tiff_nifds; i++)
    if (i != raw &&
        (tiff_ifd[i].samples == max_samp || (tiff_ifd[i].comp == 7 && tiff_ifd[i].samples == 1)) /* Allow 1-bps JPEGs */
        && tiff_ifd[i].bps > 0 && tiff_ifd[i].bps < 33 && tiff_ifd[i].phint != 32803 && tiff_ifd[i].phint != 34892 &&
        unsigned(tiff_ifd[i].t_width | tiff_ifd[i].t_height) < 0x10000 &&
        tiff_ifd[i].t_width * tiff_ifd[i].t_height / (SQR(tiff_ifd[i].bps) + 1) >
            thumb_width * thumb_height / (SQR(thumb_misc) + 1) &&
        tiff_ifd[i].comp != 34892)
    {
      thumb_width = tiff_ifd[i].t_width;
      thumb_height = tiff_ifd[i].t_height;
      thumb_offset = tiff_ifd[i].offset;
      thumb_length = tiff_ifd[i].bytes;
      thumb_misc = tiff_ifd[i].bps;
      thm = i;
    }
  if (thm >= 0)
  {
    thumb_misc |= tiff_ifd[thm].samples << 5;
    switch (tiff_ifd[thm].comp)
    {
    case 0:
      write_thumb = &CLASS layer_thumb;
      break;
    case 1:
      if (tiff_ifd[thm].bps <= 8)
        write_thumb = &CLASS ppm_thumb;
      else if (!strncmp(make, "Imacon", 6))
        write_thumb = &CLASS ppm16_thumb;
      else
        thumb_load_raw = &CLASS kodak_thumb_load_raw;
      break;
    case 65000:
      thumb_load_raw = tiff_ifd[thm].phint == 6 ? &CLASS kodak_ycbcr_load_raw : &CLASS kodak_rgb_load_raw;
    }
  }
}

Project: LibRaw
File: dcraw.c

int CLASS phase_one_correct()
{
  unsigned entries, tag, data, save, col, row, type;
  int len, i, j, k, cip, val[4], dev[4], sum, max;
  int head[9], diff, mindiff = INT_MAX, off_412 = 0;
  /* static */ const signed char dir[12][2] = {{-1, -1}, {-1, 1}, {1, -1},  {1, 1},  {-2, 0}, {0, -2},
                                               {0, 2},   {2, 0},  {-2, -2}, {-2, 2}, {2, -2}, {2, 2}};
  float poly[8], num, cfrac, frac, mult[2], *yval[2] = {NULL, NULL};
  ushort *xval[2];
  int qmult_applied = 0, qlin_applied = 0;

  if (half_size || !meta_length)
    return 0;
#ifdef DCRAW_VERBOSE
  if (verbose)
    fprintf(stderr, _("Phase One correction...\n"));
#endif
  fseek(ifp, meta_offset, SEEK_SET);
  order = get2();
  fseek(ifp, 6, SEEK_CUR);
  fseek(ifp, meta_offset + get4(), SEEK_SET);
  entries = get4();
  get4();

#ifdef LIBRAW_LIBRARY_BUILD
  try
  {
#endif
    while (entries--)
    {
#ifdef LIBRAW_LIBRARY_BUILD
      checkCancel();
#endif
      tag = get4();
      len = get4();
      data = get4();
      save = ftell(ifp);
      fseek(ifp, meta_offset + data, SEEK_SET);
      if (tag == 0x419)
      { /* Polynomial curve */
        for (get4(), i = 0; i < 8; i++)
          poly[i] = getreal(11);
        poly[3] += (ph1.tag_210 - poly[7]) * poly[6] + 1;
        for (i = 0; i < 0x10000; i++)
        {
          num = (poly[5] * i + poly[3]) * i + poly[1];
          curve[i] = LIM(num, 0, 65535);
        }
        goto apply; /* apply to right half */
      }
      else if (tag == 0x41a)
      { /* Polynomial curve */
        for (i = 0; i < 4; i++)
          poly[i] = getreal(11);
        for (i = 0; i < 0x10000; i++)
        {
          for (num = 0, j = 4; j--;)
            num = num * i + poly[j];
          curve[i] = LIM(num + i, 0, 65535);
        }
      apply: /* apply to whole image */
        for (row = 0; row < raw_height; row++)
        {
#ifdef LIBRAW_LIBRARY_BUILD
          checkCancel();
#endif
          for (col = (tag & 1) * ph1.split_col; col < raw_width; col++)
            RAW(row, col) = curve[RAW(row, col)];
        }
      }
      else if (tag == 0x400)
      { /* Sensor defects */
        while ((len -= 8) >= 0)
        {
          col = get2();
          row = get2();
          type = get2();
          get2();
          if (col >= raw_width)
            continue;
          if (type == 131 || type == 137) /* Bad column */
            for (row = 0; row < raw_height; row++)
              if (FC(row - top_margin, col - left_margin) == 1)
              {
                for (sum = i = 0; i < 4; i++)
                  sum += val[i] = raw(row + dir[i][0], col + dir[i][1]);
                for (max = i = 0; i < 4; i++)
                {
                  dev[i] = abs((val[i] << 2) - sum);
                  if (dev[max] < dev[i])
                    max = i;
                }
                RAW(row, col) = (sum - val[max]) / 3.0 + 0.5;
              }
              else
              {
                for (sum = 0, i = 8; i < 12; i++)
                  sum += raw(row + dir[i][0], col + dir[i][1]);
                RAW(row, col) = 0.5 + sum * 0.0732233 + (raw(row, col - 2) + raw(row, col + 2)) * 0.3535534;
              }
          else if (type == 129)
          { /* Bad pixel */
            if (row >= raw_height)
              continue;
            j = (FC(row - top_margin, col - left_margin) != 1) * 4;
            for (sum = 0, i = j; i < j + 8; i++)
              sum += raw(row + dir[i][0], col + dir[i][1]);
            RAW(row, col) = (sum + 4) >> 3;
          }
        }
      }
      else if (tag == 0x401)
      { /* All-color flat fields */
        phase_one_flat_field(1, 2);
      }
      else if (tag == 0x416 || tag == 0x410)
      {
        phase_one_flat_field(0, 2);
      }
      else if (tag == 0x40b)
      { /* Red+blue flat field */
        phase_one_flat_field(0, 4);
      }
      else if (tag == 0x412)
      {
        fseek(ifp, 36, SEEK_CUR);
        diff = abs(get2() - ph1.tag_21a);
        if (mindiff > diff)
        {
          mindiff = diff;
          off_412 = ftell(ifp) - 38;
        }
      }
      else if (tag == 0x41f && !qlin_applied)
      { /* Quadrant linearization */
        ushort lc[2][2][16], ref[16];
        int qr, qc;
        for (qr = 0; qr < 2; qr++)
          for (qc = 0; qc < 2; qc++)
            for (i = 0; i < 16; i++)
              lc[qr][qc][i] = get4();
        for (i = 0; i < 16; i++)
        {
          int v = 0;
          for (qr = 0; qr < 2; qr++)
            for (qc = 0; qc < 2; qc++)
              v += lc[qr][qc][i];
          ref[i] = (v + 2) >> 2;
        }
        for (qr = 0; qr < 2; qr++)
        {
          for (qc = 0; qc < 2; qc++)
          {
            int cx[19], cf[19];
            for (i = 0; i < 16; i++)
            {
              cx[1 + i] = lc[qr][qc][i];
              cf[1 + i] = ref[i];
            }
            cx[0] = cf[0] = 0;
            cx[17] = cf[17] = ((unsigned int)ref[15] * 65535) / lc[qr][qc][15];
            cf[18] = cx[18] = 65535;
            cubic_spline(cx, cf, 19);

            for (row = (qr ? ph1.split_row : 0); row < (qr ? raw_height : ph1.split_row); row++)
            {
#ifdef LIBRAW_LIBRARY_BUILD
              checkCancel();
#endif
              for (col = (qc ? ph1.split_col : 0); col < (qc ? raw_width : ph1.split_col); col++)
                RAW(row, col) = curve[RAW(row, col)];
            }
          }
        }
        qlin_applied = 1;
      }
      else if (tag == 0x41e && !qmult_applied)
      { /* Quadrant multipliers */
        float qmult[2][2] = {{1, 1}, {1, 1}};
        get4();
        get4();
        get4();
        get4();
        qmult[0][0] = 1.0 + getreal(11);
        get4();
        get4();
        get4();
        get4();
        get4();
        qmult[0][1] = 1.0 + getreal(11);
        get4();
        get4();
        get4();
        qmult[1][0] = 1.0 + getreal(11);
        get4();
        get4();
        get4();
        qmult[1][1] = 1.0 + getreal(11);
        for (row = 0; row < raw_height; row++)
        {
#ifdef LIBRAW_LIBRARY_BUILD
          checkCancel();
#endif
          for (col = 0; col < raw_width; col++)
          {
            i = qmult[row >= ph1.split_row][col >= ph1.split_col] * RAW(row, col);
            RAW(row, col) = LIM(i, 0, 65535);
          }
        }
        qmult_applied = 1;
      }
      else if (tag == 0x431 && !qmult_applied)
      { /* Quadrant combined */
        ushort lc[2][2][7], ref[7];
        int qr, qc;
        for (i = 0; i < 7; i++)
          ref[i] = get4();
        for (qr = 0; qr < 2; qr++)
          for (qc = 0; qc < 2; qc++)
            for (i = 0; i < 7; i++)
              lc[qr][qc][i] = get4();
        for (qr = 0; qr < 2; qr++)
        {
          for (qc = 0; qc < 2; qc++)
          {
            int cx[9], cf[9];
            for (i = 0; i < 7; i++)
            {
              cx[1 + i] = ref[i];
              cf[1 + i] = ((unsigned)ref[i] * lc[qr][qc][i]) / 10000;
            }
            cx[0] = cf[0] = 0;
            cx[8] = cf[8] = 65535;
            cubic_spline(cx, cf, 9);
            for (row = (qr ? ph1.split_row : 0); row < (qr ? raw_height : ph1.split_row); row++)
            {
#ifdef LIBRAW_LIBRARY_BUILD
              checkCancel();
#endif
              for (col = (qc ? ph1.split_col : 0); col < (qc ? raw_width : ph1.split_col); col++)
                RAW(row, col) = curve[RAW(row, col)];
            }
          }
        }
        qmult_applied = 1;
        qlin_applied = 1;
      }
      fseek(ifp, save, SEEK_SET);
    }
    if (off_412)
    {
      fseek(ifp, off_412, SEEK_SET);
      for (i = 0; i < 9; i++)
        head[i] = get4() & 0x7fff;
      yval[0] = (float *)calloc(head[1] * head[3] + head[2] * head[4], 6);
      merror(yval[0], "phase_one_correct()");
      yval[1] = (float *)(yval[0] + head[1] * head[3]);
      xval[0] = (ushort *)(yval[1] + head[2] * head[4]);
      xval[1] = (ushort *)(xval[0] + head[1] * head[3]);
      get2();
      for (i = 0; i < 2; i++)
        for (j = 0; j < head[i + 1] * head[i + 3]; j++)
          yval[i][j] = getreal(11);
      for (i = 0; i < 2; i++)
        for (j = 0; j < head[i + 1] * head[i + 3]; j++)
          xval[i][j] = get2();
      for (row = 0; row < raw_height; row++)
      {
#ifdef LIBRAW_LIBRARY_BUILD
        checkCancel();
#endif
        for (col = 0; col < raw_width; col++)
        {
          cfrac = (float)col * head[3] / raw_width;
          cfrac -= cip = cfrac;
          num = RAW(row, col) * 0.5;
          for (i = cip; i < cip + 2; i++)
          {
            for (k = j = 0; j < head[1]; j++)
              if (num < xval[0][k = head[1] * i + j])
                break;
            frac = (j == 0 || j == head[1]) ? 0 : (xval[0][k] - num) / (xval[0][k] - xval[0][k - 1]);
            mult[i - cip] = yval[0][k - 1] * frac + yval[0][k] * (1 - frac);
          }
          i = ((mult[0] * (1 - cfrac) + mult[1] * cfrac) * row + num) * 2;
          RAW(row, col) = LIM(i, 0, 65535);
        }
      }
      free(yval[0]);
    }
#ifdef LIBRAW_LIBRARY_BUILD
  }
  catch (...)
  {
    if (yval[0])
      free(yval[0]);
    return LIBRAW_CANCELLED_BY_CALLBACK;
  }
#endif
  return 0;
}