// (c) 1994-2007 Electronic Arts Inc.

/* ABSTRACT */
/*------------------------------------------------------------------*/
/*                                                                  */
/*                        HSI - Raw Gimex                           */
/*                                                                  */
/*                    by FrANK G. Barchard, EAC                     */
/*                                                                  */
/*------------------------------------------------------------------*/
/*                                                                  */
/* Version Date   SE History:                                       */
/* ------- ----   -- --------                                       */
/*    1.00 940621 FB Image Alchemy HSI Raw Format, based on RAW     */
/*    1.01 940622 FB DMPEG multiframe canimport                     */
/*    1.02 941007 FB 24 bit multiframe canimport/canexport          */
/*    1.03 941205 FB open read header, single gread for 8 bit       */
/*    1.04 950313 FB writehsi return, readhsi better error check    */
/*    1.05 950426 FB single palette field                           */
/*    1.06 950529 FB ginstance signature                            */
/*    1.07 960303 FB gread do gfree only if allocated ok            */
/*    1.08 000404 FB about->movie                                   */
/*    1.09 001206 FB ignore numcolours for 24 bit                   */
/*                                                                  */
/*------------------------------------------------------------------*/
/*                                                                  */
/* Module Notes:                                                    */
/* -------------                                                    */
/* 8,32 bit                                                         */
/* Reentrant                                                        */
/* Line buffered                                                    */
/* Files: hsiread.cpp hsiwrite.cpp hsigimex.h                       */
/*                                                                  */
/*------------------------------------------------------------------*/
/*                                                                  */
/* Format Notes:                                                    */
/* -------------                                                    */
/* HSI files where are generated by Image Alchemy.  They are        */
/* the simpliest format that supports both 24 bit and 8 bit.        */
/*                                                                  */
/* The image is right side up, left to right, no padding.           */
/*                                                                  */
/* This is a dump of the header on an 24 bit example.               */
/*                                                                  */
/* 00000: 6d687761 6e680004 020b01de 0000ffff  mhwanh.....^....     */
/* 00010: ffff0064 00000000 00000000 00000000  ...d............     */
/* 00020: 1c161616 10100f0b 0b100c0c 0f0f0d0d  ................     */
/*                                                                  */
/* This is a dump of the header on an 8 bit example.                */
/*                                                                  */
/* 00000: 6d687761 6e680004 014001aa 01000024  mhwanh...@.*...$     */
/* 00010: 00240000 00000000 00000000 00000000  .$..............     */
/* 00020: ffffffa5 a5a59c9c 9c949494 8c8c8c84  ...%%%..........     */
/* 00030: 84847b7b 7b737373 52525239 39392121  .....sssRRR999!!     */
/* 00040: 21ada5a5 8c848484 7b7b6b63 63393131  !-%%......kcc911     */
/*                                                                  */
/* DMPEG V1.1 by Stefan Eckart (public domain) has extended HSI     */
/* to support multiple frames, simply by concatenating the          */
/* frames to the end of the file.  No header entry reflects the     */
/* additional frames, so the file size must be used as a basis      */
/* for calculating it.                                              */
/*                                                                  */
/*------------------------------------------------------------------*/
/* END ABSTRACT */

#include <string.h>
#include "gimex.h"
#include "hsigimex.h"

/****************************************************************/
/*  Information Functions                                       */
/****************************************************************/

