// ID_CA.C
// this has been customized for WOLF
/*
=============================================================================
Id Software Caching Manager
---------------------------
Must be started BEFORE the memory manager, because it needs to get the headers
loaded into the data segment
=============================================================================
*/
#include "ID_HEADS.H"
#pragma hdrstop
#pragma warn -pro
#pragma warn -use
#define THREEbyteGRSTARTS
/*
=============================================================================
LOCAL CONSTANTS
=============================================================================
*/
typedef struct
{
unsigned bit0,bit1; // 0-255 is a character, > is a pointer to a node
} huffnode;
typedef struct
{
unsigned RLEWtag;
long headeroffsets[100];
byte tileinfo[];
} mapfiletype;
/*
=============================================================================
GLOBAL VARIABLES
=============================================================================
*/
byte _seg *tinf;
int mapon;
unsigned _seg *mapsegs[MAPPLANES];
maptype _seg *mapheaderseg[NUMMAPS];
byte _seg *audiosegs[NUMSNDCHUNKS];
void _seg *grsegs[NUMCHUNKS];
byte far grneeded[NUMCHUNKS];
byte ca_levelbit,ca_levelnum;
int profilehandle,debughandle;
char audioname[13]="AUDIO.";
/*
=============================================================================
LOCAL VARIABLES
=============================================================================
*/
extern long far CGAhead;
extern long far EGAhead;
extern byte CGAdict;
extern byte EGAdict;
extern byte far maphead;
extern byte mapdict;
extern byte far audiohead;
extern byte audiodict;
char extension[5], // Need a string, not constant to change cache files
gheadname[10]=GREXT"HEAD.",
gfilename[10]=GREXT"GRAPH.",
gdictname[10]=GREXT"DICT.",
mheadname[10]="MAPHEAD.",
mfilename[10]="MAPTEMP.",
aheadname[10]="AUDIOHED.",
afilename[10]="AUDIOT.";
void CA_CannotOpen(char *string);
long _seg *grstarts; // array of offsets in egagraph, -1 for sparse
long _seg *audiostarts; // array of offsets in audio / audiot
#ifdef GRHEADERLINKED
huffnode *grhuffman;
#else
huffnode grhuffman[255];
#endif
#ifdef AUDIOHEADERLINKED
huffnode *audiohuffman;
#else
huffnode audiohuffman[255];
#endif
int grhandle; // handle to EGAGRAPH
int maphandle; // handle to MAPTEMP / GAMEMAPS
int audiohandle; // handle to AUDIOT / AUDIO
long chunkcomplen,chunkexplen;
SDMode oldsoundmode;
void CAL_CarmackExpand (unsigned far *source, unsigned far *dest,
unsigned length);
#ifdef THREEbyteGRSTARTS
#define FILEPOSSIZE 3
//#define GRFILEPOS(c) (*(long far *)(((byte far *)grstarts)+(c)*3)&0xffffff)
long GRFILEPOS(int c)
{
long value;
int offset;
offset = c*3;
value = *(long far *)(((byte far *)grstarts)+offset);
value &= 0x00ffffffl;
if (value == 0xffffffl)
value = -1;
return value;
};
#else
#define FILEPOSSIZE 4
#define GRFILEPOS(c) (grstarts[c])
#endif
/*
=============================================================================
LOW LEVEL ROUTINES
=============================================================================
*/
/*
============================
=
= CA_OpenDebug / CA_CloseDebug
=
= Opens a binary file with the handle "debughandle"
=
============================
*/
void CA_OpenDebug (void)
{
unlink ("DEBUG.TXT");
debughandle = open("DEBUG.TXT", O_CREAT | O_WRONLY | O_TEXT);
}
void CA_CloseDebug (void)
{
close (debughandle);
}
/*
============================
=
= CAL_GetGrChunkLength
=
= Gets the length of an explicit length chunk (not tiles)
= The file pointer is positioned so the compressed data can be read in next.
=
============================
*/
void CAL_GetGrChunkLength (int chunk)
{
lseek(grhandle,GRFILEPOS(chunk),SEEK_SET);
read(grhandle,&chunkexplen,sizeof(chunkexplen));
chunkcomplen = GRFILEPOS(chunk+1)-GRFILEPOS(chunk)-4;
}
/*
==========================
=
= CA_FarRead
=
= Read from a file to a far pointer
=
==========================
*/
boolean CA_FarRead (int handle, byte far *dest, long length)
{
if (length>0xffffl)
Quit ("CA_FarRead doesn't support 64K reads yet!");
asm push ds
asm mov bx,[handle]
asm mov cx,[WORD PTR length]
asm mov dx,[WORD PTR dest]
asm mov ds,[WORD PTR dest+2]
asm mov ah,0x3f // READ w/handle
asm int 21h
asm pop ds
asm jnc good
errno = _AX;
return false;
good:
asm cmp ax,[WORD PTR length]
asm je done
errno = EINVFMT; // user manager knows this is bad read
return false;
done:
return true;
}
/*
==========================
=
= CA_segWrite
=
= Write from a file to a far pointer
=
==========================
*/
boolean CA_FarWrite (int handle, byte far *source, long length)
{
if (length>0xffffl)
Quit ("CA_FarWrite doesn't support 64K reads yet!");
asm push ds
asm mov bx,[handle]
asm mov cx,[WORD PTR length]
asm mov dx,[WORD PTR source]
asm mov ds,[WORD PTR source+2]
asm mov ah,0x40 // WRITE w/handle
asm int 21h
asm pop ds
asm jnc good
errno = _AX;
return false;
good:
asm cmp ax,[WORD PTR length]
asm je done
errno = ENOMEM; // user manager knows this is bad write
return false;
done:
return true;
}
/*
==========================
=
= CA_ReadFile
=
= Reads a file into an allready allocated buffer
=
==========================
*/
boolean CA_ReadFile (char *filename, memptr *ptr)
{
int handle;
long size;
if ((handle = open(filename,O_RDONLY | O_BINARY, S_IREAD)) == -1)
return false;
size = filelength (handle);
if (!CA_FarRead (handle,*ptr,size))
{
close (handle);
return false;
}
close (handle);
return true;
}
/*
==========================
=
= CA_WriteFile
=
= Writes a file from a memory buffer
=
==========================
*/
boolean CA_WriteFile (char *filename, void far *ptr, long length)
{
int handle;
long size;
handle = open(filename,O_CREAT | O_BINARY | O_WRONLY,
S_IREAD | S_IWRITE | S_ifREG);
if (handle == -1)
return false;
if (!CA_FarWrite (handle,ptr,length))
{
close (handle);
return false;
}
close (handle);
return true;
}
/*
==========================
=
= CA_LoadFile
=
= Allocate space for and load a file
=
==========================
*/
boolean CA_LoadFile (char *filename, memptr *ptr)
{
int handle;
long size;
if ((handle = open(filename,O_RDONLY | O_BINARY, S_IREAD)) == -1)
return false;
size = filelength (handle);
MM_GetPtr (ptr,size);
if (!CA_FarRead (handle,*ptr,size))
{
close (handle);
return false;
}
close (handle);
return true;
}
/*
============================================================================
COMPRESSION routines, see JHUFF.C for more
============================================================================
*/
/*
===============
=
= CAL_Optimizenodes
=
= Goes through a huffman table and changes the 256-511 node numbers to the
= actular address of the node. Must be called before CAL_HuffExpand
=
===============
*/
void CAL_Optimizenodes (huffnode *table)
{
huffnode *node;
int i;
node = table;
for (i=0;i 255;i++)
{
if (node->bit0 >= 256)
node->bit0 = (unsigned)(table+(node->bit0-256));
if (node->bit1 >= 256)
node->bit1 = (unsigned)(table+(node->bit1-256));
node++;
}
}
/*
======================
=
= CAL_HuffExpand
=
= Length is the length of the EXPANDED data
= if screenhack, the data is decompressed in four planes directly
= to the screen
=
======================
*/
void CAL_HuffExpand (byte huge *source, byte huge *dest,
long length,huffnode *hufftable, boolean screenhack)
{
// unsigned bit,byte,node,code;
unsigned sourceseg,sourceoff,destseg,destoff,endoff;
huffnode *headptr;
byte mapmask;
// huffnode *nodeon;
headptr = hufftable+254; // head node is allways node 254
source++; // normalize
source--;
dest++;
dest--;
if (screenhack)
{
mapmask = 1;
asm mov dx,SC_INDEX
asm mov ax,SC_MAPMASK + 256
asm out dx,ax
length >>= 2;
}
sourceseg = FP_seg(source);
sourceoff = FP_OFF(source);
destseg = FP_seg(dest);
destoff = FP_OFF(dest);
endoff = destoff+length;
//
// ds:si source
// es:di dest
// ss:bx node pointer
//
if (length 0xfff0)
{
//--------------------------
// expand less than 64k of data
//--------------------------
asm mov bx,[headptr]
asm mov si,[sourceoff]
asm mov di,[destoff]
asm mov es,[destseg]
asm mov ds,[sourceseg]
asm mov ax,[endoff]
asm mov ch,[si] // load first byte
asm inc si
asm mov cl,1
expandshort:
asm test ch,cl // bit set?
asm jnz bit1short
asm mov dx,[ss:bx] // take bit0 path from node
asm shl cl,1 // advance to next bit position
asm jc newbyteshort
asm jnc sourceupshort
bit1short:
asm mov dx,[ss:bx+2] // take bit1 path
asm shl cl,1 // advance to next bit position
asm jnc sourceupshort
newbyteshort:
asm mov ch,[si] // load next byte
asm inc si
asm mov cl,1 // back to first bit
sourceupshort:
asm or dh,dh // if dx 256 its a byte, else move node
asm jz storebyteshort
asm mov bx,dx // next node = (huffnode *)code
asm jmp expandshort
storebyteshort:
asm mov [es:di],dl
asm inc di // write a decopmpressed byte out
asm mov bx,[headptr] // back to the head node for next bit
asm cmp di,ax // done?
asm jne expandshort
//
// perform screenhack if needed
//
asm test [screenhack],1
asm jz notscreen
asm shl [mapmask],1
asm mov ah,[mapmask]
asm cmp ah,16
asm je notscreen // all four planes done
asm mov dx,SC_INDEX
asm mov al,SC_MAPMASK
asm out dx,ax
asm mov di,[destoff]
asm mov ax,[endoff]
asm jmp expandshort
notscreen:;
}
else
{
//--------------------------
// expand more than 64k of data
//--------------------------
length--;
asm mov bx,[headptr]
asm mov cl,1
asm mov si,[sourceoff]
asm mov di,[destoff]
asm mov es,[destseg]
asm mov ds,[sourceseg]
asm lodsb // load first byte
expand:
asm test al,cl // bit set?
asm jnz bit1
asm mov dx,[ss:bx] // take bit0 path from node
asm jmp gotcode
bit1:
asm mov dx,[ss:bx+2] // take bit1 path
gotcode:
asm shl cl,1 // advance to next bit position
asm jnc sourceup
asm lodsb
asm cmp si,0x10 // normalize ds:si
asm jb sinorm
asm mov cx,ds
asm inc cx
asm mov ds,cx
asm xor si,si
sinorm:
asm mov cl,1 // back to first bit
sourceup:
asm or dh,dh // if dx 256 its a byte, else move node
asm jz storebyte
asm mov bx,dx // next node = (huffnode *)code
asm jmp expand
storebyte:
asm mov [es:di],dl
asm inc di // write a decopmpressed byte out
asm mov bx,[headptr] // back to the head node for next bit
asm cmp di,0x10 // normalize es:di
asm jb dinorm
asm mov dx,es
asm inc dx
asm mov es,dx
asm xor di,di
dinorm:
asm sub [WORD PTR ss:length],1
asm jnc expand
asm dec [WORD PTR ss:length+2]
asm jns expand // when length = ffff ffff, done
}
asm mov ax,ss
asm mov ds,ax
}
/*
======================
=
= CAL_CarmackExpand
=
= Length is the length of the EXPANDED data
=
======================
*/
#define NEARTAG 0xa7
#define FARTAG 0xa8
void CAL_CarmackExpand (unsigned far *source, unsigned far *dest, unsigned length)
{
unsigned ch,chhigh,count,offset;
unsigned far *copyptr, far *inptr, far *outptr;
length/=2;
inptr = source;
outptr = dest;
while (length)
{
ch = *inptr++;
chhigh = ch>>8;
if (chhigh == NEARTAG)
{
count = ch&0xff;
if (!count)
{ // have to insert a word containing the tag byte
ch |= *((unsigned char far *)inptr)++;
*outptr++ = ch;
length--;
}
else
{
offset = *((unsigned char far *)inptr)++;
copyptr = outptr - offset;
length -= count;
while (count--)
*outptr++ = *copyptr++;
}
}
else if (chhigh == FARTAG)
{
count = ch&0xff;
if (!count)
{ // have to insert a word containing the tag byte
ch |= *((unsigned char far *)inptr)++;
*outptr++ = ch;
length --;
}
else
{
offset = *inptr++;
copyptr = dest + offset;
length -= count;
while (count--)
*outptr++ = *copyptr++;
}
}
else
{
*outptr++ = ch;
length --;
}
}
}