加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
文件
克隆/下载
bsdiff.cpp 10.85 KB
一键复制 编辑 原始数据 按行查看 历史
yuchendoudou 提交于 2020-07-26 15:07 . bsdiff也打印进度条
/*-
* Copyright 2003-2005 Colin Percival
* Copyright 2020 chenkang
* All rights reserved
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted providing that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "bsdiff.h"
#include <QDebug>
#include <iostream>
#include <QMessageBox>
#define MIN(x,y) (((x)<(y)) ? (x) : (y))
static void split(off_t *I, off_t *V, off_t start, off_t len, off_t h)
{
off_t i, j, k, x, tmp, jj, kk;
if(len < 16) {
for(k = start; k < start + len; k += j) {
j = 1;
x = V[I[k] + h];
for(i = 1; k + i < start + len; i++) {
if(V[I[k+i] + h] < x) {
x = V[I[k + i] + h];
j = 0;
};
if(V[I[k + i] + h] == x) {
tmp = I[k + j];
I[k + j] = I[k + i];
I[k + i] = tmp;
j++;
};
};
for(i = 0; i < j; i++) V[I[k + i]] = k + j - 1;
if(j == 1) I[k] = -1;
};
return;
};
x = V[I[start + len / 2] + h];
jj = 0;
kk = 0;
for(i = start; i < start + len; i++) {
if(V[I[i] + h] < x) jj++;
if(V[I[i] + h] == x) kk++;
};
jj += start;
kk += jj;
i = start;
j = 0;
k = 0;
while(i < jj) {
if(V[I[i] + h] < x) {
i++;
} else if(V[I[i] + h] == x) {
tmp = I[i];
I[i] = I[jj + j];
I[jj + j] = tmp;
j++;
} else {
tmp = I[i];
I[i] = I[kk + k];
I[kk + k] = tmp;
k++;
};
};
while(jj + j < kk) {
if(V[I[jj + j] + h] == x) {
j++;
} else {
tmp = I[jj + j];
I[jj + j] = I[kk + k];
I[kk + k] = tmp;
k++;
};
};
if(jj > start) split(I, V, start, jj-start, h);
for(i = 0; i < kk - jj; i++) V[I[jj + i]] = kk - 1;
if(jj == kk - 1) I[jj] = -1;
if(start + len > kk) split(I, V, kk, start + len - kk, h);
}
static void qsufsort(off_t *I, off_t *V, uint8_t *old_data, off_t oldsize)
{
off_t buckets[256];
off_t i, h, len;
for(i = 0; i < 256; i++)
buckets[i]=0;
for(i = 0; i < oldsize; i++)
buckets[old_data[i]]++;
for(i = 1;i < 256; i++)
buckets[i] += buckets[i-1];
for(i = 255; i > 0; i--)
buckets[i] = buckets[i-1];
buckets[0]=0;
for(i = 0; i < oldsize; i++) I[++buckets[old_data[i]]] = i;
I[0] = oldsize;
for(i = 0; i < oldsize; i++) V[i] = buckets[old_data[i]];
V[oldsize] = 0;
for(i = 1; i < 256; i++) if(buckets[i] == buckets[i - 1] + 1)
I[buckets[i]] = -1;
I[0]=-1;
for(h = 1; I[0] != -(oldsize + 1); h += h) {
len = 0;
for(i = 0; i < oldsize + 1; ) {
if(I[i] < 0) {
len -= I[i];
i -= I[i];
} else {
if(len) I[i - len] = -len;
len = V[I[i]] + 1 - i;
split(I, V, i, len, h);
i += len;
len = 0;
};
};
if(len) I[i - len] = -len;
};
for(i = 0; i < oldsize + 1; i++) I[V[i]] = i;
}
static off_t matchlen(uint8_t *old_data, off_t oldsize, uint8_t *new_data, off_t newsize)
{
off_t i;
for(i = 0; (i < oldsize) && (i < newsize); i++)
if(old_data[i] != new_data[i]) break;
return i;
}
static off_t search(off_t *I, uint8_t *old_data, off_t oldsize,
uint8_t *new_data, off_t newsize, off_t st, off_t en, off_t *pos)
{
off_t x,y;
if(en - st < 2) {
x=matchlen(old_data + I[st], oldsize - I[st], new_data, newsize);
y=matchlen(old_data + I[en], oldsize - I[en], new_data, newsize);
if(x > y) {
*pos = I[st];
return x;
} else {
*pos = I[en];
return y;
}
};
x = st + (en - st) / 2;
if(memcmp(old_data + I[x], new_data, MIN(oldsize - I[x], newsize)) < 0) {
return search(I, old_data, oldsize, new_data, newsize, x, en, pos);
} else {
return search(I, old_data, oldsize, new_data, newsize, st, x, pos);
};
}
static void offtout(off_t x,uint8_t *buf)
{
off_t y = x;
buf[0] = y % 256; y -= buf[0];
y = y / 256; buf[1] = y % 256; y -= buf[1];
y = y / 256; buf[2] = y % 256; y -= buf[2];
y = y / 256; buf[3] = y % 256; y -= buf[3];
}
int bsdiff(MasterThread *func_owner, uint8_t *old_data, off_t oldsize, uint8_t *new_data,
off_t newsize, uint8_t *patch_data, off_t *patchdata_size)
{
off_t *I,*V;
off_t scan,pos = 0,len;
off_t lastscan,lastpos,lastoffset;
off_t oldscore,scsc;
off_t s,Sf,lenf,Sb,lenb;
off_t overlap,Ss,lens;
off_t i;
off_t patchdata_pos = 0;
uint8_t ctrl_data;
/* Allocate oldsize+1 bytes instead of oldsize bytes to ensure
that we never try to malloc(0) and get a NULL pointer */
if(((I = new off_t[oldsize + 1]) == NULL) ||
((V = new off_t[oldsize + 1]) == NULL)){
QMessageBox msgBox;
msgBox.setText("内存不足");
msgBox.exec();
}
qsufsort(I, V, old_data, oldsize);
delete []V;
scan = 0; len = 0;
lastscan = 0; lastpos = 0; lastoffset = 0;
while(scan < newsize) {
oldscore = 0;
emit func_owner->Complete_Rate(scan / (newsize / 50));
for(scsc = scan += len; scan < newsize; scan++) {
len = search(I, old_data, oldsize, new_data + scan, newsize - scan,
0, oldsize, &pos);
for( ; scsc < scan + len; scsc++)
if((scsc + lastoffset < oldsize) &&
(old_data[scsc + lastoffset] == new_data[scsc]))
oldscore++;
if(((len == oldscore) && (len != 0)) ||
(len > oldscore + 8)) break;
if((scan + lastoffset < oldsize) &&
(old_data[scan + lastoffset] == new_data[scan]))
oldscore--;
};
if((len != oldscore) || (scan == newsize)) {
s = 0; Sf = 0; lenf = 0;
for(i = 0; (lastscan + i < scan) && (lastpos + i < oldsize); ) {
if(old_data[lastpos + i] == new_data[lastscan + i]) s++;
i++;
if(s * 2 - i > Sf * 2 - lenf) { Sf = s; lenf = i; };
};
lenb = 0;
if(scan < newsize) {
s = 0; Sb = 0;
for(i = 1; (scan >= lastscan + i) && (pos >= i); i++) {
if(old_data[pos - i] == new_data[scan - i]) s++;
if(s * 2 - i > Sb * 2 - lenb) { Sb = s; lenb = i; };
};
};
if(lastscan + lenf > scan - lenb) {
overlap = (lastscan + lenf) - (scan - lenb);
s = 0; Ss = 0; lens = 0;
for(i = 0; i < overlap; i++) {
if(new_data[lastscan + lenf - overlap + i] ==
old_data[lastpos + lenf - overlap + i]) s++;
if(new_data[scan - lenb + i] ==
old_data[pos - lenb + i]) s--;
if(s > Ss) { Ss = s; lens = i + 1; };
};
lenf += lens - overlap;
lenb -= lens;
};
uint8_t lastpos_ctrl_len;
uint8_t diff_ctrl_len;
uint8_t extra_ctrl_len;
if(lastpos / (1 << 24)){
lastpos_ctrl_len = 3;
}
else if(lastpos / (1 << 16)){
lastpos_ctrl_len = 2;
}
else if(lastpos / (1 << 8)){
lastpos_ctrl_len = 1;
}
else{
lastpos_ctrl_len = 0;
}
ctrl_data = lastpos_ctrl_len << 6;
if(lenf / (1 << 24)){
diff_ctrl_len = 4;
}
else if(lenf / (1 << 16)){
diff_ctrl_len = 3;
}
else if(lenf / (1 << 8)){
diff_ctrl_len = 2;
}
else if(lenf > 0){
diff_ctrl_len = 1;
}
else{
diff_ctrl_len = 0;
}
ctrl_data += diff_ctrl_len << 3;
if(((scan - lenb) - (lastscan + lenf)) / (1 << 24)){
extra_ctrl_len = 4;
}
else if(((scan - lenb) - (lastscan + lenf)) / (1 << 16)){
extra_ctrl_len = 3;
}
else if(((scan - lenb) - (lastscan + lenf)) / (1 << 8)){
extra_ctrl_len = 2;
}
else if(((scan - lenb) - (lastscan + lenf)) > 0){
extra_ctrl_len = 1;
}
else{
extra_ctrl_len = 0;
}
ctrl_data += extra_ctrl_len;
if(diff_ctrl_len || extra_ctrl_len){
patch_data[patchdata_pos++] = ctrl_data;
offtout(lastpos, &patch_data[patchdata_pos]);
patchdata_pos += lastpos_ctrl_len + 1;
offtout(lenf, &patch_data[patchdata_pos]);
patchdata_pos += diff_ctrl_len;
offtout(((scan - lenb) - (lastscan + lenf)), &patch_data[patchdata_pos]);
patchdata_pos += extra_ctrl_len;
for(i = 0; i < lenf; i++)
patch_data[patchdata_pos++] = new_data[lastscan + i] - old_data[lastpos + i];
for(i = 0; i < (scan - lenb) - (lastscan + lenf); i++)
patch_data[patchdata_pos++] = new_data[lastscan + lenf + i];
}
lastscan = scan - lenb;
lastpos = pos - lenb;
lastoffset = pos - scan;
};
};
/* Free the memory we used */
delete []I;
*patchdata_size = patchdata_pos;
return patchdata_pos;
}
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化