GABOUT * GCALL HSI_about(void)
{
    GABOUT *info;

    info = (GABOUT *) galloc(sizeof(GABOUT));
    if (info)
    {
        memset(info, 0, sizeof(GABOUT));

        info->signature       = GMAKEID('.','H','S','I');
        info->size            = sizeof(GABOUT);
        info->version         = GIMEX_VERSION;
        info->canimport       = 1;    /* supports importing */
        info->canexport       = 1;    /* supports exporting */
        info->importpacked    = 0;    /* supports importing packed */
        info->exportpacked    = 0;    /* supports exporting packed */
        info->import8         = 1;    /* supports importing 8 bit indexed */
        info->export8         = 1;    /* supports exporting 8 bit indexed */
        info->import32        = 1;    /* supports importing 32 bit direct rgb */
        info->export32        = 1;    /* supports exporting 32 bit direct rgb */
        info->multiframe      = 1;    /* supports multiple frames */
        info->multifile       = 0;    /* format requires additional files or resource fork */
        info->multisize       = 0;    /* supports each frame different size */
        info->framebuffer     = 0;    /* module requires memory to buffer entire frame */
        info->external        = 0;    /* module uses external resources */
        info->usesfile        = 1;    /* module is file based */
        info->globalpalette   = 1;    /* one palette per file */
        info->maxframename    = 0;    /* max frame name character */
        info->defaultquality  = 100;  /* default pack quality */
        info->movie           = 1;    /* movie file format */
        info->file64          = 1;    /* this format supports 64 bit file sizes */
        info->mactype[0]      = GMAKEID('.','H','S','I');   /* mac file system types used */
        strcpy(info->extensions[0], ".hsi");                /* extensions */
        strcpy(info->extensions[1], ".raw");                /* extensions */
        strcpy(info->authorstr,     "FrANK G. Barchard");   /* author */
        strcpy(info->versionstr,    "1.09");                /* version # */
        strcpy(info->shorttypestr,  "HSI");                 /* type */
        strcpy(info->wordtypestr,   "HSI");                 /* wordtype */
        strcpy(info->longtypestr,   "HSI Raw");             /* longtype */
    }
    return(info);
}

/* check for reasonable header: */
/* has 6 byte id */

int GCALL HSI_is(GSTREAM *g)
{
    unsigned char hsiheader[32];
    int ok=0;

    gseek(g,(GPOS)0);
    if (gread(g,hsiheader,32))
    {
        if (hsiheader[0]==0x6d
         && hsiheader[1]==0x68
         && hsiheader[2]==0x77
         && hsiheader[3]==0x61
         && hsiheader[4]==0x6e
         && hsiheader[5]==0x68)
            ok = 100;
    }
    return(ok);
}

/****************************************************************/
/*  Import Functions                                            */
/****************************************************************/

int GCALL HSI_open(GINSTANCE **gxptr, GSTREAM *g, const char *pathname,bool framecountflag)
{
    GINSTANCE *gx;
    int ok=0;
    GINFO *ginfo;
    GPOS framesize;
    GPOS filesize;
    int numframes;
    int colours;

    gx = (GINSTANCE *) galloc(sizeof(GINSTANCE));
    if (gx)
    {
        memset(gx, 0, sizeof(GINSTANCE));
        *gxptr = gx;
        gx->frames = 1;
        gx->signature=GMAKEID('.','H','S','I');
        gx->size=sizeof(GINSTANCE);
        gx->gstream = g;

        gx->gref = galloc(32+256*3);
        if (gx->gref)
        {
            gseek(gx->gstream,(GPOS)0);
            if (gread(gx->gstream,gx->gref,32))
            {
                colours = ggetm((unsigned char *)gx->gref+12,2); /* Number of colours in palette */
                if (colours)
                    gread(gx->gstream, (unsigned char *) gx->gref+32, colours*3);

                ginfo = HSI_info(gx,0); /* get width, height, depth for calc */
                if (ginfo)
                {
                    framesize = ginfo->width*ginfo->height*ginfo->originalbpp>>3;
                    filesize = glen(gx->gstream);
                    numframes = (int)((filesize-(32+ginfo->numcolours*3))/framesize);
                    gx->frames = numframes;
                    gfree((void *) ginfo);
                    ok = numframes;
                }
            }
        }
        if (gx->gref && !ok)
            gfree(gx->gref);
    }


    return(ok);
}

