
#include <stdio.h>
#include <stdlib.h>
#include "hel2tif.h"

#define TIFF_SIZE_32768          (512 + 160*120*2)
#define TIFF_SIZE_256            (512 + 160*120 + 1536)
#define TIFF_SIZE_16             (512 + 160*120/2)
#define TIFF_SIZE_2              (512 + 160*120/8)

const resolution_data[16] = {
    0x4b, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
    0x4b, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
};

const unsigned char header_32768[] = {
    0x49, 0x49,                                     /* Intel */
    0x2a, 0x00,                                     /* version */
    0x08, 0x00, 0x00, 0x00,                         /* directory */
    0x11, 0x00,                                     /* tagnum */
    0xfe, 0x00, 0x04, 0x00, 0x01, 0x00, 0x00, 0x00, /* New Subfile Type */
    0x00, 0x00, 0x00, 0x00,                         /* 0 */
    0x00, 0x01, 0x03, 0x00, 0x01, 0x00, 0x00, 0x00, /* Image Width */
    0xa0, 0x00, 0x00, 0x00,                         /* 160 */
    0x01, 0x01, 0x03, 0x00, 0x01, 0x00, 0x00, 0x00, /* Image Length */
    0x78, 0x00, 0x00, 0x00,                         /* 120 */
    0x02, 0x01, 0x03, 0x00, 0x01, 0x00, 0x00, 0x00, /* Bits Per Samples */
    0x10, 0x00, 0x00, 0x00,                         /* 16 (32768 colors) */
    0x03, 0x01, 0x03, 0x00, 0x01, 0x00, 0x00, 0x00, /* Compression */
    0x01, 0x00, 0x00, 0x00,                         /* 1 (not compressed) */
    0x06, 0x01, 0x03, 0x00, 0x01, 0x00, 0x00, 0x00, /* Photometric Inter. */
    0x01, 0x00, 0x00, 0x00,                         /* ??????? */
    0x0a, 0x01, 0x03, 0x00, 0x01, 0x00, 0x00, 0x00, /* File Order */
    0x01, 0x00, 0x00, 0x00,                         /* 1 */
    0x11, 0x01, 0x04, 0x00, 0x01, 0x00, 0x00, 0x00, /* Strip Offsets */
    0x00, 0x02, 0x00, 0x00,                         /* (pointer) */
    0x12, 0x01, 0x03, 0x00, 0x01, 0x00, 0x00, 0x00, /* Orientation */
    0x01, 0x00, 0x00, 0x00,                         /* 1 */
    0x15, 0x01, 0x03, 0x00, 0x01, 0x00, 0x00, 0x00, /* Samples Per Pixel */
    0x01, 0x00, 0x00, 0x00,                         /* 1 */
    0x16, 0x01, 0x03, 0x00, 0x01, 0x00, 0x00, 0x00, /* Rows Per Strip */
    0x78, 0x00, 0x00, 0x00,                         /* 120 */
    0x17, 0x01, 0x04, 0x00, 0x01, 0x00, 0x00, 0x00, /* Strip Byte Counts */
    0x00, 0x96, 0x00, 0x00,                         /* 38400 (160*120*2) */
    0x19, 0x01, 0x03, 0x00, 0x01, 0x00, 0x00, 0x00, /* Max Sample Value */
    0xff, 0x7f, 0x00, 0x00,                         /* 32768 */
    0x1a, 0x01, 0x05, 0x00, 0x01, 0x00, 0x00, 0x00, /* X Resolution */
    0xf0, 0x01, 0x00, 0x00,                         /* (pointer) */
    0x1b, 0x01, 0x05, 0x00, 0x01, 0x00, 0x00, 0x00, /* Y Resolution */
    0xf8, 0x01, 0x00, 0x00,                         /* (pointer) */
    0x1c, 0x01, 0x03, 0x00, 0x01, 0x00, 0x00, 0x00, /* Planar Configuration */
    0x01, 0x00, 0x00, 0x00,                         /* 1 */
    0x28, 0x01, 0x03, 0x00, 0x01, 0x00, 0x00, 0x00, /* Resolution Unit */
    0x02, 0x00, 0x00, 0x00,                         /* 2 (inch) */
    0x00, 0x00, 0x00, 0x00,
};

