/* based on parts of Dave Coffin's raw photo decoder
   which is Copyright 1997-2005 by Dave Coffin, dcoffin a cybercom o net
*/
/* 6/22/2008 - add fuji raw using Dave's newer code, also strip down to just
handle the nikon and fuji cases we use, we can always go back to Dave Coffin's
codes for other cameras */
#include <ctype.h>
#include <errno.h>
#include <fcntl.h>
#include <float.h>
#include <limits.h>
#include <math.h>
#include <setjmp.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include "ana_structures.h"
#include <unistd.h>
#include <utime.h>
#include <netinet/in.h>
typedef long long INT64;
typedef unsigned long long UINT64;
#ifndef LONG_BIT
#define LONG_BIT (8 * sizeof (long))
#endif

#define ushort UshORt
typedef unsigned char uchar;
typedef unsigned short ushort;
extern	struct sym_desc sym[];
extern	int	ana_type_size[];
FILE *ifp;
short order;
char *ifname, make[64], model[70], model2[64], *meta_data;
float flash_used, canon_5814;
float iso_speed, shutter, aperture, focal_len;
time_t timestamp;
int  meta_length, nikon_curve_offset;
off_t    strip_offset, data_offset;
off_t    thumb_offset, meta_offset, profile_offset;
unsigned thumb_length, profile_length;
int tiff_data_compression, kodak_data_compression;
int raw_height, raw_width, top_margin, left_margin;
int height, width, fuji_width, colors, tiff_samples;
int black, maximum, clip_max, clip_color=1;
int iheight, iwidth, shrink;
int is_dng, is_canon, is_foveon, use_coeff, use_gamma;
int trim, flip, xmag, ymag;
int zero_after_ff;
int fitsFlag;
ushort *xfits;
unsigned filters, fuji_layout, shot_select=0, multi_out=0, is_raw;
ushort (*image)[4], white[8][8], curve[0x1000];
float bright=1.0, red_scale=1.0, blue_scale=1.0;
int four_color_rgb=0, document_mode=0, quick_interpolate=0;
int verbose=0, use_auto_wb=0, use_camera_wb=0, use_camera_rgb=0;
int fuji_secondary, use_secondary=0;
float cam_mul[4], pre_mul[4], coeff[3][4];
#define camera_red  cam_mul[0]
#define camera_blue cam_mul[2]
int histogram[3][0x2000];
struct decode {
  struct decode *branch[2];
  int leaf;
} first_decode[2048], *second_decode, *free_decode;
#define FORC3 for (c=0; c < 3; c++)
#define FORC4 for (c=0; c < 4; c++)
#define FORCC for (c=0; c < colors; c++)
 /*
   In order to inline this calculation, I make the risky
   assumption that all filter patterns can be described
   by a repeating pattern of eight rows and two columns

   Return values are either 0/1/2/3 = G/M/C/Y or 0/1/2/3 = R/G1/B/G2
 */
#define FC(row,col) \
	(filters >> ((((row) << 1 & 14) + ((col) & 1)) << 1) & 3)

#define BAYER(row,col) \
	image[((row) >> shrink)*iwidth + ((col) >> shrink)][FC(row,col)]

/*
	PowerShot 600	PowerShot A50	PowerShot Pro70	Pro90 & G1
	0xe1e4e1e4:	0x1b4e4b1e:	0x1e4b4e1b:	0xb4b4b4b4:

	  0 1 2 3 4 5	  0 1 2 3 4 5	  0 1 2 3 4 5	  0 1 2 3 4 5
	0 G M G M G M	0 C Y C Y C Y	0 Y C Y C Y C	0 G M G M G M
	1 C Y C Y C Y	1 M G M G M G	1 M G M G M G	1 Y C Y C Y C
	2 M G M G M G	2 Y C Y C Y C	2 C Y C Y C Y
	3 C Y C Y C Y	3 G M G M G M	3 G M G M G M
			4 C Y C Y C Y	4 Y C Y C Y C
	PowerShot A5	5 G M G M G M	5 G M G M G M
	0x1e4e1e4e:	6 Y C Y C Y C	6 C Y C Y C Y
			7 M G M G M G	7 M G M G M G
	  0 1 2 3 4 5
	0 C Y C Y C Y
	1 G M G M G M
	2 C Y C Y C Y
	3 M G M G M G

   All RGB cameras use one of these Bayer grids:

	0x16161616:	0x61616161:	0x49494949:	0x94949494:

	  0 1 2 3 4 5	  0 1 2 3 4 5	  0 1 2 3 4 5	  0 1 2 3 4 5
	0 B G B G B G	0 G R G R G R	0 G B G B G B	0 R G R G R G
	1 G R G R G R	1 B G B G B G	1 R G R G R G	1 G B G B G B
	2 B G B G B G	2 G R G R G R	2 G B G B G B	2 R G R G R G
	3 G R G R G R	3 B G B G B G	3 R G R G R G	3 G B G B G B
 */

#ifndef __GLIBC__
char *memmem (char *haystack, size_t haystacklen,
	      char *needle, size_t needlelen)
{
  char *c;
  for (c = haystack; c <= haystack + haystacklen - needlelen; c++)
    if (!memcmp (c, needle, needlelen))
      return c;
  return NULL;
}
#endif
 /*------------------------------------------------------------------------- */
extern FILE *fopenr_sym(int nsym);
 /*
   getbits(-1) initializes the buffer
   getbits(n) where 0 <= n <= 25 returns an n-bit integer
 */
 /*------------------------------------------------------------------------- */
void merror (void *ptr, char *where)
{
  if (ptr) return;
  fprintf (stderr, "%s: Out of memory in %s\n", ifname, where);
  //longjmp (failure, 1);
}
ushort sget2 (uchar *s)
{
  if (order == 0x4949)		/* "II" means little-endian */
    return s[0] | s[1] << 8;
  else				/* "MM" means big-endian */
    return s[0] << 8 | s[1];
}
 /*------------------------------------------------------------------------- */
