void CLASS parse_exif(int base)
{
  unsigned kodak, entries, tag, type, len, save, c;
  double expo, ape;

  kodak = !strncmp(make, "EASTMAN", 7) && tiff_nifds < 3;
  entries = get2();
  if (!strncmp(make, "Hasselblad", 10) && (tiff_nifds > 3) && (entries > 512))
    return;
#ifdef LIBRAW_LIBRARY_BUILD
  INT64 fsize = ifp->size();
#endif
  while (entries--)
  {
    tiff_get(base, &tag, &type, &len, &save);

#ifdef LIBRAW_LIBRARY_BUILD
    INT64 savepos = ftell(ifp);
    if (len > 8 && savepos + len > fsize * 2)
      continue;
    if (callbacks.exif_cb)
    {
      callbacks.exif_cb(callbacks.exifparser_data, tag, type, len, order, ifp);
      fseek(ifp, savepos, SEEK_SET);
    }
#endif
    switch (tag)
    {
#ifdef LIBRAW_LIBRARY_BUILD
    case 0xa405: // FocalLengthIn35mmFormat
      imgdata.lens.FocalLengthIn35mmFormat = get2();
      break;
    case 0xa431: // BodySerialNumber
      stmread(imgdata.shootinginfo.BodySerial, len, ifp);
      break;
    case 0xa432: // LensInfo, 42034dec, Lens Specification per EXIF standard
      imgdata.lens.MinFocal = getreal(type);
      imgdata.lens.MaxFocal = getreal(type);
      imgdata.lens.MaxAp4MinFocal = getreal(type);
      imgdata.lens.MaxAp4MaxFocal = getreal(type);
      break;
    case 0xa435: // LensSerialNumber
      stmread(imgdata.lens.LensSerial, len, ifp);
      break;
    case 0xc630: // DNG LensInfo, Lens Specification per EXIF standard
      imgdata.lens.dng.MinFocal = getreal(type);
      imgdata.lens.dng.MaxFocal = getreal(type);
      imgdata.lens.dng.MaxAp4MinFocal = getreal(type);
      imgdata.lens.dng.MaxAp4MaxFocal = getreal(type);
      break;
    case 0xa433: // LensMake
      stmread(imgdata.lens.LensMake, len, ifp);
      break;
    case 0xa434: // LensModel
      stmread(imgdata.lens.Lens, len, ifp);
      if (!strncmp(imgdata.lens.Lens, "----", 4))
        imgdata.lens.Lens[0] = 0;
      break;
    case 0x9205:
      imgdata.lens.EXIF_MaxAp = powf64(2.0f, (getreal(type) / 2.0f));
      break;
#endif
    case 33434:
      tiff_ifd[tiff_nifds - 1].t_shutter = shutter = getreal(type);
      break;
    case 33437:
      aperture = getreal(type);
      break; // 0x829d FNumber
    case 34855:
      iso_speed = get2();
      break;
    case 34866:
      if (iso_speed == 0xffff && (!strncasecmp(make, "SONY", 4) || !strncasecmp(make, "CANON", 5)))
        iso_speed = getreal(type);
      break;
    case 36867:
    case 36868:
      get_timestamp(0);
      break;
    case 37377:
      if ((expo = -getreal(type)) < 128 && shutter == 0.)
        tiff_ifd[tiff_nifds - 1].t_shutter = shutter = powf64(2.0, expo);
      break;
    case 37378: // 0x9202 ApertureValue
      if ((fabs(ape = getreal(type)) < 256.0) && (!aperture))
        aperture = powf64(2.0, ape / 2);
      break;
    case 37385:
      flash_used = getreal(type);
      break;
    case 37386:
      focal_len = getreal(type);
      break;
    case 37500: // tag 0x927c
#ifdef LIBRAW_LIBRARY_BUILD
      if (((make[0] == '\0') && (!strncmp(model, "ov5647", 6))) ||
          ((!strncmp(make, "RaspberryPi", 11)) && (!strncmp(model, "RP_OV5647", 9))) ||
          ((!strncmp(make, "RaspberryPi", 11)) && (!strncmp(model, "RP_imx219", 9))))
      {
        char mn_text[512];
        char *pos;
        char ccms[512];
        ushort l;
        float num;

        fgets(mn_text, len, ifp);
        pos = strstr(mn_text, "gain_r=");
        if (pos)
          cam_mul[0] = atof(pos + 7);
        pos = strstr(mn_text, "gain_b=");
        if (pos)
          cam_mul[2] = atof(pos + 7);
        if ((cam_mul[0] > 0.001f) && (cam_mul[2] > 0.001f))
          cam_mul[1] = cam_mul[3] = 1.0f;
        else
          cam_mul[0] = cam_mul[2] = 0.0f;

        pos = strstr(mn_text, "ccm=") + 4;
        l = strstr(pos, " ") - pos;
        memcpy(ccms, pos, l);
        ccms[l] = '\0';

        pos = strtok(ccms, ",");
        for (l = 0; l < 4; l++)
        {
          num = 0.0;
          for (c = 0; c < 3; c++)
          {
            imgdata.color.ccm[l][c] = (float)atoi(pos);
            num += imgdata.color.ccm[l][c];
            pos = strtok(NULL, ",");
          }
          if (num > 0.01)
            FORC3 imgdata.color.ccm[l][c] = imgdata.color.ccm[l][c] / num;
        }
      }
      else
#endif
        parse_makernote(base, 0);
      break;
    case 40962:
      if (kodak)
        raw_width = get4();
      break;
    case 40963:
      if (kodak)
        raw_height = get4();
      break;
    case 41730:
      if (get4() == 0x20002)
        for (exif_cfa = c = 0; c < 8; c += 2)
          exif_cfa |= fgetc(ifp) * 0x01010101 << c;
    }
    fseek(ifp, save, SEEK_SET);
  }
}