/************************************************************************\
 *                                                                      *
 *  readpcx.c                                                           *
 *                                                                      *
 *  This file is part of PICTURE MAN image file converter/processor     *
 *                                                                      *
 *  1992 Potapov WORKS, STOIK Ltd.                                      *
 *                                                                      *
 *  This file contains source code for PCX file reader                  *
 *                                                                      *
 *  Compiler: MS C v.6.00A                                              *
 *                                                                      *
 *  You may use, modify and distribute this text freely                 *
 *                                                                      *
\************************************************************************/
#include <windows.h>
#include "custconv.h"
  
#define BUFSIZE 4096
  
#define SEEK_SET 0
#define SEEK_END 2

typedef struct {
                int file, bplin, pos, buflen, count;
                BYTE byte, buffer[BUFSIZE];
                int iCur;
            	}PCXStruct;
  
/************************************************************************\
 *                                                                      *
 * ROUTINE: int FAR PASCAL LibMain(HANDLE hModule, WORD wDataSeg,       *
 *                                 WORD cbHeapSize, LPSTR lpszCmdLine)  *
 * PURPOSE: DLL entry point.                                            *
 *                                                                      *
\************************************************************************/
int FAR PASCAL LibMain(HANDLE hModule, WORD wDataSeg,
WORD cbHeapSize, LPSTR lpszCmdLine)
{
    return 1;
}
  
/************************************************************************\
 *                                                                      *
 * ROUTINE: int FAR PASCAL WEP(int bSystemExit)                         *
 *                                                                      *
 * PURPOSE: DLL exit procedure                                          *
 *                                                                      *
\************************************************************************/
int FAR PASCAL WEP(int bSystemExit)
{
    return 1;
}
  
/************************************************************************\
 *                                                                      *
 * ROUTINE: WORD FAR PASCAL Magic(void)                                 *
 *                                                                      *
 * PURPOSE: Identification routine                                      *
 * RETURNS: 'Magic number' SRC_MAGIC                                    *
 *                                                                      *
\************************************************************************/
WORD FAR PASCAL Magic(void)
{
    return SRC_MAGIC;
}
  
/************************************************************************\
 *                                                                      *
 * ROUTINE: DWORD FAR PASCAL GetFlags(void)                             *
 *                                                                      *
 * PURPOSE: Sets flag for SetOptions Dialog box                         *
 *                                                                      *
 * PARAMETERS: None                                                     *
 *                                                                      *
 * RETURNS:                                                             *
 *          INFO_HASOPTIONS if converter supports SetOptions dialog box *
 *          0ul  otherwise                                              *
 *                                                                      *
\************************************************************************/
DWORD FAR PASCAL GetFlags(void)
{
    return 0ul;
}
  
/************************************************************************\
 *                                                                      *
 * ROUTINE: void FAR PASCAL GetDescription(LPSTR str)                   *
 *                                                                      *
 * PURPOSE: Sets format name                                            *
 *                                                                      *
 * PARAMETERS: LPSTR str - pointer for format name storage. The length  *
 *             name must be less than 40!                               *
 *                                                                      *
\************************************************************************/
void FAR PASCAL GetDescription(LPSTR str)
{
    lstrcpy(str,"ZSoft PaintBrush PCX");
}
  
/************************************************************************\
 *                                                                      *
 * ROUTINE: void FAR PASCAL GetExtension(LPSTR str)                     *
 *                                                                      *
 * PURPOSE: Sets format file extension                                  *
 *                                                                      *
 * PARAMETERS: LPSTR str - pointer for format file extension.           *
 *                                                                      *
\************************************************************************/
void FAR PASCAL GetExtension(LPSTR str)
{
    lstrcpy(str,"PCX");
}

/************************************************************************\
 *                                                                      *
 * ROUTINE: int FAR PASCAL GetPrivateSize()                             *
 *                                                                      *
 * PURPOSE: Returns size of private memory block                        *
 *                                                                      *
 *                                                                      *
\************************************************************************/
int FAR PASCAL GetPrivateSize()
{
   return sizeof(PCXStruct);
}
  