const unsigned char header_256[] = {
    0x49, 0x49,                                     /* Intel */
    0x2a, 0x00,                                     /* version */
    0x08, 0x00, 0x00, 0x00,                         /* directory */
    0x12, 0x00,                                     /* tagnum */
    0xfe, 0x00, 0x04, 0x00, 0x01, 0x00, 0x00, 0x00, /* New Subfile Type */
    0x00, 0x00, 0x00, 0x00,                         /* 0 */
    0x00, 0x01, 0x03, 0x00, 0x01, 0x00, 0x00, 0x00, /* Image Width */
    0xa0, 0x00, 0x00, 0x00,                         /* 160 */
    0x01, 0x01, 0x03, 0x00, 0x01, 0x00, 0x00, 0x00, /* Image Length */
    0x78, 0x00, 0x00, 0x00,                         /* 120 */
    0x02, 0x01, 0x03, 0x00, 0x01, 0x00, 0x00, 0x00, /* Bits Per Samples */
    0x08, 0x00, 0x00, 0x00,                         /* 8 (256 colors) */
    0x03, 0x01, 0x03, 0x00, 0x01, 0x00, 0x00, 0x00, /* Compression */
    0x01, 0x00, 0x00, 0x00,                         /* 1 (not compressed) */
    0x06, 0x01, 0x03, 0x00, 0x01, 0x00, 0x00, 0x00, /* Photometric Inter. */
    0x03, 0x00, 0x00, 0x00,                         /* 3 (palette) */
    0x0a, 0x01, 0x03, 0x00, 0x01, 0x00, 0x00, 0x00, /* File Order */
    0x01, 0x00, 0x00, 0x00,                         /* 1 */
    0x11, 0x01, 0x04, 0x00, 0x01, 0x00, 0x00, 0x00, /* Strip Offsets */
    0x00, 0x08, 0x00, 0x00,                         /* (pointer) */
    0x12, 0x01, 0x03, 0x00, 0x01, 0x00, 0x00, 0x00, /* Orientation */
    0x01, 0x00, 0x00, 0x00,                         /* 1 */
    0x15, 0x01, 0x03, 0x00, 0x01, 0x00, 0x00, 0x00, /* Samples Per Pixel */
    0x01, 0x00, 0x00, 0x00,                         /* 1 */
    0x16, 0x01, 0x03, 0x00, 0x01, 0x00, 0x00, 0x00, /* Rows Per Strip */
    0x78, 0x00, 0x00, 0x00,                         /* 120 */
    0x17, 0x01, 0x04, 0x00, 0x01, 0x00, 0x00, 0x00, /* Strip Byte Counts */
    0x00, 0x4b, 0x00, 0x00,                         /* 19200 (160*120) */
    0x19, 0x01, 0x03, 0x00, 0x01, 0x00, 0x00, 0x00, /* Max Sample Value */
    0x01, 0x00, 0x00, 0x00,                         /* 1 */
    0x1a, 0x01, 0x05, 0x00, 0x01, 0x00, 0x00, 0x00, /* X Resolution */
    0xf0, 0x01, 0x00, 0x00,                         /* (pointer) */
    0x1b, 0x01, 0x05, 0x00, 0x01, 0x00, 0x00, 0x00, /* Y Resolution */
    0xf8, 0x01, 0x00, 0x00,                         /* (pointer) */
    0x1c, 0x01, 0x03, 0x00, 0x01, 0x00, 0x00, 0x00, /* Planar Configuration */
    0x01, 0x00, 0x00, 0x00,                         /* 1 */
    0x28, 0x01, 0x03, 0x00, 0x01, 0x00, 0x00, 0x00, /* Resolution Unit */
    0x02, 0x00, 0x00, 0x00,                         /* 2 (inch) */
    0x40, 0x01, 0x03, 0x00, 0x00, 0x03, 0x00, 0x00, /* Color Map */
    0x00, 0x02, 0x00, 0x00,                         /* (pointer) */
    0x00, 0x00, 0x00, 0x00,
};

