Commit message: possible buffer overrun in Fuji makernotes parser
CVE: CVE-2018-20337
CWE: CWE-787
Vulnerability description: There is a stack-based buffer overflow in the parse_makernote function of dcraw_common.cpp in LibRaw 0.19.1. Crafted input will lead to a denial of service or possibly unspecified other impact.

Project: LibRaw
File: dcraw.c

void CLASS parse_phase_one(int base)
{
  unsigned entries, tag, type, len, data, save, i, c;
  float romm_cam[3][3];
  char *cp;

  memset(&ph1, 0, sizeof ph1);
  fseek(ifp, base, SEEK_SET);
  order = get4() & 0xffff;
  if (get4() >> 8 != 0x526177)
    return; /* "Raw" */
  unsigned offset = get4();
  if(offset == 0xbad0bad) return;
  fseek(ifp, offset + base, SEEK_SET);
  entries = get4();
  if(entries > 8192) return; // too much??
  get4();
  while (entries--)
  {
    tag = get4();
    type = get4();
    len = get4();
    data = get4();
    save = ftell(ifp);
    fseek(ifp, base + data, SEEK_SET);
    switch (tag)
    {

#ifdef LIBRAW_LIBRARY_BUILD
    case 0x0102:
      stmread(imgdata.shootinginfo.BodySerial, len, ifp);
      if ((imgdata.shootinginfo.BodySerial[0] == 0x4c) && (imgdata.shootinginfo.BodySerial[1] == 0x49))
      {
        unique_id =
            (((imgdata.shootinginfo.BodySerial[0] & 0x3f) << 5) | (imgdata.shootinginfo.BodySerial[2] & 0x3f)) - 0x41;
      }
      else
      {
        unique_id =
            (((imgdata.shootinginfo.BodySerial[0] & 0x3f) << 5) | (imgdata.shootinginfo.BodySerial[1] & 0x3f)) - 0x41;
      }
      setPhaseOneFeatures(unique_id);
      break;
    case 0x0211:
      imgdata.other.SensorTemperature2 = int_to_float(data);
      break;
    case 0x0401:
      if (type == 4)
        imgdata.lens.makernotes.CurAp = libraw_powf64l(2.0f, (int_to_float(data) / 2.0f));
      else
        imgdata.lens.makernotes.CurAp = libraw_powf64l(2.0f, (getreal(type) / 2.0f));
      break;
    case 0x0403:
      if (type == 4)
        imgdata.lens.makernotes.CurFocal = int_to_float(data);
      else
        imgdata.lens.makernotes.CurFocal = getreal(type);
      break;
    case 0x0410:
      stmread(imgdata.lens.makernotes.body, len, ifp);
      break;
    case 0x0412:
      stmread(imgdata.lens.makernotes.Lens, len, ifp);
      break;
    case 0x0414:
      if (type == 4)
      {
        imgdata.lens.makernotes.MaxAp4CurFocal = libraw_powf64l(2.0f, (int_to_float(data) / 2.0f));
      }
      else
      {
        imgdata.lens.makernotes.MaxAp4CurFocal = libraw_powf64l(2.0f, (getreal(type) / 2.0f));
      }
      break;
    case 0x0415:
      if (type == 4)
      {
        imgdata.lens.makernotes.MinAp4CurFocal = libraw_powf64l(2.0f, (int_to_float(data) / 2.0f));
      }
      else
      {
        imgdata.lens.makernotes.MinAp4CurFocal = libraw_powf64l(2.0f, (getreal(type) / 2.0f));
      }
      break;
    case 0x0416:
      if (type == 4)
      {
        imgdata.lens.makernotes.MinFocal = int_to_float(data);
      }
      else
      {
        imgdata.lens.makernotes.MinFocal = getreal(type);
      }
      if (imgdata.lens.makernotes.MinFocal > 1000.0f)
      {
        imgdata.lens.makernotes.MinFocal = 0.0f;
      }
      break;
    case 0x0417:
      if (type == 4)
      {
        imgdata.lens.makernotes.MaxFocal = int_to_float(data);
      }
      else
      {
        imgdata.lens.makernotes.MaxFocal = getreal(type);
      }
      break;
#endif

    case 0x100:
      flip = "0653"[data & 3] - '0';
      break;
    case 0x106:
      for (i = 0; i < 9; i++)
#ifdef LIBRAW_LIBRARY_BUILD
        imgdata.color.P1_color[0].romm_cam[i] =
#endif
            ((float *)romm_cam)[i] = getreal(11);
      romm_coeff(romm_cam);
      break;
    case 0x107:
      FORC3 cam_mul[c] = getreal(11);
      break;
    case 0x108:
      raw_width = data;
      break;
    case 0x109:
      raw_height = data;
      break;
    case 0x10a:
      left_margin = data;
      break;
    case 0x10b:
      top_margin = data;
      break;
    case 0x10c:
      width = data;
      break;
    case 0x10d:
      height = data;
      break;
    case 0x10e:
      ph1.format = data;
      break;
    case 0x10f:
      data_offset = data + base;
      break;
    case 0x110:
      meta_offset = data + base;
      meta_length = len;
      break;
    case 0x112:
      ph1.key_off = save - 4;
      break;
    case 0x210:
      ph1.tag_210 = int_to_float(data);
#ifdef LIBRAW_LIBRARY_BUILD
      imgdata.other.SensorTemperature = ph1.tag_210;
#endif
      break;
    case 0x21a:
      ph1.tag_21a = data;
      break;
    case 0x21c:
      strip_offset = data + base;
      break;
    case 0x21d:
      ph1.t_black = data;
      break;
    case 0x222:
      ph1.split_col = data;
      break;
    case 0x223:
      ph1.black_col = data + base;
      break;
    case 0x224:
      ph1.split_row = data;
      break;
    case 0x225:
      ph1.black_row = data + base;
      break;
#ifdef LIBRAW_LIBRARY_BUILD
    case 0x226:
      for (i = 0; i < 9; i++)
        imgdata.color.P1_color[1].romm_cam[i] = getreal(11);
      break;
#endif
    case 0x301:
      model[63] = 0;
      fread(model, 1, 63, ifp);
      if ((cp = strstr(model, " camera")))
        *cp = 0;
    }
    fseek(ifp, save, SEEK_SET);
  }

#ifdef LIBRAW_LIBRARY_BUILD
  if (!imgdata.lens.makernotes.body[0] && !imgdata.shootinginfo.BodySerial[0])
  {
    fseek(ifp, meta_offset, SEEK_SET);
    order = get2();
    fseek(ifp, 6, SEEK_CUR);
    fseek(ifp, meta_offset + get4(), SEEK_SET);
    entries = get4();
    get4();
    while (entries--)
    {
      tag = get4();
      len = get4();
      data = get4();
      save = ftell(ifp);
      fseek(ifp, meta_offset + data, SEEK_SET);
      if (tag == 0x0407)
      {
        stmread(imgdata.shootinginfo.BodySerial, len, ifp);
        if ((imgdata.shootinginfo.BodySerial[0] == 0x4c) && (imgdata.shootinginfo.BodySerial[1] == 0x49))
        {
          unique_id =
              (((imgdata.shootinginfo.BodySerial[0] & 0x3f) << 5) | (imgdata.shootinginfo.BodySerial[2] & 0x3f)) - 0x41;
        }
        else
        {
          unique_id =
              (((imgdata.shootinginfo.BodySerial[0] & 0x3f) << 5) | (imgdata.shootinginfo.BodySerial[1] & 0x3f)) - 0x41;
        }
        setPhaseOneFeatures(unique_id);
      }
      fseek(ifp, save, SEEK_SET);
    }
  }
#endif

  load_raw = ph1.format < 3 ? &CLASS phase_one_load_raw : &CLASS phase_one_load_raw_c;
  maximum = 0xffff;
  strcpy(make, "Phase One");
  if (model[0])
    return;
  switch (raw_height)
  {
  case 2060:
    strcpy(model, "LightPhase");
    break;
  case 2682:
    strcpy(model, "H 10");
    break;
  case 4128:
    strcpy(model, "H 20");
    break;
  case 5488:
    strcpy(model, "H 25");
    break;
  }
}

