/* 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 "compression/warnmalloc.h" #include "compression/merge_sort.h" #include "compression/huffman.h" #define MAX_HUFFMAN_LEN 31 enum htree_type { htree_leaf, htree_node }; struct htree_leaf { enum htree_type nodeleaf; unsigned int idict; /* Index into input dictionary */ unsigned int prob; unsigned int bit; /* One or zero */ }; struct htree_node { enum htree_type nodeleaf; union htree_nodeleaf *n1; union htree_nodeleaf *n2; unsigned int bit; /* One or zero */ unsigned int prob; }; union htree_nodeleaf { enum htree_type nodeleaf; struct htree_node node; struct htree_leaf leaf; }; struct codelength { unsigned int code; int length; unsigned int dict; unsigned int prob; }; static int comp_htree(const void *leafptr1, const void *leafptr2, const void *private) { const union htree_nodeleaf *leaf1=(union htree_nodeleaf *)leafptr1; const union htree_nodeleaf *leaf2=(union htree_nodeleaf *)leafptr2; int rval=0; (void)private; if (leaf1->leaf.probleaf.prob) rval=1; else if (leaf1->leaf.prob>leaf2->leaf.prob) rval=-1; return rval; } static void assign_codes(union htree_nodeleaf *htree, struct codelength *codelength, unsigned int code, int length, int top) { #if 0 printf("Assign codes called with code %d length %d\n",code,length); #endif if (htree->nodeleaf==htree_leaf) { codelength[htree->leaf.idict].length=length+1; codelength[htree->leaf.idict].code=(code<<1)|htree->leaf.bit; #if 0 printf("I am a leaf: %d %d\n", codelength[htree->leaf.idict].length, codelength[htree->leaf.idict].code); #endif } else { if (!top) { code<<=1; code|=htree->node.bit; length++; } #if 0 printf("I am a node length: %d\n",length); printf("I am a node code: %d\n",code); #endif assign_codes(htree->node.n1,codelength,code,length,0); assign_codes(htree->node.n2,codelength,code,length,0); } } static void free_nodes(union htree_nodeleaf *htree, int top) { if (htree->nodeleaf==htree_leaf) { if (!top) free(htree); } else { free_nodes(htree->node.n1,0); free_nodes(htree->node.n2,0); if (!top) free(htree); } } static void flush_8bits(unsigned int *combine, unsigned char **output, int *bitptr) { while ((*bitptr)>=8) { unsigned int mask=~(0xFFU<<((*bitptr)-8)); unsigned char out=(unsigned char)((*combine)>>((*bitptr)-8)); **output=out; (*output)++; (*bitptr)-=8; (*combine)&=mask; } } static void writebits(unsigned int value,int length, unsigned char **output, int *bitptr) { unsigned int mask; unsigned int combine=(unsigned int)**output; if (length>=8) mask=0xFFU<<(length-8); else mask=0xFFU>>(8-length); while (length>8) { /* Make room for the bits. */ combine<<=8; (*bitptr)+=8; combine|=(value&mask)>>(length-8); flush_8bits(&combine,output,bitptr); length-=8; mask>>=8; } if (length) { /* Make room for the bits. */ combine<<=length; (*bitptr)+=length; combine|=value; flush_8bits(&combine,output,bitptr); } **output=(unsigned char)combine; } static unsigned int readbits(int length, unsigned char **input, int *bitptr) { unsigned int val=0U; unsigned int extract_mask=0x80U>>*bitptr; unsigned char thisval=**input; while (length--) { val<<=1; val|=((extract_mask & thisval)!=0); *bitptr=(*bitptr)+1; extract_mask>>=1; if (!extract_mask) { extract_mask=0x80U; *input=(*input)+1; *bitptr=0; thisval=**input; } } return val; } static int comp_codes(const void *codeptr1, const void *codeptr2, const void *private) { const struct codelength *code1=(struct codelength *)codeptr1; const struct codelength *code2=(struct codelength *)codeptr2; int rval=0; /* It shouldn't be possible to get equal here, though. */ (void)private; if (code1->length>code2->length) rval=1; else if (code1->lengthlength) rval=-1; else if (code1->dict>code2->dict) rval=1; else rval=-1; return rval; } static int comp_codes_value(const void *codeptr1, const void *codeptr2, const void *private) { const struct codelength *code1=(struct codelength *)codeptr1; const struct codelength *code2=(struct codelength *)codeptr2; int rval=0; /* It shouldn't be possible to get equal here, though. */ (void)private; if (code1->dict>code2->dict) rval=1; else rval=-1; return rval; } /* The huffman_dict array should be 131077 (0x20005) long. The huffman_dict_unpacked array should be 131077 long (note five longer than 0x20000) */ void Ptngc_comp_conv_to_huffman(unsigned int *vals, int nvals, unsigned int *dict, int ndict, unsigned int *prob, unsigned char *huffman, int *huffman_len, unsigned char *huffman_dict, int *huffman_dictlen, unsigned int *huffman_dict_unpacked, int *huffman_dict_unpackedlen) { int i; int nleft; union htree_nodeleaf *htree; struct codelength *codelength; int bitptr; unsigned char *huffman_ptr; int code; int longcodes=1; while (longcodes) { /* Create array of leafs (will be array of nodes/trees during buildup of tree. */ htree=warnmalloc(ndict*sizeof *htree); codelength=warnmalloc(ndict*sizeof *codelength); bitptr=0; huffman_ptr=huffman; for (i=0; i1) { union htree_nodeleaf *n1=warnmalloc(sizeof *n1); union htree_nodeleaf *n2=warnmalloc(sizeof *n2); int new_place; int p1,p2, new_prob; *n1=htree[nleft-1]; *n2=htree[nleft-2]; if (n1->nodeleaf==htree_leaf) { p1=n1->leaf.prob; n1->leaf.bit=0; } else { p1=n1->node.prob; n1->node.bit=0; } if (n2->nodeleaf==htree_leaf) { p2=n2->leaf.prob; n2->leaf.bit=1; } else { p2=n2->node.prob; n2->node.bit=1; } nleft--; /* Create a new node */ htree[nleft-1].nodeleaf=htree_node; htree[nleft-1].node.n1=n1; htree[nleft-1].node.n2=n2; new_prob=p1+p2; htree[nleft-1].node.prob=new_prob; /* Use insertion sort to place this in the correct place in the array. */ /* Where should it be inserted? */ new_place=nleft; while (new_place>0) { int pc; if (htree[new_place-1].nodeleaf==htree_node) pc=htree[new_place-1].node.prob; else pc=htree[new_place-1].leaf.prob; if (new_probMAX_HUFFMAN_LEN) longcodes=1; /* If the codes are too long alter the probabilities. */ if (longcodes) { for (i=0; i>=1; if (prob[i]==0) prob[i]=1; } /* Free codelength. We will compute a new one. */ free(codelength); } } #if 0 { for (i=0; i=0; j--) { int bit=c&mask; if (bit) printf("1"); else printf("0"); mask>>=1; } printf("\n"); } } } #endif /* Simply do compression by writing out the bits. */ for (i=0; i>8)&0xFFU); *huffman_ptr++=(unsigned char)((codelength[ndict-1].dict>>16)&0xFFU); huffman_dict_unpacked[0]=(unsigned char)(codelength[ndict-1].dict&0xFFU); huffman_dict_unpacked[1]=(unsigned char)((codelength[ndict-1].dict>>8)&0xFFU); huffman_dict_unpacked[2]=(unsigned char)((codelength[ndict-1].dict>>16)&0xFFU); for (i=0; i<=(int)codelength[ndict-1].dict; i++) { /* Do I have this value? */ int ihave=0; int j; for (j=0; j=0; j--) { int bit=c&mask; if (bit) printf("1"); else printf("0"); mask>>=1; } printf("\n"); } } } #endif /* Decompress data. */ huffman_ptr=huffman; bitptr=0; for (i=0; i