#include #include #include #include #include #include #include #include "nmglobal.h" #include "randnum.h" /************************ ** HUFFMAN COMPRESSION ** ************************/ /* ** DEFINES */ #define EXCLUDED 32000L /* Big positive value */ /* ** TYPEDEFS */ typedef struct { unsigned char c; /* Byte value */ float freq; /* Frequency */ int parent; /* Parent node */ int left; /* Left pointer = 0 */ int right; /* Right pointer = 1 */ } huff_node; /* ** GLOBALS */ static huff_node *hufftree; /* The huffman tree */ static long plaintextlen; /* Length of plaintext */ /* ** PROTOTYPES */ static void create_text_line(char *dt,long nchars); static void create_text_block(char *tb, unsigned long tblen, unsigned short maxlinlen); static clock_t DoHuffIteration(char *plaintext, char *comparray, char *decomparray, unsigned long arraysize, unsigned long nloops, huff_node *hufftree); static void SetCompBit(uint8_t *comparray, uint32_t bitoffset, char bitchar); static int GetCompBit(uint8_t *comparray, uint32_t bitoffset); /************** ** DoHuffman ** *************** ** Execute a huffman compression on a block of plaintext. ** Note that (as with IDEA encryption) an iteration of the ** Huffman test includes a compression AND a decompression. ** Also, the compression cycle includes building the ** Huffman tree. */ void DoHuffman(void) { const char* context = "CPU:Huffman"; HuffStruct* lochuffstruct = &global_huffstruct; clock_t total_time = 0; int iterations = 0; char* comparray = NULL; char* decomparray = NULL; char* plaintext = NULL; /* ** Allocate memory for the plaintext and the compressed text. ** We'll be really pessimistic here, and allocate equal amounts ** for both (though we know...well, we PRESUME) the compressed ** stuff will take less than the plain stuff. ** Also note that we'll build a 3rd buffer to decompress ** into, and we preallocate space for the huffman tree. ** (We presume that the Huffman tree will grow no larger ** than 512 bytes. This is actually a super-conservative ** estimate...but, who cares?) */ plaintext = malloc(lochuffstruct->arraysize); if (!plaintext) { fprintf(stderr, "Error in %s, could not allocate memory. Exitting...\n", context); exit(1); } comparray = malloc(lochuffstruct->arraysize); if (!comparray) { fprintf(stderr, "Error in %s, could not allocate memory. Exitting...\n", context); free(plaintext); exit(1); /* FIXME: do I need exits here? */ } decomparray = malloc(lochuffstruct->arraysize); if (!decomparray) { fprintf(stderr, "Error in %s, could not allocate memory. Exitting...\n", context); free(plaintext); free(comparray); exit(1); } hufftree = malloc(sizeof(huff_node) * 512); if (!hufftree) { fprintf(stderr, "Error in %s, could not allocate memory. Exitting...\n", context); free(plaintext); free(comparray); free(decomparray); exit(1); } /* ** Build the plaintext buffer. Since we want this to ** actually be able to compress, we'll use the ** wordcatalog to build the plaintext stuff. */ /* ** Reset random number generator so things repeat. ** added by Uwe F. Mayer */ randnum((int32_t)13); create_text_block(plaintext,lochuffstruct->arraysize-1,(unsigned short)500); plaintext[lochuffstruct->arraysize-1L]='\0'; plaintextlen=lochuffstruct->arraysize; /* ** See if we need to perform self adjustment loop. */ if (lochuffstruct->adjust == FALSE) { lochuffstruct->adjust = TRUE; /* ** Do self-adjustment. This involves initializing the ** # of loops and increasing the loop count until we ** get a number of loops that we can use. */ for (lochuffstruct->loops = 100; lochuffstruct->loops < MAXHUFFLOOPS; lochuffstruct->loops += 10) { if (DoHuffIteration(plaintext, comparray, decomparray, lochuffstruct->arraysize, lochuffstruct->loops, hufftree) > global_min_ticks) { break; } } } do { total_time += DoHuffIteration(plaintext, comparray, decomparray, lochuffstruct->arraysize, lochuffstruct->loops, hufftree); iterations += lochuffstruct->loops; } while (total_time < lochuffstruct->request_secs * CLOCKS_PER_SEC); free(plaintext); free(comparray); free(decomparray); free(hufftree); lochuffstruct->iterspersec = (double)(iterations * CLOCKS_PER_SEC) / (double)total_time; } /********************* ** create_text_line ** ********************** ** Create a random line of text, stored at *dt. The line may be ** no more than nchars long. */ static void create_text_line(char *dt, long nchars) { long charssofar = 0; /* # of characters so far */ long tomove; /* # of characters to move */ char myword[40]; /* Local buffer for words */ char *wordptr; /* Pointer to word from catalog */ /* ** Word catalog */ #define WORDCATSIZE 50 char * wordcatarray[WORDCATSIZE] = { "Hello", "He", "Him", "the", "this", "that", "though", "rough", "cough", "obviously", "But", "but", "bye", "begin", "beginning", "beginnings", "of", "our", "ourselves", "yourselves", "to", "together", "togetherness", "from", "either", "I", "A", "return", "However", "that", "example", "yet", "quickly", "all", "if", "were", "includes", "always", "never", "not", "small", "returns", "set", "basic", "Entered", "with", "used", "shown", "you", "know" }; do { /* ** Grab a random word from the wordcatalog */ wordptr=wordcatarray[abs_randwc((int32_t)WORDCATSIZE)]; memmove(myword, wordptr, strlen(wordptr) + 1); /* ** Append a blank. */ tomove=strlen(myword)+1; myword[tomove-1]=' '; /* ** See how long it is. If its length+charssofar > nchars, we have ** to trim it. */ if((tomove+charssofar)>nchars) tomove=nchars-charssofar; /* ** Attach the word to the current line. Increment counter. */ memmove(dt, myword, tomove); charssofar+=tomove; dt+=tomove; /* ** If we're done, bail out. Otherwise, go get another word. */ } while(charssofartblen) linelen=tblen-bytessofar; if(linelen>1) { create_text_line(tb,linelen); } tb+=linelen-1; /* Add the carriage return */ *tb++='\n'; bytessofar+=linelen; } while(bytessofar>3; bitnumb=bitoffset % 8; /* ** Set or clear */ if(bitchar=='1') comparray[byteoffset]|=(1<>3; bitnumb=bitoffset % 8; /* ** Fetch */ return((1<