Project: LibRaw
File: dcraw.c

void CLASS parse_minolta(int base)
{
  int tag, len, offset, high = 0, wide = 0, i, c;
  short sorder = order;
#ifdef LIBRAW_LIBRARY_BUILD
  INT64 save;
#else
  int save;
#endif

  fseek(ifp, base, SEEK_SET);
  if (fgetc(ifp) || fgetc(ifp) - 'M' || fgetc(ifp) - 'R')
    return;
  order = fgetc(ifp) * 0x101;
  offset = base + get4() + 8;
#ifdef LIBRAW_LIBRARY_BUILD
  INT64 fsize = ifp->size();
  if(offset>fsize-8) // At least 8 bytes for tag/len
    offset = fsize-8;
#endif

  while ((save = ftell(ifp)) < offset)
  {
    for (tag = i = 0; i < 4; i++)
      tag = tag << 8 | fgetc(ifp);
    len = get4();
    if(len < 0)
      return; // just ignore wrong len?? or raise bad file exception?
#ifdef LIBRAW_LIBRARY_BUILD
    if((INT64)len + save + 8ULL > fsize)
      return; // just ignore out of file metadata, stop parse
#endif
    switch (tag)
    {
    case 0x505244: /* PRD */
      fseek(ifp, 8, SEEK_CUR);
      high = get2();
      wide = get2();
      break;
#ifdef LIBRAW_LIBRARY_BUILD
    case 0x524946: /* RIF */
      if (!strncasecmp(model, "DSLR-A100", 9))
      {
        fseek(ifp, 8, SEEK_CUR);
        imgdata.color.WB_Coeffs[LIBRAW_WBI_Tungsten][0] = get2();
        imgdata.color.WB_Coeffs[LIBRAW_WBI_Tungsten][2] = get2();
        imgdata.color.WB_Coeffs[LIBRAW_WBI_Daylight][0] = get2();
        imgdata.color.WB_Coeffs[LIBRAW_WBI_Daylight][2] = get2();
        imgdata.color.WB_Coeffs[LIBRAW_WBI_Cloudy][0] = get2();
        imgdata.color.WB_Coeffs[LIBRAW_WBI_Cloudy][2] = get2();
        imgdata.color.WB_Coeffs[LIBRAW_WBI_FL_W][0] = get2();
        imgdata.color.WB_Coeffs[LIBRAW_WBI_FL_W][2] = get2();
        imgdata.color.WB_Coeffs[LIBRAW_WBI_Flash][0] = get2();
        imgdata.color.WB_Coeffs[LIBRAW_WBI_Flash][2] = get2();
        get4();
        imgdata.color.WB_Coeffs[LIBRAW_WBI_Shade][0] = get2();
        imgdata.color.WB_Coeffs[LIBRAW_WBI_Shade][2] = get2();
        imgdata.color.WB_Coeffs[LIBRAW_WBI_FL_D][0] = get2();
        imgdata.color.WB_Coeffs[LIBRAW_WBI_FL_D][2] = get2();
        imgdata.color.WB_Coeffs[LIBRAW_WBI_FL_N][0] = get2();
        imgdata.color.WB_Coeffs[LIBRAW_WBI_FL_N][2] = get2();
        imgdata.color.WB_Coeffs[LIBRAW_WBI_FL_WW][0] = get2();
        imgdata.color.WB_Coeffs[LIBRAW_WBI_FL_WW][2] = get2();
        imgdata.color.WB_Coeffs[LIBRAW_WBI_Daylight][1] = imgdata.color.WB_Coeffs[LIBRAW_WBI_Daylight][3] =
            imgdata.color.WB_Coeffs[LIBRAW_WBI_Tungsten][1] = imgdata.color.WB_Coeffs[LIBRAW_WBI_Tungsten][3] =
                imgdata.color.WB_Coeffs[LIBRAW_WBI_Flash][1] = imgdata.color.WB_Coeffs[LIBRAW_WBI_Flash][3] =
                    imgdata.color.WB_Coeffs[LIBRAW_WBI_Cloudy][1] = imgdata.color.WB_Coeffs[LIBRAW_WBI_Cloudy][3] =
                        imgdata.color.WB_Coeffs[LIBRAW_WBI_Shade][1] = imgdata.color.WB_Coeffs[LIBRAW_WBI_Shade][3] =
                            imgdata.color.WB_Coeffs[LIBRAW_WBI_FL_D][1] = imgdata.color.WB_Coeffs[LIBRAW_WBI_FL_D][3] =
                                imgdata.color.WB_Coeffs[LIBRAW_WBI_FL_N][1] =
                                    imgdata.color.WB_Coeffs[LIBRAW_WBI_FL_N][3] =
                                        imgdata.color.WB_Coeffs[LIBRAW_WBI_FL_W][1] =
                                            imgdata.color.WB_Coeffs[LIBRAW_WBI_FL_W][3] =
                                                imgdata.color.WB_Coeffs[LIBRAW_WBI_FL_WW][1] =
                                                    imgdata.color.WB_Coeffs[LIBRAW_WBI_FL_WW][3] = 0x100;
      }
      break;
#endif
    case 0x574247: /* WBG */
      get4();
      i = strcmp(model, "DiMAGE A200") ? 0 : 3;
      FORC4 cam_mul[c ^ (c >> 1) ^ i] = get2();
      break;
    case 0x545457: /* TTW */
      parse_tiff(ftell(ifp));
      data_offset = offset;
    }
    fseek(ifp, save + len + 8, SEEK_SET);
  }
  raw_height = high;
  raw_width = wide;
  order = sorder;
}

