Not logged in.  Login/Logout/Register | List snippets | | Create snippet | Upload image | Upload data

756
LINES

< > BotCompany Repo | #1031420 // ZPAQ decompressor, C++

Document

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<math.h>
#include<stdint.h>
#include<string>
using std::string;
typedef uint8_t U8;
typedef uint16_t U16;
typedef uint32_t U32;
typedef uint64_t U64;
template<typename T>
struct Array{
T*data;
size_t n;
Array(size_t sz=0,int ex=0):data(0),n(0){
resize(sz,ex);
}
void resize(size_t sz,int ex=0);
~Array(){
resize(0);
}
size_t size(){
return n;
}
T&operator[](size_t i){
return data[i];
}
T&operator()(size_t i){
return data[i&(n-1)];
}
}
;
template<typename T>
void Array<T>::resize(size_t sz,int ex){
if(n>0)free((char*)data);
n=0;
if(sz==0)return;
n=sz<<ex;
const size_t nb=128+n*sizeof(T);
data=(T*)calloc(nb,1);
}
typedef enum{
NONE,CONS,CM,ICM,MATCH,AVG,MIX2,MIX,ISSE,SSE}
CompType;
const int compsize[256]={
0,2,3,2,3,4,6,6,3,5}
;
struct ZP{
ZP(){
out=0;
clear();
}
void clear();
void run(U32 input){
pc=hbegin;
a=input;
while(execute());
}
int read(FILE*in2);
FILE*out;
Array<U8>hd,m;
Array<U32>h,r;
int cend,hbegin,hend,f,pc;
U32 a,b,c,d;
void init(int hbits,int mbits);
int execute();
void div(U32 x){
if(x)a/=x;
else a=0;
}
void mod(U32 x){
if(x)a%=x;
else a=0;
}
void swap(U32&x){
a^=x;
x^=a;
a^=x;
}
void swap(U8&x){
a^=x;
x^=a;
a^=x;
}
}
;
int ZP::read(FILE*in2){
int hsize=getc(in2);
hsize+=getc(in2)*256;
hd.resize(hsize+300);
cend=hbegin=hend=0;
hd[cend++]=hsize&255;
hd[cend++]=hsize>>8;
while(cend<7)hd[cend++]=getc(in2);
int n=hd[cend-1];
for(int i=0;i<n;++i){
int type=getc(in2);
hd[cend++]=type;
int size=compsize[type];
for(int j=1;j<size;++j)
hd[cend++]=getc(in2);
}
hd[cend++]=getc(in2);
hbegin=hend=cend+128;
while(hend<hsize+129){
int op=getc(in2);
hd[hend++]=op;
}
hd[hend++]=getc(in2);
return cend+hend-hbegin;
}
void ZP::clear(){
cend=hbegin=hend=0;
hd.resize(0);
a=b=c=d=f=pc=0;
h.resize(0);
m.resize(0);
r.resize(0);
}
void ZP::init(int hbits,int mbits){
a=b=c=d=f=pc=0;
h.resize(1,hbits);
m.resize(1,mbits);
r.resize(256);
}
#define C(i,L,R)\
case i:L(a R);break;\
case i+1:L(b R);break;\
case i+2:L(c R);break;\
case i+3:L(d R);break;\
case i+4:L(U32(m(b))R);break;\
case i+5:L(U32(m(c))R);break;\
case i+6:L(h(d) R);break;\
case i+7:L(U32(hd[pc++])R);break;
#define C1(i,x)\
case i:swap(x);break;\
case i+1:++x;break;\
case i+2:--x;break;\
case i+3:x=~x;break;\
case i+4:x=0;break;
int ZP::execute(){
switch(hd[pc++]){
case 7:a=r[hd[pc++]];break;
case 15:b=r[hd[pc++]];break;
case 23:c=r[hd[pc++]];break;
case 31:d=r[hd[pc++]];break;
case 39:if(f)pc+=((hd[pc]+128)&255)-127;else ++pc;break;
case 47:if(!f)pc+=((hd[pc]+128)&255)-127;else ++pc;break;
case 55:r[hd[pc++]]=a;break;
case 56:return 0;
case 57:if(out)putc(a,out);break;
case 59:a=(a+m(b)+512)*773;break;
case 60:h(d)=(h(d)+a+512)*773;break;
case 63:pc+=((hd[pc]+128)&255)-127;break;
C1(0,a)
C1(8,b)
C1(16,c)
C1(24,d)
C1(32,m(b))
C1(40,m(c))
C1(48,h(d))
C(64,a=,)
C(72,b=,)
C(80,c=,)
C(88,d=,)
C(96,m(b)=,)
C(104,m(c)=,)
C(112,h(d)=,)
C(128,a+=,)
C(136,a-=,)
C(144,a*=,)
C(152,div,)
C(160,mod,)
C(168,a&=,)
C(176,a&= ~,)
C(184,a|=,)
C(192,a^=,)
C(200,a<<=,&31)
C(208,a>>=,&31)
C(216,f=,==a)
C(224,f=,>a)
C(232,f=,<a)
}
return 1;
}
struct CP{
U32 limit,cxt,a,b,c;
Array<U32>cm;
Array<U8>ht;
Array<U16>a16;
void init();
CP(){
init();
}
}
;
void CP::init(){
limit=cxt=a=b=c=0;
cm.resize(0);
ht.resize(0);
a16.resize(0);
}
struct ST{
enum{
N=64}
;
int nns(int n0,int n1);
void ds(int&n0);
void nx(int&n0,int&n1,int y);
U8 ns[1024];
int cminit(int state){
return((ns[state*4+3]*2+1)<<22)/(ns[state*4+2]+ns[state*4+3]+1);
}
ST();
}
;
int ST::nns(int n0,int n1){
const int B=6,bound[B]={
20,48,15,8,6,5}
;
if(n0<n1)return nns(n1,n0);
if(n0<0||n1<0||n1>=B||n0>bound[n1])return 0;
return 1+(n1>0&&n0+n1<=17);
}
void ST::ds(int&n0){
n0=(n0>=1)+(n0>=2)+(n0>=3)+(n0>=4)+(n0>=5)+(n0>=7)+(n0>=8);
}
void ST::nx(int&n0,int&n1,int y){
if(n0<n1)
nx(n1,n0,1-y);
else{
if(y){
++n1;
ds(n0);
}
else{
++n0;
ds(n1);
}
while(!nns(n0,n1)){
if(n1<2)--n0;
else{
n0=(n0*(n1-1)+(n1/2))/n1;
--n1;
}
}
}
}
ST::ST(){
const int N=50;
U8 t[N][N][2]={
{
{
0}
}
}
;
int state=0;
for(int i=0;i<N;++i){
for(int n1=0;n1<=i;++n1){
int n0=i-n1;
int n=nns(n0,n1);
if(n){
t[n0][n1][0]=state;
t[n0][n1][1]=state+n-1;
state+=n;
}
}
}
memset(ns,0,sizeof(ns));
for(int n0=0;n0<N;++n0){
for(int n1=0;n1<N;++n1){
for(int y=0;y<nns(n0,n1);++y){
int s=t[n0][n1][y];
int s0=n0,s1=n1;
nx(s0,s1,0);
ns[s*4+0]=t[s0][s1][0];
s0=n0,s1=n1;
nx(s0,s1,1);
ns[s*4+1]=t[s0][s1][1];
ns[s*4+2]=n0;
ns[s*4+3]=n1;
}
}
}
}
struct PR{
PR(ZP&);
void init();
int predict();
void update(int y);
bool im(){
return z.hd[6]!=0;
}
int c8,hmap4,p[256];
U32 h[256];
ZP&z;
CP comp[256];
int dt2k[256];
int dt[1024];
U16 squasht[4096];
short stretcht[32768];
ST st;
void train(CP&cr,int y){
U32&pn=cr.cm(cr.cxt);
U32 count=pn&0x3ff;
int error=y*32767-(cr.cm(cr.cxt)>>17);
pn+=(error*dt[count]&-1024)+(count<cr.limit);
}
int squash(int x){
return squasht[x+2048];
}
int stretch(int x){
return stretcht[x];
}
int clamp2k(int x){
if(x<-2048)return -2048;
else if(x>2047)return 2047;
else return x;
}
int clamp512k(int x){
if(x<-(1<<19))return -(1<<19);
else if(x>=(1<<19))return(1<<19)-1;
else return x;
}
size_t find(Array<U8>&ht,int sizebits,U32 cxt);
}
;
PR::PR(ZP&zr):
c8(1),hmap4(1),z(zr){
dt2k[0]=0;
for(int i=1;i<256;++i)
dt2k[i]=2048/i;
for(int i=0;i<1024;++i)
dt[i]=(1<<17)/(i*2+3)*2;
for(int i=0;i<32768;++i)
stretcht[i]=int(log((i+0.5)/(32767.5-i))*64+0.5+100000)-100000;
for(int i=0;i<4096;++i)
squasht[i]=int(32768.0/(1+exp((i-2048)*(-1.0/64))));
}
void PR::init(){
z.init(z.hd[2],z.hd[3]);
for(int i=0;i<256;++i)h[i]=p[i]=0;
for(int i=0;i<256;++i)comp[i].init();
int n=z.hd[6];
const U8*cp=&z.hd[7];
for(int i=0;i<n;++i){
CP&cr=comp[i];
switch(cp[0]){
case CONS:
p[i]=(cp[1]-128)*4;
break;
case CM:
cr.cm.resize(1,cp[1]);
cr.limit=cp[2]*4;
for(size_t j=0;j<cr.cm.size();++j)
cr.cm[j]=0x80000000;
break;
case ICM:
cr.limit=1023;
cr.cm.resize(256);
cr.ht.resize(64,cp[1]);
for(size_t j=0;j<cr.cm.size();++j)
cr.cm[j]=st.cminit(j);
break;
case MATCH:
cr.cm.resize(1,cp[1]);
cr.ht.resize(1,cp[2]);
cr.ht(0)=1;
break;
case MIX2:
cr.c=(size_t(1)<<cp[1]);
cr.a16.resize(1,cp[1]);
for(size_t j=0;j<cr.a16.size();++j)
cr.a16[j]=32768;
break;
case MIX:{
int m=cp[3];
cr.c=(size_t(1)<<cp[1]);
cr.cm.resize(m,cp[1]);
for(size_t j=0;j<cr.cm.size();++j)
cr.cm[j]=65536/m;
break;
}
case ISSE:
cr.ht.resize(64,cp[1]);
cr.cm.resize(512);
for(int j=0;j<256;++j){
cr.cm[j*2]=1<<15;
cr.cm[j*2+1]=clamp512k(stretch(st.cminit(j)>>8)<<10);
}
break;
case SSE:
cr.cm.resize(32,cp[1]);
cr.limit=cp[4]*4;
for(size_t j=0;j<cr.cm.size();++j)
cr.cm[j]=squash((j&31)*64-992)<<17|cp[3];
break;
}
cp+=compsize[*cp];
}
}
int PR::predict(){
int n=z.hd[6];
const U8*cp=&z.hd[7];
for(int i=0;i<n;++i){
CP&cr=comp[i];
switch(cp[0]){
case CM:
cr.cxt=h[i]^hmap4;
p[i]=stretch(cr.cm(cr.cxt)>>17);
break;
case ICM:
if(c8==1||(c8&0xf0)==16)cr.c=find(cr.ht,cp[1]+2,h[i]+16*c8);
cr.cxt=cr.ht[cr.c+(hmap4&15)];
p[i]=stretch(cr.cm(cr.cxt)>>8);
break;
case MATCH:
if(cr.a==0)p[i]=0;
else{
cr.c=(cr.ht(cr.limit-cr.b)>>(7-cr.cxt))&1;
p[i]=stretch(dt2k[cr.a]*(cr.c*-2+1)&32767);
}
break;
case AVG:
p[i]=(p[cp[1]]*cp[3]+p[cp[2]]*(256-cp[3]))>>8;
break;
case MIX2:{
cr.cxt=((h[i]+(c8&cp[5]))&(cr.c-1));
int w=cr.a16[cr.cxt];
p[i]=(w*p[cp[2]]+(65536-w)*p[cp[3]])>>16;
}
break;
case MIX:{
int m=cp[3];
cr.cxt=h[i]+(c8&cp[5]);
cr.cxt=(cr.cxt&(cr.c-1))*m;
int*wt=(int*)&cr.cm[cr.cxt];
p[i]=0;
for(int j=0;j<m;++j)
p[i]+=(wt[j]>>8)*p[cp[2]+j];
p[i]=clamp2k(p[i]>>8);
}
break;
case ISSE:{
if(c8==1||(c8&0xf0)==16)
cr.c=find(cr.ht,cp[1]+2,h[i]+16*c8);
cr.cxt=cr.ht[cr.c+(hmap4&15)];
int*wt=(int*)&cr.cm[cr.cxt*2];
p[i]=clamp2k((wt[0]*p[cp[2]]+wt[1]*64)>>16);
}
break;
case SSE:{
cr.cxt=(h[i]+c8)*32;
int pq=p[cp[2]]+992;
if(pq<0)pq=0;
if(pq>1983)pq=1983;
int wt=pq&63;
pq>>=6;
cr.cxt+=pq;
p[i]=stretch(((cr.cm(cr.cxt)>>10)*(64-wt)+(cr.cm(cr.cxt+1)>>10)*wt)
>>13);
cr.cxt+=wt>>5;
}
}
cp+=compsize[cp[0]];
}
return squash(p[n-1]);
}
void PR::update(int y){
const U8*cp=&z.hd[7];
int n=z.hd[6];
for(int i=0;i<n;++i){
CP&cr=comp[i];
switch(cp[0]){
case CM:
train(cr,y);
break;
case ICM:{
cr.ht[cr.c+(hmap4&15)]=st.ns[cr.ht[cr.c+(hmap4&15)]*4+y];
U32&pn=cr.cm(cr.cxt);
pn+=int(y*32767-(pn>>8))>>2;
}
break;
case MATCH:
{
if(int(cr.c)!=y)cr.a=0;
cr.ht(cr.limit)+=cr.ht(cr.limit)+y;
if(++cr.cxt==8){
cr.cxt=0;
++cr.limit;
cr.limit&=(1<<cp[2])-1;
if(cr.a==0){
cr.b=cr.limit-cr.cm(h[i]);
if(cr.b&(cr.ht.size()-1))
while(cr.a<255&&cr.ht(cr.limit-cr.a-1)==cr.ht(cr.limit-cr.a-cr.b-1))
++cr.a;
}
else cr.a+=cr.a<255;
cr.cm(h[i])=cr.limit;
}
}
break;
case MIX2:{
int err=(y*32767-squash(p[i]))*cp[4]>>5;
int w=cr.a16[cr.cxt];
w+=(err*(p[cp[2]]-p[cp[3]])+(1<<12))>>13;
if(w<0)w=0;
if(w>65535)w=65535;
cr.a16[cr.cxt]=w;
}
break;
case MIX:{
int m=cp[3];
int err=(y*32767-squash(p[i]))*cp[4]>>4;
int*wt=(int*)&cr.cm[cr.cxt];
for(int j=0;j<m;++j)
wt[j]=clamp512k(wt[j]+((err*p[cp[2]+j]+(1<<12))>>13));
}
break;
case ISSE:{
int err=y*32767-squash(p[i]);
int*wt=(int*)&cr.cm[cr.cxt*2];
wt[0]=clamp512k(wt[0]+((err*p[cp[2]]+(1<<12))>>13));
wt[1]=clamp512k(wt[1]+((err+16)>>5));
cr.ht[cr.c+(hmap4&15)]=st.ns[cr.cxt*4+y];
}
break;
case SSE:
train(cr,y);
}
cp+=compsize[cp[0]];
}
c8+=c8+y;
if(c8>=256){
z.run(c8-256);
hmap4=1;
c8=1;
for(int i=0;i<n;++i)h[i]=z.h(i);
}
else if(c8>=16&&c8<32)
hmap4=(hmap4&0xf)<<5|y<<4|1;
else
hmap4=(hmap4&0x1f0)|(((hmap4&0xf)*2+y)&0xf);
}
size_t PR::find(Array<U8>&ht,int sizebits,U32 cxt){
int chk=cxt>>sizebits&255;
size_t h0=(cxt*16)&(ht.size()-16);
if(ht[h0]==chk)return h0;
size_t h1=h0^16;
if(ht[h1]==chk)return h1;
size_t h2=h0^32;
if(ht[h2]==chk)return h2;
if(ht[h0+1]<=ht[h1+1]&&ht[h0+1]<=ht[h2+1])
return memset(&ht[h0],0,16),ht[h0]=chk,h0;
else if(ht[h1+1]<ht[h2+1])
return memset(&ht[h1],0,16),ht[h1]=chk,h1;
else
return memset(&ht[h2],0,16),ht[h2]=chk,h2;
}
struct DE{
FILE*in;
DE(ZP&z);
int de();
void init();
U32 low,high;
U32 curr;
PR pr;
int decode(int p);
}
;
DE::DE(ZP&z):
in(0),low(1),high(0xFFFFFFFF),curr(0),pr(z){
}
void DE::init(){
pr.init();
if(pr.im())low=1,high=0xFFFFFFFF,curr=0;
else low=high=curr=0;
}
int DE::decode(int p){
U32 mid=low+U32(((high-low)*U64(U32(p)))>>16);
int y=curr<=mid;
if(y)high=mid;
else low=mid+1;
while((high^low)<0x1000000){
high=high<<8|255;
low=low<<8;
low+=(low==0);
curr=curr<<8|getc(in);
}
return y;
}
int DE::de(){
if(pr.im()){
if(curr==0){
for(int i=0;i<4;++i)
curr=curr<<8|getc(in);
}
if(decode(0)){
return -1;
}
else{
int c=1;
while(c<256){
int p=pr.predict()*2+1;
c+=c+decode(p);
pr.update(c&1);
}
return c-256;
}
}
else{
if(curr==0){
for(int i=0;i<4;++i)
curr=curr<<8|getc(in);
if(curr==0)return -1;
}
--curr;
return getc(in);
}
}
struct PP{
int state;
int hsize;
int ph,pm;
ZP z;
PP():state(0),hsize(0),ph(0),pm(0){
}
void init(int h,int m);
int write(int c);
}
;
void PP::init(int h,int m){
state=hsize=0;
ph=h;
pm=m;
z.clear();
}
int PP::write(int c){
switch(state){
case 0:
state=c+1;
if(state==1)z.clear();
break;
case 1:
if(c>=0&&z.out)putc(c,z.out);
break;
case 2:
hsize=c;
state=3;
break;
case 3:
hsize+=c*256;
z.hd.resize(hsize+300);
z.cend=8;
z.hbegin=z.hend=z.cend+128;
z.hd[4]=ph;
z.hd[5]=pm;
state=4;
break;
case 4:
z.hd[z.hend++]=c;
if(z.hend-z.hbegin==hsize){
hsize=z.cend-2+z.hend-z.hbegin;
z.hd[0]=hsize&255;
z.hd[1]=hsize>>8;
z.init(z.hd[4],z.hd[5]);
state=5;
}
break;
case 5:
z.run(c);
break;
}
return state;
}
struct DC{
DC():z(),dec(z),pp(),ds(0){
}
bool fb();
bool ff(string&);
void de();
ZP z;
DE dec;
PP pp;
int ds;
}
;
bool DC::fb(){
U32 h1=0x3D49B113,h2=0x29EB7F93,h3=0x2614BE13,h4=0x3828EB13;
int c;
while((c=getc(dec.in))!=EOF){
h1=h1*12+c;
h2=h2*20+c;
h3=h3*28+c;
h4=h4*44+c;
if(h1==0xB16B88F1&&h2==0xFF5376F1&&h3==0x72AC5BF1&&h4==0x2F909AF1)
break;
}
if(c<0)return false;
getc(dec.in);
getc(dec.in);
z.read(dec.in);
ds=0;
return true;
}
bool DC::ff(string&filename){
int c=getc(dec.in);
if(c==1){
while(true){
c=getc(dec.in);
if(c==0){
return true;
}
filename+=char(c);
}
}
return false;
}
void DC::de(){
while(getc(dec.in));
getc(dec.in);
if(ds==0){
dec.init();
pp.init(z.hd[4],z.hd[5]);
ds=1;
}
while((pp.state&3)!=1)
pp.write(dec.de());
while(true){
int c=dec.de();
pp.write(c);
if(c==-1)break;
}
if(getc(dec.in)==253){
for(int i=1;i<=20;++i)
getc(dec.in);
}
}
int main(int argc,char**argv){
DC d;
if(argc<2||!(d.dec.in=fopen(argv[1],"rb")))return 0;
string sout;
while(d.fb()){
while(d.ff(sout)){
if(sout!=""){
if(d.pp.z.out)fclose(d.pp.z.out);
d.pp.z.out=fopen(sout.c_str(),"wb");
sout="";
}
d.de();
}
}
return 0;
}

download  show line numbers   

Travelled to 4 computer(s): bhatertpkbcr, mqqgnosmbjvj, pyentgdyhuwx, vouqrxazstgt

No comments. add comment

Snippet ID: #1031420
Snippet name: ZPAQ decompressor, C++
Eternal ID of this version: #1031420/1
Text MD5: e5d306ed04e90a89961178559ec6be72
Author: stefan
Category: zpaq
Type: Document
Public (visible to everyone): Yes
Archived (hidden from active list): No
Created/modified: 2021-06-12 04:30:25
Source code size: 13106 bytes / 756 lines
Pitched / IR pitched: No / No
Views / Downloads: 122 / 48
Referenced in: [show references]