/************************************************************************/
/************************************************************************/
/************************************************************************/
/* PCX File Header */
typedef struct {
    char         manuf;          /* Always =10 for Paintbrush   */
    char         hard;           /* Version information         */
    char         encod;          /* Run-length encoding (=1)    */
    char         bitpx;          /* Bits per pixel              */
    unsigned     x1;             /* Picture dimensions (incl)   */
    unsigned     y1;
    unsigned     x2;
    unsigned     y2;
    unsigned     hres;           /* Display horiz resolution    */
    unsigned     vres;           /* Display vert  resolution    */
    char         clrma[48];      /* Pallete                     */
    char         vmode;          /* (ignored)                   */
    char         nplanes;        /* Number of planes (ver 2.5=0)*/
    unsigned     bplin;          /* Bytes per line              */
    unsigned     palinfo;        /* Palette Info (1=col, 2=gray)*/
    unsigned     shres;          /* Scanner resolution          */
    unsigned     svres;          /*                             */
    char         xtra[54];       /* Extra space (filler)        */
} pcxheader;
  
/************************************************************************\
 *                                                                      *
 * ROUTINE: int FAR PASCAL ReadHeader(LPINFO p, void FAR * lpPrivate)   *
 *                                                                      *
 * PURPOSE: Reads image header. Fills INFO structure.                   *
 *                                                                      *
 * PARAMETERS: LPINFO p - pointer to INFO structure                     *
 *             void far * lpPrivate - pointer to                        *
 *             custom structure to store private data                   *
 * RETURNS:                                                             *
 * OK         - Success                                                 *
 * BADFORMAT  - Bad signature                                           *
 * UNSUPPORTED- Unsupported subformat                                   *
 * BADFILE    - Error in file structure                                 *
 * CANNOTOPEN - Cannot open src/dest                                    *
 * INTERNAL   - Reserved                                                *
 * BADDLL     - Error initializing DLL                                  *
 * BADREQUEST - Unsupported type of conversion                          *
 * BADTEMPFILE- Error creating/reading tempfile                         *
 * NOMEMORY   - No enough global heap                                   *
 * NODISK     - No enough disk space                                    *
 * USERABORT  - Cancelled by user                                       *
 * BADPARMS   - Conflicting parameters                                  *
 *                                                                      *
\************************************************************************/
int FAR PASCAL ReadHeader(LPINFO p, void far * lpPrivate)
{
    pcxheader hdr;
    int i,j;
    char c;
	HANDLE hTmp;
	PCXStruct far *lpPCXStruct = lpPrivate;
  
    if( _llseek(p->file,0l,SEEK_SET) == -1 ) return BADFILE;
    if( _lread(p->file,(LPSTR)&hdr,sizeof(hdr)) != sizeof(hdr))
        return BADFILE;
    if( hdr.manuf != 10 || hdr.encod != 1 ) return BADFORMAT;
    if( (hdr.bitpx != 1 || (hdr.nplanes != 1 && hdr.nplanes != 4)) &&
        (hdr.bitpx != 8 || (hdr.nplanes != 1 && hdr.nplanes != 3)))
        return UNSUPPORTED;
  
    p->w        = hdr.x2-hdr.x1+1;
    p->h        = hdr.y2-hdr.y1+1;
    p->nplanes  = hdr.nplanes;
    p->bplin    = hdr.bplin;
    p->xres     = (DWORD)hdr.hres;
    p->yres     = (DWORD)hdr.vres;
    p->resunit  = RES_SCREEN;
    p->flags    = INFO_COMPRESSED | INFO_FORWARD;
  
    if( hdr.bitpx < 8 ) p->flags |= INFO_PACKED;
    if( hdr.nplanes > 1 ) p->flags |= INFO_SEPARATE;
  
    p->bps      = hdr.bitpx * hdr.nplanes;
    p->numcolors= ( p->bps == 24 ) ? 0u : (1u << p->bps);
  
    if(p->bps == 8)
    {
        if(_llseek(p->file,-0x301l,SEEK_END) == -1
            || _lread(p->file,&c,1) != 1 ) return BADFILE;
        if(c == 0x0C )
        {
            for(i=0;i<256;i++)
                for(j = 0; j < 3; j++)
                    if(_lread(p->file,&(p->pal[j][i]),1) != 1 )
                        return BADFILE;
            if(_llseek(p->file,sizeof(pcxheader),SEEK_SET) == -1)
                return BADFILE;
            p->flags |= INFO_COLOR | INFO_PALETTE;
        }
    }
    else if(p->bps == 4)
    {
        for( i = 0; i < 16; i++)
            for(j = 0; j < 3; j++)
                p->pal[j][i] = hdr.clrma[i*3+j];
        p->flags |= INFO_COLOR | INFO_PALETTE;
    }
    else if(p->bps == 24) p->flags |= INFO_COLOR;
  
    lpPCXStruct->file  = p->file;
    lpPCXStruct->bplin = hdr.nplanes * hdr.bplin;
    lpPCXStruct->count = 0;
    lpPCXStruct->pos   = 0;
    lpPCXStruct->buflen= 0;
  
    return OK;
}
  