ushort get2()
{
  uchar str[2] = { 0xff,0xff };
  fread (str, 1, 2, ifp);
  return sget2(str);
}
 /*------------------------------------------------------------------------- */
int sget4 (uchar *s)
{
  if (order == 0x4949)
    return s[0] | s[1] << 8 | s[2] << 16 | s[3] << 24;
  else
    return s[0] << 24 | s[1] << 16 | s[2] << 8 | s[3];
}
 /*------------------------------------------------------------------------- */
int get4()
{
  uchar str[4] = { 0xff,0xff,0xff,0xff };
  fread (str, 1, 4, ifp);
  return sget4(str);
}
 /*------------------------------------------------------------------------- */
double getrat()
{
  double num = get4();
  return num / get4();
}
 /*------------------------------------------------------------------------- */
void read_shorts (ushort *pixel, int count)
{
  fread (pixel, 2, count, ifp);
  if ((order == 0x4949) == (ntohs(0x1234) == 0x1234))
    swab (pixel, pixel, count*2);
}
 /*------------------------------------------------------------------------- */
float int_to_float (int i)
{
  union { int i; float f; } u;
  u.i = i;
  return u.f;
}
 /*------------------------------------------------------------------------- */
double getreal (int type)
{
  union { char c[8]; double d; } u;
  int i, rev;

  switch (type) {
    case 3: return (unsigned short) get2();
    case 4: return (unsigned int) get4();
    case 5:  u.d = (unsigned int) get4();
      return u.d / (unsigned int) get4();
    case 8: return (signed short) get2();
    case 9: return (signed int) get4();
    case 10: u.d = (signed int) get4();
      return u.d / (signed int) get4();
    case 11: return int_to_float (get4());
    case 12:
      rev = 7 * ((order == 0x4949) == (ntohs(0x1234) == 0x1234));
      for (i=0; i < 8; i++)
	u.c[i ^ rev] = fgetc(ifp);
      return u.d;
    default: return fgetc(ifp);
  }
}
 /*------------------------------------------------------------------------- */
unsigned getbits (int nbits)
{
  static unsigned long bitbuf=0;
  static int vbits=0;
  unsigned c, ret;

  if (nbits == 0) return 0;
  if (nbits == -2)
    return ftell(ifp) + (-vbits >> 3);
  if (nbits == -1)
    ret = bitbuf = vbits = 0;
  else {
    ret = bitbuf << (LONG_BIT - vbits) >> (LONG_BIT - nbits);
    vbits -= nbits;
  }
  while (vbits < LONG_BIT - 7) {
    c = fgetc(ifp);
    bitbuf = (bitbuf << 8) + c;
    if (c == 0xff && zero_after_ff)
      fgetc(ifp);
    vbits += 8;
  }
  return ret;
}
 /*------------------------------------------------------------------------- */
