Search code examples
ciorun-length-encoding

program to compress a fileinto run-length code in C


I am writing a program to compress a file consisting of hexadecimal values into run-length code. For example, given a file:

46 6f 6f 20 62 61 72 21 21 21 20 20 20 20 20

my code should produce the following file:

01 46 02 6f 01 20 01 62 01 61 01 72 03 21 05 20

I don't know why the program I've written gets stuck. Any help would be appreciated.

#include <stdio.h>
#include <stdlib.h>

#define TRUE 1
#define FALSE 0

int main(void){
    int a, b, c, count=1, flag=TRUE;

    FILE *file;
    FILE *out;

    file = fopen("input.txt", "r");

    if(file){
        out = fopen("input.txt.out", "a");
        fscanf(file, "%x", &a);
        while(fscanf(file, "%x", &c)){
            while(flag==TRUE){
                if(c==a){
                    count= count+1;
                }else{
                    flag = FALSE;
                }
                b=a;
                a=c;
            }
            fprintf(out, "%d %02x ", count, b);
            count = 1;
            flag = TRUE;
        }
    }else{
        printf("ERROR: file not found.");
    }
}

EDIT: I updated the code removing the !feof(file) argument and replacing it with an actual I/O function instead. Thanks for the insight. However, my program still doesn't work.


Solution

  • I don't know why your program "gets stuck" but this might work better. Note I have dumped the meaningless a, b, c and the truth stuff.

    #include <stdio.h>
    #include <stdlib.h>
    
    int main(void){
        int lastchar, thischar, count;
    
        FILE *finp;
        FILE *fout;
        finp = fopen("input.txt", "r");
        fout = fopen("output.txt", "w");                // changed "a" to "w"
        if(fout == NULL || finp == NULL) {
            puts("Error opening file(s)");
            exit(1);
        }
    
        count = 1;
        fscanf(finp, "%x", &lastchar);
    
        while(fscanf(finp, "%x", &thischar) == 1) {     // func value better then feof
            if(thischar == lastchar) {
                count++;
            }
            else {
                fprintf(fout, "%02X %02X ", count, lastchar);
                count = 1;
            }
            lastchar = thischar;
        }
        fprintf(fout, "%02X %02X ", count, lastchar);   // discharge remaining
    
        fclose(fout);
        fclose(finp);
        return 0;
    }
    
    Program input:  46 6f 6f 20 62 61 72 21 21 21 20 20 20 20 20
    
    Program output: 01 46 02 6F 01 20 01 62 01 61 01 72 03 21 05 20 
    

    A better way of implementing RLE is to choose an "escape" value to define when a compression follows. Thus 3 values will encode a compression sequence, and so it is only worth compressing 3 or more the same. All other characters are verbatim, except the escape character itself.