Project: LibRaw
File: dcraw.c

void CLASS parse_sinar_ia()
{
  int entries, off;
  char str[8], *cp;

  order = 0x4949;
  fseek(ifp, 4, SEEK_SET);
  entries = get4();
  if(entries < 1 || entries > 8192) return;
  fseek(ifp, get4(), SEEK_SET);
  while (entries--)
  {
    off = get4();
    get4();
    fread(str, 8, 1, ifp);
    if (!strcmp(str, "META"))
      meta_offset = off;
    if (!strcmp(str, "THUMB"))
      thumb_offset = off;
    if (!strcmp(str, "RAW0"))
      data_offset = off;
  }
  fseek(ifp, meta_offset + 20, SEEK_SET);
  fread(make, 64, 1, ifp);
  make[63] = 0;
  if ((cp = strchr(make, ' ')))
  {
    strcpy(model, cp + 1);
    *cp = 0;
  }
  raw_width = get2();
  raw_height = get2();
  load_raw = &CLASS unpacked_load_raw;
  thumb_width = (get4(), get2());
  thumb_height = get2();
  write_thumb = &CLASS ppm_thumb;
  maximum = 0x3fff;
}

Project: LibRaw
File: dcraw.c

void CLASS parse_ciff(int offset, int length, int depth)
{
  int tboff, nrecs, c, type, len, save, wbi = -1;
  ushort key[] = {0x410, 0x45f3};
#ifdef LIBRAW_LIBRARY_BUILD
  INT64 fsize = ifp->size();
#endif

  fseek(ifp, offset + length - 4, SEEK_SET);
  tboff = get4() + offset;
  fseek(ifp, tboff, SEEK_SET);
  nrecs = get2();
  if (nrecs<1) return;
  if ((nrecs | depth) > 127)
    return;
#ifdef LIBRAW_LIBRARY_BUILD
  if(nrecs*10 + offset > fsize) return;
#endif

  while (nrecs--)
  {
    type = get2();
    len = get4();
    save = ftell(ifp) + 4;
    INT64 see = offset + get4();
#ifdef LIBRAW_LIBRARY_BUILD
	if(see >= fsize  ) // At least one byte
	{
		fseek(ifp, save, SEEK_SET);
		continue;
	}
#endif
    fseek(ifp, see, SEEK_SET);
    if ((((type >> 8) + 8) | 8) == 0x38)
    {
      parse_ciff(ftell(ifp), len, depth + 1); /* Parse a sub-table */
    }
#ifdef LIBRAW_LIBRARY_BUILD
    if (type == 0x3004)
      parse_ciff(ftell(ifp), len, depth + 1);
#endif
    if (type == 0x0810)
      fread(artist, 64, 1, ifp);
    if (type == 0x080a)
    {
      fread(make, 64, 1, ifp);
      fseek(ifp, strbuflen(make) - 63, SEEK_CUR);
      fread(model, 64, 1, ifp);
    }
    if (type == 0x1810)
    {
      width = get4();
      height = get4();
      pixel_aspect = int_to_float(get4());
      flip = get4();
    }
    if (type == 0x1835) /* Get the decoder table */
      tiff_compress = get4();
    if (type == 0x2007)
    {
      thumb_offset = ftell(ifp);
      thumb_length = len;
    }
    if (type == 0x1818)
    {
      shutter = libraw_powf64l(2.0f, -int_to_float((get4(), get4())));
      aperture = libraw_powf64l(2.0f, int_to_float(get4()) / 2);
#ifdef LIBRAW_LIBRARY_BUILD
      imgdata.lens.makernotes.CurAp = aperture;
#endif
    }
    if (type == 0x102a)
    {
      //      iso_speed = pow (2.0, (get4(),get2())/32.0 - 4) * 50;
      iso_speed = libraw_powf64l(2.0f, ((get2(), get2()) + get2()) / 32.0f - 5.0f) * 100.0f;
#ifdef LIBRAW_LIBRARY_BUILD
      aperture = _CanonConvertAperture((get2(), get2()));
      imgdata.lens.makernotes.CurAp = aperture;
#else
      aperture = libraw_powf64l(2.0, (get2(), (short)get2()) / 64.0);
#endif
      shutter = libraw_powf64l(2.0, -((short)get2()) / 32.0);
      wbi = (get2(), get2());
      if (wbi > 17)
        wbi = 0;
      fseek(ifp, 32, SEEK_CUR);
      if (shutter > 1e6)
        shutter = get2() / 10.0;
    }
    if (type == 0x102c)
    {
      if (get2() > 512)
      { /* Pro90, G1 */
        fseek(ifp, 118, SEEK_CUR);
        FORC4 cam_mul[c ^ 2] = get2();
      }
      else
      { /* G2, S30, S40 */
        fseek(ifp, 98, SEEK_CUR);
        FORC4 cam_mul[c ^ (c >> 1) ^ 1] = get2();
      }
    }
#ifdef LIBRAW_LIBRARY_BUILD
    if (type == 0x10a9)
    {
      INT64 o = ftell(ifp);
      fseek(ifp, (0x1 << 1), SEEK_CUR);
      FORC4 imgdata.color.WB_Coeffs[LIBRAW_WBI_Auto][c ^ (c >> 1)] = get2();
      Canon_WBpresets(0, 0);
      fseek(ifp, o, SEEK_SET);
    }
    if (type == 0x102d)
    {
      INT64 o = ftell(ifp);
      Canon_CameraSettings();
      fseek(ifp, o, SEEK_SET);
    }
    if (type == 0x580b)
    {
      if (strcmp(model, "Canon EOS D30"))
        sprintf(imgdata.shootinginfo.BodySerial, "%d", len);
      else
        sprintf(imgdata.shootinginfo.BodySerial, "%0x-%05d", len >> 16, len & 0xffff);
    }
#endif
    if (type == 0x0032)
    {
      if (len == 768)
      { /* EOS D30 */
        fseek(ifp, 72, SEEK_CUR);
        FORC4
        {
          ushort q = get2();
          cam_mul[c ^ (c >> 1)] = 1024.0/ MAX(1,q);
        }
        if (!wbi)
          cam_mul[0] = -1; /* use my auto white balance */
      }
      else if (!cam_mul[0])
      {
        if (get2() == key[0]) /* Pro1, G6, S60, S70 */
          c = (strstr(model, "Pro1") ? "012346000000000000" : "01345:000000006008")[LIM(0, wbi, 17)] - '0' + 2;
        else
        { /* G3, G5, S45, S50 */
          c = "023457000000006000"[LIM(0, wbi, 17)] - '0';
          key[0] = key[1] = 0;
        }
        fseek(ifp, 78 + c * 8, SEEK_CUR);
        FORC4 cam_mul[c ^ (c >> 1) ^ 1] = get2() ^ key[c & 1];
        if (!wbi)
          cam_mul[0] = -1;
      }
    }
    if (type == 0x10a9)
    { /* D60, 10D, 300D, and clones */
      if (len > 66)
        wbi = "0134567028"[LIM(0, wbi, 9)] - '0';
      fseek(ifp, 2 + wbi * 8, SEEK_CUR);
      FORC4 cam_mul[c ^ (c >> 1)] = get2();
    }
    if (type == 0x1030 && wbi >= 0 && (0x18040 >> wbi & 1))
      ciff_block_1030(); /* all that don't have 0x10a9 */
    if (type == 0x1031)
    {
      raw_width = (get2(), get2());
      raw_height = get2();
    }
    if (type == 0x501c)
    {
      iso_speed = len & 0xffff;
    }
    if (type == 0x5029)
    {
#ifdef LIBRAW_LIBRARY_BUILD
      imgdata.lens.makernotes.CurFocal = len >> 16;
      imgdata.lens.makernotes.FocalType = len & 0xffff;
      if (imgdata.lens.makernotes.FocalType == 2)
      {
        imgdata.lens.makernotes.CanonFocalUnits = 32;
        if (imgdata.lens.makernotes.CanonFocalUnits > 1)
          imgdata.lens.makernotes.CurFocal /= (float)imgdata.lens.makernotes.CanonFocalUnits;
      }
      focal_len = imgdata.lens.makernotes.CurFocal;
#else
      focal_len = len >> 16;
      if ((len & 0xffff) == 2)
        focal_len /= 32;
#endif
    }
    if (type == 0x5813)
      flash_used = int_to_float(len);
    if (type == 0x5814)
      canon_ev = int_to_float(len);
    if (type == 0x5817)
      shot_order = len;
    if (type == 0x5834)
    {
      unique_id = len;
#ifdef LIBRAW_LIBRARY_BUILD
      unique_id = setCanonBodyFeatures(unique_id);
#endif
    }
    if (type == 0x580e)
      timestamp = len;
    if (type == 0x180e)
      timestamp = get4();
#ifdef LOCALTIME
    if ((type | 0x4000) == 0x580e)
      timestamp = mktime(gmtime(&timestamp));
#endif
    fseek(ifp, save, SEEK_SET);
  }
}

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;
  unsigned typeCanonCameraInfo = 0;

  uchar *table_buf;
  uchar *table_buf_0x0116;
  ushort table_buf_0x0116_len = 0;
  uchar *table_buf_0x2010;
  ushort table_buf_0x2010_len = 0;
  uchar *table_buf_0x9050;
  ushort table_buf_0x9050_len = 0;
  uchar *table_buf_0x9400;
  ushort table_buf_0x9400_len = 0;
  uchar *table_buf_0x9402;
  ushort table_buf_0x9402_len = 0;
  uchar *table_buf_0x9403;
  ushort table_buf_0x9403_len = 0;
  uchar *table_buf_0x9406;
  ushort table_buf_0x9406_len = 0;
  uchar *table_buf_0x940c;
  ushort table_buf_0x940c_len = 0;
  uchar *table_buf_0x940e;
  ushort table_buf_0x940e_len = 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);

  /*
    printf("===>>buf: 0x");
    for (int i = 0; i < sizeof buf; i ++) {
          printf("%02x", buf[i]);
    }
    putchar('\n');
  */

  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)
    {
      fseek(ifp, save, SEEK_SET); // Recover tiff-read position!!
      continue;
    }
    if (!strncasecmp(model, "KODAK P880", 10) || !strncasecmp(model, "KODAK P850", 10) ||
        !strncasecmp(model, "KODAK P712", 10))
    {
      if (tag == 0xf90b)
      {
        imgdata.makernotes.kodak.clipBlack = get2();
      }
      else if (tag == 0xf90c)
      {
        imgdata.makernotes.kodak.clipWhite = get2();
      }
    }
    if (!strncmp(make, "Canon", 5))
    {
      if (tag == 0x000d && len < 256000) // camera info
      {
        if (type != 4)
        {
          CanonCameraInfo = (uchar *)malloc(MAX(16, len));
          fread(CanonCameraInfo, len, 1, ifp);
        }
        else
        {
          CanonCameraInfo = (uchar *)malloc(MAX(16, len * 4));
          fread(CanonCameraInfo, len, 4, ifp);
        }
        lenCanonCameraInfo = len;
        typeCanonCameraInfo = type;
      }

      else if (tag == 0x10) // Canon ModelID
      {
        unique_id = get4();
        unique_id = setCanonBodyFeatures(unique_id);
        if (lenCanonCameraInfo)
        {
          processCanonCameraInfo(unique_id, CanonCameraInfo, lenCanonCameraInfo, typeCanonCameraInfo);
          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 = MIN((sizeof(ynum)-1), (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(model, "Hasselblad X1D", 14) || !strncasecmp(model, "Hasselblad H6D", 14) ||
             !strncasecmp(model, "Hasselblad A6D", 14))
    {
      if (tag == 0x0045)
      {
        imgdata.makernotes.hasselblad.BaseISO = get4();
      }
      else if (tag == 0x0046)
      {
        imgdata.makernotes.hasselblad.Gain = getreal(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);
        imgdata.color.dng_color[ind].parsedfields |= LIBRAW_DNGFM_FORWARDMATRIX;
      }

      if (tag == 0x34003402)
        imgdata.other.CameraTemperature = getreal(type);

      if ((tag == 0x0320) && (type == 9) && (len == 1) && !strncasecmp(make, "Leica Camera AG", 15) &&
          !strncmp(buf, "LEICA", 5) && (buf[5] == 0) && (buf[6] == 0) && (buf[7] == 0))
        imgdata.other.CameraTemperature = 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 == 0x003b) // all 1s for regular exposures
      {
        imgdata.makernotes.nikon.ME_WB[0] = getreal(type);
        imgdata.makernotes.nikon.ME_WB[2] = getreal(type);
        imgdata.makernotes.nikon.ME_WB[1] = getreal(type);
        imgdata.makernotes.nikon.ME_WB[3] = getreal(type);
      }
      else if (tag == 0x0045)
      {
        imgdata.sizes.raw_crop.cleft = get2();
        imgdata.sizes.raw_crop.ctop = get2();
        imgdata.sizes.raw_crop.cwidth = get2();
        imgdata.sizes.raw_crop.cheight = get2();
      }
      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) // Nikon compression
      {
        imgdata.makernotes.nikon.NEFCompression = 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 (tag == 0x00b0)
      {
        get4(); // ME tag version, 4 symbols
        imgdata.makernotes.nikon.ExposureMode = get4();
        imgdata.makernotes.nikon.nMEshots = get4();
        imgdata.makernotes.nikon.MEgainOn = get4();
      }
      else if (tag == 0x00b9)
      {
        uchar uc;
        int8_t sc;
        fread(&uc, 1, 1, ifp);
        imgdata.makernotes.nikon.AFFineTune = uc;
        fread(&uc, 1, 1, ifp);
        imgdata.makernotes.nikon.AFFineTuneIndex = uc;
        fread(&sc, 1, 1, ifp);
        imgdata.makernotes.nikon.AFFineTuneAdj = sc;
      }
    }

    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];
        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 = libraw_powf64l(2.0f, getreal(type) / 2);
        break;
      case 0x20400612:
      case 0x30000612:
        imgdata.sizes.raw_crop.cleft = get2();
        break;
      case 0x20400613:
      case 0x30000613:
        imgdata.sizes.raw_crop.ctop = get2();
        break;
      case 0x20400614:
      case 0x30000614:
        imgdata.sizes.raw_crop.cwidth = get2();
        break;
      case 0x20400615:
      case 0x30000615:
        imgdata.sizes.raw_crop.cheight = get2();
        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 = libraw_powf64l(sqrt(2.0f), get2() / 256.0f);
        break;
      case 0x20100206:
        imgdata.lens.makernotes.MaxAp4MaxFocal = libraw_powf64l(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 = libraw_powf64l(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 0x1007:
        imgdata.other.SensorTemperature = (float)get2();
        break;
      case 0x1008:
        imgdata.other.LensTemperature = (float)get2();
        break;
      case 0x20401306:
      {
        int temp = get2();
        if ((temp != 0) && (temp != 100))
        {
          if (temp < 61)
            imgdata.other.CameraTemperature = (float)temp;
          else
            imgdata.other.CameraTemperature = (float)(temp - 32) / 1.8f;
          if ((OlyID == 0x4434353933ULL) && // TG-5
              (imgdata.other.exifAmbientTemperature > -273.15f))
            imgdata.other.CameraTemperature += imgdata.other.exifAmbientTemperature;
        }
      }
      break;
      case 0x20501500:
        if (OlyID != 0x0ULL)
        {
          short temp = get2();
          if ((OlyID == 0x4434303430ULL) || // E-1
              (OlyID == 0x5330303336ULL) || // E-M5
              (len != 1))
            imgdata.other.SensorTemperature = (float)temp;
          else if ((temp != -32768) && (temp != 0))
          {
            if (temp > 199)
              imgdata.other.SensorTemperature = 86.474958f - 0.120228f * (float)temp;
            else
              imgdata.other.SensorTemperature = (float)temp;
          }
        }
        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 == 0x000d)
      {
        imgdata.makernotes.pentax.FocusMode = get2();
      }
      else if (tag == 0x000e)
      {
        imgdata.makernotes.pentax.AFPointSelected = get2();
      }
      else if (tag == 0x000f)
      {
        imgdata.makernotes.pentax.AFPointsInFocus = getint(type);
      }
      else if (tag == 0x0010)
      {
        imgdata.makernotes.pentax.FocusPosition = get2();
      }
      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 == 0x0034)
      {
        uchar uc;
        FORC4
        {
          fread(&uc, 1, 1, ifp);
          imgdata.makernotes.pentax.DriveMode[c] = uc;
        }
      }
      else if (tag == 0x0038)
      {
        imgdata.sizes.raw_crop.cleft = get2();
        imgdata.sizes.raw_crop.ctop = get2();
      }
      else if (tag == 0x0039)
      {
        imgdata.sizes.raw_crop.cwidth = get2();
        imgdata.sizes.raw_crop.cheight = get2();
      }
      else if (tag == 0x003f)
      {
        imgdata.lens.makernotes.LensID = fgetc(ifp) << 8 | fgetc(ifp);
      }
      else if (tag == 0x0047)
      {
        imgdata.other.CameraTemperature = (float)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 == 0x0072)
      {
        imgdata.makernotes.pentax.AFAdjustment = get2();
      }
      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) && (tag <= 0x0214))
      {
        FORC4 imgdata.color.WB_Coeffs[Pentax_wb_list1[tag - 0x020d]][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)
      {
        int wb_ind;
        getc(ifp);
        for (int wb_cnt = 0; wb_cnt < nPentax_wb_list2; wb_cnt++)
        {
          wb_ind = getc(ifp);
          if (wb_ind < nPentax_wb_list2)
            FORC4 imgdata.color.WB_Coeffs[Pentax_wb_list2[wb_ind]][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 == 0x0043)
      {
        int temp = get4();
        if (temp)
        {
          imgdata.other.CameraTemperature = (float)temp;
          if (get4() == 10)
            imgdata.other.CameraTemperature /= 10.0f;
        }
      }
      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))))
    {
      parseSonyMakernotes(tag, type, len, nonDNG, table_buf_0x0116, table_buf_0x0116_len, table_buf_0x2010,
                          table_buf_0x2010_len, table_buf_0x9050, table_buf_0x9050_len, table_buf_0x9400,
                          table_buf_0x9400_len, table_buf_0x9402, table_buf_0x9402_len, table_buf_0x9403,
                          table_buf_0x9403_len, table_buf_0x9406, table_buf_0x9406_len, table_buf_0x940c,
                          table_buf_0x940c_len, table_buf_0x940e, table_buf_0x940e_len);
    }

    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 * libraw_powf64l(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 * libraw_powf64l(2.0, i / 32.0 - 4);
#ifdef LIBRAW_LIBRARY_BUILD
      get4();
#else
      if ((i = (get2(), get2())) != 0x7fff && !aperture)
        aperture = libraw_powf64l(2.0, i / 64.0);
#endif
      if ((i = get2()) != 0xffff && !shutter)
        shutter = libraw_powf64l(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 == 0x20400101) && (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 >= 0x20400101) && (tag <= 0x20400111))
      {
        nWB = tag - 0x20400101;
        tWB = Oly_wb_list2[nWB << 1];
        ushort CT = Oly_wb_list2[(nWB << 1) | 1];
        int wb[4];
        wb[0] = get2();
        wb[2] = get2();
        if (tWB != 0x100)
        {
          imgdata.color.WB_Coeffs[tWB][0] = wb[0];
          imgdata.color.WB_Coeffs[tWB][2] = wb[2];
        }
        if (CT)
        {
          imgdata.color.WBCT_Coeffs[nWB - 1][0] = CT;
          imgdata.color.WBCT_Coeffs[nWB - 1][1] = wb[0];
          imgdata.color.WBCT_Coeffs[nWB - 1][3] = wb[2];
        }
        if (len == 4)
        {
          wb[1] = get2();
          wb[3] = get2();
          if (tWB != 0x100)
          {
            imgdata.color.WB_Coeffs[tWB][1] = wb[1];
            imgdata.color.WB_Coeffs[tWB][3] = wb[3];
          }
          if (CT)
          {
            imgdata.color.WBCT_Coeffs[nWB - 1][2] = wb[1];
            imgdata.color.WBCT_Coeffs[nWB - 1][4] = wb[3];
          }
        }
      }
      if ((tag >= 0x20400112) && (tag <= 0x2040011e))
      {
        nWB = tag - 0x20400112;
        int wbG = get2();
        tWB = Oly_wb_list2[nWB << 1];
        if (nWB)
          imgdata.color.WBCT_Coeffs[nWB - 1][2] = imgdata.color.WBCT_Coeffs[nWB - 1][4] = wbG;
        if (tWB != 0x100)
          imgdata.color.WB_Coeffs[tWB][1] = imgdata.color.WB_Coeffs[tWB][3] = wbG;
      }

      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)
      {
        int wbG = get2();
        if (imgdata.color.WB_Coeffs[LIBRAW_WBI_Flash][0])
          imgdata.color.WB_Coeffs[LIBRAW_WBI_Flash][1] = imgdata.color.WB_Coeffs[LIBRAW_WBI_Flash][3] = wbG;
        FORC4 if (imgdata.color.WB_Coeffs[LIBRAW_WBI_Custom1 + c][0])
            imgdata.color.WB_Coeffs[LIBRAW_WBI_Custom1 + c][1] = imgdata.color.WB_Coeffs[LIBRAW_WBI_Custom1 + c][3] =
            wbG;
      }
      if ((tag == 0x30000110) && strcmp(software, "v757-71"))
      {
        imgdata.color.WB_Coeffs[LIBRAW_WBI_Auto][0] = get2();
        imgdata.color.WB_Coeffs[LIBRAW_WBI_Auto][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 >= 0x30000120) && (tag <= 0x30000124)) || ((tag >= 0x30000130) && (tag <= 0x30000133))) &&
          strcmp(software, "v757-71"))
      {
        int wb_ind;
        if (tag <= 0x30000124)
          wb_ind = tag - 0x30000120;
        else
          wb_ind = tag - 0x30000130 + 5;
        imgdata.color.WB_Coeffs[Oly_wb_list1[wb_ind]][0] = get2();
        imgdata.color.WB_Coeffs[Oly_wb_list1[wb_ind]][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 == 0x20200306)
      {
        uchar uc;
        fread(&uc, 1, 1, ifp);
        imgdata.makernotes.olympus.AFFineTune = uc;
      }
      if (tag == 0x20200307)
      {
        FORC3 imgdata.makernotes.olympus.AFFineTuneAdj[c] = get2();
      }
      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) && strncasecmp(make, "Samsung", 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) // Pentax black level
      FORC4 cblack[c ^ c >> 1] = get2();
    if (tag == 0x201 && len == 4) // Pentax As Shot WB
      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) && strcmp(software, "v757-71"))
      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) || (tag == 0x2050)) &&
        ((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 == 0xa022)
      {
        FORC4 imgdata.color.WB_Coeffs[LIBRAW_WBI_Auto][c ^ (c >> 1)] = get4() - SamsungKey[c + 4];
        if (imgdata.color.WB_Coeffs[LIBRAW_WBI_Auto][0] < (imgdata.color.WB_Coeffs[LIBRAW_WBI_Auto][1] >> 1))
        {
          imgdata.color.WB_Coeffs[LIBRAW_WBI_Auto][1] = imgdata.color.WB_Coeffs[LIBRAW_WBI_Auto][1] >> 4;
          imgdata.color.WB_Coeffs[LIBRAW_WBI_Auto][3] = imgdata.color.WB_Coeffs[LIBRAW_WBI_Auto][3] >> 4;
        }
      }

      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) {
              i = get4();
              imgdata.color.linear_max[0] = imgdata.color.linear_max[1] = imgdata.color.linear_max[2] =
                  imgdata.color.linear_max[3] = i - SamsungKey[0]; printf ("Samsung 0xa025 %d\n", i); }
      */
      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();
    }
