/* X3F_IO.H - Library for accessing X3F Files.
 * 
 * Copyright (c) 2008 - Roland Karlsson (roland@proxel.se)
 * BSD-style - see readme.txt
 * 
 */

/* NOTE about endianess. We assume that the X3F file is little
   endian. All multi byte (eg uint32) elements are stored in the
   native endian of the machine. Byte streams are stored as found in
   the file, i.e. little endian. Multi byte streams are stored each
   multi byte element in the native endian - but the stream is stored
   little endian. */


#ifndef X3F_IO_H
#define X3F_IO_H

#include <inttypes.h>
#include <stdio.h>

#define SIZE_UNIQUE_IDENTIFIER 16
#define SIZE_WHITE_BALANCE 32
#define NUM_EXT_DATA 32

#define X3F_VERSION(MAJ,MIN) (uint32_t)(((MAJ)<<16) + MIN)
#define X3F_VERSION_2_0 X3F_VERSION(2,0)
#define X3F_VERSION_2_1 X3F_VERSION(2,1)

/* Main file identifier */
#define X3F_FOVb (uint32_t)(0x62564f46)
/* Directory identifier */
#define X3F_SECd (uint32_t)(0x64434553)
/* Property section identifiers */
#define X3F_PROP (uint32_t)(0x504f5250)
#define X3F_SECp (uint32_t)(0x70434553)
/* Image section identifiers */
#define X3F_IMAG (uint32_t)(0x46414d49)
#define X3F_IMA2 (uint32_t)(0x32414d49)
#define X3F_SECi (uint32_t)(0x69434553)
/* CAMF identifiers */
#define X3F_CAMF (uint32_t)(0x464d4143)
#define X3F_SECc (uint32_t)(0x63434553)

#define X3F_IMAGE_RAW_DP1           (uint32_t)(0x0003001e)
#define X3F_IMAGE_RAW_HUFFMAN_10BIT (uint32_t)(0x00030006)
#define X3F_IMAGE_THUMB             (uint32_t)(0x00020003)
#define X3F_IMAGE_THUMB_HUFFMAN     (uint32_t)(0x0002000b)
#define X3F_IMAGE_THUMB_JPEG        (uint32_t)(0x00020012)

#define X3F_IMAGE_HEADER_SIZE 28


typedef uint16_t utf16_t;

typedef enum x3f_extended_types_e {
  X3F_EXT_TYPE_NONE=0,
  X3F_EXT_TYPE_EXPOSURE_ADJUST=1,
  X3F_EXT_TYPE_CONTRAST_ADJUST=2,
  X3F_EXT_TYPE_SHADOW_ADJUST=3,
  X3F_EXT_TYPE_HIGHLIGHT_ADJUST=4,
  X3F_EXT_TYPE_SATURATION_ADJUST=5,
  X3F_EXT_TYPE_SHARPNESS_ADJUST=6,
  X3F_EXT_TYPE_RED_ADJUST=7,
  X3F_EXT_TYPE_GREEN_ADJUST=8,
  X3F_EXT_TYPE_BLUE_ADJUST=9,
  X3F_EXT_TYPE_FILL_LIGHT_ADJUST=10
} x3f_extended_types_t;

typedef struct x3f_property_entry_s {
  utf16_t *name;                /* 0x00 terminated UTF 16 */
  utf16_t *value;               /* 0x00 terminated UTF 16 */
} x3f_property_entry_t;

typedef struct x3f_property_list_s {
  /* 2.0 Fields */
  uint32_t num_properties;
  uint32_t character_format;
  uint32_t reserved;
  uint32_t total_length;

  x3f_property_entry_t *entry;  /* Take from file if NULL */

} x3f_property_list_t;

typedef struct x3f_table8_s {
  uint32_t size;
  uint8_t *element;
} x3f_table8_t;

typedef struct x3f_table16_s {
  uint32_t size;
  uint16_t *element;
} x3f_table16_t;

typedef struct x3f_table32_s {
  uint32_t size;
  uint32_t *element;
} x3f_table32_t;

typedef struct x3f_hufftree_s {
  struct x3f_hufftree_s *branch[2];
  uint32_t leaf;
} x3f_hufftree_t;

typedef struct x3f_huffman_s {
  uint32_t raw_bits;
  x3f_table16_t mapping;   /* Value Mapping = X3F lossy compression */
  x3f_table32_t table;          /* Coding Table */
  uint32_t free_node;           /* Free node index in huffman tree array */
  x3f_hufftree_t *tree;         /* Coding tree */
  x3f_table32_t row_offsets;    /* Row offsets */
  x3f_table8_t rgb8;            /* 3x8 bit RGB data */
  x3f_table16_t rgb16;          /* 3x16 bit RGB data */
  x3f_table16_t x3rgb16;        /* 3x16 bit X3-RGB data */
} x3f_huffman_t;

