// by el Gozer/Condense
// read pcx file (8 bits only!) from file or buffer
// if the two pointers (filename & buffer) passed to read_pcx are not zero,
// then it return a null pointer
// if a pcx buffer is passed to the func, it will not be deleted
// the buffer of the image will not be destroyed after class is deleted
// you can specifie a color transparency in the palette
// then the alpha value will be changed in the output buffer
// you can specify more than one coulour transparence with the char *colors
// ex: "10,255,0,15"
class pcx {
public:;
	short ximg,yimg;
	void *img32Bpp;

	pcx()
	{
		img32Bpp = NULL;
	}


void* read_pcx(char *messie, void *buff, long fileSize, char *colors)
{
 ULONG pal[256];
 unsigned char lect, j, comp;
 UCHAR *Eight;
 int i=0,k=0;


 if( (messie!=NULL) && (buff!=NULL) ) return NULL;

// read file
 if(messie != NULL)
 {
	FILE *handle = fopen(messie, "rb");
	if( handle == NULL) return NULL;
	fseek(handle, 0L, SEEK_END);
	fileSize = ftell(handle);
	fseek(handle, 0L, SEEK_SET);
	buff = (void*) new char[fileSize];
	fread( buff, 1, fileSize, handle);
	fclose(handle);
 }
//
 if(((UCHAR*)buff)[65] != 1)	// only one color plan (8 bits only)
 {
	 if( messie!= NULL) delete buff;
	 return NULL;
 }

 long bPL = ((UCHAR*)buff)[66] | ((USHORT)(((UCHAR*)buff)[67])<<8);	// bytes per line

 long offsetPCX= 0;
 lect = ((UCHAR*)buff)[0];
 if (lect!=10) return NULL;//exit_error("Not a PCX file.");
 offsetPCX = 2;
 comp = ((UCHAR*)buff)[offsetPCX];

 if (comp!=0 && comp!=1) return NULL;//exit_error("PCX file is corrupt.");
 offsetPCX = 4;
 ximg = *((USHORT*)(buff) + offsetPCX) +1;
 yimg = *((USHORT*)(buff) + offsetPCX + 1) +1;
 
 Eight = new UCHAR[ximg*yimg];
 img32Bpp = (void*)new ULONG[ximg*yimg];

 UCHAR *read = (UCHAR*)buff + 128;
 offsetPCX =0;
 i=0;
 long extra = bPL - ximg;
 long countx = 0;
 while(i<(ximg*yimg))
 {
  if( countx>=ximg )
  {
	  if( countx == ximg) offsetPCX += extra; // skip next data
	  else i -= extra; // skip extra
	  countx = 0;
  }
  lect = read[offsetPCX++];
  if (((lect & 0xc0)!=0xc0) || comp==0)
  {
	  Eight[i++]=lect;
	  countx++;
  }
  else
  {
    j=lect & 0x3f;
	lect = read[offsetPCX++];
    for (;j>0;j--)
	{
		Eight[i++]=lect;
		countx++;
		if(i>=(ximg*yimg)) break;
	}
  }
 }

 // some lines could be added :( let's note the "could" !!!!!
 while(lect!=0x0c)
 {
	 lect = read[offsetPCX++];
	 if(offsetPCX >= (fileSize-128) )
	 {
		delete Eight;
		if(messie != NULL) delete buff;
		delete img32Bpp;
		return NULL;
	 }
 }

 // the palette ....
 i= 0;
 ULONG rgb[3];
 long lp;
 for(lp=0;lp<256;lp++)
 {
  for(long o=0;o<3;o++)
  {
	rgb[o] = (ULONG)read[offsetPCX++];
  }
  pal[i++]= 0xff000000 | (rgb[0]<<16) | (rgb[1]<<8) | rgb[2];
 }

// colors transparency
 lp = 0;
 long transparency = 0;
 if(colors != NULL)
 {
	while( 1 )
	{
		transparency = atoi(colors+lp);
		pal[transparency] &= ~0xff000000;	// set transparency color
		while( colors[lp++]!=',')
		{
			if( colors[lp] == 0)
			{
				transparency = -1;
				break;
			}
		}
		if (transparency < 0) break;
	}
 }

// now build the 32 Bpp buffer
 for(lp=0;lp<(ximg*yimg);lp++) ((ULONG*)img32Bpp)[lp] = pal[Eight[lp]];

 delete Eight;
 if(messie != NULL) delete buff;
 return img32Bpp;
}
};