GINFO * GCALL HSI_info(GINSTANCE *gx, int framenum)
{
    unsigned char *hsiheader;
    GINFO *ginfo=0;
    int colours;
    int i;
    unsigned char *palbuf;

    hsiheader = (unsigned char*)gx->gref;

    if (framenum < gx->frames)
        ginfo = (GINFO *) galloc(sizeof(GINFO));
    if (ginfo)
    {
        memset(ginfo,0,sizeof(GINFO));

        /* template for ginfo */

        ginfo->signature        = GMAKEID('.','H','S','I');   /* Gimex type */
        ginfo->size             = sizeof(GINFO);            /* Length of GINFO */
        ginfo->version          = GIMEX_VERSION;
        ginfo->framenum         = framenum;    /* Current frame */
        ginfo->subtype          = 0;    /* Internal format sub-type 0-default */
        ginfo->packed           = 0;    /* Type of packing on original image. 0 none, 1 run, n other */
        ginfo->quality          = 100;  /* Quality of lossy packing 0..100 */
        ginfo->alphabits        = 0;    /* Number of bits in alpha channel */
        ginfo->redbits          = 8;    /* Number of bits in red channel */
        ginfo->greenbits        = 8;    /* Number of bits in grreen channel */
        ginfo->bluebits         = 8;    /* Number of bits in blue channel */
        ginfo->centerx          = 0;    /* Center Point relative to upper left corner */
        ginfo->centery          = 0;
        ginfo->defaultx         = 0;    /* Default Coordinate Point */
        ginfo->defaulty         = 0;
        ginfo->numhotspots      = 0;    /* Number of Hot Spots defined */

        ginfo->width  = ggetm(hsiheader+8,2);   /* Width of bitmap in pixels */
        ginfo->height = ggetm(hsiheader+10,2);  /* Height of bitmap in pixels */

        colours = ggetm(hsiheader+12,2);        /* Number of colours in palette */
        if (colours)
        {
            ginfo->bpp              = 8;    /* Bits per pixel (8 or 32) */
            /*ginfo->indexed          = 1;    \* 0 no, 1 yes (indexed meaning it uses a palette) *\ */
            ginfo->originalbpp      = 8;    /* Bits per pixel in original image (1 to 32) */
            /*ginfo->originalindexed  = 1;    \* 0 no, 1 yes (indexed meaning it used a palette) *\ */
            ginfo->numcolours  = colours;  /* Number of colours in original indexed palette */

            palbuf = (unsigned char *)gx->gref+32;
/*            gread(gx->gstream, (unsigned char *) palbuf, colours*3); */
            for (i=0; i<colours; ++i)
            {
                ginfo->colourtbl[i].a = 255;
                ginfo->colourtbl[i].r = palbuf[i*3+0];
                ginfo->colourtbl[i].g = palbuf[i*3+1];
                ginfo->colourtbl[i].b = palbuf[i*3+2];
            }
        }
        else
        {
            ginfo->bpp              = 32;   /* Bits per pixel (8 or 32) */
            /*ginfo->indexed          = 0;    \* 0 no, 1 yes (indexed meaning it uses a palette) *\ */
            ginfo->originalbpp      = 24;   /* Bits per pixel in original image (1 to 32) */
            /*ginfo->originalindexed  = 0;    \* 0 no, 1 yes (indexed meaning it used a palette) *\ */
            ginfo->numcolours  = 0;    /* Number of colours in original indexed palette */
        }
    }

    return(ginfo);
}

int GCALL HSI_read(GINSTANCE *gx, GINFO *ginfo, char *dest, int rowbytes)
{
    char *linebuf;
    char *lineptr;
    int bpp;
    int bpl;
    int x;
    int y;
    int ok=0;
    ARGB *d;
    GPOS framesize;

    framesize = ginfo->width*ginfo->height*ginfo->originalbpp>>3;
    gseek(gx->gstream,32+ginfo->numcolours*3+ginfo->framenum*framesize);
    bpp = ginfo->originalbpp/8;
    bpl = ginfo->width*bpp;

    if (bpp==1 && rowbytes==ginfo->width)
    {
        ok = gread(gx->gstream,dest,(int)framesize);
    }
    else
    {
        linebuf = (char *) galloc(bpl);

        if (linebuf)
        {
            ok = 1;

            for (y=0; y<ginfo->height && ok; ++y)
            {
                d = (ARGB *) (dest+rowbytes*y);

                if (bpp==1)
                {
                    ok = gread(gx->gstream,(unsigned char *)d,bpl);
                }
                else
                {
                    ok = gread(gx->gstream,linebuf,bpl);
                    lineptr = linebuf;

                    for (x=0; x<ginfo->width; ++x)
                    {
                        d->a = 255;
                        d->r = lineptr[0];
                        d->g = lineptr[1];
                        d->b = lineptr[2];
                        ++d;
                        lineptr += 3;
                    }
                }
            }
            gfree(linebuf);
        }
    }
    return(ok);
}

int GCALL HSI_close(GINSTANCE *gx)
{
    int ok=0;

    if (gx)
    {
        if (gx->gref)
            gfree(gx->gref);

        ok = gfree((void *) gx);
    }
    return(ok);
}

