Files
meep-eep e7eabd46b9 Old tools that got removed a long time ago.
git-svn-id: svn://svn.code.sf.net/p/sc2/code/trunk@1545 8092fc87-c524-0410-9efc-e669fe64eaf9
2005-02-19 00:38:46 +00:00

388 lines
11 KiB
C++

/*--pbio.c----------------------------------------------------------*
* *
* Routines to read & write PC Paintbrush files. *
* *
* Date Who Changes *
* --------- --- -------------------------------------------------- *
* 31-Mar-89 mjc band read & write to allow large files. *
* 19-Apr-89 mjc 256 color palette added at end of paintbrush file. *
* *
* TBD: haven't added scroll-offset logic to "to planar" case, since
* ANIMDISK is only 8 bpp.
*------------------------------------------------------------------*/
#include "main.h"
#include <fcntl.h>
#include <malloc.h>
#include <sys\types.h>
#include <sys\stat.h>
#include <io.h>
#include <stdio.h>
#define local static
/* RowBytes computes the number of bytes in a row, from the width in pixels.*/
#define RowBytes(w) (((w) + 15) >> 4 << 1)
/*------------------------------------------------------------------
* 256 Color Palette
*
* When reading the paintbrush file, the 256 color palette is
* sought only if the version number in the header is 5 and the
* bits per pixel * planes == 8. The last 769 bytes of the file
* must start with 0x0C, and be followed by the 768 byte palette.
*
* When writing the paintbrush file, we write
* version 5 in the header, and append the palette to the end of
* the file in the same format as above (0x0C followed by 768
* bytes of palette).
*------------------------------------------------------------------
*/
/* Return SUCCESS, FAIL, or specific errors ... */
#define PB_NOT_ENUF_MEM 2
#define PB_NO_256_PALETTE 3
local WORD readCount; /* For compression. */
local UBYTE readChar;
/* --- Forward declarations. */
void GetByte(WORD file);
BOOL PutBytes(BYTE far * ptr, WORD bytes, WORD file);
/*-----------------------------------------------------------------*/
typedef struct {
BYTE manufacturer;
BYTE version;
BYTE encoding;
BYTE bitsperpixel;
WORD xmin, ymin, xmax, ymax;
WORD hres, vres;
BYTE colormap[16][3];
BYTE reserved;
BYTE nplanes;
WORD bytesperline;
} PCPAINTBRUSH_HEADER;
local PCPAINTBRUSH_HEADER *pbh = NULL; /* paintbrush header pointer */
/* Global pointer so can allocate in header, use fields in body. */
/*--------------------- Bad Paintbrush Header ----------------------*/
#define BadPbHeader(s) (FAIL)
/*-------------------- Invalid Paintbrush File ---------------------*/
#define InvalidPbFile() (FAIL)
#define WrongPbFileType() (FAIL) /* Expected different data format.*/
#define PCXNo256PaletteMsg()
/*-----------------------------------------------------------------*
* Read the header of a pc paintbrush file.
* Sets bmHdr fields. Calls reSize if necessary.
* Returns SUCCESS or FAIL.
*-----------------------------------------------------------------*/
BOOL ReadPCX_Header(WORD file, BITMAP *bitmap, LONG *palette,
BitMapHeader *bmHdr)
{
register WORD i;
UBYTE c, palet[256][3];
if (!pbh) /* Test in case we come through twice w/o freeing. */
pbh = malloc(sizeof(PCPAINTBRUSH_HEADER) + 4);
if (!pbh)
return (FAIL);
if (read(file, (char *)pbh, sizeof(PCPAINTBRUSH_HEADER)) !=
sizeof(PCPAINTBRUSH_HEADER))
return (InvalidPbFile());
/* --- To start of pixel data. */
if (0 > lseek(file, (LONG) 128, SEEK_SET))
return (InvalidPbFile());
/* --- Check that the header info is valid. */
if (pbh->manufacturer != 10)
return (InvalidPbFile());
/* --- Expecting version with palette at end. */
if (pbh->version != 5)
return (BadPbHeader(s_wrongPBVersion));
if (pbh->encoding != 1)
return (BadPbHeader(s_unknownEncoding));
if (pbh->bitsperpixel != 1 && pbh->nplanes != 1)
return (BadPbHeader(s_wrongLayout));
if (pbh->bitsperpixel != 8)
return (WrongPbFileType());
/* --- Compute dimensions and # colors. */
setmem(bmHdr, sizeof(BitMapHeader), 0);
bmHdr->w = 1 + pbh->xmax - pbh->xmin;
bmHdr->h = 1 + pbh->ymax - pbh->ymin;
bmHdr->nPlanes = pbh->bitsperpixel * pbh->nplanes;
/* MAY BE PACKED. */
/* --- Get the color map. */
if (palette != NULL) {
/* If a 256 color palette should be present at the end of the
* file, try to fetch it from disk and copy it to the palette.
*/
c = 0;
if (lseek(file, (LONG)-769, SEEK_END) >= 0)
if (read(file, &c, 1) == 1)
if (read(file, (UBYTE *)&palet[0][0], 768) == 768)
if (c == 0x0C)
for (i = 0; i < 256; ++i)
palette[i] = ((LONG)palet[i][0] << 16) +
((LONG)palet[i][1] << 8) +
((LONG)palet[i][2]);
/* --- To start of pixel data (again). */
lseek(file, (LONG)128, SEEK_SET);
if (c != 0x0C) {
/* ---- We couldn't read a 256 color palette at the end
* of the file.
*/
PCXNo256PaletteMsg();
return (PB_NO_256_PALETTE);
}
}
return (SUCCESS); /* Header done; BODY yet to do. */
}
/*-----------------------------------------------------------------*
* Read the pixel data into the bitmap. Return SUCCESS or FAIL.
*-----------------------------------------------------------------*/
#define MaxPCXPlanes 8 /* 256-color, no mask. */
BOOL ReadPCX_BODY(WORD file, BITMAP *bitmap, BitMapHeader *bmHdr)
{
register WORD i, iPlane;
BOOL result = SUCCESS;
BYTE far *dest;
WORD bodyNRows, srcPlanesToUse;
WORD bodyIRow; /* Increment from 0..bodyNRows-1. */
BYTE far *dests[MaxPCXPlanes]; /* Ptrs to dest scan lines. */
WORD useBytes;
/* --------- Initialization. ---------- */
readCount = 0; /* For compression. */
bodyNRows = MIN(bmHdr->h, bitmap->box.h);
srcPlanesToUse = MIN(bitmap->planes + bpp_minus1, bmHdr->nPlanes);
/* ---------- Read all scan lines. ---------- */
OpenIOBuffer(FALSE);
for (bodyIRow = 0; bodyIRow < bodyNRows; ++bodyIRow) {
readCount = 0; /* Just in case, supposed to start anew each line. */
useBytes = MIN(bitmap->width, pbh->bytesperline);
/* ----- Read a scan line. */
dest = (BYTE far *)BMLineStart(bitmap, bodyIRow, 0);
for (i = 0; i < pbh->bytesperline; i++) {
GetByte(file);
if (i < useBytes)
*dest++ = readChar;
}
}
CloseIOBuffer(file);
done:
return (result);
}
/*--------------------- Close Paintbrush File ---------------------*/
/* --- NOTE: if change, must change WritePCX_Done, since it calls this. */
void ReadPCX_Done()
{
/* --- Free pbh, which is shared by header & body routines. */
if (pbh)
free(pbh);
pbh = NULL;
}
void WritePCX_Done()
{
ReadPCX_Done();
}
/*---------------------------- Get Byte ---------------------------*/
/* Set readCount & readChar. At EOF or file error, returns 0's forever. */
void GetByte(WORD file)
{
UBYTE c;
/* --- if in the middle of a run of encoded bytes, don't read any
* more
*/
if (readCount > 0) {
--readCount;
return;
}
readCount = 0;
if (GReadOne(file, &c) != 1) {
sawEOF:
readCount = 32767; /* Huge count of 0's to pad the end. */
readChar = 0;
return;
}
if ((c & 0xc0) == 0xc0) {
readCount = (0x3f & c) - 1; /* "-1": consuming one of count. */
if (GReadOne(file, &c) != 1)
goto sawEOF;
}
readChar = c;
}
/*----------------------------------------------------------------------*
Output File Routines & Variables
*----------------------------------------------------------------------*/
/*---------------------------------------------------------------*
Output header for a PC Paintbrush file with the given number
of bitsperpixel and planes. One of these two parms must be 1.
ASSUMES OKAY TO TRASH buffer[].
Returns SUCCESS or FAIL.
*---------------------------------------------------------------*/
BOOL WritePCX_Header(WORD file, BITMAP *bitmap, LONG *palette)
{
register PCPAINTBRUSH_HEADER *ppbh;
WORD i;
#define GAP_SIZE (128 - sizeof(PCPAINTBRUSH_HEADER))
UBYTE buffer1[GAP_SIZE];
/* --- init the header that we'll write.
* Note: since DPaint never reads & writes at the same time,
* it is okay to share the same read & write structure,
* unlike in CONVERT.EXE.
*/
if (!pbh) /* Test in case we come through twice w/o
* freeing. */
pbh = malloc(sizeof(PCPAINTBRUSH_HEADER) + 4);
if (!pbh)
return (FAIL);
ppbh = pbh; /* Register variable for smaller, faster code. */
setmem(ppbh, sizeof(PCPAINTBRUSH_HEADER) + 4, 0);
ppbh->manufacturer = 10;
ppbh->version = 5;
ppbh->encoding = 1;
ppbh->bitsperpixel = bpp;
ppbh->xmin = ppbh->ymin = 0;
ppbh->xmax = bitmap->box.w - 1;
ppbh->ymax = bitmap->box.h - 1;
ppbh->hres = N_COLUMNS;
ppbh->vres = N_LINES;
/* --- bytesperline doesn't take into account multiple planes.
* Output in same format as bitmap (planar vs packed).
*/
ppbh->bytesperline = bitmap->width;
ppbh->nplanes = bitmap->planes;
ppbh->reserved = 0;
/* --- First 16 colors of our palette info. */
for (i = 0; i < 16; ++i) {
ppbh->colormap[i][0] = (BYTE)(palette[i] >> 16);
ppbh->colormap[i][1] = (BYTE)(palette[i] >> 8);
ppbh->colormap[i][2] = (BYTE) palette[i];
}
/* --- write the 128-byte header */
if (GWrite(file, (char *)ppbh, sizeof(PCPAINTBRUSH_HEADER))
!= sizeof(PCPAINTBRUSH_HEADER))
goto error;
setmem(buffer1, GAP_SIZE, 0);
if (GWrite(file, buffer1, GAP_SIZE) != GAP_SIZE)
error:
return (FAIL);
return (SUCCESS);
}
/* --------------- WritePCX_BODY ---------------
* Write the pixel data.
* Returns SUCCESS or an error condition.
* -------------------------------------------------------------------
*/
WORD WritePCX_BODY(WORD file, BITMAP *bitmap)
{
register WORD y;
/* --- Write to a bit-packed file. */
for (y = 0; y < bitmap->box.h; ++y) { /* for each line in band */
if (PutBytes((BYTE far *)BMLineStart(bitmap, y, 0),
pbh->bytesperline, file))
return FAIL;
}
return SUCCESS;
}
/*-------------------- Output any 256-color palette ------------------------*/
BOOL WritePCX_256Palette(WORD file, LONG *palette)
{
register WORD i;
UBYTE c, palet[256][3];
if (pbh->version == 5 && pbh->bitsperpixel == 8) {
for (i = 0; i < 256; ++i) {
palet[i][0] = (BYTE)(palette[i] >> 16);
palet[i][1] = (BYTE)(palette[i] >> 8);
palet[i][2] = (BYTE) palette[i];
}
c = 0x0C;
if (GWrite(file, &c, 1) != 1 ||
GWrite(file, (char *)&palet[0][0], 768) != 768)
return FAIL;
}
return SUCCESS;
}
/*-------------------------------------------------------------------
* Write bytes to a file, handling packing as it goes.
* Returns SUCCESS or FAIL.
*-------------------------------------------------------------------
*/
BOOL PutBytes(BYTE far *ptr, WORD bytes, WORD file)
{
register WORD startbyte, count;
char b;
while (bytes > 0) {
/* --- check for a repeating byte value */
startbyte = *ptr++;
--bytes;
count = 1;
while (*ptr == startbyte && bytes > 0 && count < 63) {
++ptr;
--bytes;
++count;
}
/* --- If we can pack the sequence, or if we have to add a
* byte before it because the top 2 bits of the value
* are 1's, write a packed sequence of 2 bytes.
* Otherwise, just write the byte value.
*/
if (count > 1 || (startbyte & 0xc0) == 0xc0) {
b = 0xc0 | count;
if (GWrite(file, &b, 1) != 1)
return FAIL;
}
b = startbyte;
if (GWrite(file, &b, 1) != 1)
return FAIL;
}
return SUCCESS;
}