File indexing completed on 2025-01-05 03:56:59

0001 /* -*- C++ -*-
0002  * Copyright 2019-2021 LibRaw LLC (info@libraw.org)
0003  *
0004  LibRaw uses code from dcraw.c -- Dave Coffin's raw photo decoder,
0005  dcraw.c is copyright 1997-2018 by Dave Coffin, dcoffin a cybercom o net.
0006  LibRaw do not use RESTRICTED code from dcraw.c
0007 
0008  LibRaw is free software; you can redistribute it and/or modify
0009  it under the terms of the one of two licenses as you choose:
0010 
0011 1. GNU LESSER GENERAL PUBLIC LICENSE version 2.1
0012    (See file LICENSE.LGPL provided in LibRaw distribution archive for details).
0013 
0014 2. COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0
0015    (See file LICENSE.CDDL provided in LibRaw distribution archive for details).
0016 
0017  */
0018 
0019 #include "../../internal/dcraw_defs.h"
0020 
0021 int LibRaw::guess_RAFDataGeneration (uchar *RAFData_start) // returns offset to first valid width/height pair
0022 {
0023 
0024 /* RAFDataGeneration codes, values are 4 bytes, little endian
0025 
0026    RAFData gen. 0: no RAFData
0027      DBP for GX680 / DX-2000
0028      E550, E900, (F500 / F505?) F550, F600 / F605, F700, F770 / F775, F800, F810, F900
0029      HS10 HS11, HS20 / HS22, HS30 / HS33 / HS35, HS50
0030      S1, SL1000, S100, S200 / S205, S20Pro, S2Pro, S3Pro, S5Pro
0031      S5000, S5100 / S5500, S5200 / S5600, S6000 / S6500, S7000, S9000 / S9500, S9100 / S9600
0032 
0033    RAFData gen. 1, offset to WH pair (offsetWH_inRAFData) = 0:
0034    - number in bytes 0..1 is less than 10000
0035    - contains WH pair, recommended image size WH pair, 16 bytes unknown, 2*13 values (for crops, scales?)
0036      X100, X-Pro1, X-S1, X10, XF1
0037 
0038    RAFData gen. 2, offset to WH pair = 4:
0039    - bytes 0..1 contain a number greater than 10000; bytes 2..3 contain zero;
0040      version is in bytes 0..1, possibly big endian
0041      - contains WH pair, recommended image size WH pair, 16 bytes unknown, 2*13 values
0042      X-E1
0043 
0044    RAFData gen. 3, offset to WH pair = 4:
0045    - bytes 0..1 contain zero; bytes 2..3 contain version;
0046    - contains a table of 3+2*13 values; first 3 values look like WHW
0047      X-A1, X-A2, X-E2, X-M1
0048      X-T1, X-T10
0049      X100S, X100T
0050      X20, X30, X70, XQ1, XQ2
0051 
0052    RAFData gen. 4, offset to WH pair = 8:
0053    - same conditions as for RAFData gen. 3, but also adds WRTS in bytes 4..7
0054    - contains a table of 3+2*13 values; first 3 values look like WHW
0055    - H in WHW group has a different meaning if the shot is taken in crop 2 mode
0056      GFX 100, GFX 100S, GFX 50R, GFX 50S, GFX 50S II
0057      X-E2S, X-E3, X-H1, X-S10
0058      X-T2, X-T3, X-T4, X-T20, X-T30
0059      X-Pro2, X-Pro3
0060      X100F, X100V
0061 
0062    RAFData gen. set to 4096:
0063    - RAFData length is exactly 4096
0064      X-A3, X-A5, X-A7, X-A10, X-A20
0065      X-T100, X-T200,
0066      XF10
0067 */
0068 
0069   int offsetWH_inRAFData=0; /* clang warns about not initialized value */
0070   ushort b01  = sget2(RAFData_start);   // bytes 0..1
0071   ushort b23  = sget2(RAFData_start+2); // bytes 2..3
0072   int is_WRTS = (sget4(RAFData_start + 4) == 0x53545257); // STRW
0073   if (b01 && !b23 && (b01<10000))
0074   {
0075     imFuji.RAFDataGeneration = 1;
0076     offsetWH_inRAFData = 0;
0077   }
0078   else if ((b01>10000) && !b23)
0079   {
0080     imFuji.RAFDataGeneration = 2;
0081     imFuji.RAFDataVersion = b01;
0082     offsetWH_inRAFData = 4;
0083   }
0084   else if (!b01)
0085   {
0086     if (!is_WRTS)
0087     {
0088       imFuji.RAFDataGeneration = 3;
0089       offsetWH_inRAFData = 4;
0090     }
0091     else
0092     {
0093       imFuji.RAFDataGeneration = 4;
0094       offsetWH_inRAFData = 8;
0095     }
0096     imFuji.RAFDataVersion = b23;
0097   }
0098 
0099 // printf ("RAFDataVersion: 0x%04x, RAFDataGeneration: %d\n",
0100 // imFuji.RAFDataVersion, imFuji.RAFDataGeneration);
0101 
0102   return offsetWH_inRAFData;
0103 }
0104 
0105 void LibRaw::parseAdobeRAFMakernote()
0106 {
0107 
0108   uchar *PrivateMknBuf;
0109   unsigned posPrivateMknBuf=0; /* clang warns about not inited value */
0110   unsigned PrivateMknLength;
0111   unsigned PrivateOrder;
0112   unsigned ifd_start, ifd_len;
0113   unsigned PrivateEntries, PrivateTagID;
0114   unsigned PrivateTagBytes;
0115   int FujiShotSelect;
0116   unsigned wb_section_offset = 0;
0117   int posWB;
0118   int c;
0119 
0120 #define CHECKSPACE_ABS3(s1, s2, s3)                                                                                    \
0121   if (INT64(s1) + INT64(s2) + INT64(s3) > INT64(PrivateMknLength))                                                     \
0122   {                                                                                                                    \
0123     free(PrivateMknBuf);                                                                                               \
0124     return;                                                                                                            \
0125   }
0126 
0127 #define CHECKSPACE_ABS2(s1,s2)                                                                                         \
0128   if (INT64(s1) + INT64(s2) > INT64(PrivateMknLength))                                                            \
0129   {                                                                                                                    \
0130     free(PrivateMknBuf);                                                                                               \
0131     return;                                                                                                            \
0132   }
0133 
0134 #define CHECKSPACE(s)                                                          \
0135   if (INT64(posPrivateMknBuf) + INT64(s) > INT64(PrivateMknLength))            \
0136   {                                                                            \
0137     free(PrivateMknBuf);                                                       \
0138     return;                                                                    \
0139   }
0140 
0141 #define isWB(posWB)                                                            \
0142   sget2(posWB) != 0 && sget2(posWB + 2) != 0 && sget2(posWB + 4) != 0 &&       \
0143       sget2(posWB + 6) != 0 && sget2(posWB + 8) != 0 &&                        \
0144       sget2(posWB + 10) != 0 && sget2(posWB) != 0xff &&                        \
0145       sget2(posWB + 2) != 0xff && sget2(posWB + 4) != 0xff &&                  \
0146       sget2(posWB + 6) != 0xff && sget2(posWB + 8) != 0xff &&                  \
0147       sget2(posWB + 10) != 0xff && sget2(posWB) == sget2(posWB + 6) &&         \
0148       sget2(posWB) < sget2(posWB + 2) && sget2(posWB) < sget2(posWB + 4) &&    \
0149       sget2(posWB) < sget2(posWB + 8) && sget2(posWB) < sget2(posWB + 10)
0150 
0151 #define get_average_WB(wb_index)                                               \
0152   CHECKSPACE(8);                                                               \
0153   FORC4 icWBC[wb_index][GRGB_2_RGBG(c)] =                                      \
0154       sget2(PrivateMknBuf + posPrivateMknBuf + (c << 1));                      \
0155   if ((PrivateTagBytes == 16) && average_WBData) {                             \
0156     CHECKSPACE(16);                                                            \
0157     FORC4 icWBC[wb_index][GRGB_2_RGBG(c)] =                                    \
0158              (icWBC[wb_index][GRGB_2_RGBG(c)] +                                \
0159               sget2(PrivateMknBuf + posPrivateMknBuf + (c << 1)+8)) /2;        \
0160   }                                                                            \
0161   if (use_WBcorr_coeffs) {                                                     \
0162     icWBC[wb_index][0] *= wbR_corr;                                            \
0163     icWBC[wb_index][2] *= wbB_corr;                                            \
0164   }
0165 
0166   ushort use_WBcorr_coeffs = 0;
0167   double wbR_corr = 1.0;
0168   double wbB_corr = 1.0;
0169 
0170   if (strstr(model, "S2Pro")
0171       || strstr(model, "S20Pro")
0172       || strstr(model, "F700")
0173       || strstr(model, "S5000")
0174       || strstr(model, "S7000")
0175       ) {
0176     use_WBcorr_coeffs = 1;
0177     wbR_corr = 10.0 / 17.0 / 0.652941;
0178     wbB_corr = 2.0 /3.0 / (3.0 / 4.0 + 1.0 / 300.0);
0179   } else if (strstr(model, "DBP") || strstr(model, "DX-2000")) {
0180     use_WBcorr_coeffs = 1;
0181     wbR_corr = 0.7632653061;
0182     wbB_corr = 0.8591549296;
0183   }
0184 
0185   FujiShotSelect = LIM(shot_select, 0, 1);
0186   int average_WBData = 1;
0187 
0188   order = 0x4d4d;
0189   PrivateMknLength = get4();
0190 
0191   // At least 0x36 bytes because of memcpy(imFuji.RAFVersion, PrivateMknBuf + 0x32, 4);
0192   if ((PrivateMknLength >= 0x36) && (PrivateMknLength < 10240000) &&
0193       (PrivateMknBuf = (uchar *)malloc(PrivateMknLength + 1024))) // 1024b for safety
0194   {
0195     fread(PrivateMknBuf, PrivateMknLength, 1, ifp);
0196     memcpy(imFuji.SerialSignature, PrivateMknBuf + 6, 0x0c);
0197     imFuji.SerialSignature[0x0c] = 0;
0198     memcpy(imFuji.SensorID, imFuji.SerialSignature + 0x06, 0x04);
0199     imFuji.SensorID[0x04] = 0;
0200     c = 11;
0201     while (isdigit(imFuji.SerialSignature[c]) && (c>0))
0202       c--;
0203     ilm.CamID = unique_id = (unsigned long long)atoi(imFuji.SerialSignature+c+1);
0204     memcpy(model, PrivateMknBuf + 0x12, 0x20);
0205     model[0x20] = 0;
0206     memcpy(imFuji.RAFVersion, PrivateMknBuf + 0x32, 4);
0207     imFuji.RAFVersion[4] = 0;
0208 
0209     PrivateOrder = sget2(PrivateMknBuf);
0210     unsigned s, l;
0211     s = ifd_start = sget4(PrivateMknBuf +2)+6;
0212     CHECKSPACE(INT64(ifd_start)+4LL);
0213     l = ifd_len = sget4(PrivateMknBuf +ifd_start);
0214     CHECKSPACE_ABS3(ifd_start, ifd_len, 4);
0215 
0216     if (!sget4(PrivateMknBuf+ifd_start+ifd_len+4))
0217       FujiShotSelect = 0;
0218 
0219     if ((FujiShotSelect == 1) && (PrivateMknLength > ifd_len*2)) {
0220       ifd_start += (ifd_len+4);
0221       CHECKSPACE_ABS2(ifd_start, 4);
0222       ifd_len = sget4(PrivateMknBuf +ifd_start);
0223       if ((ifd_start+ifd_len) > PrivateMknLength) {
0224         ifd_start = s;
0225         ifd_len = l;
0226         FujiShotSelect = 0;
0227       }
0228     } else FujiShotSelect = 0;
0229 
0230     CHECKSPACE_ABS3(ifd_start, 4, 4);
0231     PrivateEntries = sget4(PrivateMknBuf + ifd_start + 4);
0232     if ((PrivateEntries > 1000) ||
0233         ((PrivateOrder != 0x4d4d) && (PrivateOrder != 0x4949)))
0234     {
0235       free(PrivateMknBuf);
0236       return;
0237     }
0238     posPrivateMknBuf = (ifd_start+8);
0239 
0240     /*
0241      * because Adobe DNG converter strips or misplaces 0xfnnn tags,
0242      * for now, Auto WB is missing for the following cameras:
0243      * - F550EXR / F600EXR / F770EXR / F800EXR / F900EXR
0244      * - HS10 / HS11 / HS20EXR / HS30EXR / HS33EXR / HS35EXR / HS50EXR
0245      * - S1 / SL1000
0246      **/
0247     while (PrivateEntries--)
0248     {
0249       order = 0x4d4d;
0250       CHECKSPACE(4);
0251       PrivateTagID = sget2(PrivateMknBuf + posPrivateMknBuf);
0252       PrivateTagBytes = sget2(PrivateMknBuf + posPrivateMknBuf + 2);
0253       posPrivateMknBuf += 4;
0254       order = PrivateOrder;
0255 
0256       if (PrivateTagID == 0x2000)
0257       {
0258         get_average_WB(LIBRAW_WBI_Auto);
0259       }
0260       else if (PrivateTagID == 0x2100)
0261       {
0262         get_average_WB(LIBRAW_WBI_FineWeather);
0263       }
0264       else if (PrivateTagID == 0x2200)
0265       {
0266         get_average_WB(LIBRAW_WBI_Shade);
0267       }
0268       else if (PrivateTagID == 0x2300)
0269       {
0270         get_average_WB(LIBRAW_WBI_FL_D);
0271       }
0272       else if (PrivateTagID == 0x2301)
0273       {
0274         get_average_WB(LIBRAW_WBI_FL_N);
0275       }
0276       else if (PrivateTagID == 0x2302)
0277       {
0278         get_average_WB(LIBRAW_WBI_FL_W);
0279       }
0280       else if (PrivateTagID == 0x2310)
0281       {
0282         get_average_WB(LIBRAW_WBI_FL_WW);
0283       }
0284       else if (PrivateTagID == 0x2311)
0285       {
0286         get_average_WB(LIBRAW_WBI_FL_L);
0287       }
0288       else if (PrivateTagID == 0x2400)
0289       {
0290         get_average_WB(LIBRAW_WBI_Tungsten);
0291       }
0292       else if (PrivateTagID == 0x2410)
0293       {
0294         get_average_WB(LIBRAW_WBI_Flash);
0295       }
0296       else if (PrivateTagID == 0x2f00)
0297       {
0298         CHECKSPACE(4);
0299         int nWBs = MIN(sget4(PrivateMknBuf + posPrivateMknBuf), 6);
0300         posWB = posPrivateMknBuf + 4;
0301         for (int wb_ind = LIBRAW_WBI_Custom1; wb_ind < LIBRAW_WBI_Custom1+nWBs; wb_ind++) {
0302           CHECKSPACE_ABS2(posWB, 8);
0303           FORC4 icWBC[wb_ind][GRGB_2_RGBG(c)] =
0304                   sget2(PrivateMknBuf + posWB + (c << 1));
0305           if ((PrivateTagBytes >= unsigned(4+16*nWBs)) && average_WBData) {
0306             posWB += 8;
0307             CHECKSPACE_ABS2(posWB, 8);
0308             FORC4 icWBC[wb_ind][GRGB_2_RGBG(c)] =
0309                     (icWBC[wb_ind][GRGB_2_RGBG(c)] +
0310                      sget2(PrivateMknBuf + posWB + (c << 1))) /2;
0311           }
0312           if (use_WBcorr_coeffs) {
0313              icWBC[wb_ind][0] *= wbR_corr;
0314              icWBC[wb_ind][2] *= wbB_corr;
0315           }
0316           posWB += 8;
0317         }
0318       }
0319       else if (PrivateTagID == 0x2ff0)
0320       {
0321         get_average_WB(LIBRAW_WBI_AsShot);
0322         FORC4 cam_mul[c] = icWBC[LIBRAW_WBI_AsShot][c];
0323       }
0324       else if ((PrivateTagID == 0x4000) &&
0325                ((PrivateTagBytes == 8) || (PrivateTagBytes == 16)))
0326       {
0327         imFuji.BlackLevel[0] = PrivateTagBytes / 2;
0328         CHECKSPACE(10);
0329         FORC4 imFuji.BlackLevel[GRGB_2_RGBG(c)+1] =
0330             sget2(PrivateMknBuf + posPrivateMknBuf + (c << 1));
0331         if (imFuji.BlackLevel[0] == 8) {
0332           CHECKSPACE(18);
0333           FORC4 imFuji.BlackLevel[GRGB_2_RGBG(c) + 5] =
0334               sget2(PrivateMknBuf + posPrivateMknBuf + (c << 1) + 8);
0335         }
0336       }
0337       else if (PrivateTagID == 0x9650)
0338       {
0339         CHECKSPACE(4);
0340         short a = (short)sget2(PrivateMknBuf + posPrivateMknBuf);
0341         float b = fMAX(1.0f, sget2(PrivateMknBuf + posPrivateMknBuf + 2));
0342         imFuji.ExpoMidPointShift = a / b;
0343         imCommon.ExposureCalibrationShift += imFuji.ExpoMidPointShift;
0344       }
0345       else if ((PrivateTagID == 0xc000) && (PrivateTagBytes > 3) &&
0346                (PrivateTagBytes < 10240000))
0347       {
0348         order = 0x4949;
0349         if (PrivateTagBytes != 4096) // not one of Fuji X-A3, X-A5, X-A7, X-A10, X-A20, X-T100, X-T200, XF10
0350         {
0351           int is34 = 0;
0352           CHECKSPACE(8);
0353           guess_RAFDataGeneration (PrivateMknBuf + posPrivateMknBuf);
0354 // printf ("RAFDataVersion: 0x%04x, RAFDataGeneration: %d\n",
0355 // imFuji.RAFDataVersion, imFuji.RAFDataGeneration);
0356 
0357           for (posWB = 0; posWB < (int)PrivateTagBytes - 16; posWB++)
0358           {
0359             CHECKSPACE_ABS2(posWB, 12);
0360             if ((!memcmp(PrivateMknBuf + posWB, "TSNERDTS", 8) &&
0361                  (sget2(PrivateMknBuf + posWB + 10) > 125)))
0362             {
0363               posWB += 10;
0364               icWBC[LIBRAW_WBI_Auto][1] =
0365                   icWBC[LIBRAW_WBI_Auto][3] =
0366                       sget2(PrivateMknBuf + posWB);
0367               icWBC[LIBRAW_WBI_Auto][0] =
0368                   sget2(PrivateMknBuf + posWB + 2);
0369               icWBC[LIBRAW_WBI_Auto][2] =
0370                   sget2(PrivateMknBuf + posWB + 4);
0371               break;
0372             }
0373           }
0374 
0375           if ((imFuji.RAFDataVersion == 0x0260) || // X-Pro3, GFX 100S
0376               (imFuji.RAFDataVersion == 0x0261) || // X100V, GFX 50S II
0377               (imFuji.RAFDataVersion == 0x0262) || // X-T4
0378               (imFuji.RAFDataVersion == 0x0264) || // X-S10
0379               (imFuji.RAFDataVersion == 0x0265) || // X-E4
0380               (imFuji.RAFDataVersion == 0x0266) || // X-T30 II
0381                 !strcmp(model, "X-Pro3")     ||
0382                 !strcmp(model, "GFX 100S")   ||
0383                 !strcmp(model, "GFX100S")    ||
0384                 !strcmp(model, "GFX 50S II") ||
0385                 !strcmp(model, "GFX50S II")  ||
0386                 !strcmp(model, "X100V")      ||
0387                 !strcmp(model, "X-T4")       ||
0388                 !strcmp(model, "X-E4")       ||
0389                 !strcmp(model, "X-T30 II")   ||
0390                 !strcmp(model, "X-S10"))
0391             is34 = 1;
0392 
0393           if (imFuji.RAFDataVersion == 0x4500) // X-E1, RAFData gen. 3
0394           {
0395             wb_section_offset = 0x13ac;
0396           }
0397           else if (imFuji.RAFDataVersion == 0x0146 || // X20
0398                    imFuji.RAFDataVersion == 0x0149 || // X100S
0399                    imFuji.RAFDataVersion == 0x0249)   // X100S
0400           {
0401             wb_section_offset = 0x1410;
0402           }
0403           else if (imFuji.RAFDataVersion == 0x014d || // X-M1
0404                    imFuji.RAFDataVersion == 0x014e)   // X-A1, X-A2
0405           {
0406             wb_section_offset = 0x1474;
0407           }
0408           else if (imFuji.RAFDataVersion == 0x014f || // X-E2
0409                    imFuji.RAFDataVersion == 0x024f || // X-E2
0410                    imFuji.RAFDataVersion == 0x025d || // X-H1
0411                    imFuji.RAFDataVersion == 0x035d)   // X-H1
0412           {
0413             wb_section_offset = 0x1480;
0414           }
0415           else if (imFuji.RAFDataVersion == 0x0150) // XQ1, XQ2
0416           {
0417             wb_section_offset = 0x1414;
0418           }
0419           else if (imFuji.RAFDataVersion == 0x0151 || // X-T1 w/diff. fws
0420                    imFuji.RAFDataVersion == 0x0251 || imFuji.RAFDataVersion == 0x0351 ||
0421                    imFuji.RAFDataVersion == 0x0451 || imFuji.RAFDataVersion == 0x0551)
0422           {
0423             wb_section_offset = 0x14b0;
0424           }
0425           else if (imFuji.RAFDataVersion == 0x0152 || // X30
0426                    imFuji.RAFDataVersion == 0x0153)   // X100T
0427           {
0428             wb_section_offset = 0x1444;
0429           }
0430           else if (imFuji.RAFDataVersion == 0x0154) // X-T10
0431           {
0432             wb_section_offset = 0x1824;
0433           }
0434           else if (imFuji.RAFDataVersion == 0x0155) // X70
0435           {
0436             wb_section_offset = 0x17b4;
0437           }
0438           else if (imFuji.RAFDataVersion == 0x0255 || // X-Pro2
0439                    imFuji.RAFDataVersion == 0x0455)
0440           {
0441             wb_section_offset = 0x135c;
0442           }
0443           else if (imFuji.RAFDataVersion == 0x0258 || // X-T2
0444                    imFuji.RAFDataVersion == 0x025b)   // X-T20
0445           {
0446             wb_section_offset = 0x13dc;
0447           }
0448           else if (imFuji.RAFDataVersion == 0x0259) // X100F
0449           {
0450             wb_section_offset = 0x1370;
0451           }
0452           else if (imFuji.RAFDataVersion == 0x025a || // GFX 50S
0453                    imFuji.RAFDataVersion == 0x045a)
0454           {
0455             wb_section_offset = 0x1424;
0456          }
0457           else if (imFuji.RAFDataVersion == 0x025c) // X-E3
0458           {
0459             wb_section_offset = 0x141c;
0460           }
0461           else if (imFuji.RAFDataVersion == 0x025e) // X-T3
0462           {
0463             wb_section_offset = 0x2014;
0464           }
0465           else if (imFuji.RAFDataVersion == 0x025f) // X-T30, GFX 50R, GFX 100 (? RAFDataVersion 0x045f)
0466           {
0467             if (!strcmp(model, "X-T30")) {   
0468               CHECKSPACE(0x20b8 + 12);
0469               if (isWB(PrivateMknBuf + posPrivateMknBuf + 0x20b8))
0470                 wb_section_offset = 0x20b8;
0471               else
0472               {
0473                   CHECKSPACE(0x20c8 + 12);
0474                   if (isWB(PrivateMknBuf + posPrivateMknBuf + 0x20c8))
0475                       wb_section_offset = 0x20c8;
0476               }
0477             }
0478             else if (!strcmp(model, "GFX 50R"))
0479               wb_section_offset = 0x1424;
0480             else if (!strcmp(model, "GFX 100"))
0481               wb_section_offset = 0x20e4;
0482           }
0483           else if (imFuji.RAFDataVersion == 0x0260) // X-Pro3, GFX 100S
0484           {
0485            if (!strcmp(model, "X-Pro3"))
0486               wb_section_offset = 0x20e8;
0487             else if (!strcmp(model, "GFX 100S") || !strcmp(model, "GFX100S"))
0488               wb_section_offset = 0x2108;
0489           }
0490           else if (imFuji.RAFDataVersion == 0x0261) // X100V, GFX 50S II
0491           {
0492             if (!strcmp(model, "X100V"))
0493               wb_section_offset = 0x2078;
0494             else if (!strcmp(model, "GFX 50S II") || !strcmp(model, "GFX50S II"))
0495               wb_section_offset = 0x214c;
0496           }
0497           else if (imFuji.RAFDataVersion == 0x0262) // X-T4
0498           {
0499             wb_section_offset = 0x21c8;
0500           }
0501           else if (imFuji.RAFDataVersion == 0x0264) // X-S10
0502           {
0503             wb_section_offset = 0x21de;
0504           }
0505           else if ((imFuji.RAFDataVersion == 0x0265)  || // X-E4
0506                    (imFuji.RAFDataVersion == 0x0266))    // X-T30 II
0507           {
0508             wb_section_offset = 0x21cc;
0509           }
0510           else if (imFuji.RAFDataVersion == 0x0355) // X-E2S
0511           {
0512             wb_section_offset = 0x1840;
0513           }
0514 
0515 /* try for unknown RAF Data versions */
0516           else if (!strcmp(model, "X-Pro2"))
0517           {
0518             CHECKSPACE(0x135c + 12);
0519             if (isWB(PrivateMknBuf + posPrivateMknBuf + 0x135c))
0520               wb_section_offset = 0x135c;
0521           }
0522           else if (!strcmp(model, "X100F"))
0523           {
0524             CHECKSPACE(0x1370 + 12);
0525             if (isWB(PrivateMknBuf + posPrivateMknBuf + 0x1370))
0526               wb_section_offset = 0x1370;
0527           }
0528           else if (!strcmp(model, "X-E1"))
0529           {
0530             CHECKSPACE(0x13ac + 12);
0531             if (isWB(PrivateMknBuf + posPrivateMknBuf + 0x13ac))
0532               wb_section_offset = 0x13ac;
0533           }
0534           else if (!strcmp(model, "X-T2") ||
0535                    !strcmp(model, "X-T20"))
0536           {
0537             CHECKSPACE(0x13dc + 12);
0538             if (isWB(PrivateMknBuf + posPrivateMknBuf + 0x13dc))
0539               wb_section_offset = 0x13dc;
0540           }
0541           else if (!strcmp(model, "X20") ||
0542                    !strcmp(model, "X100S"))
0543           {
0544             CHECKSPACE(0x1410 + 12);
0545             if (isWB(PrivateMknBuf + posPrivateMknBuf + 0x1410))
0546               wb_section_offset = 0x1410;
0547           }
0548           else if (!strcmp(model, "XQ1") ||
0549                    !strcmp(model, "XQ2"))
0550           {
0551             CHECKSPACE(0x1414+ 12);
0552             if (isWB(PrivateMknBuf + posPrivateMknBuf + 0x1414))
0553               wb_section_offset = 0x1414;
0554           }
0555           else if (!strcmp(model, "X-E3"))
0556           {
0557             CHECKSPACE(0x141c + 12);
0558             if (isWB(PrivateMknBuf + posPrivateMknBuf + 0x141c))
0559               wb_section_offset = 0x141c;
0560           }
0561           else if (!strcmp(model, "GFX 50S") ||
0562                    !strcmp(model, "GFX 50R"))
0563           {
0564             CHECKSPACE(0x1424 + 12);
0565             if (isWB(PrivateMknBuf + posPrivateMknBuf + 0x1424))
0566               wb_section_offset = 0x1424;
0567           }
0568           else if (!strcmp(model, "GFX 50S II") || !strcmp(model, "GFX50S II")) {
0569             CHECKSPACE(0x214c + 12);
0570             if (isWB(PrivateMknBuf + posPrivateMknBuf + 0x214c))
0571               wb_section_offset = 0x214c;
0572           }
0573           else if (!strcmp(model, "X30") ||
0574                    !strcmp(model, "X100T"))
0575           {
0576             CHECKSPACE(0x1444 + 12);
0577             if (isWB(PrivateMknBuf + posPrivateMknBuf + 0x1444))
0578               wb_section_offset = 0x1444;
0579           }
0580           else if (!strcmp(model, "X-M1") ||
0581                    !strcmp(model, "X-A1") ||
0582                    !strcmp(model, "X-A2"))
0583           {
0584             CHECKSPACE(0x1474 + 12);
0585             if (isWB(PrivateMknBuf + posPrivateMknBuf + 0x1474))
0586               wb_section_offset = 0x1474;
0587           }
0588           else if (!strcmp(model, "X-E2") ||
0589                    !strcmp(model, "X-H1"))
0590           {
0591             CHECKSPACE(0x1480 + 12);
0592             if (isWB(PrivateMknBuf + posPrivateMknBuf + 0x1480))
0593               wb_section_offset = 0x1480;
0594           }
0595           else if (!strcmp(model, "X-T1"))
0596           {
0597             CHECKSPACE(0x14b0 + 12);
0598             if (isWB(PrivateMknBuf + posPrivateMknBuf + 0x14b0))
0599               wb_section_offset = 0x14b0;
0600           }
0601           else if (!strcmp(model, "X70"))
0602           {
0603             CHECKSPACE(0x17b4 + 12);
0604             if (isWB(PrivateMknBuf + posPrivateMknBuf + 0x17b4))
0605               wb_section_offset = 0x17b4;
0606           }
0607           else if (!strcmp(model, "X-T10"))
0608           {
0609             CHECKSPACE(0x1824 + 12);
0610             if (isWB(PrivateMknBuf + posPrivateMknBuf + 0x1824))
0611               wb_section_offset = 0x1824;
0612           }
0613           else if (!strcmp(model, "X-E2S"))
0614           {
0615             CHECKSPACE(0x1840 + 12);
0616             if (isWB(PrivateMknBuf + posPrivateMknBuf + 0x1840))
0617               wb_section_offset = 0x1840;
0618           }
0619           else if (!strcmp(model, "X-T3"))
0620           {
0621             CHECKSPACE(0x2014 + 12);
0622             if (isWB(PrivateMknBuf + posPrivateMknBuf + 0x2014))
0623               wb_section_offset = 0x2014;
0624           }
0625           else if (!strcmp(model, "X100V"))
0626           {
0627             CHECKSPACE(0x2078 + 12);
0628             if (isWB(PrivateMknBuf + posPrivateMknBuf + 0x2078))
0629               wb_section_offset = 0x2078;
0630           }
0631           else if (!strcmp(model, "X-T30"))
0632           {
0633             CHECKSPACE(0x20b8 + 12);
0634             if (isWB(PrivateMknBuf + posPrivateMknBuf + 0x20b8))
0635               wb_section_offset = 0x20b8;
0636             else
0637             {
0638                 CHECKSPACE(0x20c8 + 12);
0639                 if (isWB(PrivateMknBuf + posPrivateMknBuf + 0x20c8))
0640                     wb_section_offset = 0x20c8;
0641             }
0642           }
0643           else if (!strcmp(model, "GFX 100"))
0644           {
0645             CHECKSPACE(0x20e4 + 12);
0646             if (isWB(PrivateMknBuf + posPrivateMknBuf + 0x20e4))
0647               wb_section_offset = 0x20e4;
0648           }
0649           else if (!strcmp(model, "X-Pro3"))
0650           {
0651             CHECKSPACE(0x20e8 + 12);
0652             if (isWB(PrivateMknBuf + posPrivateMknBuf + 0x20e8))
0653               wb_section_offset = 0x20e8;
0654           }
0655           else if (!strcmp(model, "GFX100S") || !strcmp(model, "GFX 100S"))
0656           {
0657             CHECKSPACE(0x2108 + 12);
0658             if (isWB(PrivateMknBuf + posPrivateMknBuf + 0x2108))
0659               wb_section_offset = 0x2108;
0660           }
0661           else if (!strcmp(model, "X-T4"))
0662           {
0663             CHECKSPACE(0x21c8 + 12);
0664             if (isWB(PrivateMknBuf + posPrivateMknBuf + 0x21c8))
0665               wb_section_offset = 0x21c8;
0666           }
0667           else if ((!strcmp(model, "X-E4"))       ||
0668                    (!strcmp(model, "X-T30 II")))
0669           {
0670             CHECKSPACE(0x21cc + 12);
0671             if (isWB(PrivateMknBuf + posPrivateMknBuf + 0x21cc))
0672               wb_section_offset = 0x21cc;
0673           }
0674           else if (!strcmp(model, "X-S10"))
0675           {
0676             CHECKSPACE(0x21de + 12);
0677             if (isWB(PrivateMknBuf + posPrivateMknBuf + 0x21de))
0678               wb_section_offset = 0x21de;
0679           }
0680 /* no RAF Data version for the models below */
0681           else if (!strcmp(model, "FinePix X100")) // X100 0 0x19f0 0x19e8
0682           {
0683             if (!strcmp(imFuji.RAFVersion, "0069"))
0684               wb_section_offset = 0x19e8;
0685             else if (!strcmp(imFuji.RAFVersion, "0100") ||
0686                      !strcmp(imFuji.RAFVersion, "0110"))
0687               wb_section_offset = 0x19f0;
0688             else
0689             {
0690                 CHECKSPACE(0x19e8 + 12);
0691                 if (isWB(PrivateMknBuf + posPrivateMknBuf + 0x19e8))
0692                     wb_section_offset = 0x19e8;
0693                 else
0694                 {
0695                     CHECKSPACE(0x19f0 + 12);
0696                     if (isWB(PrivateMknBuf + posPrivateMknBuf + 0x19f0))
0697                         wb_section_offset = 0x19f0;
0698                 }
0699             }
0700           }
0701           else if (!strcmp(model, "X-Pro1")) // X-Pro1 0 0x13a4
0702           {
0703             if (!strcmp(imFuji.RAFVersion, "0100") ||
0704                 !strcmp(imFuji.RAFVersion, "0101") ||
0705                 !strcmp(imFuji.RAFVersion, "0204"))
0706               wb_section_offset = 0x13a4;
0707             else
0708             {
0709                 CHECKSPACE(0x13a4 + 12);
0710                 if (isWB(PrivateMknBuf + posPrivateMknBuf + 0x13a4))
0711                     wb_section_offset = 0x13a4;
0712             }
0713           }
0714           else if (!strcmp(model, "XF1")) // XF1 0 0x138c
0715           {
0716             if (!strcmp(imFuji.RAFVersion, "0100"))
0717               wb_section_offset = 0x138c;
0718             else
0719             {
0720                 CHECKSPACE(0x138c + 12);
0721                 if (isWB(PrivateMknBuf + posPrivateMknBuf + 0x138c))
0722                     wb_section_offset = 0x138c;
0723             }
0724           }
0725           else if (!strcmp(model, "X-S1")) // X-S1 0 0x1284
0726           {
0727             if (!strcmp(imFuji.RAFVersion, "0100"))
0728               wb_section_offset = 0x1284;
0729             else
0730             {
0731                 CHECKSPACE(0x1284 + 12);
0732                 if (isWB(PrivateMknBuf + posPrivateMknBuf + 0x1284))
0733                     wb_section_offset = 0x1284;
0734             }
0735           }
0736           else if (!strcmp(model, "X10")) // X10 0 0x1280 0x12d4
0737           {
0738             if (!strcmp(imFuji.RAFVersion, "0100") ||
0739                 !strcmp(imFuji.RAFVersion, "0102"))
0740               wb_section_offset = 0x1280;
0741             else if (!strcmp(imFuji.RAFVersion, "0103"))
0742               wb_section_offset = 0x12d4;
0743             else
0744             {
0745                 CHECKSPACE(0x1280 + 12);
0746                 if (isWB(PrivateMknBuf + posPrivateMknBuf + 0x1280))
0747                     wb_section_offset = 0x1280;
0748                 else
0749                 {
0750                     CHECKSPACE(0x12d4 + 12);
0751                     if (isWB(PrivateMknBuf + posPrivateMknBuf + 0x12d4))
0752                         wb_section_offset = 0x12d4;
0753                 }
0754             }
0755           }
0756           else if (!strcmp(model, "XF1")) // XF1 0 0x138c
0757           {
0758             if (!strcmp(imFuji.RAFVersion, "0100"))
0759               wb_section_offset = 0x138c;
0760             else
0761             {
0762                 CHECKSPACE(0x138c + 12);
0763                 if (isWB(PrivateMknBuf + posPrivateMknBuf + 0x138c))
0764                     wb_section_offset = 0x138c;
0765             }
0766           }
0767 
0768           if (wb_section_offset)
0769           {
0770               CHECKSPACE(INT64(wb_section_offset) + 12LL);
0771           }
0772 
0773           if (wb_section_offset &&
0774               isWB(PrivateMknBuf + posPrivateMknBuf + wb_section_offset))
0775           {
0776 
0777             if (!imFuji.RAFDataVersion)
0778             {
0779               posWB = posPrivateMknBuf + wb_section_offset - 6;
0780               CHECKSPACE_ABS2(posWB, 6);
0781               icWBC[LIBRAW_WBI_Auto][1] =
0782                   icWBC[LIBRAW_WBI_Auto][3] =
0783                       sget2(PrivateMknBuf + posWB);
0784               icWBC[LIBRAW_WBI_Auto][0] =
0785                   sget2(PrivateMknBuf + posWB + 2);
0786               icWBC[LIBRAW_WBI_Auto][2] =
0787                   sget2(PrivateMknBuf + posWB + 4);
0788             }
0789 
0790             posWB = posPrivateMknBuf + wb_section_offset;
0791             for (int wb_ind = 0; wb_ind < (int)Fuji_wb_list1.size(); posWB += 6, wb_ind++)
0792             {
0793               CHECKSPACE_ABS2(posWB, 6);
0794               icWBC[Fuji_wb_list1[wb_ind]][1] =
0795                   icWBC[Fuji_wb_list1[wb_ind]][3] =
0796                       sget2(PrivateMknBuf + posWB);
0797               icWBC[Fuji_wb_list1[wb_ind]][0] =
0798                   sget2(PrivateMknBuf + posWB + 2);
0799               icWBC[Fuji_wb_list1[wb_ind]][2] =
0800                   sget2(PrivateMknBuf + posWB + 4);
0801             }
0802             int found = 0;
0803             if (is34)
0804               posWB += 0x30;
0805             posWB += 0xc0;
0806             CHECKSPACE_ABS2(posWB, 2);
0807             ushort Gval = sget2(PrivateMknBuf + posWB);
0808             for (int posEndCCTsection = posWB; posEndCCTsection < (posWB + 30);
0809                  posEndCCTsection += 6)
0810             {
0811               CHECKSPACE_ABS2(posEndCCTsection, 2);
0812               if (sget2(PrivateMknBuf + posEndCCTsection) != Gval)
0813               {
0814                 if (is34)
0815                   wb_section_offset = posEndCCTsection - 34*3*2; // 34 records, 3 2-byte values in a record
0816                 else
0817                   wb_section_offset = posEndCCTsection - 31*3*2; // 31 records, 3 2-byte values in a record
0818                 found = 1;
0819                 break;
0820               }
0821             }
0822 
0823             if (found)
0824             {
0825               for (int iCCT = 0; iCCT < 31; iCCT++)
0826               {
0827                 CHECKSPACE_ABS2(wb_section_offset, iCCT*6+6);
0828                 icWBCCTC[iCCT][0] = FujiCCT_K[iCCT];
0829                 icWBCCTC[iCCT][1] = sget2(PrivateMknBuf + wb_section_offset + iCCT * 6 + 2);
0830                 icWBCCTC[iCCT][2] = icWBCCTC[iCCT][4] = sget2(PrivateMknBuf + wb_section_offset + iCCT * 6);
0831                 icWBCCTC[iCCT][3] = sget2(PrivateMknBuf + wb_section_offset + iCCT * 6 + 4);
0832               }
0833             }
0834           }
0835         }
0836         else // process 4K raf data
0837         {
0838           int wb[4];
0839           int nWB, tWB, pWB;
0840           int iCCT = 0;
0841           imFuji.RAFDataGeneration = 4096; // X-A3, X-A5, X-A7, X-A10, X-A20, X-T100, X-T200, XF10
0842           posWB = posPrivateMknBuf + 0x200;
0843           for (int wb_ind = 0; wb_ind < 42; wb_ind++)
0844           {
0845             CHECKSPACE_ABS2(posWB, 24);
0846             nWB = sget4(PrivateMknBuf + posWB);
0847             posWB += 4;
0848             tWB = sget4(PrivateMknBuf + posWB);
0849             posWB += 4;
0850             wb[0] = sget4(PrivateMknBuf + posWB) << 1;
0851             posWB += 4;
0852             wb[1] = sget4(PrivateMknBuf + posWB);
0853             posWB += 4;
0854             wb[3] = sget4(PrivateMknBuf + posWB);
0855             posWB += 4;
0856             wb[2] = sget4(PrivateMknBuf + posWB) << 1;
0857             posWB += 4;
0858 
0859             if (tWB && (iCCT < 255))
0860             {
0861               icWBCCTC[iCCT][0] = tWB;
0862               FORC4 icWBCCTC[iCCT][c + 1] = wb[c];
0863               iCCT++;
0864             }
0865             if (nWB != 0x46)
0866             {
0867               for (pWB = 1; pWB < (int)Fuji_wb_list2.size(); pWB += 2)
0868               {
0869                 if (Fuji_wb_list2[pWB] == nWB)
0870                 {
0871                   FORC4 icWBC[Fuji_wb_list2[pWB - 1]][c] = wb[c];
0872                   break;
0873                 }
0874               }
0875             }
0876           }
0877         }
0878       }
0879       posPrivateMknBuf += PrivateTagBytes;
0880     }
0881     free(PrivateMknBuf);
0882   }
0883 #undef get_average_WB
0884 #undef CHECKSPACE
0885 #undef CHECKSPACE_ABS2
0886 #undef CHECKSPACE_ABS3
0887 }
0888 
0889 void LibRaw::parseFujiMakernotes(unsigned tag, unsigned type, unsigned len,
0890                                  unsigned /*dng_writer*/)
0891 {
0892   if (tag == 0x0010)
0893   {
0894     char FujiSerial[sizeof(imgdata.shootinginfo.InternalBodySerial)];
0895     char *words[4] = { 0,0,0,0 };
0896     char yy[2], mm[3], dd[3], ystr[16], ynum[16];
0897     int year, nwords, ynum_len;
0898     unsigned c;
0899     memset(FujiSerial, 0, sizeof(imgdata.shootinginfo.InternalBodySerial));
0900     ifp->read(FujiSerial, MIN(len,sizeof(FujiSerial)), 1);
0901     nwords = getwords(FujiSerial, words, 4,
0902                       sizeof(imgdata.shootinginfo.InternalBodySerial));
0903     for (int i = 0; i < nwords; i++)
0904     {
0905       if (!words[i]) break;  // probably damaged input
0906       mm[2] = dd[2] = 0;
0907       if (strnlen(words[i],
0908                   sizeof(imgdata.shootinginfo.InternalBodySerial) - 1) < 18)
0909       {
0910         if (i == 0)
0911         {
0912           strncpy(imgdata.shootinginfo.InternalBodySerial, words[0],
0913                   sizeof(imgdata.shootinginfo.InternalBodySerial) - 1);
0914         }
0915         else
0916         {
0917           char tbuf[sizeof(imgdata.shootinginfo.InternalBodySerial)];
0918           snprintf(tbuf, sizeof(tbuf)-1, "%s %s",
0919                    imgdata.shootinginfo.InternalBodySerial, words[i]);
0920           strncpy(imgdata.shootinginfo.InternalBodySerial, tbuf,
0921                   sizeof(imgdata.shootinginfo.InternalBodySerial) - 1);
0922         }
0923       }
0924       else
0925       {
0926         strncpy(
0927             dd,
0928             words[i] +
0929                 strnlen(words[i],
0930                         sizeof(imgdata.shootinginfo.InternalBodySerial) - 1) -
0931                 14,
0932             2);
0933         strncpy(
0934             mm,
0935             words[i] +
0936                 strnlen(words[i],
0937                         sizeof(imgdata.shootinginfo.InternalBodySerial) - 1) -
0938                 16,
0939             2);
0940         strncpy(
0941             yy,
0942             words[i] +
0943                 strnlen(words[i],
0944                         sizeof(imgdata.shootinginfo.InternalBodySerial) - 1) -
0945                 18,
0946             2);
0947         year = (yy[0] - '0') * 10 + (yy[1] - '0');
0948         if (year < 70)
0949           year += 2000;
0950         else
0951           year += 1900;
0952 
0953         ynum_len = MIN(
0954             int(sizeof(ynum) - 1),
0955             (int)strnlen(words[i],
0956                          sizeof(imgdata.shootinginfo.InternalBodySerial) - 1) -
0957                 18);
0958         strncpy(ynum, words[i], ynum_len);
0959         ynum[ynum_len] = 0;
0960         for (int j = 0; ynum[j] && ynum[j + 1] && sscanf(ynum + j, "%2x", &c);
0961              j += 2)
0962           ystr[j / 2] = c;
0963         ynum_len /= 2;
0964         ystr[ynum_len + 1] = 0;
0965         strcpy(model2, ystr);
0966 
0967         if (i == 0)
0968         {
0969           char tbuf[sizeof(imgdata.shootinginfo.InternalBodySerial)];
0970 
0971           if (nwords == 1)
0972           {
0973             snprintf(
0974               tbuf, sizeof(tbuf), "%s %d:%s:%s %s",
0975               ystr, year, mm, dd,
0976               words[0] +
0977                 strnlen(words[0], sizeof(imgdata.shootinginfo.InternalBodySerial)-1)-12);
0978           }
0979           else
0980           {
0981             snprintf(
0982                 tbuf, sizeof(tbuf), "%s %d:%s:%s %s", ystr, year, mm, dd,
0983                 words[0] +
0984                     strnlen(words[0],
0985                             sizeof(imgdata.shootinginfo.InternalBodySerial) -
0986                                 1) -
0987                     12);
0988           }
0989           strncpy(imgdata.shootinginfo.InternalBodySerial, tbuf,
0990                   sizeof(imgdata.shootinginfo.InternalBodySerial) - 1);
0991         }
0992         else
0993         {
0994           char tbuf[sizeof(imgdata.shootinginfo.InternalBodySerial)];
0995           snprintf(
0996               tbuf, sizeof(tbuf), "%s %s %d:%s:%s %s",
0997               imgdata.shootinginfo.InternalBodySerial, ystr, year, mm, dd,
0998               words[i] +
0999                   strnlen(words[i],
1000                           sizeof(imgdata.shootinginfo.InternalBodySerial) - 1) -
1001                   12);
1002           strncpy(imgdata.shootinginfo.InternalBodySerial, tbuf,
1003                   sizeof(imgdata.shootinginfo.InternalBodySerial) - 1);
1004         }
1005       }
1006     }
1007   }
1008   else
1009     switch (tag)
1010     {
1011     case 0x1002:
1012       imFuji.WB_Preset = get2();
1013       break;
1014     case 0x1011:
1015       imCommon.FlashEC = getreal(type);
1016       break;
1017     case 0x1020:
1018       imFuji.Macro = get2();
1019       break;
1020     case 0x1021:
1021       imFuji.FocusMode = imgdata.shootinginfo.FocusMode = get2();
1022       break;
1023     case 0x1022:
1024       imFuji.AFMode = get2();
1025       break;
1026     case 0x1023:
1027       imFuji.FocusPixel[0] = get2();
1028       imFuji.FocusPixel[1] = get2();
1029       break;
1030     case 0x102b:
1031       imFuji.PrioritySettings = get2();
1032       break;
1033     case 0x102d:
1034       imFuji.FocusSettings = get4();
1035       break;
1036     case 0x102e:
1037       imFuji.AF_C_Settings = get4();
1038       break;
1039     case 0x1034:
1040       imFuji.ExrMode = get2();
1041       break;
1042     case 0x104d:
1043       FujiCropMode = get2(); // odd: one of raw dimensions here can be lost
1044       break;
1045     case 0x1050:
1046       imFuji.ShutterType = get2();
1047       break;
1048     case 0x1100:
1049       imFuji.AutoBracketing = get2(); // AutoBracketing = 6 for pixel shift mode 
1050       break;
1051     case 0x1101:
1052       imFuji.SequenceNumber = get2();
1053       break;
1054     case 0x1103:
1055       imgdata.shootinginfo.DriveMode = get2();
1056       imFuji.DriveMode = imgdata.shootinginfo.DriveMode & 0xff;
1057       break;
1058     case 0x1105:
1059       imFuji.SeriesLength = get2();
1060       break;
1061     case 0x1106:
1062       imFuji.PixelShiftOffset[0] = getreal(type);
1063       imFuji.PixelShiftOffset[1] = getreal(type);
1064       break;
1065     case 0x1301:
1066       imFuji.FocusWarning = get2();
1067       break;
1068     case 0x1400:
1069       imFuji.DynamicRange = get2();
1070       break;
1071     case 0x1401:
1072       imFuji.FilmMode = get2();
1073       break;
1074     case 0x1402:
1075       imFuji.DynamicRangeSetting = get2();
1076       break;
1077     case 0x1403:
1078       imFuji.DevelopmentDynamicRange = get2();
1079       break;
1080     case 0x1404:
1081       ilm.MinFocal = getreal(type);
1082       break;
1083     case 0x1405:
1084       ilm.MaxFocal = getreal(type);
1085       break;
1086     case 0x1406:
1087       ilm.MaxAp4MinFocal = getreal(type);
1088       break;
1089     case 0x1407:
1090       ilm.MaxAp4MaxFocal = getreal(type);
1091       break;
1092     case 0x140b:
1093       imFuji.AutoDynamicRange = get2();
1094       break;
1095     case 0x1422:
1096       imFuji.ImageStabilization[0] = get2();
1097       imFuji.ImageStabilization[1] = get2();
1098       imFuji.ImageStabilization[2] = get2();
1099       imgdata.shootinginfo.ImageStabilization =
1100           (imFuji.ImageStabilization[0] << 9) + imFuji.ImageStabilization[1];
1101       break;
1102     case 0x1438:
1103       imFuji.ImageCount = get2();
1104       break;
1105     case 0x1431:
1106       imFuji.Rating = get4();
1107       break;
1108     case 0x1443:
1109       imFuji.DRangePriority = get2();
1110       break;
1111     case 0x1444:
1112       imFuji.DRangePriorityAuto = get2();
1113       break;
1114     case 0x1445:
1115       imFuji.DRangePriorityFixed = get2();
1116       break;
1117     }
1118   return;
1119 }
1120 
1121 void LibRaw::parse_fuji_thumbnail(int offset)
1122 {
1123     uchar xmpmarker[] = "http://ns.adobe.com/xap/1.0/";
1124     uchar buf[sizeof(xmpmarker)+1];
1125     int xmpsz = sizeof(xmpmarker); // we do not
1126 
1127     INT64 pos = ftell(ifp);
1128     fseek(ifp, offset, SEEK_SET);
1129     ushort s_order = order;
1130     order = 0x4a4a; // JPEG is always in MM order
1131 
1132     if (get2() == 0xFFD8)
1133     {
1134         while (1)
1135         {
1136           ushort tag = get2();
1137           if (tag != 0xFFE1 && tag != 0xFFE2) // allow APP1/APP2 only
1138             break;
1139           INT64 tpos = ftell(ifp);
1140           int len = get2();
1141           if (len > xmpsz + 2)
1142           {
1143               if ((fread(buf, 1, xmpsz, ifp) == xmpsz) && !memcmp(buf, xmpmarker, xmpsz)) // got it
1144               {
1145                   xmplen = len - xmpsz - 2;
1146                   xmpdata = (char*) malloc(xmplen+1);
1147                   fread(xmpdata, 1, xmplen, ifp);
1148                   xmpdata[xmplen] = 0;
1149                   break;
1150               }
1151           }
1152           fseek(ifp, tpos + len, SEEK_SET);
1153         }
1154     }
1155 
1156     order = s_order;
1157     fseek(ifp, pos, SEEK_SET);
1158 }
1159 
1160 void LibRaw::parse_fuji(int offset)
1161 {
1162   unsigned entries, tag, len, save, c;
1163 
1164 #define get_average_WB(wb_index)                                               \
1165   FORC4 icWBC[wb_index][GRGB_2_RGBG(c)] = get2();                              \
1166   if ((len == 16) && average_WBData) {                                         \
1167     FORC4 icWBC[wb_index][GRGB_2_RGBG(c)] =                                    \
1168              (icWBC[wb_index][GRGB_2_RGBG(c)] + get2())/2;                     \
1169   }                                                                            \
1170   if (use_WBcorr_coeffs) {                                                     \
1171     icWBC[wb_index][0] *= wbR_corr;                                            \
1172     icWBC[wb_index][2] *= wbB_corr;                                            \
1173   }
1174 
1175   ushort raw_inset_present = 0;
1176   ushort use_WBcorr_coeffs = 0;
1177   double wbR_corr = 1.0;
1178   double wbB_corr = 1.0;
1179   ilm.CamID = unique_id;
1180   int average_WBData = 1;
1181 
1182   fseek(ifp, offset, SEEK_SET);
1183   entries = get4();
1184   if (entries > 255)
1185     return;
1186   imgdata.process_warnings |= LIBRAW_WARN_PARSEFUJI_PROCESSED;
1187 
1188   if (strstr(model, "S2Pro")
1189       || strstr(model, "S20Pro")
1190       || strstr(model, "F700")
1191       || strstr(model, "S5000")
1192       || strstr(model, "S7000")
1193       ) {
1194     use_WBcorr_coeffs = 1;
1195     wbR_corr = 10.0 / 17.0 / 0.652941;
1196     wbB_corr = 2.0 /3.0 / (3.0 / 4.0 + 1.0 / 300.0);
1197   } else if (strstr(model, "DBP") || strstr(model, "DX-2000")) {
1198     use_WBcorr_coeffs = 1;
1199     wbR_corr = 0.7632653061;
1200     wbB_corr = 0.8591549296;
1201   }
1202 
1203   while (entries--)
1204   {
1205     tag = get2();
1206     len = get2();
1207     save = ftell(ifp);
1208     if (tag == 0x0100) // RawImageFullSize
1209     {
1210       raw_height = get2();
1211       raw_width = get2();
1212       raw_inset_present = 1;
1213     }
1214     else if ((tag == 0x0110) && raw_inset_present) // RawImageCropTopLeft
1215     {
1216       imgdata.sizes.raw_inset_crops[0].ctop = get2();
1217       imgdata.sizes.raw_inset_crops[0].cleft = get2();
1218     }
1219     else if ((tag == 0x0111) && raw_inset_present) // RawImageCroppedSize
1220     {
1221       imgdata.sizes.raw_inset_crops[0].cheight = get2();
1222       imgdata.sizes.raw_inset_crops[0].cwidth = get2();
1223     }
1224     else if ((tag == 0x0115) && raw_inset_present) // RawImageAspectRatio
1225     {
1226       int a = get2();
1227       int b = get2();
1228       if (a * b == 6)
1229         imgdata.sizes.raw_aspect = LIBRAW_IMAGE_ASPECT_3to2;
1230       else if (a * b == 12)
1231         imgdata.sizes.raw_aspect = LIBRAW_IMAGE_ASPECT_4to3;
1232       else if (a * b == 144)
1233         imgdata.sizes.raw_aspect = LIBRAW_IMAGE_ASPECT_16to9;
1234       else if (a * b == 1)
1235         imgdata.sizes.raw_aspect = LIBRAW_IMAGE_ASPECT_1to1;
1236     }
1237     else if (tag == 0x0121) // RawImageSize
1238     {
1239       height = get2();
1240       if ((width = get2()) == 4284)
1241         width += 3;
1242     }
1243     else if (tag == 0x0130) // FujiLayout,
1244     {
1245       fuji_layout = fgetc(ifp) >> 7;
1246       fuji_width  = !(fgetc(ifp) & 8);
1247     }
1248     else if (tag == 0x0131) // XTransLayout
1249     {
1250       filters = 9;
1251       char *xtrans_abs_alias = &xtrans_abs[0][0];
1252       FORC(36)
1253       {
1254         int q = fgetc(ifp);
1255         xtrans_abs_alias[35 - c] = MAX(0, MIN(q, 2)); /* & 3;*/
1256       }
1257     }
1258     else if (tag == 0x2ff0) // WB_GRGBLevels
1259     {
1260       get_average_WB(LIBRAW_WBI_AsShot);
1261       FORC4 cam_mul[c] = icWBC[LIBRAW_WBI_AsShot][c];
1262     }
1263     else if ((tag == 0x4000) &&
1264              ((len == 8) || (len == 16)))
1265     {
1266       imFuji.BlackLevel[0] = len / 2;
1267       FORC4 imFuji.BlackLevel[GRGB_2_RGBG(c)+1] = get2();
1268       if (imFuji.BlackLevel[0] == 8)
1269         FORC4 imFuji.BlackLevel[GRGB_2_RGBG(c)+5] = get2();
1270       if (imFuji.BlackLevel[0] == 4)
1271         FORC4 cblack[c] = imFuji.BlackLevel[c+1];
1272       else if (imFuji.BlackLevel[0] == 8)
1273         FORC4 cblack[c] = (imFuji.BlackLevel[c+1]+imFuji.BlackLevel[c+5]) /2;
1274     }
1275     else if (tag == 0x9200) // RelativeExposure
1276     {
1277       int s1 = get2();
1278       int s2 = get2();
1279       if ((s1 == s2) || !s1)
1280         imFuji.BrightnessCompensation = 0.0f;
1281       else if ((s1*4) == s2)
1282         imFuji.BrightnessCompensation = 2.0f;
1283       else if ((s1*16) == s2)
1284         imFuji.BrightnessCompensation = 4.0f;
1285       else
1286         imFuji.BrightnessCompensation = log(double(s2)/double(s1))/log(2.0);
1287     }
1288     else if (tag == 0x9650) // RawExposureBias
1289     {
1290       short a = (short)get2();
1291       float b = fMAX(1.0f, get2());
1292       imFuji.ExpoMidPointShift = a / b;
1293       imCommon.ExposureCalibrationShift += imFuji.ExpoMidPointShift;
1294     }
1295     else if (tag == 0x2000) // WB_GRGBLevelsAuto
1296     {
1297       get_average_WB(LIBRAW_WBI_Auto);
1298     }
1299     else if (tag == 0x2100) // WB_GRGBLevelsDaylight
1300     {
1301       get_average_WB(LIBRAW_WBI_FineWeather);
1302     }
1303     else if (tag == 0x2200) // WB_GRGBLevelsCloudy
1304     {
1305       get_average_WB(LIBRAW_WBI_Shade);
1306     }
1307     else if (tag == 0x2300) // WB_GRGBLevelsDaylightFluor
1308     {
1309       get_average_WB(LIBRAW_WBI_FL_D);
1310     }
1311     else if (tag == 0x2301) // WB_GRGBLevelsDayWhiteFluor
1312     {
1313       get_average_WB(LIBRAW_WBI_FL_N);
1314     }
1315     else if (tag == 0x2302) // WB_GRGBLevelsWhiteFluorescent
1316     {
1317       get_average_WB(LIBRAW_WBI_FL_W);
1318     }
1319     else if (tag == 0x2310) // WB_GRGBLevelsWarmWhiteFluor
1320     {
1321       get_average_WB(LIBRAW_WBI_FL_WW);
1322     }
1323     else if (tag == 0x2311) // WB_GRGBLevelsLivingRoomWarmWhiteFluor
1324     {
1325       get_average_WB(LIBRAW_WBI_FL_L);
1326     }
1327     else if (tag == 0x2400) // WB_GRGBLevelsTungsten
1328     {
1329       get_average_WB(LIBRAW_WBI_Tungsten);
1330     }
1331     else if (tag == 0x2410)
1332     {
1333       get_average_WB(LIBRAW_WBI_Flash);
1334     }
1335     else if (tag == 0x2f00) // WB_GRGBLevels
1336     {
1337       int nWBs = get4();
1338       nWBs = MIN(nWBs, 6);
1339       for (int wb_ind = LIBRAW_WBI_Custom1; wb_ind < LIBRAW_WBI_Custom1+nWBs; wb_ind++) {
1340         FORC4 icWBC[wb_ind][GRGB_2_RGBG(c)] = get2();
1341         if ((len >= unsigned(4+16*nWBs)) && average_WBData) {
1342           FORC4 icWBC[wb_ind][GRGB_2_RGBG(c)] =
1343                   (icWBC[wb_ind][GRGB_2_RGBG(c)] +get2()) /2;
1344         }
1345         if (use_WBcorr_coeffs) {
1346           icWBC[LIBRAW_WBI_Custom1 + wb_ind][0] *= wbR_corr;
1347           icWBC[LIBRAW_WBI_Custom1 + wb_ind][2] *= wbB_corr;
1348         }
1349       }
1350     }
1351 
1352     else if (tag == 0xc000) // RAFData
1353     {
1354       int offsetWH_inRAFData;
1355       unsigned save_order = order;
1356       order = 0x4949;
1357       if (len > 20000)
1358       {
1359         uchar RAFDataHeader[16];
1360         libraw_internal_data.unpacker_data.posRAFData = save;
1361         libraw_internal_data.unpacker_data.lenRAFData = (len >> 1);
1362         fread(RAFDataHeader, sizeof RAFDataHeader, 1, ifp);
1363         offsetWH_inRAFData = guess_RAFDataGeneration(RAFDataHeader);
1364         fseek(ifp, offsetWH_inRAFData-int(sizeof RAFDataHeader), SEEK_CUR);
1365         for (int i=0;
1366              i< (int)((sizeof imFuji.RAFData_ImageSizeTable) / (sizeof imFuji.RAFData_ImageSizeTable[0]));
1367              i++) {
1368           imFuji.RAFData_ImageSizeTable[i] = get4();
1369         }
1370 
1371 //         if ((width > raw_width)
1372 //             || (raw_inset_present && (width < imgdata.sizes.raw_inset_crops[0].cwidth))
1373 //         )
1374 //           width = raw_width;
1375 //         if ((height > raw_height)
1376 //             || (raw_inset_present && (height < imgdata.sizes.raw_inset_crops[0].cheight))
1377 //         )
1378 //           height = raw_height;
1379 //
1380 
1381       }
1382       else if (len == 4096) // X-A3, X-A5, X-A7, X-A10, X-A20, X-T100, X-T200, XF10
1383       {                     // Ill.A aligned to CCT 2850
1384         int wb[4];
1385         int nWB, tWB;
1386         int iCCT = 0;
1387         imFuji.RAFDataGeneration = 4096;
1388         fseek(ifp, save + 0x200, SEEK_SET);
1389         for (int wb_ind = 0; wb_ind < 42; wb_ind++)
1390         {
1391           nWB = get4();
1392           tWB = get4();
1393           wb[0] = get4() << 1;
1394           wb[1] = get4();
1395           wb[3] = get4();
1396           wb[2] = get4() << 1;
1397           if (tWB && (iCCT < 255))
1398           {
1399             icWBCCTC[iCCT][0] = tWB;
1400             FORC4 icWBCCTC[iCCT][c + 1] = wb[c];
1401             iCCT++;
1402           }
1403           if (nWB != 70)
1404           {
1405             for (int pWB = 1; pWB < (int)Fuji_wb_list2.size(); pWB += 2)
1406             {
1407               if (Fuji_wb_list2[pWB] == nWB)
1408               {
1409                 FORC4 icWBC[Fuji_wb_list2[pWB - 1]][c] = wb[c];
1410                 break;
1411               }
1412             }
1413           }
1414         }
1415       }
1416       order = save_order;
1417     }
1418     fseek(ifp, save + len, SEEK_SET);
1419   }
1420 
1421   if (!imFuji.RAFDataGeneration) {
1422     height <<= fuji_layout;
1423     width >>= fuji_layout;
1424   }
1425 #undef get_average_WB
1426 }
1427