void parse_makernote()
{
  static const uchar xlat[2][256] = {
  { 0xc1,0xbf,0x6d,0x0d,0x59,0xc5,0x13,0x9d,0x83,0x61,0x6b,0x4f,0xc7,0x7f,0x3d,0x3d,
    0x53,0x59,0xe3,0xc7,0xe9,0x2f,0x95,0xa7,0x95,0x1f,0xdf,0x7f,0x2b,0x29,0xc7,0x0d,
    0xdf,0x07,0xef,0x71,0x89,0x3d,0x13,0x3d,0x3b,0x13,0xfb,0x0d,0x89,0xc1,0x65,0x1f,
    0xb3,0x0d,0x6b,0x29,0xe3,0xfb,0xef,0xa3,0x6b,0x47,0x7f,0x95,0x35,0xa7,0x47,0x4f,
    0xc7,0xf1,0x59,0x95,0x35,0x11,0x29,0x61,0xf1,0x3d,0xb3,0x2b,0x0d,0x43,0x89,0xc1,
    0x9d,0x9d,0x89,0x65,0xf1,0xe9,0xdf,0xbf,0x3d,0x7f,0x53,0x97,0xe5,0xe9,0x95,0x17,
    0x1d,0x3d,0x8b,0xfb,0xc7,0xe3,0x67,0xa7,0x07,0xf1,0x71,0xa7,0x53,0xb5,0x29,0x89,
    0xe5,0x2b,0xa7,0x17,0x29,0xe9,0x4f,0xc5,0x65,0x6d,0x6b,0xef,0x0d,0x89,0x49,0x2f,
    0xb3,0x43,0x53,0x65,0x1d,0x49,0xa3,0x13,0x89,0x59,0xef,0x6b,0xef,0x65,0x1d,0x0b,
    0x59,0x13,0xe3,0x4f,0x9d,0xb3,0x29,0x43,0x2b,0x07,0x1d,0x95,0x59,0x59,0x47,0xfb,
    0xe5,0xe9,0x61,0x47,0x2f,0x35,0x7f,0x17,0x7f,0xef,0x7f,0x95,0x95,0x71,0xd3,0xa3,
    0x0b,0x71,0xa3,0xad,0x0b,0x3b,0xb5,0xfb,0xa3,0xbf,0x4f,0x83,0x1d,0xad,0xe9,0x2f,
    0x71,0x65,0xa3,0xe5,0x07,0x35,0x3d,0x0d,0xb5,0xe9,0xe5,0x47,0x3b,0x9d,0xef,0x35,
    0xa3,0xbf,0xb3,0xdf,0x53,0xd3,0x97,0x53,0x49,0x71,0x07,0x35,0x61,0x71,0x2f,0x43,
    0x2f,0x11,0xdf,0x17,0x97,0xfb,0x95,0x3b,0x7f,0x6b,0xd3,0x25,0xbf,0xad,0xc7,0xc5,
    0xc5,0xb5,0x8b,0xef,0x2f,0xd3,0x07,0x6b,0x25,0x49,0x95,0x25,0x49,0x6d,0x71,0xc7 },
  { 0xa7,0xbc,0xc9,0xad,0x91,0xdf,0x85,0xe5,0xd4,0x78,0xd5,0x17,0x46,0x7c,0x29,0x4c,
    0x4d,0x03,0xe9,0x25,0x68,0x11,0x86,0xb3,0xbd,0xf7,0x6f,0x61,0x22,0xa2,0x26,0x34,
    0x2a,0xbe,0x1e,0x46,0x14,0x68,0x9d,0x44,0x18,0xc2,0x40,0xf4,0x7e,0x5f,0x1b,0xad,
    0x0b,0x94,0xb6,0x67,0xb4,0x0b,0xe1,0xea,0x95,0x9c,0x66,0xdc,0xe7,0x5d,0x6c,0x05,
    0xda,0xd5,0xdf,0x7a,0xef,0xf6,0xdb,0x1f,0x82,0x4c,0xc0,0x68,0x47,0xa1,0xbd,0xee,
    0x39,0x50,0x56,0x4a,0xdd,0xdf,0xa5,0xf8,0xc6,0xda,0xca,0x90,0xca,0x01,0x42,0x9d,
    0x8b,0x0c,0x73,0x43,0x75,0x05,0x94,0xde,0x24,0xb3,0x80,0x34,0xe5,0x2c,0xdc,0x9b,
    0x3f,0xca,0x33,0x45,0xd0,0xdb,0x5f,0xf5,0x52,0xc3,0x21,0xda,0xe2,0x22,0x72,0x6b,
    0x3e,0xd0,0x5b,0xa8,0x87,0x8c,0x06,0x5d,0x0f,0xdd,0x09,0x19,0x93,0xd0,0xb9,0xfc,
    0x8b,0x0f,0x84,0x60,0x33,0x1c,0x9b,0x45,0xf1,0xf0,0xa3,0x94,0x3a,0x12,0x77,0x33,
    0x4d,0x44,0x78,0x28,0x3c,0x9e,0xfd,0x65,0x57,0x16,0x94,0x6b,0xfb,0x59,0xd0,0xc8,
    0x22,0x36,0xdb,0xd2,0x63,0x98,0x43,0xa1,0x04,0x87,0x86,0xf7,0xa6,0x26,0xbb,0xd6,
    0x59,0x4d,0xbf,0x6a,0x2e,0xaa,0x2b,0xef,0xe6,0x78,0xb6,0x4e,0xe0,0x2f,0xdc,0x7c,
    0xbe,0x57,0x19,0x32,0x7e,0x2a,0xd0,0xb8,0xba,0x29,0x00,0x3c,0x52,0x7d,0xa8,0x49,
    0x3b,0x2d,0xeb,0x25,0x49,0xfa,0xa3,0xaa,0x39,0xa7,0xc5,0xa7,0x50,0x11,0x36,0xfb,
    0xc6,0x67,0x4a,0xf5,0xa5,0x12,0x65,0x7e,0xb0,0xdf,0xaf,0x4e,0xb3,0x61,0x7f,0x2f } };
  unsigned base=0, offset=0, entries, tag, type, len, save, c;
  unsigned ver97=0, serial=0, i;
  uchar buf97[324], ci, cj, ck;
  static const int size[] = { 1,1,1,2,4,8,1,1,2,4,8,4,8 };
  short sorder;
  char buf[10];
/*
   The MakerNote might have its own TIFF header (possibly with
   its own byte-order!), or it might just be a table.
 */
  sorder = order;
  fread (buf, 1, 10, ifp);
  if (!strncmp (buf,"KC" ,2) ||		/* these aren't TIFF format */
      !strncmp (buf,"MLY",3)) return;
  if (!strcmp (buf,"Nikon")) {
    base = ftell(ifp);
    order = get2();
    if (get2() != 42) goto quit;
    offset = get4();
    fseek (ifp, offset-8, SEEK_CUR);
  } else if (!strncmp (buf,"FUJIFILM",8) ||
	     !strcmp  (buf,"Panasonic")) {
    order = 0x4949;
    fseek (ifp,  2, SEEK_CUR);
  } else if (!strcmp (buf,"OLYMP") ||
	     !strcmp (buf,"LEICA") ||
	     !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);

  entries = get2();
  while (entries--) {
    tag  = get2();
    type = get2();
    len  = get4();
    save = ftell(ifp);
    if (len * size[type < 13 ? type:0] > 4)
      fseek (ifp, get4()+base, SEEK_SET);

    if (tag == 0xc && len == 4) {
      camera_red  = getrat();
      camera_blue = getrat();
    }
    if (tag == 0x14 && len == 2560 && type == 7) {
      fseek (ifp, 1248, SEEK_CUR);
      goto get2_256;
    }
    if (strstr(make,"PENTAX")) {
      if (tag == 0x1b) tag = 0x1018;
      if (tag == 0x1c) tag = 0x1017;
    }
    if (tag == 0x1d)
      while ((c = fgetc(ifp)))
	serial = serial*10 + (isdigit(c) ? c - '0' : c % 10);
    if (tag == 0x8c)
      nikon_curve_offset = ftell(ifp) + 2112;
    if (tag == 0x96)
      nikon_curve_offset = ftell(ifp) + 2;
    if (tag == 0x97) {
      for (i=0; i < 4; i++)
	ver97 = (ver97 << 4) + fgetc(ifp)-'0';
      switch (ver97) {
	case 0x100:
	  fseek (ifp, 68, SEEK_CUR);
	  FORC4 cam_mul[(c >> 1) | ((c & 1) << 1)] = get2();
	  break;
	case 0x102:
	  fseek (ifp, 6, SEEK_CUR);
	  goto get2_rggb;
	case 0x103:
	  fseek (ifp, 16, SEEK_CUR);
	  FORC4 cam_mul[c] = get2();
      }
      if (ver97 >> 8 == 2) {
	if (ver97 != 0x205) fseek (ifp, 280, SEEK_CUR);
	fread (buf97, 324, 1, ifp);
      }
    }
    if (tag == 0xa7 && ver97 >> 8 == 2) {
      ci = xlat[0][serial & 0xff];
      cj = xlat[1][fgetc(ifp)^fgetc(ifp)^fgetc(ifp)^fgetc(ifp)];
      ck = 0x60;
      for (i=0; i < 324; i++)
	buf97[i] ^= (cj += ci * ck++);
      FORC4 cam_mul[c ^ (c >> 1)] =
	sget2 (buf97 + (ver97 == 0x205 ? 14:6) + c*2);
    }
    if (tag == 0xe0 && len == 17) {
      get2();
      raw_width  = get2();
      raw_height = get2();
    }
    if (tag == 0x200 && len == 4)
      black = (get2()+get2()+get2()+get2())/4;
    if (tag == 0x201 && len == 4)
      goto get2_rggb;
    if (tag == 0x401 && len == 4) {
      black = (get4()+get4()+get4()+get4())/4;
    }
    if (tag == 0xe80 && len == 256 && type == 7) {
      fseek (ifp, 48, SEEK_CUR);
      camera_red  = get2() * 508 * 1.078 / 0x10000;
      camera_blue = get2() * 382 * 1.173 / 0x10000;
    }
    if (tag == 0xf00 && len == 614 && type == 7) {
      fseek (ifp, 188, SEEK_CUR);
      goto get2_256;
    }
    if (tag == 0x1017)
      camera_red  = get2() / 256.0;
    if (tag == 0x1018)
      camera_blue = get2() / 256.0;
    if (tag == 0x2011 && len == 2) {
get2_256:
      order = 0x4d4d;
      camera_red  = get2() / 256.0;
      camera_blue = get2() / 256.0;
    }
    if (tag == 0x4001) {
      fseek (ifp, strstr(model,"EOS-1D") ? 68:50, SEEK_CUR);
get2_rggb:
      FORC4 cam_mul[c ^ (c >> 1)] = get2();
    }
    fseek (ifp, save+4, SEEK_SET);
  }
quit:
  order = sorder;
}
 /*------------------------------------------------------------------------- */
