ultimatepp/uppsrc/ide/LayDes/sdiff.cpp
mdelfede 263ff5f895 changed svn layout
git-svn-id: svn://ultimatepp.org/upp/trunk@281 f0d560ea-af0d-0410-9eb7-867de7ffcac7
2008-06-07 22:31:27 +00:00

158 lines
3.1 KiB
C++

#include "LayDes.h"
static inline int sMatchLen(const char *a, const char *al, const char *b, const char *bl)
{
const char *q = a;
if(al - a < bl - b)
while(a < al && *a == *b) {
a++;
b++;
}
else
while(b < bl && *a == *b) {
a++;
b++;
}
return int(a - q);
}
unsigned HashPos(byte *s)
{
return s[0] + (s[1] << 8) + (s[2] << 16) + (s[3] << 24);
}
void DiffPacker::SetMaster(const String& m)
{
master = m;
mapn = master.GetLength() | 5;
prev.Alloc(master.GetLength(), -1);
map.Alloc(mapn, -1);
for(int i = master.GetLength() - 4; i >= 0; --i) {
int hp = HashPos((byte *)~master + i) % mapn;
prev[i] = map[hp];
map[hp] = i;
}
}
String DiffPacker::Pack(const String& data)
{
String result;
const char *masterend = master.End();
const char *dataend = data.End();
const char *s = data;
while(s < dataend) {
int pos = 0;
int ml = 0;
int p = map[HashPos((byte *)s) % mapn];
int ni = INT_MAX;
while(p >= 0 && ml < ni) {
int l = sMatchLen(s, dataend, ~master + p, masterend);
if(l > ml) {
pos = p;
ml = l;
}
p = prev[p];
ni >>= 1;
}
if(ml > 65535)
ml = 65535;
if(pos <= 255 && ml <= 255 && ml > 3) {
result.Cat(0xfb);
result.Cat(pos);
result.Cat(ml);
s += ml;
}
else
if(pos <= 65535 && ml <= 255 && ml > 4) {
result.Cat(0xfc);
result.Cat(LOBYTE(pos));
result.Cat(HIBYTE(pos));
result.Cat(ml);
s += ml;
}
else
if(pos <= 65535 && ml > 5) {
result.Cat(0xfd);
result.Cat(LOBYTE(pos));
result.Cat(HIBYTE(pos));
result.Cat(LOBYTE(ml));
result.Cat(HIBYTE(ml));
s += ml;
}
else
if(ml > 7) {
result.Cat(0xfe);
result.Cat(LOBYTE(LOWORD(pos)));
result.Cat(HIBYTE(LOWORD(pos)));
result.Cat(LOBYTE(HIWORD(pos)));
result.Cat(HIBYTE(HIWORD(pos)));
result.Cat(LOBYTE(ml));
result.Cat(HIBYTE(ml));
s += ml;
}
else {
if((byte)*s >= 0xfb)
result.Cat(0xff);
result.Cat(*s++);
}
}
result.Shrink();
return result;
}
String DiffPack(const String& master, const String& data)
{
DiffPacker p;
p.SetMaster(master);
return p.Pack(data);
}
String DiffUnpack(const String& master, const String& pack)
{
String result;
const char *s = pack;
while(s < pack.End()) {
int c = (byte)*s++;
if(c == 0xfb) {
ASSERT(s <= pack.End() - 2);
byte p = (byte)*s++;
byte l = (byte)*s++;
result.Cat(~master + p, l);
}
else
if(c == 0xfc) {
ASSERT(s <= pack.End() - 3);
byte pl = (byte)*s++;
byte ph = (byte)*s++;
byte ln = (byte)*s++;
result.Cat(~master + MAKEWORD(pl, ph), ln);
}
else
if(c == 0xfd) {
ASSERT(s <= pack.End() - 4);
byte pl = (byte)*s++;
byte ph = (byte)*s++;
byte ll = (byte)*s++;
byte lh = (byte)*s++;
result.Cat(~master + MAKEWORD(pl, ph), MAKEWORD(ll, lh));
}
else
if(c == 0xfe) {
ASSERT(s <= pack.End() - 5);
byte pll = (byte)*s++;
byte plh = (byte)*s++;
byte phl = (byte)*s++;
byte phh = (byte)*s++;
byte ll = (byte)*s++;
byte lh = (byte)*s++;
result.Cat(~master + MAKELONG(MAKEWORD(pll, plh), MAKEWORD(phl, phh)),
MAKEWORD(ll, lh));
}
else
if(c == 0xff)
result.Cat(*s++);
else
result.Cat(c);
}
return result;
}