/************************************************************************/
/************************************************************************/
/************************************************************************/
/* useful subfunction */
static int getbuf(void far *lpPrivate)
{
 PCXStruct far *lpPCXStruct = lpPrivate;

    lpPCXStruct->pos = 1;
  
    if( (lpPCXStruct->buflen = _lread(lpPCXStruct->file,lpPCXStruct->buffer,BUFSIZE)) <= 0 ) return -1;
    return (int)lpPCXStruct->buffer[0];
}
  
/* useful subfunction */
static int getbyte(void far *lpPrivate)
{
 PCXStruct far *lpPCXStruct = lpPrivate;


 return (lpPCXStruct->pos<lpPCXStruct->buflen) ?
 (int)lpPCXStruct->buffer[lpPCXStruct->pos++] :
  getbuf(lpPrivate);
}
  
/************************************************************************\
 *                                                                      *
 * ROUTINE: int FAR PASCAL ReadRow(int row, LPBYTE p,                   *
 *                                         void far * lpPrivate)        *
 *                                                                      *
 * PURPOSE: Reads image row.                                            *
 *                                                                      *
 * PARAMETERS: int row - the number of row to read                      *
 *             LPBYTE p - pointer to buffer to store image row          *
 *             void far * lpPrivate - pointer to                        *
 *             custom structure to store private data                   *
 *                                                                      *
 * RETURNS:                                                             *
 * OK         - Success                                                 *
 * BADFORMAT  - Bad signature                                           *
 * UNSUPPORTED- Unsupported subformat                                   *
 * BADFILE    - Error in file structure                                 *
 * CANNOTOPEN - Cannot open src/dest                                    *
 * INTERNAL   - Reserved                                                *
 * BADDLL     - Error initializing DLL                                  *
 * BADREQUEST - Unsupported type of conversion                          *
 * BADTEMPFILE- Error creating/reading tempfile                         *
 * NOMEMORY   - No enough global heap                                   *
 * NODISK     - No enough disk space                                    *
 * USERABORT  - Cancelled by user                                       *
 * BADPARMS   - Conflicting parameters                                  *
 *                                                                      *
\************************************************************************/
int FAR PASCAL ReadRow(int row, LPBYTE p, void far *lpPrivate)
{
    int len,n;
    LPBYTE buf;
	PCXStruct far *lpPCXStruct = lpPrivate;
  
    while(lpPCXStruct->iCur <= row)
    {
        buf = p;
        len = lpPCXStruct->bplin;
        while(len)
        {
            while(lpPCXStruct->count && len)
            {
                *buf++ = lpPCXStruct->byte; lpPCXStruct->count--; len--;
            }
  
            if(!len) goto Done;
  
            if( ( n = getbyte(lpPrivate)) == -1 ) return BADFILE;
            if( ( n & 0xC0) == 0xC0 )
            {
                lpPCXStruct->count = n & 0x3F;
                if( ( n = getbyte(lpPrivate)) == -1  ) return BADFILE;
                lpPCXStruct->byte = (BYTE)n;
            }
            else
            {
                *buf++ = (BYTE)n; len--;
            }
        }
  
        Done:
        lpPCXStruct->iCur++;
    }
    return OK;
}
  
/************************************************************************\
 *                                                                      *
 * ROUTINE: void FAR PASCAL CleanUp(void far *lpPrivate)                *
 *             void far * lpPrivate - pointer to                        *
 *             custom structure to store private data                   *
 *                                                                      *
 * PURPOSE: Frees all auxiliary buffers. Terminates conversion.         *
 *                                                                      *
\************************************************************************/
void FAR PASCAL CleanUp(void far *lpPrivate)
{
}
