414 lines
6.3 KiB
C++
414 lines
6.3 KiB
C++
/*
|
|
Pletter v0.5c1
|
|
|
|
XL2S Entertainment
|
|
*/
|
|
|
|
#pragma warning(disable: 4996)
|
|
|
|
#include <stdlib.h>
|
|
#include <string>
|
|
#include <iostream>
|
|
#include <cstring>
|
|
using namespace std;
|
|
|
|
unsigned char *inData;
|
|
|
|
unsigned maxlen[7] = { 128, 128+128, 512+128, 1024+128, 2048+128, 4096+128, 8192+128 };
|
|
unsigned varcost[65536];
|
|
|
|
struct metadata
|
|
{
|
|
unsigned reeks;
|
|
unsigned cpos[7], clen[7];
|
|
} *meta;
|
|
|
|
struct pakdata
|
|
{
|
|
unsigned cost, mode, mlen;
|
|
} *p[7];
|
|
|
|
string sourcefilename, destfilename;
|
|
bool savelength = false;
|
|
unsigned inLength, offset;
|
|
|
|
struct saves
|
|
{
|
|
unsigned char *outData;
|
|
int ep, dp, p, e;
|
|
void init()
|
|
{
|
|
ep = dp = p = e = 0;
|
|
outData = new unsigned char[inLength * 2];
|
|
}
|
|
void add0()
|
|
{
|
|
if (p == 0)
|
|
claimevent();
|
|
e *= 2;
|
|
++p;
|
|
if (p == 8)
|
|
addevent();
|
|
}
|
|
void add1()
|
|
{
|
|
if (p == 0)
|
|
claimevent();
|
|
e *= 2;
|
|
++p;
|
|
++e;
|
|
if (p == 8)
|
|
addevent();
|
|
}
|
|
void addbit(int b)
|
|
{
|
|
if (b)
|
|
add1();
|
|
else
|
|
add0();
|
|
}
|
|
void add3(int b)
|
|
{
|
|
addbit(b & 4);
|
|
addbit(b & 2);
|
|
addbit(b & 1);
|
|
}
|
|
void addvar(int i)
|
|
{
|
|
int j = 32768;
|
|
while (!(i & j))
|
|
j /= 2;
|
|
do
|
|
{
|
|
if (j == 1)
|
|
{
|
|
add0();
|
|
return;
|
|
}
|
|
j/=2;
|
|
add1();
|
|
if (i & j)
|
|
add1();
|
|
else
|
|
add0();
|
|
}
|
|
while (1);
|
|
}
|
|
void adddata(unsigned char d)
|
|
{
|
|
outData[dp++] = d;
|
|
}
|
|
void addevent()
|
|
{
|
|
outData[ep] = e;
|
|
e = p = 0;
|
|
}
|
|
void claimevent()
|
|
{
|
|
ep = dp;
|
|
++dp;
|
|
}
|
|
void done()
|
|
{
|
|
if (p != 0)
|
|
{
|
|
while (p != 8)
|
|
{
|
|
e *= 2;
|
|
++p;
|
|
}
|
|
addevent();
|
|
}
|
|
FILE *file;
|
|
if (!(file = fopen(destfilename.c_str(), "wb")))
|
|
{
|
|
cout << "Error writing file!\n";
|
|
exit(1);
|
|
}
|
|
fwrite(outData, 1, dp, file);
|
|
fclose(file);
|
|
cout << " " << destfilename << ": " << inLength << " -> " << dp << endl;
|
|
}
|
|
} s;
|
|
|
|
void loadfile(string sourcefilename)
|
|
{
|
|
FILE *file;
|
|
if ((file = fopen(sourcefilename.c_str(), "rb")) == NULL)
|
|
{
|
|
cout << "Error opening file:" << sourcefilename << endl;
|
|
exit(1);
|
|
}
|
|
if (!inLength)
|
|
{
|
|
fseek(file, 0, SEEK_END);
|
|
inLength = ftell(file) - offset;
|
|
}
|
|
fseek(file, offset, SEEK_SET);
|
|
inData = new unsigned char[inLength + 1];
|
|
meta = new metadata[inLength + 1];
|
|
if (!fread(inData, inLength, 1, file))
|
|
{
|
|
cout << "Filesize error" << endl;
|
|
exit(1);
|
|
}
|
|
inData[inLength] = 0;
|
|
fclose(file);
|
|
}
|
|
|
|
void initvarcost()
|
|
{
|
|
int v=1, b=1, r=1;
|
|
while (r != 65536)
|
|
{
|
|
for (int j = 0; j != r; ++j)
|
|
varcost[v++] = b;
|
|
b += 2;
|
|
r *= 2;
|
|
}
|
|
}
|
|
|
|
void createmetadata()
|
|
{
|
|
unsigned i, j;
|
|
unsigned *last = new unsigned[65536];
|
|
memset(last, -1, 65536 * sizeof(unsigned));
|
|
unsigned *prev = new unsigned[inLength + 1];
|
|
for (i = 0; i != inLength; ++i)
|
|
{
|
|
meta[i].cpos[0] = meta[i].clen[0] = 0;
|
|
prev[i] = last[inData[i] + inData[i + 1] * 256];
|
|
last[inData[i] + inData[i + 1] * 256] = i;
|
|
}
|
|
unsigned r=-1, t=0;
|
|
for (i = inLength - 1; i != -1; --i)
|
|
if (inData[i] == r)
|
|
meta[i].reeks = ++t;
|
|
else
|
|
{
|
|
r = inData[i];
|
|
meta[i].reeks = t = 1;
|
|
}
|
|
for (int bl = 0; bl != 7; ++bl)
|
|
{
|
|
for (i = 0; i < inLength; ++i)
|
|
{
|
|
unsigned l, p;
|
|
p = i;
|
|
if (bl)
|
|
{
|
|
meta[i].clen[bl] = meta[i].clen[bl - 1];
|
|
meta[i].cpos[bl] = meta[i].cpos[bl - 1];
|
|
p = i - meta[i].cpos[bl];
|
|
}
|
|
while((p = prev[p]) != -1)
|
|
{
|
|
if (i - p > maxlen[bl])
|
|
break;
|
|
l = 0;
|
|
while (inData[p + l] == inData[i + l] && (i + l) < inLength)
|
|
{
|
|
if (meta[i + l].reeks > 1)
|
|
{
|
|
if ((j = meta[i + l].reeks) > meta[p + l].reeks)
|
|
j = meta[p + l].reeks;
|
|
l+=j;
|
|
}
|
|
else
|
|
++l;
|
|
}
|
|
if (l > meta[i].clen[bl])
|
|
{
|
|
meta[i].clen[bl] = l;
|
|
meta[i].cpos[bl] = i - p;
|
|
}
|
|
}
|
|
}
|
|
cout << ".";
|
|
}
|
|
cout << " ";
|
|
// delete [] prev;
|
|
// delete [] last;
|
|
}
|
|
|
|
int getlen(pakdata *p, unsigned q)
|
|
{
|
|
unsigned i, j, cc, ccc, kc, kmode, kl;
|
|
p[inLength].cost=0;
|
|
for (i = inLength - 1; i != -1; --i)
|
|
{
|
|
kmode = 0;
|
|
kl = 0;
|
|
kc = 9 + p[i + 1].cost;
|
|
|
|
j=meta[i].clen[0];
|
|
while (j > 1)
|
|
{
|
|
cc = 9 + varcost[j - 1] + p[i + j].cost;
|
|
if (cc < kc)
|
|
{
|
|
kc = cc;
|
|
kmode = 1;
|
|
kl = j;
|
|
}
|
|
--j;
|
|
}
|
|
|
|
j = meta[i].clen[q];
|
|
if (q == 1)
|
|
ccc = 9;
|
|
else
|
|
ccc = 9 + q;
|
|
while (j > 1)
|
|
{
|
|
cc = ccc + varcost[j - 1] + p[i + j].cost;
|
|
if (cc < kc)
|
|
{
|
|
kc = cc;
|
|
kmode = 2;
|
|
kl = j;
|
|
}
|
|
--j;
|
|
}
|
|
|
|
p[i].cost=kc; p[i].mode=kmode; p[i].mlen=kl;
|
|
}
|
|
return p[0].cost;
|
|
}
|
|
|
|
void save(pakdata *p, unsigned q)
|
|
{
|
|
s.init();
|
|
unsigned i, j;
|
|
|
|
if (savelength)
|
|
{
|
|
s.adddata(inLength & 255);
|
|
s.adddata(inLength >> 8);
|
|
}
|
|
|
|
s.add3(q-1);
|
|
s.adddata(inData[0]);
|
|
|
|
i=1;
|
|
while(i<inLength)
|
|
{
|
|
switch (p[i].mode)
|
|
{
|
|
case 0:
|
|
s.add0();
|
|
s.adddata(inData[i]);
|
|
++i;
|
|
break;
|
|
case 1:
|
|
s.add1();
|
|
s.addvar(p[i].mlen - 1);
|
|
j = meta[i].cpos[0] - 1;
|
|
if (j > 127)
|
|
cout << "-j>128-";
|
|
s.adddata(j);
|
|
i += p[i].mlen;
|
|
break;
|
|
case 2:
|
|
s.add1();
|
|
s.addvar(p[i].mlen - 1);
|
|
j = meta[i].cpos[q] - 1;
|
|
if (j < 128)
|
|
cout << "-j<128-";
|
|
j -= 128;
|
|
s.adddata(128 | j & 127);
|
|
switch (q)
|
|
{
|
|
case 6: s.addbit(j & 4096);
|
|
case 5: s.addbit(j & 2048);
|
|
case 4: s.addbit(j & 1024);
|
|
case 3: s.addbit(j & 512);
|
|
case 2: s.addbit(j & 256);
|
|
s.addbit(j & 128);
|
|
case 1:
|
|
break;
|
|
default:
|
|
cout << "-2-";
|
|
break;
|
|
}
|
|
i += p[i].mlen;
|
|
break;
|
|
default:
|
|
cout << "-?-";
|
|
break;
|
|
}
|
|
}
|
|
|
|
for (i = 0; i != 34; ++i)
|
|
s.add1();
|
|
s.done();
|
|
}
|
|
|
|
int main(int argc, char *argv[])
|
|
{
|
|
if (argc == 1)
|
|
cout << endl;
|
|
cout << "Pletter v0.5c2 - www.xl2s.tk" << endl;
|
|
if (argc == 1)
|
|
{
|
|
cout << "\nUsage:\npletter [-s[ave_length]] sourcefile [[offset [inLength]] [destinationfile]]\n";
|
|
exit(0);
|
|
}
|
|
|
|
offset = 0;
|
|
inLength = 0;
|
|
|
|
int i = 1;
|
|
if (argv[i][0] == '-')
|
|
{
|
|
savelength = (argv[i][1] == 's') || (argv[i][1] == 'S');
|
|
++i;
|
|
}
|
|
if (argv[i])
|
|
sourcefilename = argv[i++];
|
|
if (argv[i] && isdigit(argv[i][0]))
|
|
{
|
|
offset=atoi(argv[i++]);
|
|
if (argv[i] && isdigit(argv[i][0]))
|
|
inLength = atoi(argv[i++]);
|
|
}
|
|
if (argv[i])
|
|
destfilename = argv[i++];
|
|
|
|
if (!sourcefilename[0])
|
|
{
|
|
cout << "No inputfile" << endl;
|
|
exit(1);
|
|
}
|
|
if (!destfilename[0])
|
|
destfilename = sourcefilename + ".plet5";
|
|
|
|
loadfile(sourcefilename);
|
|
|
|
initvarcost();
|
|
createmetadata();
|
|
|
|
int minlen = inLength * 1000;
|
|
int minbl = 0;
|
|
for(i = 1; i != 7; ++i)
|
|
{
|
|
p[i] = new pakdata[inLength + 1];
|
|
int l = getlen(p[i], i);
|
|
if (l < minlen && i)
|
|
{
|
|
minlen = l;
|
|
minbl = i;
|
|
}
|
|
cout << ".";
|
|
}
|
|
save(p[minbl], minbl);
|
|
|
|
#ifdef _DEBUG
|
|
cin.get();
|
|
#endif
|
|
|
|
return 0;
|
|
}
|
|
|
|
//eof
|