/* This code is part of the tng compression routines. * * Written by Daniel Spangberg * Copyright (c) 2010, 2013, The GROMACS development team. * * * This program is free software; you can redistribute it and/or * modify it under the terms of the Revised BSD License. */ #include #include #include #include "../../include/compression/warnmalloc.h" #include "../../include/compression/tng_compress.h" #include "../../include/compression/bwlzh.h" #include "../../include/compression/dict.h" #include "../../include/compression/vals16.h" #include "../../include/compression/rle.h" #include "../../include/compression/mtf.h" #include "../../include/compression/bwt.h" #include "../../include/compression/lz77.h" #if 0 #define SHOWIT #endif #if 0 #define SHOWTEST #endif #define MAX_VALS_PER_BLOCK 200000 #if 1 #define PARTIAL_MTF3 #endif #if 0 #define PARTIAL_MTF #endif int bwlzh_get_buflen(const int nvals) { return 132000+nvals*8+12*((nvals+MAX_VALS_PER_BLOCK)/MAX_VALS_PER_BLOCK); } #ifdef SHOWIT static void printvals(const char *name, unsigned int *vals, const int nvals) { int i; int nvalsmax=nvals; if (nvalsmax>99) nvalsmax=99; #if 0 for (i=0; i>8)&0xFFU; output[outdata++]=(((unsigned int)nvals)>>16)&0xFFU; output[outdata++]=(((unsigned int)nvals)>>24)&0xFFU; valsleft=nvals; valstart=0; while (valsleft) { int reducealgo=1; /* Reduce algo is LZ77. */ if (!enable_lz77) reducealgo=0; thisvals=valsleft; if (thisvals>max_vals_per_block) thisvals=max_vals_per_block; valsleft-=thisvals; if (verbose) fprintf(stderr,"Creating vals16 block from %d values.\n",thisvals); #ifdef SHOWIT printvals("vals",vals+valstart,thisvals); #endif Ptngc_comp_conv_to_vals16(vals+valstart,thisvals,vals16,&nvals16); valstart+=thisvals; #ifdef SHOWTEST nvals16=99; #endif #ifdef SHOWIT printvals("vals16",vals16,nvals16); #endif if (verbose) { fprintf(stderr,"Resulting vals16 values: %d\n",nvals16); } if (verbose) { fprintf(stderr,"BWT\n"); } Ptngc_comp_to_bwt(vals16,nvals16,bwt,&bwt_index); #ifdef SHOWIT printvals("bwt",bwt,nvals16); fprintf(stderr,"BWT INDEX is %d\n",bwt_index); #endif /* Store the number of real values in this block. */ output[outdata++]=((unsigned int)thisvals)&0xFFU; output[outdata++]=(((unsigned int)thisvals)>>8)&0xFFU; output[outdata++]=(((unsigned int)thisvals)>>16)&0xFFU; output[outdata++]=(((unsigned int)thisvals)>>24)&0xFFU; /* Store the number of nvals16 values in this block. */ output[outdata++]=((unsigned int)nvals16)&0xFFU; output[outdata++]=(((unsigned int)nvals16)>>8)&0xFFU; output[outdata++]=(((unsigned int)nvals16)>>16)&0xFFU; output[outdata++]=(((unsigned int)nvals16)>>24)&0xFFU; /* Store the BWT index. */ output[outdata++]=((unsigned int)bwt_index)&0xFFU; output[outdata++]=(((unsigned int)bwt_index)>>8)&0xFFU; output[outdata++]=(((unsigned int)bwt_index)>>16)&0xFFU; output[outdata++]=(((unsigned int)bwt_index)>>24)&0xFFU; if (verbose) fprintf(stderr,"MTF\n"); #ifdef PARTIAL_MTF3 Ptngc_comp_conv_to_mtf_partial3(bwt,nvals16, mtf3); for (imtfinner=0; imtfinner<3; imtfinner++) { int i; if (verbose) fprintf(stderr,"Doing partial MTF: %d\n",imtfinner); for (i=0; i>=1; } coarse[numbits-1]+=thist[jj]; } #if 1 for (jj=0; jj>8)&0xFFU; output[outdata++]=(((unsigned int)nrle)>>16)&0xFFU; output[outdata++]=(((unsigned int)nrle)>>24)&0xFFU; /* Store the size of the huffman block. */ output[outdata++]=((unsigned int)bwlzhhufflen)&0xFFU; output[outdata++]=(((unsigned int)bwlzhhufflen)>>8)&0xFFU; output[outdata++]=(((unsigned int)bwlzhhufflen)>>16)&0xFFU; output[outdata++]=(((unsigned int)bwlzhhufflen)>>24)&0xFFU; /* Store the huffman block. */ memcpy(output+outdata,bwlzhhuff,bwlzhhufflen); outdata+=bwlzhhufflen; if (reducealgo==1) { /* Store the number of values in this block. */ output[outdata++]=((unsigned int)noffsets)&0xFFU; output[outdata++]=(((unsigned int)noffsets)>>8)&0xFFU; output[outdata++]=(((unsigned int)noffsets)>>16)&0xFFU; output[outdata++]=(((unsigned int)noffsets)>>24)&0xFFU; if (noffsets>0) { if (verbose) fprintf(stderr,"Huffman for offsets\n"); huffalgo=-1; Ptngc_comp_huff_compress_verbose(offsets,noffsets,bwlzhhuff,&bwlzhhufflen,&huffdatalen,nhufflen,&huffalgo,1); if (verbose) { int i; fprintf(stderr,"Huffman data length is %d B.\n",huffdatalen); for (i=0; i>8)&0xFFU; output[outdata++]=(((unsigned int)bwlzhhufflen)>>16)&0xFFU; output[outdata++]=(((unsigned int)bwlzhhufflen)>>24)&0xFFU; /* Store the huffman block. */ memcpy(output+outdata,bwlzhhuff,bwlzhhufflen); outdata+=bwlzhhufflen; } else { int i; output[outdata++]=1; for (i=0; i>8)&0xFFU; } if (verbose) fprintf(stderr,"Store raw offsets: %d B\n",noffsets*2); } } #if 0 { int i,ndict; FILE *f=fopen("len.dict","w"); Ptngc_comp_make_dict_hist(lens,nlens,dict,&ndict,hist); for (i=0; i>8)&0xFFU; output[outdata++]=(((unsigned int)nlens)>>16)&0xFFU; output[outdata++]=(((unsigned int)nlens)>>24)&0xFFU; /* Store the size of the huffman block. */ output[outdata++]=((unsigned int)bwlzhhufflen)&0xFFU; output[outdata++]=(((unsigned int)bwlzhhufflen)>>8)&0xFFU; output[outdata++]=(((unsigned int)bwlzhhufflen)>>16)&0xFFU; output[outdata++]=(((unsigned int)bwlzhhufflen)>>24)&0xFFU; /* Store the huffman block. */ memcpy(output+outdata,bwlzhhuff,bwlzhhufflen); outdata+=bwlzhhufflen; } #ifdef PARTIAL_MTF3 } #endif } *output_len=outdata; free(hist); free(dict); free(bwlzhhuff); #ifdef PARTIAL_MTF3 free(mtf3); #endif free(tmpmem); } void DECLSPECDLLEXPORT bwlzh_compress(unsigned int *vals, const int nvals, unsigned char *output, int *output_len) { bwlzh_compress_gen(vals,nvals,output,output_len,1,0); } void DECLSPECDLLEXPORT bwlzh_compress_verbose(unsigned int *vals, const int nvals, unsigned char *output, int *output_len) { bwlzh_compress_gen(vals,nvals,output,output_len,1,1); } void DECLSPECDLLEXPORT bwlzh_compress_no_lz77(unsigned int *vals, const int nvals, unsigned char *output, int *output_len) { bwlzh_compress_gen(vals,nvals,output,output_len,0,0); } void DECLSPECDLLEXPORT bwlzh_compress_no_lz77_verbose(unsigned int *vals, const int nvals, unsigned char *output, int *output_len) { bwlzh_compress_gen(vals,nvals,output,output_len,0,1); } static void bwlzh_decompress_gen(unsigned char *input, const int nvals, unsigned int *vals, const int verbose) { unsigned int *vals16; int nvals16; int bwt_index; unsigned int *bwt=NULL; unsigned int *mtf=NULL; #ifdef PARTIAL_MTF3 unsigned char *mtf3=NULL; int imtfinner; #endif unsigned int *rle=NULL; unsigned int *offsets=NULL; unsigned int *lens=NULL; unsigned int *dict=warnmalloc(0x20004*sizeof *dict); unsigned int *hist=warnmalloc(0x20004*sizeof *hist); int nrle, noffsets, nlens; unsigned char *bwlzhhuff=NULL; int bwlzhhufflen; int max_vals_per_block=MAX_VALS_PER_BLOCK; int valsleft; int thisvals; int valstart; int inpdata=0; int nvalsfile; unsigned int *tmpmem=warnmalloc(max_vals_per_block*18*sizeof *tmpmem); #if 0 verbose=1; #endif bwlzhhuff=warnmalloc(Ptngc_comp_huff_buflen(3*nvals)); vals16=tmpmem; bwt=tmpmem+max_vals_per_block*3; mtf=tmpmem+max_vals_per_block*6; rle=tmpmem+max_vals_per_block*9; offsets=tmpmem+max_vals_per_block*12; lens=tmpmem+max_vals_per_block*15; #ifdef PARTIAL_MTF3 mtf3=warnmalloc(max_vals_per_block*3*3*sizeof *mtf3); /* 3 due to expansion of 32 bit to 16 bit, 3 due to up to 3 bytes per 16 value. */ #endif if (verbose) { fprintf(stderr,"Number of input values: %d\n",nvals); } /* Read the number of real values in the whole block. */ nvalsfile=(int)(((unsigned int)input[inpdata]) | (((unsigned int)input[inpdata+1])<<8) | (((unsigned int)input[inpdata+2])<<16) | (((unsigned int)input[inpdata+3])<<24)); inpdata+=4; if (nvalsfile!=nvals) { fprintf(stderr,"BWLZH: The number of values found in the file is different from the number of values expected.\n"); exit(EXIT_FAILURE); } valsleft=nvals; valstart=0; while (valsleft) { int valsnew; int reducealgo; /* Read the number of real values in this block. */ thisvals=(int)(((unsigned int)input[inpdata]) | (((unsigned int)input[inpdata+1])<<8) | (((unsigned int)input[inpdata+2])<<16) | (((unsigned int)input[inpdata+3])<<24)); inpdata+=4; valsleft-=thisvals; /* Read the number of nvals16 values in this block. */ nvals16=(int)(((unsigned int)input[inpdata]) | (((unsigned int)input[inpdata+1])<<8) | (((unsigned int)input[inpdata+2])<<16) | (((unsigned int)input[inpdata+3])<<24)); inpdata+=4; /* Read the BWT index. */ bwt_index=(int)(((unsigned int)input[inpdata]) | (((unsigned int)input[inpdata+1])<<8) | (((unsigned int)input[inpdata+2])<<16) | (((unsigned int)input[inpdata+3])<<24)); inpdata+=4; if (thisvals>max_vals_per_block) { /* More memory must be allocated for decompression. */ max_vals_per_block=thisvals; if (verbose) fprintf(stderr,"Allocating more memory: %d B\n",(int)(max_vals_per_block*15*sizeof *tmpmem)); tmpmem=warnrealloc(tmpmem,max_vals_per_block*18*sizeof *tmpmem); vals16=tmpmem; bwt=tmpmem+max_vals_per_block*3; mtf=tmpmem+max_vals_per_block*6; rle=tmpmem+max_vals_per_block*9; offsets=tmpmem+max_vals_per_block*12; lens=tmpmem+max_vals_per_block*15; #ifdef PARTIAL_MTF3 mtf3=warnrealloc(mtf3,max_vals_per_block*3*3*sizeof *mtf3); /* 3 due to expansion of 32 bit to 16 bit, 3 due to up to 3 bytes per 16 value. */ #endif } #ifdef PARTIAL_MTF3 for (imtfinner=0; imtfinner<3; imtfinner++) { int i; if (verbose) fprintf(stderr,"Doing partial MTF: %d\n",imtfinner); #endif reducealgo=(int)input[inpdata]; inpdata++; /* Read the number of huffman values in this block. */ nrle=(int)(((unsigned int)input[inpdata]) | (((unsigned int)input[inpdata+1])<<8) | (((unsigned int)input[inpdata+2])<<16) | (((unsigned int)input[inpdata+3])<<24)); inpdata+=4; /* Read the size of the huffman block. */ bwlzhhufflen=(int)(((unsigned int)input[inpdata]) | (((unsigned int)input[inpdata+1])<<8) | (((unsigned int)input[inpdata+2])<<16) | (((unsigned int)input[inpdata+3])<<24)); inpdata+=4; if (verbose) fprintf(stderr,"Decompressing huffman block of length %d.\n",bwlzhhufflen); /* Decompress the huffman block. */ Ptngc_comp_huff_decompress(input+inpdata,bwlzhhufflen,rle); inpdata+=bwlzhhufflen; if (reducealgo==1) /* LZ77 */ { int offstore; /* Read the number of huffman values in this block. */ noffsets=(int)(((unsigned int)input[inpdata]) | (((unsigned int)input[inpdata+1])<<8) | (((unsigned int)input[inpdata+2])<<16) | (((unsigned int)input[inpdata+3])<<24)); inpdata+=4; if (noffsets>0) { /* How are the offsets stored? */ offstore=(int)input[inpdata++]; if (offstore==0) { /* Read the size of the huffman block. */ bwlzhhufflen=(int)(((unsigned int)input[inpdata]) | (((unsigned int)input[inpdata+1])<<8) | (((unsigned int)input[inpdata+2])<<16) | (((unsigned int)input[inpdata+3])<<24)); inpdata+=4; if (verbose) fprintf(stderr,"Decompressing offset huffman block.\n"); /* Decompress the huffman block. */ Ptngc_comp_huff_decompress(input+inpdata,bwlzhhufflen,offsets); inpdata+=bwlzhhufflen; } else { int i; if (verbose) fprintf(stderr,"Reading offset block.\n"); for (i=0; i