#ifdef LIBRAW_LIBRARY_BUILD
    if (tag == 0x4021 && (imgdata.makernotes.canon.multishot[0] = get4()) &&
        (imgdata.makernotes.canon.multishot[1] = get4()))
    {
      if (len >= 4)
      {
        imgdata.makernotes.canon.multishot[2] = get4();
        imgdata.makernotes.canon.multishot[3] = get4();
      }
      FORC4 cam_mul[c] = 1024;
    }
#else
    if (tag == 0x4021 && get4() && get4())
      FORC4 cam_mul[c] = 1024;
#endif
  next:
    fseek(ifp, save, SEEK_SET);
  }
quit:
  order = sorder;
}

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( tiff_ifd[i].t_width < 1 ||  tiff_ifd[i].t_width > 65535
       || tiff_ifd[i].t_height < 1 || tiff_ifd[i].t_height > 65535)
          continue; /* wrong image dimensions */
    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:
#ifdef LIBRAW_LIBRARY_BUILD
      if (!dng_version && INT64(tiff_ifd[raw].bytes) == INT64(raw_width) * INT64(raw_height))
#else
      if (tiff_ifd[raw].bytes == raw_width * raw_height)
#endif
      {
        tiff_bps = 14;
        load_raw = &CLASS sony_arw2_load_raw;
        break;
      }
