/* invtest.c — teste do inversor alternado com seletor (ideia v2.4). * * Cadeia A: bits originais. Cadeia B: inverte/não-inverte alternado * (t = b ^ (j&1), j = índice dentro do chunk). A cada chunk de N bits * (N = 8/16/32/64/128) codifica das duas formas com range binário order-0 * adaptativo (modelos zerados no início do chunk, dos dois lados iguais), * escolhe a menor e grava 1 bit seletor (0=A, 1=B). * Formato: [INVB][N:u8][mode:u8][nbits:u64][sellen:u32][sel][paylen:u32][payload] * mode: 0=auto (com seletor), 1=força A, 2=força B (sem seletor, controle). */ #include #include #include #include #include #define INVB_MAGIC 0x42564E49u /* "INVB" LE */ /* ---- LE helpers ---- */ static void w32(FILE *f, uint32_t v){ uint8_t b[4]; b[0]=v; b[1]=v>>8; b[2]=v>>16; b[3]=v>>24; fwrite(b,1,4,f); } static void w64(FILE *f, uint64_t v){ uint8_t b[8]; for(int i=0;i<8;i++) b[i]=(uint8_t)(v>>(8*i)); fwrite(b,1,8,f); } static int r32(FILE *f, uint32_t *o){ uint8_t b[4]; if(fread(b,1,4,f)!=4) return 0; *o=b[0]|((uint32_t)b[1]<<8)|((uint32_t)b[2]<<16)|((uint32_t)b[3]<<24); return 1; } static int r64(FILE *f, uint64_t *o){ uint8_t b[8]; if(fread(b,1,8,f)!=8) return 0; uint64_t v=0; for(int i=0;i<8;i++) v|=(uint64_t)b[i]<<(8*i); *o=v; return 1; } /* ---- núcleo range bytewise (mesmo da v2.3, provado por roundtrip) ---- */ typedef struct { uint32_t f[2]; uint32_t tot; } BModel; static void bmodel_init(BModel *m){ m->f[0]=m->f[1]=1; m->tot=2; } static void bmodel_rescale(BModel *m){ m->f[0]=(m->f[0]+1)>>1; m->f[1]=(m->f[1]+1)>>1; if(!m->f[0])m->f[0]=1; if(!m->f[1])m->f[1]=1; m->tot=m->f[0]+m->f[1]; } typedef struct { FILE *f; uint64_t low; uint32_t range; uint8_t cache; uint32_t cacheSize; } RCW; static void rcw_init(RCW *e, FILE *f){ e->f=f; e->low=0; e->range=0xFFFFFFFFu; e->cache=0; e->cacheSize=1; } static void rcw_shift(RCW *e){ if((uint32_t)e->low < 0xFF000000u || (e->low >> 32) != 0){ uint8_t tmp = e->cache; do { fputc((int)(tmp + (uint8_t)(e->low >> 32)), e->f); tmp = 0xFF; } while(--e->cacheSize != 0); e->cache = (uint8_t)(((uint32_t)e->low >> 24) & 0xFF); } e->cacheSize++; e->low = (uint64_t)(uint32_t)(e->low << 8); } static void rcb_encode(RCW *e, BModel *m, int bit){ uint32_t cum = bit ? m->f[0] : 0; uint32_t fs = bit ? m->f[1] : m->f[0]; uint32_t total = m->tot; e->low += (uint64_t)cum * (e->range /= total); e->range *= fs; while(e->range < 0x01000000u){ rcw_shift(e); e->range <<= 8; } m->f[bit]++; m->tot++; if(m->tot > 512) bmodel_rescale(m); } static void rcw_flush(RCW *e){ for(int i=0;i<5;i++){ rcw_shift(e); e->range <<= 8; } } typedef struct { const uint8_t *p; size_t n, pos; uint32_t code, range; } RCMem; static void rcp_init(RCMem *d, const uint8_t *buf, size_t n){ d->p=buf; d->n=n; d->pos=0; d->code=0; d->range=0xFFFFFFFFu; for(int i=0;i<5 && d->poscode=(d->code<<8)|d->p[d->pos++]; } } static int rcb_decode(RCMem *d, BModel *m){ uint32_t total = m->tot; uint32_t count = d->code / (d->range /= total); int bit = (count >= m->f[0]) ? 1 : 0; uint32_t cum = bit ? m->f[0] : 0; d->code -= cum * d->range; d->range *= bit ? m->f[1] : m->f[0]; while(d->range < 0x01000000u){ uint8_t b = (d->posn)? d->p[d->pos++] : 0; d->code = (d->code<<8)|b; d->range <<= 8; } m->f[bit]++; m->tot++; if(m->tot > 512) bmodel_rescale(m); return bit; } /* ---- bits de arquivo (MSB primeiro) ---- */ static uint8_t *file_to_bits(const char *path, uint64_t *nbits){ FILE *f=fopen(path,"rb"); if(!f) return NULL; fseek(f,0,SEEK_END); long nb=ftell(f); fseek(f,0,SEEK_SET); if(nb<=0){ fclose(f); return NULL; } uint8_t *raw=malloc(nb); if(fread(raw,1,nb,f)!=(size_t)nb){ fclose(f); free(raw); return NULL; } fclose(f); uint8_t *bits=malloc((size_t)nb*8); for(long i=0;i>(7-k))&1; free(raw); *nbits=(uint64_t)nb*8; return bits; } static int bits_to_file(const char *path, const uint8_t *bits, uint64_t nbits){ FILE *f=fopen(path,"wb"); if(!f) return 1; uint64_t nb=(nbits+7)/8; for(uint64_t i=0;if[bit] / (float)m->tot; if(p < 0.0005f) p = 0.0005f; return -256.0f * log2f(p); } /* modo 3: juiz implícito por chunk. Modelos contínuos (sem reset), notas com decaimento. Escolha do chunk = função pura do passado -> decoder reproduz sem nenhum bit lateral. */ #define JUDGE_DECAY 0.99f /* custo com freqs explícitas (p/ estado pré-update salvo) */ static float bitcost_f(uint32_t f0, uint32_t f1, uint32_t tot, int bit){ float p = (float)(bit?f1:f0)/(float)tot; if(p < 0.0005f) p = 0.0005f; return -256.0f * log2f(p); } /* ---- modo 3/4: juiz implícito (0 bit lateral). reset=0: modelos contínuos; reset=1: modelos zerados por chunk (notas do juiz contínuas) ---- */ static int do_compress3(const char *in, const char *out, int N, int reset){ uint64_t nbits=0; uint8_t *bits=file_to_bits(in,&nbits); if(!bits){ printf("open fail\n"); return 1; } uint64_t nch=(nbits+N-1)/N; FILE *pay=tmpfile(); if(!pay){ free(bits); return 1; } RCW e; rcw_init(&e,pay); BModel mA, mB; bmodel_init(&mA); bmodel_init(&mB); float sA=0, sB=0; uint64_t picksB=0; for(uint64_t c=0;c512) bmodel_rescale(&mA); } else { mB.f[tb]++; mB.tot++; if(mB.tot>512) bmodel_rescale(&mB); } } } rcw_flush(&e); fflush(pay); long paylen=ftell(pay); FILE *f=fopen(out,"wb"); if(!f){ free(bits); fclose(pay); return 1; } w32(f,INVB_MAGIC); fputc(N,f); fputc(reset?4:3,f); w64(f,nbits); w32(f,0); w32(f,(uint32_t)paylen); if(paylen>0){ rewind(pay); uint8_t cb[4096]; long left=paylen; while(left>0){ size_t w=(size_t)(left>4096?4096:left); size_t g=fread(cb,1,w,pay); if(!g) break; fwrite(cb,1,g,f); left-=g; } } fclose(f); fclose(pay); free(bits); printf("INVB N=%d mode=%d: bits=%llu chunks=%llu B=%llu pay=%ld sel=0 total=%ld\n", N,reset?4:3,(unsigned long long)nbits,(unsigned long long)nch,(unsigned long long)picksB,paylen, (long)(4+1+1+8+4+4+paylen)); return 0; } static int do_decompress3(const char *in, const char *out, int reset){ FILE *f=fopen(in,"rb"); if(!f){ printf("open fail\n"); return 1; } uint32_t mg=0; if(!r32(f,&mg)||mg!=INVB_MAGIC){ printf("bad magic\n"); fclose(f); return 1; } int N=fgetc(f), mode=fgetc(f); uint64_t nbits=0; uint32_t sellen=0, paylen=0; if((mode!=3&&mode!=4)||!r64(f,&nbits)||!r32(f,&sellen)||sellen!=0){ fclose(f); return 1; } if(!r32(f,&paylen)){ fclose(f); return 1; } uint8_t *pay=malloc(paylen?paylen:1); if(paylen && fread(pay,1,paylen,f)!=paylen){ fclose(f); free(pay); return 1; } fclose(f); RCMem d; rcp_init(&d,pay,paylen); uint8_t *bits=malloc((size_t)(nbits?nbits:1)); BModel mA, mB; bmodel_init(&mA); bmodel_init(&mB); float sA=0, sB=0; uint64_t nch=(nbits+N-1)/N; for(uint64_t c=0;cf[0], q1=mu->f[1], qt=mu->tot; int t=rcb_decode(&d,mu); if(t<0){ printf("range fault chunk %llu\n",(unsigned long long)c); free(pay); free(bits); return 1; } int b=useB?(t^(j&1)):t, tb=b^(j&1); float cA, cB; if(useB){ cB=bitcost_f(q0,q1,qt,t); cA=bitcost(&mA,b); } else { cA=bitcost_f(q0,q1,qt,b); cB=bitcost(&mB,tb); } #ifdef JDBG2 if(c==1) fprintf(stderr,"D j=%d b=%d t=%d A=[%u %u %u] cA=%.3f B=[%u %u %u] cB=%.3f\n", j,b,t,mA.f[0],mA.f[1],mA.tot,cA,mB.f[0],mB.f[1],mB.tot,cB); #endif sA=sA*JUDGE_DECAY+cA; sB=sB*JUDGE_DECAY+cB; bits[pos+j]=(uint8_t)b; if(useB){ mA.f[b]++; mA.tot++; if(mA.tot>512) bmodel_rescale(&mA); } else { mB.f[tb]++; mB.tot++; if(mB.tot>512) bmodel_rescale(&mB); } } } int rc=bits_to_file(out,bits,nbits); free(pay); free(bits); if(!rc) printf("INVB decode OK N=%d mode=%d bits=%llu\n",N,reset?4:3,(unsigned long long)nbits); return rc; } /* forward: modos 3/4/5 definidos após do_decompress */ static int do_compress3(const char *in, const char *out, int N, int reset); static int do_decompress3(const char *in, const char *out, int reset); static int do_compress5(const char *in, const char *out, int N); static int do_decompress5(const char *in, const char *out); static int do_compress(const char *in, const char *out, int N, int mode){ uint64_t nbits=0; uint8_t *bits=file_to_bits(in,&nbits); if(!bits){ printf("open fail\n"); return 1; } uint64_t nch=(nbits+N-1)/N; uint8_t *sel=(uint8_t*)calloc((size_t)((nch+7)/8),1); FILE *pay=tmpfile(); if(!pay){ free(bits); free(sel); return 1; } RCW e; rcw_init(&e,pay); BModel mA, mB; for(uint64_t c=0;c>3]|=(uint8_t)(1<<(c&7)); } else useB=(mode==2); /* regra determinística: zera os dois no início do chunk, atualiza o usado */ bmodel_init(&mA); bmodel_init(&mB); BModel *m = useB ? &mB : &mA; for(int j=0;j0){ rewind(pay); uint8_t cb[4096]; long left=paylen; while(left>0){ size_t w=(size_t)(left>4096?4096:left); size_t g=fread(cb,1,w,pay); if(!g) break; fwrite(cb,1,g,f); left-=g; } } fclose(f); fclose(pay); free(bits); free(sel); printf("INVB N=%d mode=%d: bits=%llu chunks=%llu pay=%ld sel=%u total=%ld\n", N,mode,(unsigned long long)nbits,(unsigned long long)nch,paylen,sellen, (long)(4+1+1+8+4+sellen+4+paylen)); return 0; } static int do_decompress(const char *in, const char *out){ FILE *f=fopen(in,"rb"); if(!f){ printf("open fail\n"); return 1; } uint32_t mg=0; if(!r32(f,&mg)||mg!=INVB_MAGIC){ printf("bad magic\n"); fclose(f); return 1; } int N=fgetc(f), mode=fgetc(f); uint64_t nbits=0; uint32_t sellen=0, paylen=0; if(mode==3||mode==4){ fclose(f); return do_decompress3(in,out,mode==4); } if(mode==5){ fclose(f); return do_decompress5(in,out); } if(!r64(f,&nbits)||!r32(f,&sellen)){ fclose(f); return 1; } uint8_t *sel=NULL; if(sellen){ sel=malloc(sellen); if(fread(sel,1,sellen,f)!=sellen){ fclose(f); return 1; } } if(!r32(f,&paylen)){ fclose(f); free(sel); return 1; } uint8_t *pay=malloc(paylen?paylen:1); if(paylen && fread(pay,1,paylen,f)!=paylen){ fclose(f); free(sel); free(pay); return 1; } fclose(f); RCMem d; rcp_init(&d,pay,paylen); uint8_t *bits=malloc((size_t)(nbits?nbits:1)); BModel mA, mB; uint64_t nch=(nbits+N-1)/N; for(uint64_t c=0;c>3]>>(c&7))&1):(mode==2); bmodel_init(&mA); bmodel_init(&mB); BModel *m = useB ? &mB : &mA; for(int j=0;j512) bmodel_rescale(&mA); } else { mB[prev].f[b]++; mB[prev].tot++; if(mB[prev].tot>512) bmodel_rescale(&mB[prev]); } prev=b; } } rcw_flush(&e); fflush(pay); long paylen=ftell(pay); FILE *f=fopen(out,"wb"); if(!f){ free(bits); fclose(pay); return 1; } w32(f,INVB_MAGIC); fputc(N,f); fputc(5,f); w64(f,nbits); w32(f,0); w32(f,(uint32_t)paylen); if(paylen>0){ rewind(pay); uint8_t cb[4096]; long left=paylen; while(left>0){ size_t w=(size_t)(left>4096?4096:left); size_t g=fread(cb,1,w,pay); if(!g) break; fwrite(cb,1,g,f); left-=g; } } fclose(f); fclose(pay); free(bits); printf("INVB N=%d mode=5: bits=%llu chunks=%llu B=%llu pay=%ld sel=0 total=%ld\n", N,(unsigned long long)nbits,(unsigned long long)nch,(unsigned long long)picksB,paylen, (long)(4+1+1+8+4+4+paylen)); return 0; } static int do_decompress5(const char *in, const char *out){ FILE *f=fopen(in,"rb"); if(!f){ printf("open fail\n"); return 1; } uint32_t mg=0; if(!r32(f,&mg)||mg!=INVB_MAGIC){ printf("bad magic\n"); fclose(f); return 1; } int N=fgetc(f), mode=fgetc(f); uint64_t nbits=0; uint32_t sellen=0, paylen=0; if(mode!=5||!r64(f,&nbits)||!r32(f,&sellen)||sellen!=0){ fclose(f); return 1; } if(!r32(f,&paylen)){ fclose(f); return 1; } uint8_t *pay=malloc(paylen?paylen:1); if(paylen && fread(pay,1,paylen,f)!=paylen){ fclose(f); free(pay); return 1; } fclose(f); RCMem d; rcp_init(&d,pay,paylen); uint8_t *bits=malloc((size_t)(nbits?nbits:1)); BModel mA, mB[2]; bmodel_init(&mA); bmodel_init(&mB[0]); bmodel_init(&mB[1]); float sA=0, sB=0; int prev=0; uint64_t nch=(nbits+N-1)/N; for(uint64_t c=0;cf[0], q1=mu->f[1], qt=mu->tot; int t=rcb_decode(&d,mu); if(t<0){ printf("range fault chunk %llu\n",(unsigned long long)c); free(pay); free(bits); return 1; } int b=t; float cA, cB; if(useB){ cB=bitcost_f(q0,q1,qt,b); cA=bitcost(&mA,b); } else { cA=bitcost_f(q0,q1,qt,b); cB=bitcost(&mB[prev],b); } sA=sA*JUDGE_DECAY+cA; sB=sB*JUDGE_DECAY+cB; bits[pos+j]=(uint8_t)b; if(useB){ mA.f[b]++; mA.tot++; if(mA.tot>512) bmodel_rescale(&mA); } else { mB[prev].f[b]++; mB[prev].tot++; if(mB[prev].tot>512) bmodel_rescale(&mB[prev]); } prev=b; } } int rc=bits_to_file(out,bits,nbits); free(pay); free(bits); if(!rc) printf("INVB decode OK N=%d mode=5 bits=%llu\n",N,(unsigned long long)nbits); return rc; } int main(int argc,char**argv){ if(argc==6 && strcmp(argv[1],"-c")==0){ int NN=atoi(argv[2]), MM=atoi(argv[3]); if(MM==3) return do_compress3(argv[4],argv[5],NN,0); if(MM==4) return do_compress3(argv[4],argv[5],NN,1); if(MM==5) return do_compress5(argv[4],argv[5],NN); return do_compress(argv[4],argv[5],NN,MM); } if(argc==4 && strcmp(argv[1],"-d")==0) return do_decompress(argv[2],argv[3]); printf("Uso:\n %s -c N modo entrada saida (N=8/16/32/64/128, modo 0=auto 1=A 2=B)\n %s -d entrada saida\n",argv[0],argv[0]); return 1; }