int ljpeg_diff (struct decode *dindex)
{
  int len, diff;

  while (dindex->branch[0])
    dindex = dindex->branch[getbits(1)];
  diff = getbits (len = dindex->leaf);
  if ((diff & (1 << (len-1))) == 0)
    diff -= (1 << len) - 1;
  return diff;
}
/*------------------------------------------------------------------------- */
/*
   Since the TIFF DateTime string has no timezone information,
   assume that the camera's clock was set to Universal Time.
 */
void get_timestamp (int reversed)
{
  struct tm t;
  time_t ts;
  char str[20];
  int i;

  str[19] = 0;
  if (reversed)
    for (i=19; i--; ) str[i] = fgetc(ifp);
  else
    fread (str, 19, 1, ifp);
  if (sscanf (str, "%d:%d:%d %d:%d:%d", &t.tm_year, &t.tm_mon,
	&t.tm_mday, &t.tm_hour, &t.tm_min, &t.tm_sec) != 6)
    return;
  t.tm_year -= 1900;
  t.tm_mon -= 1;
  putenv ("TZ=UTC");		/* Remove this to assume local time */
  if ((ts = mktime(&t)) > 0)
    timestamp = ts;
}

/*------------------------------------------------------------------------- */
void init_decoder ()
{
  memset (first_decode, 0, sizeof first_decode);
  free_decode = first_decode;
}
/*------------------------------------------------------------------------- */

/*
   Construct a decode tree according the specification in *source.
   The first 16 bytes specify how many codes should be 1-bit, 2-bit
   3-bit, etc.  Bytes after that are the leaf values.

   For example, if the source is

    { 0,1,4,2,3,1,2,0,0,0,0,0,0,0,0,0,
      0x04,0x03,0x05,0x06,0x02,0x07,0x01,0x08,0x09,0x00,0x0a,0x0b,0xff  },

   then the code is

	00		0x04
	010		0x03
	011		0x05
	100		0x06
	101		0x02
	1100		0x07
	1101		0x01
	11100		0x08
	11101		0x09
	11110		0x00
	111110		0x0a
	1111110		0x0b
	1111111		0xff
 */
/*------------------------------------------------------------------------- */
uchar * make_decoder (const uchar *source, int level)
{
  struct decode *cur;
  static int leaf;
  int i, next;

  if (level==0) leaf=0;
  cur = free_decode++;
//   if (free_decode 
//   > first_decode+2048) {
//     fprintf (stderr, "%s: decoder table overflow\n", ifname);
//     longjmp (failure, 2);
//   }
  for (i=next=0; i <= leaf && next < 16; )
    i += source[next++];
  if (i > leaf) {
    if (level < next) {
      cur->branch[0] = free_decode;
      make_decoder (source, level+1);
      cur->branch[1] = free_decode;
      make_decoder (source, level+1);
    } else
      cur->leaf = source[16 + leaf++];
  }
  return (uchar *) source + 16 + leaf;
}
 /*------------------------------------------------------------------------- */
/*
   Figure out if a NEF file is compressed.  These fancy heuristics
   are only needed for the D100, thanks to a bug in some cameras
   that tags all images as "compressed".
 */
int nikon_is_compressed()
{
  uchar test[256];
  int i;

  if (tiff_data_compression != 34713)
    return 0;
  if (strcmp(model,"D100"))
    return 1;
  fseek (ifp, data_offset, SEEK_SET);
  fread (test, 1, 256, ifp);
  for (i=15; i < 256; i+=16)
    if (test[i]) return 1;
  return 0;
}
 /*------------------------------------------------------------------------- */
