/*
** Command & Conquer Generals(tm)
** Copyright 2025 Electronic Arts Inc.
**
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program. If not, see .
*/
// Copyright (C) Electronic Arts Canada Inc. 1995-2002. All rights reserved.
#ifndef __REFWRITE
#define __REFWRITE 1
#include
#include "codex.h"
#include "refcodex.h"
/****************************************************************/
/* Internal Functions */
/****************************************************************/
static unsigned int matchlen(unsigned char *s,unsigned char *d, unsigned int maxmatch)
{
unsigned int current;
for (current=0; current (unsigned int)131071)
maxback = 131071;
hashtbl = (int *) galloc(65536L*sizeof(int));
if (!hashtbl)
return(0);
link = (int *) galloc(131072L*sizeof(int));
if (!link)
return(0);
memset(hashtbl,-1,65536L*sizeof(int));
len -= 4;
while (len>=0)
{
boffset = 0;
blen = 2;
bcost = 2;
// ccost = 0;
mlen = qmin(len,1028);
tptr=cptr-1;
hash = HASH(cptr);
hoffset = hashtbl[hash];
minhoffset = qmax(cptr-from-131071,0);
if (hoffset>=minhoffset)
{
do
{
tptr = from+hoffset;
if (cptr[blen]==tptr[blen])
{
tlen = matchlen(cptr,tptr,mlen);
if (tlen > blen)
{
toffset = (cptr-1)-tptr;
if (toffset<1024 && tlen<=10) /* two byte int form */
tcost = 2;
else if (toffset<16384 && tlen<=67) /* three byte int form */
tcost = 3;
else /* four byte very int form */
tcost = 4;
if (tlen-tcost+4 > blen-bcost+4)
{
blen = tlen;
bcost = tcost;
boffset = toffset;
if (blen>=1028) break;
}
}
}
} while ((hoffset = link[hoffset&131071]) >= minhoffset);
}
// ccost = 0;
// if ((run<4) && ((run+blen)>=4))
// ccost = 1; // extra packet cost to switch out of literal into reference
// if (bcost>blen || (blen<=2 && bcost==blen && !ccost) || (len<4))
if (bcost>=blen || len<4)
{
hoffset = (cptr-from);
link[hoffset&131071] = hashtbl[hash];
hashtbl[hash] = hoffset;
++run;
++cptr;
--len;
}
else
{
while (run>3) /* literal block of data */
{
tlen = qmin(112,run&~3);
run -= tlen;
*to++ = (unsigned char) (0xe0+(tlen>>2)-1);
memcpy(to,rptr,tlen);
rptr += tlen;
to += tlen;
++countliterals;
}
if (bcost==2) /* two byte int form */
{
*to++ = (unsigned char) (((boffset>>8)<<5) + ((blen-3)<<2) + run);
*to++ = (unsigned char) boffset;
++countshort;
}
else if (bcost==3) /* three byte int form */
{
*to++ = (unsigned char) (0x80 + (blen-4));
*to++ = (unsigned char) ((run<<6) + (boffset>>8));
*to++ = (unsigned char) boffset;
++countint;
}
else /* four byte very int form */
{
*to++ = (unsigned char) (0xc0 + ((boffset>>16)<<4) + (((blen-5)>>8)<<2) + run);
*to++ = (unsigned char) (boffset>>8);
*to++ = (unsigned char) (boffset);
*to++ = (unsigned char) (blen-5);
++countvint;
}
if (run)
{
memcpy(to, rptr, run);
to += run;
run = 0;
}
if (quick)
{
hoffset = (cptr-from);
link[hoffset&131071] = hashtbl[hash];
hashtbl[hash] = hoffset;
cptr += blen;
}
else
{
for (i=0; i < (int)blen; ++i)
{
hash = HASH(cptr);
hoffset = (cptr-from);
link[hoffset&131071] = hashtbl[hash];
hashtbl[hash] = hoffset;
++cptr;
}
}
rptr = cptr;
len -= blen;
}
}
len += 4;
run += len;
while (run>3) /* no match at end, use literal */
{
tlen = qmin(112,run&~3);
run -= tlen;
*to++ = (unsigned char) (0xe0+(tlen>>2)-1);
memcpy(to,rptr,tlen);
rptr += tlen;
to += tlen;
}
*to++ = (unsigned char) (0xfc+run); /* end of stream command + 0..3 literal */
if (run)
{
memcpy(to,rptr,run);
to += run;
}
gfree(link);
gfree(hashtbl);
return(to-dest);
}
/****************************************************************/
/* Encode Function */
/****************************************************************/
int GCALL REF_encode(void *compresseddata, const void *source, int sourcesize, int *opts)
{
int maxback=131072;
int quick=0;
int plen;
int hlen;
/* simple fb6 header */
if (sourcesize>0xffffff) // 32 bit header required
{
gputm(compresseddata, (unsigned int) 0x90fb, 2);
gputm((char *)compresseddata+2, (unsigned int) sourcesize, 4);
hlen = 6L;
}
else
{
gputm(compresseddata, (unsigned int) 0x10fb, 2);
gputm((char *)compresseddata+2, (unsigned int) sourcesize, 3);
hlen = 5L;
}
plen = hlen+refcompress((unsigned char *)source, sourcesize, (unsigned char *)compresseddata+hlen, maxback, quick);
return(plen);
}
#endif