733 lines
20 KiB
C
733 lines
20 KiB
C
|
/*
|
||
|
* RING16.C: Ring buffer code
|
||
|
*
|
||
|
* History:
|
||
|
* 30-Oct-1996 jforbes Cloned from QUANTUM\DECOMP.C
|
||
|
*/
|
||
|
|
||
|
#include <stdio.h> /* for NULL */
|
||
|
#include <stdlib.h> /* for disk ring buffer code (SEEK_SET) */
|
||
|
#include <fcntl.h> /* for disk ring buffer code (_O_*) */
|
||
|
#include <sys\stat.h> /* for disk ring buffer code (_S_I*) */
|
||
|
#include <io.h>
|
||
|
#include "decoder.h"
|
||
|
|
||
|
|
||
|
/* --- local function prototypes ------------------------------------------ */
|
||
|
|
||
|
static void NEAR DComp_Internal_Literal(t_decoder_context *context, int Chr );
|
||
|
static void NEAR DComp_Internal_Match(t_decoder_context *context, MATCH Match );
|
||
|
|
||
|
static void NEAR DComp_Ring_Close(t_decoder_context *context);
|
||
|
static int NEAR DComp_Ring_Init(t_decoder_context *context);
|
||
|
static void NEAR DComp_Ring_Literal(t_decoder_context *context, int Chr );
|
||
|
static BYTE * NEAR DComp_Ring_Load(t_decoder_context *context, int page,int fWrite);
|
||
|
static void NEAR DComp_Ring_Match(t_decoder_context *context, MATCH Match );
|
||
|
static void NEAR DComp_Ring_Reset(t_decoder_context *context);
|
||
|
|
||
|
|
||
|
#define Disk context->Disk
|
||
|
|
||
|
#define DComp context->DComp
|
||
|
|
||
|
|
||
|
/* --- DComp_Close() ------------------------------------------------------ */
|
||
|
void NEAR DComp_Close(t_decoder_context *context)
|
||
|
{
|
||
|
if (DComp.Buf == NULL)
|
||
|
{
|
||
|
DComp_Ring_Close(context); /* if using a disk-based ring buffer */
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
context->dec_free( DComp.Buf ); /* if using memory-based ring buffer */
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
/* --- DComp_Init() ------------------------------------------------------- */
|
||
|
int NEAR DComp_Init(t_decoder_context *context)
|
||
|
{
|
||
|
DComp.Cur = 0;
|
||
|
DComp.fRingFault = 0;
|
||
|
|
||
|
if( (DComp.Buf = context->dec_malloc( context->dec_window_size )) != NULL )
|
||
|
{
|
||
|
DComp.BufPos = DComp.Buf;
|
||
|
DComp.BufEnd = DComp.Buf + context->dec_window_size;
|
||
|
|
||
|
context->DComp_Token_Match = DComp_Internal_Match; /* use internal buffering */
|
||
|
context->DComp_Token_Literal = DComp_Internal_Literal;
|
||
|
}
|
||
|
else if (DComp_Ring_Init(context)) /* try disk ring buffer */
|
||
|
{
|
||
|
context->DComp_Token_Match = DComp_Ring_Match; /* use disk buffering */
|
||
|
context->DComp_Token_Literal = DComp_Ring_Literal;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
return (1); /* if can't create ring buffer */
|
||
|
}
|
||
|
|
||
|
return(0);
|
||
|
}
|
||
|
|
||
|
/* --- DComp_Internal_Literal() ------------------------------------------- */
|
||
|
|
||
|
static void NEAR DComp_Internal_Literal(t_decoder_context *context, int Chr)
|
||
|
{
|
||
|
if (DComp.NumBytes)
|
||
|
{
|
||
|
DComp.NumBytes--;
|
||
|
DComp.Cur++;
|
||
|
|
||
|
*context->dec_output_curpos++ = *DComp.BufPos++ = (BYTE) Chr;
|
||
|
|
||
|
if (DComp.BufPos == DComp.BufEnd)
|
||
|
DComp.BufPos = DComp.Buf;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
/* --- DComp_Internal_Match() --------------------------------------------- */
|
||
|
|
||
|
static void NEAR DComp_Internal_Match(t_decoder_context *context, MATCH Match)
|
||
|
{
|
||
|
BYTE HUGE *SrcPtr;
|
||
|
|
||
|
if (DComp.NumBytes >= (unsigned) Match.Len)
|
||
|
{
|
||
|
SrcPtr = DComp.Buf +
|
||
|
((DComp.Cur - Match.Dist) & context->dec_window_mask);
|
||
|
|
||
|
DComp.NumBytes -= Match.Len;
|
||
|
DComp.Cur += Match.Len;
|
||
|
|
||
|
while (Match.Len--)
|
||
|
{
|
||
|
*context->dec_output_curpos++ = *DComp.BufPos++ = *SrcPtr++;
|
||
|
|
||
|
if (SrcPtr == DComp.BufEnd)
|
||
|
SrcPtr = DComp.Buf;
|
||
|
|
||
|
if (DComp.BufPos == DComp.BufEnd)
|
||
|
DComp.BufPos = DComp.Buf;
|
||
|
}
|
||
|
}
|
||
|
else /* match too large to fit */
|
||
|
{
|
||
|
DComp.NumBytes = 0;
|
||
|
DComp.fOutOverflow = 1;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* --- DComp_Reset() ------------------------------------------------------ */
|
||
|
|
||
|
void NEAR DComp_Reset(t_decoder_context *context)
|
||
|
{
|
||
|
DComp.Cur = 0;
|
||
|
DComp.fRingFault = 0;
|
||
|
|
||
|
if (DComp.Buf != NULL)
|
||
|
DComp.BufPos = DComp.Buf; /* big buffer */
|
||
|
else
|
||
|
DComp_Ring_Reset(context); /* ring buffer */
|
||
|
}
|
||
|
|
||
|
/* --- DComp_Ring_Close() ------------------------------------------------- */
|
||
|
|
||
|
static void NEAR DComp_Ring_Close(t_decoder_context *context)
|
||
|
{
|
||
|
PBUFFER pBuffer, pNext; /* buffer walk pointer */
|
||
|
|
||
|
context->dec_free(Disk.PageTable); /* discard page table */
|
||
|
|
||
|
pBuffer = Disk.pNewest;
|
||
|
|
||
|
while (pBuffer != NULL) /* discard buffer chain */
|
||
|
{
|
||
|
pNext = pBuffer->pLinkOlder;
|
||
|
context->dec_free(pBuffer);
|
||
|
pBuffer = pNext;
|
||
|
}
|
||
|
|
||
|
context->dec_close(Disk.Handle); /* close that file (and delete) */
|
||
|
}
|
||
|
|
||
|
|
||
|
/* --- DComp_Ring_Init() -------------------------------------------------- */
|
||
|
|
||
|
static int NEAR DComp_Ring_Init(t_decoder_context *context)
|
||
|
{
|
||
|
RINGNAME ringName;
|
||
|
PBUFFER pBuffer;
|
||
|
int cBuffers;
|
||
|
|
||
|
ringName.wildName[0] = '*';
|
||
|
ringName.wildName[1] = '\0';
|
||
|
ringName.fileSize = context->dec_window_size;
|
||
|
|
||
|
Disk.Handle = context->dec_open(
|
||
|
(char FAR *) &ringName,
|
||
|
(_O_BINARY|_O_RDWR|_O_CREAT),
|
||
|
(_S_IREAD|_S_IWRITE)
|
||
|
);
|
||
|
|
||
|
if (Disk.Handle == -1)
|
||
|
{
|
||
|
return(0); /* failed, can't make disk file */
|
||
|
}
|
||
|
|
||
|
Disk.RingPages = (int) (context->dec_window_size / BUFFER_SIZE);
|
||
|
|
||
|
if (Disk.RingPages < MIN_BUFFERS)
|
||
|
{
|
||
|
Disk.RingPages = MIN_BUFFERS; /* if DComp.WindowSize < BUFFER_SIZE */
|
||
|
}
|
||
|
|
||
|
Disk.PageTable = context->dec_malloc(sizeof(PAGETABLEENTRY) * Disk.RingPages);
|
||
|
|
||
|
if (Disk.PageTable == NULL)
|
||
|
{
|
||
|
context->dec_close(Disk.Handle); /* close the file */
|
||
|
|
||
|
return(0); /* failed, can't get page table */
|
||
|
}
|
||
|
|
||
|
Disk.pNewest = NULL;
|
||
|
|
||
|
/* DComp_Ring_Close() can be used to abort from this point on */
|
||
|
|
||
|
for (cBuffers = 0; cBuffers < Disk.RingPages; cBuffers++)
|
||
|
{
|
||
|
pBuffer = context->dec_malloc(sizeof(BUFFER));
|
||
|
|
||
|
if (pBuffer != NULL)
|
||
|
{
|
||
|
pBuffer->pLinkNewer = NULL; /* none are newer */
|
||
|
pBuffer->pLinkOlder = Disk.pNewest; /* all the others older now */
|
||
|
|
||
|
if (Disk.pNewest != NULL)
|
||
|
{
|
||
|
Disk.pNewest->pLinkNewer = pBuffer; /* old guy now knows about new */
|
||
|
}
|
||
|
else /* if nobody else */
|
||
|
{
|
||
|
Disk.pOldest = pBuffer; /* guess I'm the oldest too */
|
||
|
}
|
||
|
|
||
|
Disk.pNewest = pBuffer; /* I'm the newest */
|
||
|
}
|
||
|
else /* if pBuffer == NULL */
|
||
|
{
|
||
|
if (cBuffers < MIN_BUFFERS) /* less than minimum? */
|
||
|
{
|
||
|
DComp_Ring_Close(context); /* give it up */
|
||
|
|
||
|
return(0); /* failed, can't get min buffers */
|
||
|
}
|
||
|
else /* if we got the minimum */
|
||
|
{
|
||
|
break; /* got enough, quit trying */
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// printf("Got %d of %d ring pages\n",cBuffers,Disk.RingPages);
|
||
|
|
||
|
return(1); /* ring buffer created */
|
||
|
}
|
||
|
|
||
|
|
||
|
/* --- DComp_Ring_Literal() ----------------------------------------------- */
|
||
|
static void NEAR DComp_Ring_Literal(t_decoder_context *context, int Chr)
|
||
|
{
|
||
|
if (DComp.NumBytes)
|
||
|
{
|
||
|
DComp.NumBytes--;
|
||
|
DComp.Cur++;
|
||
|
|
||
|
*context->dec_output_curpos++ = (BYTE) Chr;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
/*
|
||
|
* Insert output buffer contents into the page table
|
||
|
*/
|
||
|
static void NEAR save_page(
|
||
|
t_decoder_context * context,
|
||
|
int page,
|
||
|
byte * data
|
||
|
)
|
||
|
{
|
||
|
PBUFFER pBuffer;
|
||
|
long iPagefileOffset;
|
||
|
|
||
|
pBuffer = Disk.PageTable[page].pBuffer; /* look up this page */
|
||
|
|
||
|
if (pBuffer != NULL) /* if it's in the table */
|
||
|
{
|
||
|
if (pBuffer != Disk.pNewest) /* promote if not newest */
|
||
|
{
|
||
|
pBuffer->pLinkNewer->pLinkOlder = pBuffer->pLinkOlder;
|
||
|
|
||
|
if (pBuffer->pLinkOlder != NULL) /* if there is someone older */
|
||
|
{
|
||
|
pBuffer->pLinkOlder->pLinkNewer = pBuffer->pLinkNewer;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
Disk.pOldest = pBuffer->pLinkNewer;
|
||
|
}
|
||
|
|
||
|
/* link into head of chain */
|
||
|
|
||
|
Disk.pNewest->pLinkNewer = pBuffer; /* newest now knows one newer */
|
||
|
pBuffer->pLinkNewer = NULL; /* nobody's newer */
|
||
|
pBuffer->pLinkOlder = Disk.pNewest; /* everybody's older */
|
||
|
Disk.pNewest = pBuffer; /* I'm the newest */
|
||
|
}
|
||
|
|
||
|
memcpy(
|
||
|
pBuffer->Buffer,
|
||
|
data,
|
||
|
BUFFER_SIZE
|
||
|
);
|
||
|
|
||
|
pBuffer->BufferDirty = 1; /* might already be dirty */
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
pBuffer = Disk.pOldest; /* choose the oldest buffer */
|
||
|
|
||
|
if (pBuffer->BufferPage != -1) /* take it out of page table */
|
||
|
{
|
||
|
Disk.PageTable[pBuffer->BufferPage].pBuffer = NULL; /* not here now */
|
||
|
|
||
|
if (pBuffer->BufferDirty) /* write on eject, if dirty */
|
||
|
{
|
||
|
iPagefileOffset = (long) pBuffer->BufferPage * BUFFER_SIZE;
|
||
|
|
||
|
if (context->dec_seek(Disk.Handle,iPagefileOffset,SEEK_SET) !=
|
||
|
iPagefileOffset)
|
||
|
{
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if (context->dec_write(Disk.Handle,pBuffer->Buffer,BUFFER_SIZE) !=
|
||
|
BUFFER_SIZE)
|
||
|
{
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
Disk.PageTable[pBuffer->BufferPage].fDiskValid = 1;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
Disk.pOldest = Disk.pOldest->pLinkNewer; /* newer is now oldest */
|
||
|
Disk.pOldest->pLinkOlder = NULL; /* oldest knows none older */
|
||
|
|
||
|
Disk.pNewest->pLinkNewer = pBuffer;
|
||
|
pBuffer->pLinkNewer = NULL; /* link into head of chain */
|
||
|
pBuffer->pLinkOlder = Disk.pNewest;
|
||
|
Disk.pNewest = pBuffer;
|
||
|
|
||
|
/* add new buffer to paging table */
|
||
|
Disk.PageTable[page].pBuffer = pBuffer; /* add new to paging table */
|
||
|
|
||
|
memcpy(
|
||
|
pBuffer->Buffer,
|
||
|
data,
|
||
|
BUFFER_SIZE
|
||
|
);
|
||
|
|
||
|
pBuffer->BufferDirty = 1;
|
||
|
pBuffer->BufferPage = page; /* our new page number */
|
||
|
}
|
||
|
|
||
|
|
||
|
static void NEAR init_last_chance_table(t_decoder_context *context)
|
||
|
{
|
||
|
int i;
|
||
|
|
||
|
for (i = 0; i < NUM_OUTPUT_BUFFER_PAGES; i++)
|
||
|
context->dec_pos_to_page[i] = -1;
|
||
|
|
||
|
context->dec_last_chance_page_to_use = NUM_OUTPUT_BUFFER_PAGES;
|
||
|
}
|
||
|
|
||
|
|
||
|
static byte * NEAR last_chance_retrieve(t_decoder_context *context, int page)
|
||
|
{
|
||
|
int used_output_pages;
|
||
|
int table_entry;
|
||
|
|
||
|
/*
|
||
|
* Where in the output buffer would our page be?
|
||
|
*/
|
||
|
table_entry = Disk.PageTable[page].last_chance_ptr;
|
||
|
|
||
|
/*
|
||
|
* It's not there
|
||
|
*/
|
||
|
if (table_entry == -1)
|
||
|
return NULL;
|
||
|
|
||
|
/*
|
||
|
* It's now an invalid entry
|
||
|
*/
|
||
|
if (context->dec_pos_to_page[table_entry] != page)
|
||
|
return NULL;
|
||
|
|
||
|
context->dec_pos_to_page[table_entry] = -1;
|
||
|
Disk.PageTable[page].last_chance_ptr = -1;
|
||
|
|
||
|
used_output_pages = (int) (((context->dec_output_curpos - context->dec_output_buffer) / BUFFER_SIZE) + 1);
|
||
|
|
||
|
if (table_entry <= used_output_pages)
|
||
|
return NULL;
|
||
|
|
||
|
return (context->dec_output_buffer + (BUFFER_SIZE * table_entry));
|
||
|
}
|
||
|
|
||
|
|
||
|
static void NEAR last_chance_store(t_decoder_context *context, int page, byte *data)
|
||
|
{
|
||
|
int used_output_pages;
|
||
|
int prev_owner;
|
||
|
int dest;
|
||
|
|
||
|
used_output_pages = (int) (((context->dec_output_curpos - context->dec_output_buffer) / BUFFER_SIZE) + 1);
|
||
|
|
||
|
if (used_output_pages >= NUM_OUTPUT_BUFFER_PAGES)
|
||
|
return;
|
||
|
|
||
|
context->dec_last_chance_page_to_use--;
|
||
|
|
||
|
if (context->dec_last_chance_page_to_use < used_output_pages)
|
||
|
context->dec_last_chance_page_to_use = NUM_OUTPUT_BUFFER_PAGES-1;
|
||
|
|
||
|
dest = context->dec_last_chance_page_to_use;
|
||
|
|
||
|
/*
|
||
|
* If any other page was pointing to this area of the buffer
|
||
|
* as a last chance page, toast them.
|
||
|
*/
|
||
|
prev_owner = context->dec_pos_to_page[dest];
|
||
|
|
||
|
if (prev_owner != -1)
|
||
|
{
|
||
|
Disk.PageTable[prev_owner].last_chance_ptr = -1;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Now we own this area
|
||
|
*/
|
||
|
Disk.PageTable[page].last_chance_ptr = dest;
|
||
|
context->dec_pos_to_page[dest] = page;
|
||
|
|
||
|
memcpy(
|
||
|
context->dec_output_buffer + (BUFFER_SIZE*dest),
|
||
|
data,
|
||
|
BUFFER_SIZE
|
||
|
);
|
||
|
}
|
||
|
|
||
|
|
||
|
void NEAR DComp_Save_Output_Pages(
|
||
|
t_decoder_context * context,
|
||
|
uint bytes_decoded
|
||
|
)
|
||
|
{
|
||
|
uint pages_to_save;
|
||
|
int page_num;
|
||
|
uint i;
|
||
|
byte * data;
|
||
|
|
||
|
/*
|
||
|
* If we managed to allocate one big buffer in the first place, then
|
||
|
* there are no ring pages to save.
|
||
|
*/
|
||
|
if (DComp.Buf != NULL)
|
||
|
return;
|
||
|
|
||
|
pages_to_save = (bytes_decoded / BUFFER_SIZE);
|
||
|
|
||
|
page_num = (int) ((context->dec_position_at_start & context->dec_window_mask) / (long) BUFFER_SIZE);
|
||
|
data = context->dec_output_buffer;
|
||
|
|
||
|
for (i = 0; i < pages_to_save; i++)
|
||
|
{
|
||
|
save_page(context, page_num, data);
|
||
|
|
||
|
page_num++;
|
||
|
|
||
|
if (page_num >= Disk.RingPages)
|
||
|
page_num = 0;
|
||
|
|
||
|
data += BUFFER_SIZE;
|
||
|
}
|
||
|
|
||
|
init_last_chance_table(context);
|
||
|
}
|
||
|
|
||
|
|
||
|
static int NEAR retrieve_page_from_disk(t_decoder_context *context, int page, byte *buffer)
|
||
|
{
|
||
|
long iPagefileOffset;
|
||
|
byte *data;
|
||
|
|
||
|
data = last_chance_retrieve(context, page);
|
||
|
|
||
|
if (data)
|
||
|
{
|
||
|
memcpy(buffer, data, BUFFER_SIZE);
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
iPagefileOffset = (long) page * BUFFER_SIZE;
|
||
|
|
||
|
if (context->dec_seek(Disk.Handle,iPagefileOffset,SEEK_SET) !=
|
||
|
iPagefileOffset)
|
||
|
{
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
if (context->dec_read(Disk.Handle,buffer,BUFFER_SIZE) !=
|
||
|
BUFFER_SIZE)
|
||
|
{
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
#ifdef DEBUG_VERIFY_LAST_CHANCE
|
||
|
/*
|
||
|
* verifies last chance data against disk page
|
||
|
*/
|
||
|
if (data)
|
||
|
{
|
||
|
int i;
|
||
|
|
||
|
for (i=0;i<BUFFER_SIZE;i++)
|
||
|
{
|
||
|
if (data[i] != buffer[i])
|
||
|
{
|
||
|
printf("page %3d, err@%5d: %3d vs %3d (real)\n",
|
||
|
page, i, data[i], buffer[i]);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
|
||
|
/* --- DComp_Ring_Load() -------------------------------------------------- */
|
||
|
|
||
|
/* Bring page into a buffer, return a pointer to that buffer. fWrite */
|
||
|
/* indicates the caller's intentions for this buffer, NZ->consider it */
|
||
|
/* dirty now. Returns NULL if there is a paging fault (callback */
|
||
|
/* failed) or if any internal assertions fail. */
|
||
|
|
||
|
static BYTE * NEAR DComp_Ring_Load(
|
||
|
t_decoder_context * context,
|
||
|
int page,
|
||
|
int fWrite
|
||
|
)
|
||
|
{
|
||
|
PBUFFER pBuffer;
|
||
|
long iPagefileOffset;
|
||
|
|
||
|
pBuffer = Disk.PageTable[page].pBuffer; /* look up this page */
|
||
|
|
||
|
if (pBuffer != NULL) /* if it's in the table */
|
||
|
{
|
||
|
if (pBuffer != Disk.pNewest) /* promote if not newest */
|
||
|
{
|
||
|
pBuffer->pLinkNewer->pLinkOlder = pBuffer->pLinkOlder;
|
||
|
|
||
|
if (pBuffer->pLinkOlder != NULL) /* if there is someone older */
|
||
|
{
|
||
|
pBuffer->pLinkOlder->pLinkNewer = pBuffer->pLinkNewer;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
Disk.pOldest = pBuffer->pLinkNewer;
|
||
|
}
|
||
|
|
||
|
/* link into head of chain */
|
||
|
|
||
|
Disk.pNewest->pLinkNewer = pBuffer; /* newest now knows one newer */
|
||
|
pBuffer->pLinkNewer = NULL; /* nobody's newer */
|
||
|
pBuffer->pLinkOlder = Disk.pNewest; /* everybody's older */
|
||
|
Disk.pNewest = pBuffer; /* I'm the newest */
|
||
|
}
|
||
|
|
||
|
pBuffer->BufferDirty |= fWrite; /* might already be dirty */
|
||
|
|
||
|
return(pBuffer->Buffer);
|
||
|
}
|
||
|
|
||
|
/* desired page is not in the table; discard oldest & use it */
|
||
|
|
||
|
pBuffer = Disk.pOldest; /* choose the oldest buffer */
|
||
|
|
||
|
if (pBuffer->BufferPage != -1) /* take it out of page table */
|
||
|
{
|
||
|
Disk.PageTable[pBuffer->BufferPage].pBuffer = NULL; /* not here now */
|
||
|
|
||
|
if (pBuffer->BufferDirty) /* write on eject, if dirty */
|
||
|
{
|
||
|
iPagefileOffset = (long) pBuffer->BufferPage * BUFFER_SIZE;
|
||
|
|
||
|
if (context->dec_seek(Disk.Handle,iPagefileOffset,SEEK_SET) !=
|
||
|
iPagefileOffset)
|
||
|
{
|
||
|
return(NULL);
|
||
|
}
|
||
|
|
||
|
if (context->dec_write(Disk.Handle,pBuffer->Buffer,BUFFER_SIZE) !=
|
||
|
BUFFER_SIZE)
|
||
|
{
|
||
|
return(NULL);
|
||
|
}
|
||
|
|
||
|
Disk.PageTable[pBuffer->BufferPage].fDiskValid = 1;
|
||
|
}
|
||
|
|
||
|
|
||
|
last_chance_store(context, pBuffer->BufferPage, pBuffer->Buffer);
|
||
|
}
|
||
|
|
||
|
Disk.pOldest = Disk.pOldest->pLinkNewer; /* newer is now oldest */
|
||
|
Disk.pOldest->pLinkOlder = NULL; /* oldest knows none older */
|
||
|
|
||
|
Disk.pNewest->pLinkNewer = pBuffer;
|
||
|
pBuffer->pLinkNewer = NULL; /* link into head of chain */
|
||
|
pBuffer->pLinkOlder = Disk.pNewest;
|
||
|
Disk.pNewest = pBuffer;
|
||
|
|
||
|
/* add new buffer to paging table */
|
||
|
|
||
|
Disk.PageTable[page].pBuffer = pBuffer; /* add new to paging table */
|
||
|
|
||
|
/* if this disk page is valid, load it */
|
||
|
|
||
|
if (Disk.PageTable[page].fDiskValid)
|
||
|
{
|
||
|
if (retrieve_page_from_disk(context, page, pBuffer->Buffer) == 0)
|
||
|
return NULL;
|
||
|
}
|
||
|
else if (!fWrite)
|
||
|
{
|
||
|
/* assertion failure, trying to load a never-written page from disk */
|
||
|
return(NULL);
|
||
|
}
|
||
|
|
||
|
pBuffer->BufferDirty = fWrite; /* might be dirty now */
|
||
|
pBuffer->BufferPage = page; /* our new page number */
|
||
|
|
||
|
return(pBuffer->Buffer); /* return new handle */
|
||
|
}
|
||
|
|
||
|
/* --- DComp_Ring_Match() ------------------------------------------------- */
|
||
|
static void NEAR DComp_Ring_Match(t_decoder_context *context, MATCH Match)
|
||
|
{
|
||
|
long SrcOffset; /* offset into output ring */
|
||
|
int SrcPage; /* page # where that offset lies */
|
||
|
int Chunk; /* number of bytes this pass */
|
||
|
BYTE FAR *SrcPtr; /* pointer to source bytes */
|
||
|
BYTE *SrcBuffer; /* buffer where source data is */
|
||
|
int SrcBufferOffset; /* offset within the buffer */
|
||
|
|
||
|
if (DComp.NumBytes >= (unsigned) Match.Len)
|
||
|
{
|
||
|
SrcOffset = (DComp.Cur - Match.Dist) & context->dec_window_mask;
|
||
|
DComp.NumBytes -= Match.Len;
|
||
|
DComp.Cur += Match.Len;
|
||
|
|
||
|
while (Match.Len)
|
||
|
{
|
||
|
/* Limit: number of bytes requested */
|
||
|
|
||
|
Chunk = Match.Len; /* try for everything */
|
||
|
|
||
|
/*
|
||
|
* Match source inside current output buffer?
|
||
|
*/
|
||
|
if (Match.Dist <= (long) (context->dec_output_curpos - context->dec_output_buffer))
|
||
|
{
|
||
|
SrcPtr = context->dec_output_curpos - Match.Dist;
|
||
|
|
||
|
while (Chunk--) /* copy this chunk */
|
||
|
{
|
||
|
*context->dec_output_curpos++ = *SrcPtr++;
|
||
|
}
|
||
|
|
||
|
return;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
SrcPage = (int) (SrcOffset / BUFFER_SIZE);
|
||
|
SrcBufferOffset = (int) (SrcOffset % BUFFER_SIZE);
|
||
|
|
||
|
SrcBuffer = DComp_Ring_Load(context,SrcPage,0); /* for reading */
|
||
|
|
||
|
if (SrcBuffer == NULL)
|
||
|
{
|
||
|
DComp.NumBytes = 0;
|
||
|
DComp.fRingFault = 1;
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
SrcPtr = SrcBuffer + SrcBufferOffset;
|
||
|
|
||
|
/* Limit: number of source bytes on input page */
|
||
|
|
||
|
if ((BUFFER_SIZE - SrcBufferOffset) < Chunk)
|
||
|
Chunk = (BUFFER_SIZE - SrcBufferOffset);
|
||
|
|
||
|
SrcOffset += Chunk;
|
||
|
SrcOffset &= context->dec_window_mask;
|
||
|
Match.Len -= Chunk;
|
||
|
|
||
|
while (Chunk--) /* copy this chunk */
|
||
|
{
|
||
|
*context->dec_output_curpos++ = *SrcPtr++;
|
||
|
}
|
||
|
}
|
||
|
} /* while Match.Len */
|
||
|
} /* if Match.Len size OK */
|
||
|
else /* match too large to fit */
|
||
|
{
|
||
|
DComp.NumBytes = 0;
|
||
|
DComp.fOutOverflow = 1;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
/* --- DComp_Ring_Reset() ------------------------------------------------- */
|
||
|
|
||
|
static void NEAR DComp_Ring_Reset(t_decoder_context *context)
|
||
|
{
|
||
|
PBUFFER walker;
|
||
|
int iPage;
|
||
|
|
||
|
for (walker = Disk.pNewest; walker != NULL; walker = walker->pLinkOlder)
|
||
|
{
|
||
|
walker->BufferPage = -1; /* buffer is not valid */
|
||
|
walker->BufferDirty = 0; /* and doesn't need writing */
|
||
|
}
|
||
|
|
||
|
for (iPage = 0; iPage < Disk.RingPages; iPage++)
|
||
|
{
|
||
|
Disk.PageTable[iPage].pBuffer = NULL; /* not in memory */
|
||
|
Disk.PageTable[iPage].fDiskValid = 0; /* not on disk */
|
||
|
Disk.PageTable[iPage].last_chance_ptr = -1; /* not in last chance list */
|
||
|
}
|
||
|
|
||
|
init_last_chance_table(context);
|
||
|
context->dec_last_chance_page_to_use = NUM_OUTPUT_BUFFER_PAGES;
|
||
|
}
|