const unsigned char header_16[] = {
    0x49, 0x49,                                     /* Intel */
    0x2a, 0x00,                                     /* version */
    0x08, 0x00, 0x00, 0x00,                         /* directory */
    0x12, 0x00,                                     /* tagnum */
    0xfe, 0x00, 0x04, 0x00, 0x01, 0x00, 0x00, 0x00, /* New Subfile Type */
    0x00, 0x00, 0x00, 0x00,                         /* 0 */
    0x00, 0x01, 0x03, 0x00, 0x01, 0x00, 0x00, 0x00, /* Image Width */
    0xa0, 0x00, 0x00, 0x00,                         /* 160 */
    0x01, 0x01, 0x03, 0x00, 0x01, 0x00, 0x00, 0x00, /* Image Length */
    0x78, 0x00, 0x00, 0x00,                         /* 120 */
    0x02, 0x01, 0x03, 0x00, 0x01, 0x00, 0x00, 0x00, /* Bits Per Samples */
    0x04, 0x00, 0x00, 0x00,                         /* 4 (16 colors) */
    0x03, 0x01, 0x03, 0x00, 0x01, 0x00, 0x00, 0x00, /* Compression */
    0x01, 0x00, 0x00, 0x00,                         /* 1 (not compressed) */
    0x06, 0x01, 0x03, 0x00, 0x01, 0x00, 0x00, 0x00, /* Photometric Inter. */
    0x03, 0x00, 0x00, 0x00,                         /* 3 (palette) */
    0x0a, 0x01, 0x03, 0x00, 0x01, 0x00, 0x00, 0x00, /* File Order */
    0x02, 0x00, 0x00, 0x00,                         /* 2 */
    0x11, 0x01, 0x04, 0x00, 0x01, 0x00, 0x00, 0x00, /* Strip Offsets */
    0x00, 0x02, 0x00, 0x00,                         /* (pointer) */
    0x12, 0x01, 0x03, 0x00, 0x01, 0x00, 0x00, 0x00, /* Orientation */
    0x01, 0x00, 0x00, 0x00,                         /* 1 */
    0x15, 0x01, 0x03, 0x00, 0x01, 0x00, 0x00, 0x00, /* Samples Per Pixel */
    0x01, 0x00, 0x00, 0x00,                         /* 1 */
    0x16, 0x01, 0x03, 0x00, 0x01, 0x00, 0x00, 0x00, /* Rows Per Strip */
    0x78, 0x00, 0x00, 0x00,                         /* 120 */
    0x17, 0x01, 0x04, 0x00, 0x01, 0x00, 0x00, 0x00, /* Strip Byte Counts */
    0x80, 0x25, 0x00, 0x00,                         /* 9600 (160*120/2) */
    0x19, 0x01, 0x03, 0x00, 0x01, 0x00, 0x00, 0x00, /* Max Sample Value */
    0x01, 0x00, 0x00, 0x00,                         /* 1 */
    0x1a, 0x01, 0x05, 0x00, 0x01, 0x00, 0x00, 0x00, /* X Resolution */
    0xf0, 0x01, 0x00, 0x00,                         /* (pointer) */
    0x1b, 0x01, 0x05, 0x00, 0x01, 0x00, 0x00, 0x00, /* Y Resolution */
    0xf8, 0x01, 0x00, 0x00,                         /* (pointer) */
    0x1c, 0x01, 0x03, 0x00, 0x01, 0x00, 0x00, 0x00, /* Planar Configuration */
    0x01, 0x00, 0x00, 0x00,                         /* 1 */
    0x28, 0x01, 0x03, 0x00, 0x01, 0x00, 0x00, 0x00, /* Resolution Unit */
    0x02, 0x00, 0x00, 0x00,                         /* 2 (inch) */
    0x40, 0x01, 0x03, 0x00, 0x30, 0x00, 0x00, 0x00, /* Color Map */
    0x00, 0x01, 0x00, 0x00,                         /* (pointer) */
    0x00, 0x00, 0x00, 0x00,
};