typedef enum {DATA_EMPTY, DATA_ALL, DATA_HUFFMAN} data_type_t;

typedef struct x3f_image_data_s {
  /* 2.0 Fields */
  /* ------------------------------------------------------------------ */
  /* Known combinations of type and format are:
     2-3, 2-11, 2-18, 3-6 */
  uint32_t type;                /* 2 = thumbnail or maybe just RGB
                                   3 = RAW X3 */
  uint32_t format;              /* 3 = 3x8 bit pixmap
                                   6 = 3x10 bit huffman with map table
                                   11 = 3x8 bit huffman
                                   18 = JPEG */
  uint32_t type_format;         /* type<<16 + format */
  /* ------------------------------------------------------------------ */
  uint32_t columns;             /* width / row size in pixels */
  uint32_t rows;                /* height */
  uint32_t row_stride;          /* row size in bytes */

  x3f_huffman_t *huffman;       /* Huffman help data */

  data_type_t data_type;        /* Type info for data block */
  void *data;                   /* Take from file if NULL. Otherwise,
                                   this is the actual data bytes in
                                   the file. */
} x3f_image_data_t;

typedef struct x3f_camf_s {
  /* TODO - what is this? */
  void *data;
} x3f_camf_t;

typedef struct x3f_directory_entry_header_s {
  uint32_t identifier;        /* Should be ´SECp´, "SECi", ... */
  uint32_t version;           /* 0x00020001 is version 2.1  */
  union {
    x3f_property_list_t property_list;
    x3f_image_data_t image_data;
    x3f_camf_t camf;
  } data_subsection;
} x3f_directory_entry_header_t;

typedef struct x3f_directory_entry_s {
  struct {
    uint32_t offset;
    uint32_t size;
  } input, output;

  uint32_t type;

  x3f_directory_entry_header_t header;
} x3f_directory_entry_t;

typedef struct x3f_directory_section_s {
  uint32_t identifier;          /* Should be ´SECd´ */
  uint32_t version;             /* 0x00020001 is version 2.1  */

  /* 2.0 Fields */
  uint32_t num_directory_entries;
  x3f_directory_entry_t *directory_entry;
} x3f_directory_section_t;

typedef struct x3f_header_s {
  /* 2.0 Fields */
  uint32_t identifier;          /* Should be ´FOVb´ */
  uint32_t version;             /* 0x00020001 means 2.1 */
  uint8_t unique_identifier[SIZE_UNIQUE_IDENTIFIER];
  uint32_t mark_bits;
  uint32_t columns;             /* Columns and rows ... */
  uint32_t rows;                /* ... before rotation */
  uint32_t rotation;            /* 0, 90, 180, 270 */

  /* Added for 2.1 and 2.2 */
  uint8_t white_balance[SIZE_WHITE_BALANCE];
  uint8_t extended_types[NUM_EXT_DATA]; /* x3f_extended_types_t */
  uint32_t extended_data[NUM_EXT_DATA];
} x3f_header_t;

typedef struct x3f_info_s {
  char *error;
  struct {
    FILE *file;                 /* Use if more data is needed */
  } input, output;
} x3f_info_t;

typedef struct x3f_s {
  x3f_info_t info;
  x3f_header_t header;
  x3f_directory_section_t directory_section;
} x3f_t;


extern x3f_t *x3f_new_from_file(FILE *infile);

extern void x3f_print(x3f_t *x3f);

extern void x3f_write_to_file(x3f_t *x3f, FILE *outfile);

extern void x3f_delete(x3f_t *x3f);

extern x3f_directory_entry_t *x3f_get_raw(x3f_t *x3f);

extern x3f_directory_entry_t *x3f_get_thumb(x3f_t *x3f);

extern x3f_directory_entry_t *x3f_get_thumb_huffman(x3f_t *x3f);

extern x3f_directory_entry_t *x3f_get_thumb_jpeg(x3f_t *x3f);

extern x3f_directory_entry_t *x3f_get_camf(x3f_t *x3f);

extern x3f_directory_entry_t *x3f_get_prop(x3f_t *x3f);

extern void x3f_load_data(x3f_t *x3f, x3f_directory_entry_t *DE);

extern void x3f_load_image_block(x3f_t *x3f, x3f_directory_entry_t *DE);

extern void x3f_dump_raw_data(x3f_t *x3f, char *out);

extern void x3f_dump_ppm_data_from_SDX(x3f_t *x3f, char *out, double gamma);

extern void x3f_dump_tiff_data_from_SDX(x3f_t *x3f, char *out, double gamma);

extern void x3f_dump_jpeg(x3f_t *x3f, char *outfilename);


#endif /* X3F_IO_H */