void  parse_mos (int offset)
{
  uchar data[40];
  int skip, from, i, neut[4];
  static const unsigned bayer[] =
	{ 0x94949494, 0x61616161, 0x16161616, 0x49494949 };

  fseek (ifp, offset, SEEK_SET);
  while (1) {
    fread (data, 1, 8, ifp);
    if (strcmp(data,"PKTS")) break;
    fread (data, 1, 40, ifp);
    skip = get4();
    from = ftell(ifp);
#ifdef USE_LCMS
    if (!strcmp(data,"icc_camera_profile")) {
      profile_length = skip;
      profile_offset = from;
    }
#endif
    if (!strcmp(data,"CaptProf_number_of_planes")) {
      fscanf (ifp, "%d", &i);
      if (i > 1) filters = 0;
    }
    if (!strcmp(data,"CaptProf_raw_data_rotation") && filters) {
      fscanf (ifp, "%d", &i);
      filters = bayer[i/90];
    }
    if (!strcmp(data,"NeutObj_neutrals")) {
      for (i=0; i < 4; i++)
	fscanf (ifp, "%d", neut+i);
      camera_red  = (float) neut[2] / neut[1];
      camera_blue = (float) neut[2] / neut[3];
    }
    parse_mos (from);
    fseek (ifp, skip+from, SEEK_SET);
  }
}
 /*------------------------------------------------------------------------- */
void  parse_exif (int base)
{
  int entries, tag, type, len, val, save;

  entries = get2();
  while (entries--) {
    tag  = get2();
    type = get2();
    len  = get4();
    val  = get4();
    save = ftell(ifp);

    fseek (ifp, base+val, SEEK_SET);
    if (tag == 0x9003 || tag == 0x9004)
      get_timestamp(0);
    if (tag == 0x927c) {
      if (!strncmp(make,"SONY",4))
	data_offset = base+val+len;
      else
	parse_makernote();
    }
    fseek (ifp, save, SEEK_SET);
  }
}
 /*------------------------------------------------------------------------- */
void  pseudoinverse (const double (*in)[3], double (*out)[3], int size)
{
  double work[3][6], num;
  int i, j, k;

  for (i=0; i < 3; i++) {
    for (j=0; j < 6; j++)
      work[i][j] = j == i+3;
    for (j=0; j < 3; j++)
      for (k=0; k < size; k++)
	work[i][j] += in[k][i] * in[k][j];
  }
  for (i=0; i < 3; i++) {
    num = work[i][i];
    for (j=0; j < 6; j++)
      work[i][j] /= num;
    for (k=0; k < 3; k++) {
      if (k==i) continue;
      num = work[k][i];
      for (j=0; j < 6; j++)
	work[k][j] -= work[i][j] * num;
    }
  }
  for (i=0; i < size; i++)
    for (j=0; j < 3; j++)
      for (out[i][j]=k=0; k < 3; k++)
	out[i][j] += work[j][k+3] * in[i][k];
}
 /*------------------------------------------------------------------------- */
void cam_xyz_coeff (double cam_xyz[4][3])
{
  static const double xyz_rgb[3][3] = {		/* XYZ from RGB */
	{ 0.412453, 0.357580, 0.180423 },
	{ 0.212671, 0.715160, 0.072169 },
	{ 0.019334, 0.119193, 0.950227 } };
  double cam_rgb[4][3], inverse[4][3], num;
  int i, j, k;

  for (i=0; i < colors; i++)		/* Multiply out XYZ colorspace */
    for (j=0; j < 3; j++)
      for (cam_rgb[i][j] = k=0; k < 3; k++)
	cam_rgb[i][j] += cam_xyz[i][k] * xyz_rgb[k][j];

  for (i=0; i < colors; i++) {		/* Normalize cam_rgb so that */
    for (num=j=0; j < 3; j++)		/* cam_rgb * (1,1,1) is (1,1,1,1) */
      num += cam_rgb[i][j];
    for (j=0; j < 3; j++)
      cam_rgb[i][j] /= num;
    pre_mul[i] = 1 / num;
  }
  pseudoinverse ((const double (*)[3]) cam_rgb, inverse, colors);
  for (i=0; i < 3; i++)
    for (j=0; j < colors; j++)
      coeff[i][j] = inverse[j][i];
  use_coeff = 1;
}
 /*------------------------------------------------------------------------- */