const unsigned char header_2[] = {
    0x49, 0x49,                                     /* Intel */
    0x2a, 0x00,                                     /* version */
    0x08, 0x00, 0x00, 0x00,                         /* directory */
    0x11, 0x00,                                     /* tagnum */
    0xfe, 0x00, 0x04, 0x00, 0x01, 0x00, 0x00, 0x00, /* New Subfile Type */
    0x00, 0x00, 0x00, 0x00,                         /* 0 */
    0x00, 0x01, 0x03, 0x00, 0x01, 0x00, 0x00, 0x00, /* Image Width */
    0xa0, 0x00, 0x00, 0x00,                         /* 160 */
    0x01, 0x01, 0x03, 0x00, 0x01, 0x00, 0x00, 0x00, /* Image Length */
    0x78, 0x00, 0x00, 0x00,                         /* 120 */
    0x02, 0x01, 0x03, 0x00, 0x01, 0x00, 0x00, 0x00, /* Bits Per Samples */
    0x01, 0x00, 0x00, 0x00,                         /* 1 (2 colors) */
    0x03, 0x01, 0x03, 0x00, 0x01, 0x00, 0x00, 0x00, /* Compression */
    0x01, 0x00, 0x00, 0x00,                         /* 1 (not compressed) */
    0x06, 0x01, 0x03, 0x00, 0x01, 0x00, 0x00, 0x00, /* Photometric Inter. */
    0x00, 0x00, 0x00, 0x00,                         /* ????? */
    0x0a, 0x01, 0x03, 0x00, 0x01, 0x00, 0x00, 0x00, /* File Order */
    0x01, 0x00, 0x00, 0x00,                         /* 1 */
    0x11, 0x01, 0x04, 0x00, 0x01, 0x00, 0x00, 0x00, /* Strip Offsets */
    0x00, 0x02, 0x00, 0x00,                         /* (pointer) */
    0x12, 0x01, 0x03, 0x00, 0x01, 0x00, 0x00, 0x00, /* Orientation */
    0x01, 0x00, 0x00, 0x00,                         /* 1 */
    0x15, 0x01, 0x03, 0x00, 0x01, 0x00, 0x00, 0x00, /* Samples Per Pixel */
    0x01, 0x00, 0x00, 0x00,                         /* 1 */
    0x16, 0x01, 0x03, 0x00, 0x01, 0x00, 0x00, 0x00, /* Rows Per Strip */
    0x78, 0x00, 0x00, 0x00,                         /* 120 */
    0x17, 0x01, 0x04, 0x00, 0x01, 0x00, 0x00, 0x00, /* Strip Byte Counts */
    0x60, 0x09, 0x00, 0x00,                         /* 38400 (160*120/8) */
    0x19, 0x01, 0x03, 0x00, 0x01, 0x00, 0x00, 0x00, /* Max Sample Value */
    0x01, 0x00, 0x00, 0x00,                         /* 1 */
    0x1a, 0x01, 0x05, 0x00, 0x01, 0x00, 0x00, 0x00, /* X Resolution */
    0xf0, 0x01, 0x00, 0x00,                         /* (pointer) */
    0x1b, 0x01, 0x05, 0x00, 0x01, 0x00, 0x00, 0x00, /* Y Resolution */
    0xf8, 0x01, 0x00, 0x00,                         /* (pointer) */
    0x1c, 0x01, 0x03, 0x00, 0x01, 0x00, 0x00, 0x00, /* Planar Configuration */
    0x01, 0x00, 0x00, 0x00,                         /* 1 */
    0x28, 0x01, 0x03, 0x00, 0x01, 0x00, 0x00, 0x00, /* Resolution Unit */
    0x02, 0x00, 0x00, 0x00,                         /* 2 (inch) */
    0x00, 0x00, 0x00, 0x00,
};

const unsigned char colormap_data_16[] = {

    /* red */
    0x00, 0x00, 0x00, 0x00, 0x88, 0x88, 0x88, 0x88,
    0x00, 0x00, 0x00, 0x00, 0x88, 0x88, 0x88, 0x88,
    0x44, 0x44, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
    0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
    
    /* green */
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,
    0x44, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
    
    /* blue */
    0x00, 0x00, 0x88, 0x88, 0x00, 0x00, 0x88, 0x88,
    0x00, 0x00, 0x88, 0x88, 0x00, 0x00, 0x88, 0x88,
    0x44, 0x44, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff,
    0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff,
};


