From 2e29fc7e9a20173cb2e58bb93a72bca5e57a912d Mon Sep 17 00:00:00 2001 From: Alan Kennedy Date: Wed, 23 Jun 2004 22:24:07 +0000 Subject: [PATCH] Listo Huffman Canonico, con dos nuevos parametros s y m se permite grabar una tabla luego de una compresion (-s = save) y tambien se permite cargar una tabla/modelo antes de encodear y utilizarla, salteando el scan por supuesto (-m modelfile = carga una tabla de freq de disco). Todo esto, tanto para huff por archivo o por chunk, same deal por lo que ya esta listo para usar en el TP --- src/statichuff/main.c | 18 ++++++++-- src/statichuff/main_bychunk.c | 22 +++++++++--- src/statichuff/statichuff.c | 66 ++++++++++++++++++++++++++++------- src/statichuff/statichuff.h | 6 +++- 4 files changed, 91 insertions(+), 21 deletions(-) diff --git a/src/statichuff/main.c b/src/statichuff/main.c index d7200bb..ebb7115 100644 --- a/src/statichuff/main.c +++ b/src/statichuff/main.c @@ -7,11 +7,14 @@ int main(int argc, char* argv[]) int cflag = 0; int dflag = 0; int tflag = 0; + int mflag = 0; + int sflag = 0; long int volumesize = 0; int ch; HUFF_STATE *shuff; + char *staticmodel = NULL; - while ((ch = getopt(argc, argv, "cdt:")) != -1) { + while ((ch = getopt(argc, argv, "scdm:t:")) != -1) { switch (ch) { case 'c': cflag = 1; @@ -24,13 +27,20 @@ int main(int argc, char* argv[]) volumesize = atoi(optarg); break; - default: fprintf(stderr, "Usage: %s [-cdt] sourcefile targetfile\n", argv[0]); + case 'm': mflag = 1; + staticmodel = optarg; + break; + + case 's': sflag = 1; + break; + + default: fprintf(stderr, "Usage: %s [-cds] [-t volsizekb] sourcefile targetfile [-m modeldumpfile]\n", argv[0]); return(2); } } if ( (argc == 1) || (cflag & dflag) || !(cflag | dflag) || ((argc - optind) < 2) ) { - fprintf(stderr, "Usage: %s [-cdt] sourcefile targetfile\n", argv[0]); + fprintf(stderr, "Usage: %s [-cds] [-t volsizekb] sourcefile targetfile [-m modeldumpfile]\n", argv[0]); if ((tflag == 1) && (volumesize < 0)) fprintf(stderr,"Error: The volume size must be a non-zero value\n"); return (2); } @@ -38,7 +48,9 @@ int main(int argc, char* argv[]) if (cflag == 1) { /* Comprimo */ shuff = shuff_init_encoder_byfile(argv[optind],argv[optind+1],volumesize*1024); + if (mflag == 1) shuff_loadmodel(shuff,staticmodel); shuff_encode_file(shuff); + if (sflag == 1) shuff_savemodel(shuff); shuff_deinit_encoder(shuff); free(shuff); } diff --git a/src/statichuff/main_bychunk.c b/src/statichuff/main_bychunk.c index 12f8028..f2fca86 100644 --- a/src/statichuff/main_bychunk.c +++ b/src/statichuff/main_bychunk.c @@ -10,10 +10,13 @@ int main(int argc, char* argv[]) int cflag = 0; int dflag = 0; int tflag = 0; + int sflag = 0; + int mflag = 0; long int volumesize = 0; int lastchunk,i,j,ch,decoded = 0; + char *staticmodel; - while ((ch = getopt(argc, argv, "cdt:")) != -1) { + while ((ch = getopt(argc, argv, "scdm:t:")) != -1) { switch (ch) { case 'c': cflag = 1; @@ -26,13 +29,20 @@ int main(int argc, char* argv[]) volumesize = atoi(optarg); break; - default: fprintf(stderr, "Usage: %s [-cdt] sourcefile targetfile\n", argv[0]); + case 'm': mflag = 1; + staticmodel = optarg; + break; + + case 's': sflag = 1; + break; + + default: fprintf(stderr, "Usage: %s [-cds] [-t volsizekb] sourcefile targetfile [-m modeldumpfile]\n", argv[0]); return(2); } } - if ( (argc == 1) || (cflag & dflag) || !(cflag | dflag) || ((argc - optind) < 2) ) { - fprintf(stderr, "Usage: %s [-cdt] sourcefile targetfile\n", argv[0]); + if ( (argc == 1) || (cflag & dflag) || !(cflag | dflag) || ((argc - optind) < 2) || (mflag & sflag)) { + fprintf(stderr, "Usage: %s [-cds] [-t volsizekb] sourcefile targetfile [-m modeldumpfile]\n", argv[0]); if ((tflag == 1) && (volumesize < 0)) fprintf(stderr,"Error: The volume size must be a non-zero value\n"); return (2); } @@ -40,6 +50,7 @@ int main(int argc, char* argv[]) if (cflag == 1) { /* Inicio un compresor huffman estatico por chunks */ if ((shuff = shuff_init_encoder_bychunk(argv[optind+1],volumesize*1024)) == NULL) return 0; + if (mflag == 1) shuff_loadmodel(shuff,staticmodel); /* Comprimo por chunks */ if ((fp = fopen(argv[optind],"rb")) == NULL) return 1; @@ -56,7 +67,8 @@ int main(int argc, char* argv[]) shuff_scanfreq_chunk(shuff,chunk,i); } /* Le indico al huffman que efectivamente comprima los chunks */ - shuff_encode_file(shuff); + shuff_encode_file(shuff); + if (sflag == 1) shuff_savemodel(shuff); /* De init encoder */ shuff_deinit_encoder(shuff); diff --git a/src/statichuff/statichuff.c b/src/statichuff/statichuff.c index 2e2764a..000f0ba 100644 --- a/src/statichuff/statichuff.c +++ b/src/statichuff/statichuff.c @@ -70,15 +70,17 @@ int shuff_scanfreq_chunk(HUFF_STATE *chunkshuff, char* chunk, int chunksize) int i = 0; unsigned char symbol = 0; - /* Contamos las frecuencias del chunk*/ - for (i = 0; i < chunksize; ++i) { - symbol = chunk[i]; - chunkshuff->freqtable[symbol] += 1; - chunkshuff->sumfreq += 1; + /* Contamos las frecuencias del chunk a menos que se use un canonico */ + if (!chunkshuff->canonic) { + for (i = 0; i < chunksize; ++i) { + symbol = chunk[i]; + chunkshuff->freqtable[symbol] += 1; + chunkshuff->sumfreq += 1; - /* Si llegue al tope de freq acumulada, halve em */ - if (chunkshuff->sumfreq == 14930352) - chunkshuff->sumfreq = shuff_rescalefreq(chunkshuff->freqtable); + /* Si llegue al tope de freq acumulada, halve em */ + if (chunkshuff->sumfreq == 14930352) + chunkshuff->sumfreq = shuff_rescalefreq(chunkshuff->freqtable); + } } /* Dumpeamos el chunk en el temporal homero */ @@ -273,7 +275,8 @@ int shuff_encode_file(HUFF_STATE *shuff) SHUFFCODE *codetable = (SHUFFCODE*)malloc(sizeof(SHUFFCODE)*256); /* Veo si debo armar una freqtable o si esta preloaded */ - if (!shuff->preloadfreq) if (!shuff_scanfreq(shuff->sourcefile,shuff->freqtable)) return 0; + if ((!shuff->canonic) && (!shuff->bychunk)) + if (!shuff_scanfreq(shuff->sourcefile,shuff->freqtable)) return 0; /* Genero el arbol de huffman */ shuff->codetree = shuff_buildtree(shuff->freqtable); @@ -396,7 +399,7 @@ HUFF_STATE *shuff_init_decoder(char *inputfile, char *outputfile) /* Levanto cuantos bytes debo decodificar y la freqtable */ if ((shuff->decoderfp = vfopen(shuff->sourcefile,"r",0)) == NULL) return NULL; vfread(&(shuff->bytesleft),sizeof(unsigned long int),1,shuff->decoderfp); - vfread(shuff->freqtable,sizeof(unsigned long int),256,shuff->decoderfp); + vfread(shuff->freqtable,sizeof(t_freq),256,shuff->decoderfp); /* Armo el arbol de huffman que uso para decodificar */ shuff->codetree = shuff_buildtree(shuff->freqtable); @@ -418,7 +421,7 @@ HUFF_STATE *shuff_init_encoder_byfile(char *inputfile, char *outputfile, long vo strcpy(fshuff->targetfile,outputfile); fshuff->volsize = volsize; fshuff->bychunk = 0; - fshuff->preloadfreq = 0; + fshuff->canonic = 0; fshuff->freqtable = (t_freq*)malloc(sizeof(t_freq)*256); for (i = 0; i < 256; ++i) fshuff->freqtable[i] = 0; fshuff->sumfreq = 0; @@ -442,7 +445,7 @@ HUFF_STATE *shuff_init_encoder_bychunk(char *outputfile, long volsize) strcat(cshuff->sourcefile,"~"); cshuff->volsize = volsize; cshuff->bychunk = 1; - cshuff->preloadfreq = 1; + cshuff->canonic = 0; cshuff->freqtable = (t_freq*)malloc(sizeof(t_freq)*256); for (i = 0; i < 256; ++i) cshuff->freqtable[i] = 0; cshuff->sumfreq = 0; @@ -454,6 +457,45 @@ HUFF_STATE *shuff_init_encoder_bychunk(char *outputfile, long volsize) return cshuff; } +int shuff_loadmodel(HUFF_STATE *shuff, char *modelfile) { + + FILE *fp; + + if ((shuff) && (shuff->freqtable) && (modelfile)) { + /* Cargo el modelo de disco */ + if ((fp = fopen(modelfile,"r")) == NULL) return 0; + if (fread(shuff->freqtable,sizeof(t_freq),256,fp) != 256) return 0; + shuff->canonic = 1; + if (fp) fclose(fp); + return 1; + } + return 0; +} + +int shuff_savemodel(HUFF_STATE *shuff) { + + FILE *fp; + char *auxfilename; + char *stopchar; + + if ((shuff) && (shuff->targetfile) && (shuff->freqtable)) { + /* Preparo el nombre del archivo con la tabla */ + auxfilename = (char*)malloc(strlen(shuff->targetfile)+1); + stopchar = strrchr(shuff->targetfile,'.'); + strncpy(auxfilename,shuff->targetfile,stopchar - shuff->targetfile); + auxfilename[stopchar - shuff->targetfile] = 0; + strcat(auxfilename,".ftb"); + + /* Lo creamos y dumpeamos la tabla de frecuencias (modelo) */ + if ((fp = fopen(auxfilename,"w")) == NULL) return 0; + fwrite(shuff->freqtable,sizeof(t_freq),256,fp); + if (fp) fclose(fp); + + return 1; + } + return 0; +} + void shuff_deinit_encoder(HUFF_STATE *shuff) { /* Libero mallocs y cierro archivos */ diff --git a/src/statichuff/statichuff.h b/src/statichuff/statichuff.h index 2ae1a60..97e8f4c 100644 --- a/src/statichuff/statichuff.h +++ b/src/statichuff/statichuff.h @@ -27,7 +27,7 @@ typedef struct t_huff { char *targetfile; /* Nombre del archivo comprimido */ long volsize; /* Tamanio de volumen para multivol */ char bychunk; /* 0 works byfile, 1 works bychunk */ - char preloadfreq; /* 1 Freqtable has been preloaded (bychunk | canonic) */ + char canonic; /* 1 Huffman Canonico con preloaded freqtable */ t_freq *freqtable; /* Tabla de frecuencias */ t_freq sumfreq; /* Frecuencia total acumulada */ SHUFFNODE *codetree; /* Puntero al arbol de codigos prefijos */ @@ -44,5 +44,9 @@ void shuff_deinit_encoder(HUFF_STATE *shuff); void shuff_deinit_decoder(HUFF_STATE *shuff); int shuff_encode_file(HUFF_STATE *shuff); int shuff_decode_file(HUFF_STATE *shuff); +int shuff_scanfreq_chunk(HUFF_STATE *chunkshuff, char* chunk, int chunksize); +int shuff_decode_chunk(HUFF_STATE *shuff, char *chunk, int chunksize, int *decodedbytes); +int shuff_savemodel(HUFF_STATE *shuff); +int shuff_loadmodel(HUFF_STATE *shuff, char *modelfile); #endif /* _STATICHUFF_H_ */ -- 2.43.0