int parse_tiff_ifd (int base, int level)
{
  unsigned entries, tag, type, len, plen=16, save;
  int done=0, use_cm=0, cfa, i, j, c;
  static const int size[] = { 1,1,1,2,4,8,1,1,2,4,8,4,8 };
  char software[64];
  static const int flip_map[] = { 0,1,3,2,4,6,7,5 };
  uchar cfa_pat[16], cfa_pc[] = { 0,1,2,3 }, tab[256];
  ushort scale[4];
  double dblack, cc[4][4], cm[4][3], cam_xyz[4][3];
  double ab[]={ 1,1,1,1 }, asn[] = { 0,0,0,0 }, xyz[] = { 1,1,1 };

  for (j=0; j < 4; j++)
    for (i=0; i < 4; i++)
      cc[j][i] = i == j;
  entries = get2();
  if (entries > 512) return 1;
  while (entries--) {
    tag  = get2();
    type = get2();
    len  = get4();
    save = ftell(ifp);
    if (tag > 50700 && tag < 50800) done = 1;
    if (len * size[type < 13 ? type:0] > 4)
      fseek (ifp, get4()+base, SEEK_SET);
    //printf("tag = %d, %#x, len = %d\n", tag, tag, len);
    switch (tag) {
      case 0x11:
	camera_red  = get4() / 256.0;
	break;
      case 0x12:
	camera_blue = get4() / 256.0;
	break;
      case 0x100:			/* ImageWidth */
	if (strcmp(make,"Canon") || level)
	  raw_width = type==3 ? get2() : get4();
	break;
      case 0x101:			/* ImageHeight */
	if (strcmp(make,"Canon") || level)
	  raw_height = type==3 ? get2() : get4();
	break;
      case 0x102:			/* Bits per sample */
	fuji_secondary = len == 2;
	if (level) maximum = (1 << get2()) - 1;
	break;
      case 0x103:			/* Compression */
	tiff_data_compression = get2();
	break;
      case 0x106:			/* Kodak color format */
	kodak_data_compression = get2();
	break;
      case 0x10f:			/* Make */
	fgets (make, 64, ifp);
	break;
      case 0x110:			/* Model */
	fgets (model, 64, ifp);
	break;
      case 0x111:			/* StripOffset */
	data_offset = get4();
	break;
      case 0x112:			/* Orientation */
	flip = flip_map[(get2()-1) & 7];
	break;
      case 0x115:			/* SamplesPerPixel */
	tiff_samples = get2();
	break;
      case 0x131:			/* Software tag */
	fgets (software, 64, ifp);
	if (!strncmp(software,"Adobe",5))
	  make[0] = 0;
	break;
      case 0x132:			/* DateTime tag */
	get_timestamp(0);
	break;
      case 0x144:			/* TileOffsets */
	if (level) {
	  data_offset = ftell(ifp);
	} else {
	  strcpy (make, "Leaf");
	  data_offset = get4();
	}
	break;
      case 0x14a:			/* SubIFD tag */
	if (len > 2 && !is_dng && !strcmp(make,"Kodak"))
	    len = 2;
	while (len--) {
	  i = ftell(ifp);
	  fseek (ifp, get4()+base, SEEK_SET);
	  if (parse_tiff_ifd (base, level+1)) break;
	  fseek (ifp, i+4, SEEK_SET);
	}
	break;
      case 33405:			/* Model2 */
	fgets (model2, 64, ifp);
	break;
      case 33422:			/* CFAPattern */
	if ((plen=len) > 16) plen = 16;
	fread (cfa_pat, 1, plen, ifp);
	for (colors=cfa=i=0; i < plen; i++) {
	  colors += !(cfa & (1 << cfa_pat[i]));
	  cfa |= 1 << cfa_pat[i];
	}
	if (cfa == 070) memcpy (cfa_pc,"\003\004\005",3);	/* CMY */
	if (cfa == 072) memcpy (cfa_pc,"\005\003\004\001",4);	/* GMCY */
	goto guess_cfa_pc;
      case 33434:			/* ExposureTime */
	shutter = getreal(type);
	break;
      case 34665:			/* EXIF tag */
	fseek (ifp, get4()+base, SEEK_SET);
	parse_exif (base);
	break;
      case 46275:
	strcpy (make, "Imacon");
	data_offset = ftell(ifp);
	raw_width = 4090;
	raw_height = len / raw_width / 2;
	done = 1;
	break;
      case 50706:			/* DNGVersion */
	is_dng = 1;
	break;
      case 50710:			/* CFAPlaneColor */
	if (len > 4) len = 4;
	colors = len;
	fread (cfa_pc, 1, colors, ifp);
guess_cfa_pc:
	FORCC tab[cfa_pc[c]] = c;
	for (i=16; i--; )
	  filters = filters << 2 | tab[cfa_pat[i % plen]];
	break;
      case 50711:			/* CFALayout */
	if (get2() == 2) {
	  fuji_width = 1;
	  filters = 0x49494949;
	}
      case 0x123:
      case 0x90d:
      case 50712:			/* LinearizationTable */
	if (len > 0x1000)
	    len = 0x1000;
	read_shorts (curve, len);
	for (i=len; i < 0x1000; i++)
	  maximum = curve[i] = curve[i-1];
	break;
      case 50714:			/* BlackLevel */
      case 50715:			/* BlackLevelDeltaH */
      case 50716:			/* BlackLevelDeltaV */
	for (dblack=i=0; i < len; i++)
	  dblack += getrat();
	black += dblack/len + 0.5;
	break;
      case 50717:			/* WhiteLevel */
	maximum = get2();
	break;
      case 50718:			/* DefaultScale */
	for (i=0; i < 4; i++)
	  scale[i] = get4();
	if (scale[1]*scale[2] == 2*scale[0]*scale[3]) ymag = 2;
	break;
      case 50721:			/* ColorMatrix1 */
      case 50722:			/* ColorMatrix2 */
	FORCC for (j=0; j < 3; j++)
	  cm[c][j] = getrat();
	use_cm = 1;
	break;
      case 50723:			/* CameraCalibration1 */
      case 50724:			/* CameraCalibration2 */
	for (i=0; i < colors; i++)
	  FORCC cc[i][c] = getrat();
      case 50727:			/* AnalogBalance */
	FORCC ab[c] = getrat();
	break;
      case 50728:			/* AsShotNeutral */
	FORCC asn[c] = getrat();
	break;
      case 50729:			/* AsShotWhiteXY */
	xyz[0] = getrat();
	xyz[1] = getrat();
	xyz[2] = 1 - xyz[0] - xyz[1];
    }
    fseek (ifp, save+4, SEEK_SET);
  }
  for (i=0; i < colors; i++)
    FORCC cc[i][c] *= ab[i];
  if (use_cm) {
    FORCC for (i=0; i < 3; i++)
      for (cam_xyz[c][i]=j=0; j < colors; j++)
	cam_xyz[c][i] += cc[c][j] * cm[j][i] * xyz[i];
    cam_xyz_coeff (cam_xyz);
  }
  if (asn[0])
    FORCC pre_mul[c] = 1 / asn[c];
  if (!use_cm)
    FORCC pre_mul[c] /= cc[c][c];
  return done;
}
 /*------------------------------------------------------------------------- */