static int output_a_tiff_file_32768(int fd, unsigned char *data)
{
    static unsigned char buffer[TIFF_SIZE_32768];
    unsigned char *p;
    int i, j, x;
    
    for (i=0; i<sizeof(header_32768); i++)
        buffer[i] = header_32768[i];
    for (i=sizeof(header_32768); i<0x01f8; i++)
        buffer[i] = 0;
    for (i=0; i<sizeof(resolution_data); i++)
        buffer[0x01f0+i] = resolution_data[i];
    p = buffer + 0x0200;
    for (i=0; i<160*120/8; i++){
        for (j=0; j<8; j++){
            x = (data[i] & (1<<(7-j))) ? 255 : 0;
            (*p++) = x;
            (*p++) = x;
        }
    }
    if (write(fd, buffer, TIFF_SIZE_32768) < TIFF_SIZE_32768)
        return -1;
    return 0;
}

static int output_a_tiff_file_256(int fd, unsigned char *data)
{
    static unsigned char buffer[TIFF_SIZE_256];
    unsigned char *p;
    int i, j, x;
    
    for (i=0; i<sizeof(header_256); i++)
        buffer[i] = header_256[i];
    for (i=sizeof(header_256); i<0x01f8; i++)
        buffer[i] = 0;
    for (i=0; i<sizeof(resolution_data); i++)
        buffer[0x01f0+i] = resolution_data[i];
    p = buffer + 0x0200;
    for (j=0; j<3; j++){
        for (i=0; i<256; i++){
            (*p++) = i;
            (*p++) = i;
        }
    }
    for (i=0; i<160*120/8; i++){
        for (j=0; j<8; j++){
            x = (data[i] & (1<<(7-j))) ? 255 : 0;
            (*p++) = x;
        }
    }
    if (write(fd, buffer, TIFF_SIZE_256) < TIFF_SIZE_256)
        return -1;
    return 0;
}

static int output_a_tiff_file_16(int fd, unsigned char *data)
{
    static unsigned char buffer[TIFF_SIZE_16];
    int i, j, c, x;
    
    for (i=0; i<sizeof(header_16); i++)
        buffer[i] = header_16[i];
    for (i=sizeof(header_16); i<0x0100; i++)
        buffer[i] = 0;
    for (i=0; i<sizeof(colormap_data_16); i++)
        buffer[0x0100+i] = colormap_data_16[i];
    for (i=0x0100+sizeof(colormap_data_16); i<0x01f0; i++)
        buffer[i] = 0;
    for (i=0; i<sizeof(resolution_data); i++)
        buffer[0x01f0+i] = resolution_data[i];
    for (i=0; i<160*120/2; i++)
        buffer[0x0200+i] = 0;
    c = 0;
    for (i=0; i<160*120/8; i++){
        for (j=0; j<8; j++){
            x = (data[i] & (1<<(7-j))) ? 15 : 0;
            if ((c & 1)) x <<= 4;
            buffer[0x0200+(c>>1)] |= x;
            c++;
        }
    }
    if (write(fd, buffer, TIFF_SIZE_16) < TIFF_SIZE_16)
        return -1;
    return 0;
}

static int output_a_tiff_file_2(int fd, unsigned char *data)
{
    static unsigned char buffer[TIFF_SIZE_2];
    unsigned char *p;
    int i;
    
    for (i=0; i<sizeof(header_2); i++)
        buffer[i] = header_2[i];
    for (i=sizeof(header_2); i<0x01f8; i++)
        buffer[i] = 0;
    for (i=0; i<sizeof(resolution_data); i++)
        buffer[0x01f0+i] = resolution_data[i];
    p = buffer + 0x0200;
    for (i=0; i<160*120/8; i++){
        (*p++) = data[i] ^ 255;
    }
    if (write(fd, buffer, TIFF_SIZE_2) < TIFF_SIZE_2)
        return -1;
    return 0;
}

int output_a_helahela_page(char *output_filename_header, int page,
                           unsigned char *buffer, int colors)
{
    char output_filename[256];
    int fd;

    sprintf(output_filename, "%s%03d.tif", output_filename_header, ++page);
    fd = creat(output_filename, 0644);
    if (fd == -1) return -1;

    if      (colors == 32768)
        output_a_tiff_file_32768(fd, buffer);
    else if (colors == 256)
        output_a_tiff_file_256(fd, buffer);
    else if (colors == 16)
        output_a_tiff_file_16(fd, buffer);
    else if (colors == 2)
        output_a_tiff_file_2(fd, buffer);
    
    close(fd);

    return 0;
}
