2

I'm currently trying to use a CMP decompressor: https://web.archive.org/web/20070113004119/http://rewiki.regengedanken.de:80/wiki/.CMP

It does in fact decompress the cmp, but it does not write it into a file. So i tried myself.

int main(int argc, char** argv)
{
    int length, dstLength;
    unsigned char* fileInMem; //compressed data
    unsigned char* dstFile; //decompressed data

    if (argc < 2) {
        fprintf(stderr, "give filename.cmp as parameter\n");
        return 1;
    }

    printf("%s", argv[1]);

    fileInMem = loadFile(argv[1], &length); //compressed data read
    if (fileInMem == NULL) {
        return 1;
    }

    dstFile = parseCmp(fileInMem, length, &dstLength); //decompress and assign data to dstFile
    if (dstFile) {
        /* Now we can save the file from dstFile, dstLength bytes */
        printf("%d bytes depacked\n", dstLength);

        for (int i = 0; i < 16; i++) {
            dataArray[i] = fileInMem[i];
        }

            FILE *writer = fopen(argv[2], "r+");
            //fputs(fileInMem, writer);
            //fputs(dstFile, writer);
         
            fclose(writer);
        free(dstFile);
    }

    free(fileInMem);

    return 0;
}

As you can see the decompressed data is a pointer to an unsigned char (according to the website a bitstream) and I tried fputs() from stdio.h, but the resulting file contains only 4 Bytes when viewed in a hex-editor.

If you need more information, please comment.

Thank you in advance.

Edit: This is what I was able to change thanks to your help, but when I open the file, it is still empty:

FILE* writer = fopen(argv[2], "wb");
fwrite(dstFile, 192, 192, writer);

192, because the length of the first decompressed Image is 192 Bytes large.

Fabian M.
  • 37
  • 6
  • 6
    `fputs` is for strings. It does not work with binary data as it will stop as soon as there is a 0 in the data (which is common in binary data). Use `fwrite`. – kaylum Mar 17 '21 at 00:23
  • I was able to output the original data with your help. The decompressed data is not written at all, but I don't think that has something to do with your answer. At least I learned something new. Thank you kaylum. – Fabian M. Mar 17 '21 at 01:33

1 Answers1

3

This is a common issue.

First, you need to open the output file writer for writing in binary mode ("wb").

FILE *writer = fopen(argv[2], "wb");

Second, you can't use fputs to write arbitrary data to a file, since it expects a string. Use fwrite instead: (assuming writer is the output file, dstFile the decompressed data and dstLength the amount of bytes to write)

fwrite(dstFile, 1, dstLength, writer);

If you examine the resulting file with an hex editor, you will see it is identical to the decompressed data.

Test-update

I wrote some test-code to see what is wrong, share your results so we can help you.

Add these functions to your code:

void printDataToScreen(unsigned char *dataptr, int datalen)
{
    if (dataptr == NULL)
    {
        printf("[!] ERROR, NULL POINTER PROVIDED!\n");
        return;
    }
    printf("> Dumping %d bytes of data into the terminal...\n", datalen);
    for (int i = 0; i < datalen; i++)
    {
        if (i % 16 == 0)
            printf("\n   ");
        printf("%02X ", dataptr[i]);
    }
    printf("\n\n");
}

void writeDataToFile(char *fileName, unsigned char *dataptr, int datalen)
{
    FILE *file = fopen(fileName, "wb");
    if (dataptr == NULL)
    {
        printf("[!] ERROR, NULL POINTER PROVIDED!\n");
        return;
    } else if (file == NULL)
    {
        printf("[!] ERROR WHILE OPENING FILE '%s'!\n", fileName);
        return;
    }
    
    printf("> Writting %d bytes of data to '%s'...\n", datalen, fileName);
    int writtenBytes = fwrite(dataptr, 1, datalen, file);
    printf("   Done, %d bytes written!\n\n", writtenBytes);
    
    fclose(file);
}

void runTest(char *fileName, unsigned char *dataptr, int datalen)
{
    printf("Running tests... [0/2 done]\n");
    printDataToScreen(dataptr, datalen);
    printf("Running tests... [1/2 done]\n");
    writeDataToFile(fileName, dataptr, datalen);
    printf("Finished! [2/2 done]\n");
}

Call it like this:

runTest(argv[2], dstFile, dstLength);

Add the call to this place in your code (comment this code, also the line where you close writer):

FILE *writer = fopen(argv[2], "r+");
//fputs(fileInMem, writer);
//fputs(dstFile, writer);

Please share your results.

  • I would add that you should try to write all at once (instead of 1 byte per byte) to minimize i/o operations that are costly for runtime. – Antonin GAVREL Mar 17 '21 at 03:11
  • @AntoninGAVREL `fwrite` is buffered, so the amount of costly system calls would only depend on the size of the stream buffer. I am not sure about using `write` since it is only POSIX (`fwrite` is ISO C). But now you got me curious to experiment and see if there is any noticeable speed difference when calling `fwrite` while swapping `size` and `nmemb` (I don't know how they are implemented TBH, but *my guess* is that there should be no noticeable difference). – Miguel Sandoval Mar 17 '21 at 04:07
  • 1
    @AntoninGAVREL After a dozen of experiments with medium-sized files (2GB), I ended up with the conclusion that swapping `size` and `nmemb` in `fwrite` has no positive effect in the runtime execution speed. (However, speed can vary *a lot* because of other factors I was unable to determinate, since the results I obtained were not very consistent). – Miguel Sandoval Mar 17 '21 at 05:14
  • could you share your benchmark on github? invite `agavrel`, would be delighted to take a look at it! – Antonin GAVREL Mar 17 '21 at 14:38
  • Thank you for your advice. I changed it to wb, but it still outputs nothing. – Fabian M. Mar 17 '21 at 17:24
  • @AntoninGAVREL Sure, I will tell you when I upload it. – Miguel Sandoval Mar 17 '21 at 18:56
  • @FabianM. If the data you want to write is 192 bytes long, then you must use `fwrite(dstFile, 1, 192, writer);`. Also, could you check if `writer` is not a `NULL` pointer before using it? – Miguel Sandoval Mar 17 '21 at 18:58
  • @FabianM. I added a test-code to help you find your bug. – Miguel Sandoval Mar 17 '21 at 20:55