void  parse_tiff (int base)
{
  int doff;

  fseek (ifp, base, SEEK_SET);
  order = get2();
  if (order != 0x4949 && order != 0x4d4d) return;
  get2();
  while ((doff = get4())) {
    fseek (ifp, doff+base, SEEK_SET);
    if (parse_tiff_ifd (base, 0)) break;
  }
  if (!is_dng && !strncmp(make,"Kodak",5)) {
    printf("do we get here?\n");
    fseek (ifp, 12+base, SEEK_SET);
    parse_tiff_ifd (base, 2);
  }
  fuji_width *= (raw_width+1)/2;
}
 /*------------------------------------------------------------------------- */
void parse_fuji (int offset)
{
  unsigned entries, tag, len, save, c;

  fseek (ifp, offset, SEEK_SET);
  entries = get4();
  if (entries > 255) return;
  while (entries--) {
    tag = get2();
    len = get2();
    save = ftell(ifp);
    if (tag == 0x100) {
      raw_height = get2();
      raw_width  = get2();
    } else if (tag == 0x121) {
      height = get2();
      if ((width = get2()) == 4284) width += 3;
    } else if (tag == 0x130)
      fuji_layout = fgetc(ifp) >> 7;
    if (tag == 0x2ff0)
      FORC4 cam_mul[c ^ 1] = get2();
    fseek (ifp, save+len, SEEK_SET);
  }
  height <<= fuji_layout;
  width  >>= fuji_layout;
}
 /*------------------------------------------------------------------------- */
void nikon_compressed_load_raw()
{
  static const uchar nikon_tree[] = {
    0,1,5,1,1,1,1,1,1,2,0,0,0,0,0,0,
    5,4,3,6,2,7,1,0,8,9,11,10,12
  };
  int csize, row, col, i, diff;
  ushort vpred[4], hpred[2], *curve;
  //printf("in nikon_compressed_load_raw\n");

  init_decoder();
  make_decoder (nikon_tree, 0);

  fseek (ifp, nikon_curve_offset, SEEK_SET);
  read_shorts (vpred, 4);
  csize = get2();
  //printf("csize = %d\n", csize);
  curve = calloc (csize, sizeof *curve);
  merror (curve, "nikon_compressed_load_raw()");
  read_shorts (curve, csize);

  fseek (ifp, data_offset, SEEK_SET);
  getbits(-1);
  //printf("left_margin = %d, filters = %#x\n", left_margin, filters);
  //printf("height = %d, raw_width = %d, iwidth = %d\n", height, raw_width, iwidth);

  for (row=0; row < height; row++)
    for (col=0; col < raw_width; col++)
    {
      diff = ljpeg_diff (first_decode);
      if (col < 2) {
	i = 2*(row & 1) + (col & 1);
	vpred[i] += diff;
	hpred[col] = vpred[i];
      } else
	hpred[col & 1] += diff;
      if ((unsigned) (col-left_margin) >= width) continue;
      diff = hpred[col & 1];
      if (diff >= csize) diff = csize-1;
      xfits[row*iwidth + col] = curve[diff];
      //BAYER(row,col-left_margin) = curve[diff];
    }
  free (curve);
}
 /*------------------------------------------------------------------------- */
void fuji_load_raw()
{
  ushort *pixel;
  int wide, row, col, r, c;

  fseek (ifp, (top_margin*raw_width + left_margin) * 2, SEEK_CUR);
  wide = fuji_width << !fuji_layout;
  pixel = (ushort *) calloc (wide, sizeof *pixel);
  merror (pixel, "fuji_load_raw()");
  for (row=0; row < raw_height; row++) {
    read_shorts (pixel, wide);
    fseek (ifp, 2*(raw_width - wide), SEEK_CUR);
    for (col=0; col < wide; col++) {
//       if (fuji_layout) {
// 	r = fuji_width - 1 - col + (row >> 1);
// 	c = col + ((row+1) >> 1);
//       } else {
// 	r = fuji_width - 1 + row - (col >> 1);
// 	c = row + ((col+1) >> 1);
//       }
      xfits[row*iwidth + col] = pixel[col];
      //BAYER(r,c) = pixel[col];
    }
  }
  free (pixel);
}
 /*------------------------------------------------------------------------- */
/*
   Identify which camera created this file, and set global variables
   accordingly.  Return nonzero if the file cannot be decoded.
 */