#ifdef LIBRAW_LIBRARY_BUILD
      if (!dng_version && !strncasecmp(make, "Sony", 4) && INT64(tiff_ifd[raw].bytes) == INT64(raw_width) * INT64(raw_height) * 2ULL)
#else
      if (!strncasecmp(make, "Sony", 4) && tiff_ifd[raw].bytes == raw_width * raw_height * 2)
#endif
      {
        tiff_bps = 14;
        load_raw = &CLASS unpacked_load_raw;
        break;
      }
#ifdef LIBRAW_LIBRARY_BUILD
      if (INT64(tiff_ifd[raw].bytes) * 8ULL != INT64(raw_width) * INT64(raw_height) * INT64(tiff_bps))
#else
      if (tiff_ifd[raw].bytes * 8 != raw_width * raw_height * tiff_bps)
#endif
      {
        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 (!dng_version && !strncasecmp(make, "Sony", 4) && INT64(tiff_ifd[raw].bytes) == INT64(raw_width) * INT64(raw_height) * 2ULL)
      {
        tiff_bps = 14;
        load_raw = &CLASS unpacked_load_raw;
        break;
      }
      if (!dng_version && !strncasecmp(make, "Sony", 4) && tiff_ifd[raw].samples == 4 &&
          INT64(tiff_ifd[raw].bytes) == INT64(raw_width) * INT64(raw_height) * 8ULL) // Sony ARQ
      {
        tiff_bps = 14;
        tiff_samples = 4;
        load_raw = &CLASS sony_arq_load_raw;
        filters = 0;
        strcpy(cdesc, "RGBG");
        break;
      }
      if (!strncasecmp(make, "Nikon", 5) && !strncmp(software, "Nikon Scan", 10))
      {
        load_raw = &CLASS nikon_coolscan_load_raw;
        raw_color = 1;
        filters = 0;
        break;
      }
      if (!strncmp(make, "OLYMPUS", 7) && INT64(tiff_ifd[raw].bytes) * 2ULL == INT64(raw_width) * INT64(raw_height) * 3ULL)
#else 
      if (!strncmp(make, "OLYMPUS", 7) && tiff_ifd[raw].bytes * 2 == raw_width * raw_height * 3)
#endif
        load_flags = 24;
#ifdef LIBRAW_LIBRARY_BUILD
      if (!dng_version && INT64(tiff_ifd[raw].bytes) * 5ULL == INT64(raw_width) * INT64(raw_height) * 8ULL)
#else
      if (tiff_ifd[raw].bytes * 5 == raw_width * raw_height * 8)
#endif
      {
        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;
#ifdef LIBRAW_LIBRARY_BUILD
        if (!strncmp(make, "OLYMPUS", 7) && INT64(tiff_ifd[raw].bytes) * 7ULL > INT64(raw_width) * INT64(raw_height))
#else
        if (!strncmp(make, "OLYMPUS", 7) && tiff_ifd[raw].bytes * 7 > raw_width * raw_height)
#endif
          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:
#ifdef LIBRAW_LIBRARY_BUILD
      if ((INT64(raw_width) + 9ULL) / 10ULL * 16ULL * INT64(raw_height) == INT64(tiff_ifd[raw].bytes))
#else
      if ((raw_width + 9) / 10 * 16 * raw_height == tiff_ifd[raw].bytes)
#endif
      {
        load_raw = &CLASS packed_load_raw;
        load_flags = 1;
      }
#ifdef LIBRAW_LIBRARY_BUILD
      else if (INT64(raw_width) * INT64(raw_height) * 3ULL == INT64(tiff_ifd[raw].bytes) * 2ULL)
#else
      else if (raw_width * raw_height * 3 == tiff_ifd[raw].bytes * 2)
#endif
      {
        load_raw = &CLASS packed_load_raw;
        if (model[0] == 'N')
          load_flags = 80;
      }
#ifdef LIBRAW_LIBRARY_BUILD
      else if (INT64(raw_width) * INT64(raw_height) * 3ULL == INT64(tiff_ifd[raw].bytes))
#else
      else if (raw_width * raw_height * 3 == tiff_ifd[raw].bytes)
#endif
      {
        load_raw = &CLASS nikon_yuv_load_raw;
        gamma_curve(1 / 2.4, 12.92, 1, 4095);
        memset(cblack, 0, sizeof cblack);
        filters = 0;
      }
#ifdef LIBRAW_LIBRARY_BUILD
      else if (INT64(raw_width) * INT64(raw_height) * 2ULL == INT64(tiff_ifd[raw].bytes))
#else
      else if (raw_width * raw_height * 2 == tiff_ifd[raw].bytes)
#endif
      {
        load_raw = &CLASS unpacked_load_raw;
        load_flags = 4;
        order = 0x4d4d;
      }
      else
#ifdef LIBRAW_LIBRARY_BUILD
          if (INT64(raw_width) * INT64(raw_height) * 3ULL == INT64(tiff_ifd[raw].bytes) * 2ULL)
      {
        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 (INT64(tiff_ifd[raw].strip_byte_counts[i]) * 2ULL != INT64(tiff_ifd[raw].rows_per_strip) * INT64(raw_width) * 3ULL)
          {
            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_bps == 16 && !strncmp(make, "Leaf", 4)) && // Allow Leaf/16bit/3color files
    (tiff_compress & -16) != 32768) ||
         (tiff_bps == 8 && strncmp(make, "Phase", 5) && strncmp(make, "Leaf", 4) && !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;
    }
  }
}