mirror of
https://github.com/ultimatepp/ultimatepp.git
synced 2026-05-16 14:16:09 -06:00
163 lines
No EOL
2.9 KiB
C++
163 lines
No EOL
2.9 KiB
C++
#include "Entropy.h"
|
|
|
|
#ifndef COMPRESS2
|
|
|
|
|
|
struct Recode {
|
|
byte m;
|
|
byte h1, h2, h3;
|
|
byte l1, h1l2, h2l3;
|
|
byte filler;
|
|
};
|
|
|
|
String Compress(const char *data, const char *end)
|
|
{
|
|
int stat[256] = { 0 };
|
|
{
|
|
RTIMESTOP("Stat");
|
|
for(const char *s = data; s < end; s++)
|
|
stat[(byte)*s]++;
|
|
}
|
|
|
|
|
|
for(int i = 0; i < 256; i++) {
|
|
LOG(FChar(i) << " " << stat[i]);
|
|
}
|
|
|
|
LOG("======================");
|
|
|
|
// 0000 - 1011 most frequent 12
|
|
// 1100 0000 - 1110 1111 average 48
|
|
// 1111 0000 0000 - 1111 1111 1111 rest
|
|
|
|
byte ndx[256];
|
|
for(int i = 0; i < 256; i++)
|
|
ndx[i] = i;
|
|
|
|
IndexSort(stat, stat + 256, ndx, StdGreater<int>());
|
|
|
|
for(int m = 1; m < 15; m++) {
|
|
int mini = 0;
|
|
int big = 0;
|
|
for(int i = 0; i < 256; i++) {
|
|
if(i < m)
|
|
mini += stat[i];
|
|
if(i >= (15 - m) * 16)
|
|
big += stat[i];
|
|
// LOG(FChar(ndx[i]) << " " << stat[i]);
|
|
}
|
|
|
|
LOG("==== " << m << ":" << (15 - m) * 16 << " ===");
|
|
DUMP(mini);
|
|
DUMP(big);
|
|
DUMP((mini - big) / 2);
|
|
LOG("--------------------");
|
|
}
|
|
|
|
int mini = 0;
|
|
int big = 0;
|
|
for(int i = 0; i < 256; i++) {
|
|
if(i < 12)
|
|
mini += stat[i];
|
|
if(i >= 12 + 48)
|
|
big += stat[i];
|
|
LOG(FChar(ndx[i]) << " " << stat[i]);
|
|
}
|
|
|
|
DUMP(mini);
|
|
DUMP(big);
|
|
DUMP((mini - big) / 2);
|
|
LOG("--------------------");
|
|
|
|
Recode recode[256];
|
|
|
|
Buffer<byte> output(3 * (end - data) / 2 + 10000);
|
|
byte *t = ~output;
|
|
*t++ = 1;
|
|
Poke32le(t, (end - data));
|
|
t += 4;
|
|
for(int i = 0; i < 256; i++) {
|
|
int c = ndx[i];
|
|
LOG(i << ": " << FChar(c));
|
|
Recode& r = recode[c];
|
|
if(i < 12 + 48) {
|
|
*t++ = c;
|
|
if(i < 12) {
|
|
r.m = 1;
|
|
r.h1 = i << 4;
|
|
r.h2 = 0;
|
|
r.h3 = 0;
|
|
r.l1 = i;
|
|
// r.l2 = 0;
|
|
// r.l3 = 0;
|
|
}
|
|
else {
|
|
int q = i + 0xc0;
|
|
r.m = 2;
|
|
r.h1 = q & 0xf0;
|
|
r.h2 = (q << 4) & 0xf0;
|
|
r.h3 = 0;
|
|
r.l1 = (q >> 4) & 0x0f;
|
|
r.h1l2 = r.h1 | (q & 0x0f);
|
|
// r.l3 = 0;
|
|
}
|
|
}
|
|
else {
|
|
r.m = 3;
|
|
r.h1 = 0xf0;
|
|
r.h2 = 0xf0 & i;
|
|
r.h3 = 0xf0 & (i << 4);
|
|
r.l1 = 0x0f;
|
|
// r.l2 = 0x0f & (i >> 4);
|
|
r.h2l3 = r.h2 | (0x0f & i);
|
|
}
|
|
}
|
|
|
|
NibblePtr p;
|
|
|
|
p.Set(t);
|
|
|
|
{
|
|
RTIMESTOP("Compress");
|
|
const char *s = data;
|
|
byte g = 0;
|
|
for(;;) {
|
|
nibble0:
|
|
{
|
|
if(s >= end) break;
|
|
Recode& r = recode[(byte)*s++];
|
|
if(r.m == 1) {
|
|
g = r.h1;
|
|
goto nibble1;
|
|
}
|
|
if(r.m == 2) {
|
|
*t++ = r.h1l2;
|
|
goto nibble0;
|
|
}
|
|
*t++ = r.h1l2;
|
|
g = r.h3;
|
|
goto nibble1;
|
|
}
|
|
nibble1:
|
|
{
|
|
if(s >= end) break;
|
|
Recode& r = recode[(byte)*s++];
|
|
if(r.m == 1) {
|
|
*t++ = g | r.l1;
|
|
goto nibble0;
|
|
}
|
|
if(r.m == 2) {
|
|
*t++ = g | r.l1;
|
|
g = r.h2;
|
|
goto nibble1;
|
|
}
|
|
*t++ = g | r.l1;
|
|
*t++ = r.h2l3;
|
|
goto nibble0;
|
|
}
|
|
}
|
|
}
|
|
return String(~output, t - ~output + 1);
|
|
}
|
|
|
|
#endif |