int identify (int will_decode)
{
  char head[32], *cp;
  unsigned hlen, fsize, i, c, is_jpeg=0;
  static const char *corp[] =
    { "Canon", "NIKON", "EPSON", "Kodak", "OLYMPUS", "PENTAX",
      "MINOLTA", "Minolta", "Konica", "CASIO" };

/*  What format is this file?  Set make[] if we recognize it. */

  raw_height = raw_width = fuji_width = flip = 0;
  height = width = top_margin = left_margin = 0;
  make[0] = model[0] = model2[0] = 0;
  memset (white, 0, sizeof white);
  timestamp = tiff_samples = 0;
  data_offset = meta_length = tiff_data_compression = 0;
  zero_after_ff = is_dng = fuji_secondary = 0;
  black = is_foveon = use_coeff = 0;
  use_gamma = xmag = ymag = 1;
  filters = UINT_MAX;	/* 0 = no filters, UINT_MAX = unknown */
  for (i=0; i < 4; i++) {
    cam_mul[i] = 1 & i;
    pre_mul[i] = 1;
  }
  colors = 3;
  for (i=0; i < 0x1000; i++) curve[i] = i;
  maximum = 0xfff;

  order = get2();
  hlen = get4();
  fseek (ifp, 0, SEEK_SET);
  fread (head, 1, 32, ifp);
  fseek (ifp, 0, SEEK_END);
  fsize = ftell(ifp);
  /* check for Nikon case */
  if (order == 0x4949 || order == 0x4d4d) {
    parse_tiff(0);
      if (!is_dng && !strncmp(make,"NIKON",5) && filters == UINT_MAX)
	{ printf("not a Nikon or a Fuji raw file\n");  return 1; }
    printf("make: %s\nmodel: %s\n", make, model);
    strcpy(make,"NIKON");
    printf("make: %s\nmodel: %s\n", make, model);
    parse_mos(8);
    parse_mos(3472);
  } else if (!memcmp (head,"FUJIFILM",8)) {
    fseek (ifp, 84, SEEK_SET);
    thumb_offset = get4();
    thumb_length = get4();
    fseek (ifp, 92, SEEK_SET);
    parse_fuji (get4());
    if (thumb_offset > 120) {
      fseek (ifp, 120, SEEK_SET);
      is_raw += (i = get4()) && 1;
      if (is_raw == 2 && shot_select)
	parse_fuji (i);
    }
    fseek (ifp, 100, SEEK_SET);
    data_offset = get4();
    parse_tiff (thumb_offset+12);
    printf("make: %s\nmodel: %s\n", make, model);
  } else {
    printf("not a Nikon or a Fuji raw file\n");  return 1;
  }

  cp = make + strlen(make);		/* Remove trailing spaces */
  while (*--cp == ' ') *cp = 0;
  cp = model + strlen(model);
  while (*--cp == ' ') *cp = 0;
  i = strlen(make);			/* Remove make from model */
  if (!strncmp (model, make, i++))
    memmove (model, model+i, 64-i);
  make[63] = model[63] = model2[63] = 0;

  if ((raw_height | raw_width) < 0)
       raw_height = raw_width  = 0;
  if (!height) height = raw_height;
  if (!width)  width  = raw_width;
  if (fuji_width) {
    width = height + fuji_width;
    height = width - 1;
    ymag = 1;
  }

//   printf("raw_height = %d\n", raw_height);
//   printf("raw_width = %d\n", raw_width);
//   printf("height = %d\n", height);
//   printf("width = %d\n", width);

/*  only Nikon and Fuji here */
/* Set parameters based on camera name (for non-DNG files). */

  if (filters == UINT_MAX) filters = 0x94949494;
  if (!strcmp(make,"NIKON")) {
    if ( !nikon_is_compressed() ) { printf("not a compressed NEF file\n"); return 1; }
    if (!strcmp(model,"D70")) maximum = 0xf53;
  } else if (!strcmp(make,"FUJIFILM")) {
    if (!strcmp(model+7,"S2Pro")) {
      strcpy (model+7," S2Pro");
      height = 2144;
      width  = 2880;
      flip = 6;
    } else
      maximum = 0x3e00;
//     printf("fuji_layout = %d\n", fuji_layout);
//     printf("is_raw = %d\n", is_raw);
//     printf("shot_select = %d\n", shot_select);
    if (is_raw == 2 && shot_select)
      maximum = 0x2f00;
    top_margin = (raw_height - height)/2;
    left_margin = (raw_width - width )/2;
//    printf("top_margin = %d\n", top_margin);
//    printf("left_margin = %d\n", left_margin);
    
    if (is_raw == 2)
      data_offset += (shot_select > 0) * ( fuji_layout ?
		(raw_width *= 2) : raw_height*raw_width*2 );
    fuji_width = width >> !fuji_layout;
    width = (height >> fuji_layout) + fuji_width;
    raw_height = height;
    height = width - 1;
    if (!(fuji_width & 1)) filters = 0x49494949;
  }
//   printf("raw_height = %d\n", raw_height);
//   printf("raw_width = %d\n", raw_width);
  
  if (!raw_height) raw_height = height;
  if (!raw_width ) raw_width  = width;
  use_coeff = 0;
  fseek (ifp, data_offset, SEEK_SET);
  return 0;
}
 /*------------------------------------------------------------------------- */
int ana_nikonrawread(narg,ps)	/* read Nikon raw files */
 int	narg, ps[];
 {
 int	status, return_stat, fitsFlag, iq;
 int	type, ndim, dim[2];
 struct	ahead	*h;

 /* first arg is the variable to load, second is name of file */
 if ((ifp=fopenr_sym(ps[1])) == NULL) return -1;
 if ((status = identify(1))) { /* a problem */
     goto a_bad_end; }

 //printf("flip = %d\n", flip);
 shrink = 0;
 iheight = raw_height;
 iwidth  = raw_width;
 ndim =2; dim[0] = iwidth; dim[1] = iheight; type = 1;
 fitsFlag = 1;
 //printf("fits image size is: %d\n", iheight*iwidth*2);
 iq = ps[0];
 if ( redef_array(iq, type, ndim, dim) != 1 ) goto a_bad_end;
 h = (struct ahead *) sym[iq].spec.array.ptr;
 xfits = (ushort *) ((char *)h + sizeof(struct ahead));
 
//   printf("top_margin = %d\n", top_margin);
//   printf("left_margin = %d\n", left_margin);
//   printf("raw_height = %d\n", raw_height);
//   printf("raw_width = %d\n", raw_width);
//   printf("height = %d\n", height);
//   printf("width = %d\n", width);
//   printf("fuji_layout = %d\n", fuji_layout);
//   printf("fuji_width = %d\n", fuji_width);
//  printf ("ISO speed: %d\n", (int) iso_speed);
//  printf ("Shutter: %0.3f\n", shutter);
 
 if (!strcmp(make,"NIKON")) nikon_compressed_load_raw();
   else if (!strcmp(make,"FUJIFILM")) fuji_load_raw();
 return_stat = 1;
 //printf("done with Nikon raw\n");

 the_end:
 fclose(ifp);
 return return_stat;

 a_bad_end:
 printf("error reading NIKON or FUJI raw file\n");
 return_stat = -1;
 goto the_end;
 }
 /*------------------------------------------------------------------------- */
